Created
February 15, 2013 06:52
-
-
Save mattn/4958880 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"title": "Big Sky", | |
"link": "http://mattn.kaoriya.net/", | |
"id": "tag:mattn.kaoriya.net,2008:/", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"updated": "2013-02-13T22:47:22+09:00", | |
"subtitle": "システム開発屋がひっそり語るぼやき", | |
"generator": "http://www.blosxom.com/?v=2.0", | |
"entries": [ | |
{ | |
"title": "boost::context のビルドでハマった。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20130213164417.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/c/20130213164417", | |
"summary": "\\nBoost 1.53 が<a href=\"http://www.boost.org/users/history/version_1_53_0.html\">リリースされた</a>ので入れた。<br />\\n新しく追加されたライブラリ。\\n\\n<ul>\\n\\t<li>Atomic: C++11-style atomic<> from Helge Bahmann, maintained by Tim Blechmann.</li>\\n\\t<li>Coroutine: Coroutine library, from Oliver Kowalke.</li>\\n\\t<li>Lockfree: Lockfree data structures, from Tim Blechmann.</li>\\n\\t<li>Multiprecision: Extended precision arithmetic types for floating point, integer and rational arithmetic from John Maddock and Christopher Kormanyos.</li>\\n\\t<li>Odeint: Solving ordinary differential equations, from Karsten Ahnert and Mario Mulansky.</li>\\n</ul>\\n\\n非同期関連が増えて面白くなってきた。<br />\\n試しに boost::coroutine 使おうと思ったら boost::context の make_fcontext と jump_fcontext がアセンブラでシンボルエクスポートされてなさげ。普段は <a href=\"http://www.masm32.com/\">masm</a> にパスを通しているのだけど、どうやら VC 付属の ml じゃないと駄目らしい。<br />\\n気付くまでハマった。。。<br />\\n<br />\\nようやく動くようになった。\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/coroutine/coroutine.hpp></span><br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain(){<br />\\n <span class=\"Type\">typedef</span> boost::coroutines::coroutine<std::string()> ctype;<br />\\n<br />\\n ctype<br />\\n c([] (ctype::caller_type &yeild) {<br />\\n <span class=\"Statement\">for</span> (<span class=\"Type\">int</span> i = <span class=\"Constant\">0</span>; i < <span class=\"Constant\">10</span>; i++){<br />\\n yeild(i % <span class=\"Constant\">2</span> == <span class=\"Constant\">0</span> ? <span class=\"Constant\">"フル"</span> : <span class=\"Constant\">"チン</span><span class=\"Special\">\\n</span><span class=\"Constant\">"</span>);<br />\\n }<br />\\n });<br />\\n<br />\\n <span class=\"Statement\">while</span>(c) {<br />\\n std::cout << c.get();<br />\\n c();<br />\\n }<br />\\n<br />\\n <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n}<br />\\n</blockquote>\\n実行結果\\n<blockquote class=\"code\">\\nフルチン<br />\\nフルチン<br />\\nフルチン<br />\\nフルチン<br />\\nフルチン<br />\\n</blockquote>\\nブーストフルーチンでは無いので注意。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "boost, c++", | |
"published": "2013-02-13T16:45:00+09:00" | |
}, | |
{ | |
"title": "日本語プログラミング言語「なでしこ」で LTSV パーサ書いた", | |
"link": "http://mattn.kaoriya.net/software/lang/nadesiko/20130208170356.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/nadesiko/20130208170356", | |
"summary": "\\n日本人なら日本語だろ!!<br />\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://nadesi.com/\">日本語プログラム言語「なでしこ」公式ページ</a>\\n\\t<br>\\n\\t<p>「PC Online」に執筆していたコラム(へのリンク)が、PBSupport さんのページで、FM用(FileMaker)のデータベースとして公開されました。 これは、クジラ飛行机「文系サラリーマン...</p>\\n\\t<cite>http://nadesi.com/</cite>\\n</blockquote>\\n\\n\\n<blockquote class=\"code\">\\n<span class=\"Comment\">#!cnako</span><br />\\n<br />\\nデータとはハッシュ<br />\\n「hoge:foo bar:baz time:20:30:58」を「\\t」で正規表現区切る<br />\\nそれを反復<br />\\n それを「^([^:]+):(.*)」で正規表現マッチ<br />\\n データ@抽出文字列[0]は抽出文字列[1]<br />\\n<br />\\nデータを表示<br />\\n</blockquote>\\n\\n実行結果\\n\\n<blockquote class=\"code\">\\ntime=20:30:58<br />\\nbar=baz<br />\\nhoge=foo<br />\\n</blockquote>\\n\\n参考資料\\n\\n<ul>\\n<li><a href=\"http://d.hatena.ne.jp/naoya/20130207/1360240992\">【今北産業】3分で分かるLTSV業界のまとめ【LTSV】 - naoyaのはてなダイアリー</a></li>\\n<li><a href=\"http://ltsv.org/\">Labeled Tab-separated Values (LTSV)</a></li>\\n</ul>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "LTSV, 誰得, なでしこ", | |
"published": "2013-02-08T17:04:00+09:00" | |
}, | |
{ | |
"title": "どるるでむるびぃをらん", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130206180229.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130206180229", | |
"summary": "\\nDLL(どるる)でmruby(むるびぃ)を実行(らん)してやったぜ!<br />\\ncremno さんが mruby-dll という、mruby.dll を作るバッチファイルその他を作ってくれたので試した。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/cremno/mruby-dll\">cremno/mruby-dll - GitHub</a>\\n\\t<br>\\n\\t<p>a quick-and-dirty script that creates mruby.dll</p>\\n\\t<cite>https://github.com/cremno/mruby-dll</cite>\\n</blockquote>\\n\\nmruby.dll の作り方はプロジェクトの README.md を見ていただくとして、これを使ったアプリケーションを書いてみた。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><windows.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><stdio.h></span><br />\\n<br />\\n<span class=\"PreProc\">#define _(x) #x</span><br />\\n<br />\\n<span class=\"Type\">typedef</span> <span class=\"Type\">struct</span> mrb_value {<br />\\n <span class=\"Type\">char</span> _[<span class=\"Constant\">16</span>];<br />\\n} mrb_value;<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain(<span class=\"Type\">int</span> argc, <span class=\"Type\">char</span>* argv[]) {<br />\\n HMODULE hmruby = LoadLibrary(<span class=\"Constant\">"mruby.dll"</span>);<br />\\n <span class=\"Type\">void</span>* (*mrb_open)();<br />\\n <span class=\"Type\">void</span> (*mrb_close)(<span class=\"Type\">void</span>*);<br />\\n mrb_value (*mrb_load_string)(<span class=\"Type\">void</span>*,<span class=\"Type\">const</span> <span class=\"Type\">char</span>*);<br />\\n <span class=\"Type\">void</span>* mrb;<br />\\n <span class=\"Type\">void</span>* ctx;<br />\\n <br />\\n mrb_open = (<span class=\"Type\">void</span>* (*)()) GetProcAddress(hmruby, <span class=\"Constant\">"mrb_open"</span>);<br />\\n mrb_close = (<span class=\"Type\">void</span> (*)(<span class=\"Type\">void</span>*)) GetProcAddress(hmruby, <span class=\"Constant\">"mrb_close"</span>);<br />\\n mrb_load_string = (mrb_value (*)(<span class=\"Type\">void</span>*,<span class=\"Type\">const</span> <span class=\"Type\">char</span>*)) GetProcAddress(hmruby, <span class=\"Constant\">"mrb_load_string"</span>);<br />\\n<br />\\n mrb = mrb_open();<br />\\n mrb_load_string(mrb, _(<br />\\n \\n<br />\\ndef fizz_buzz_factory \\n<br />\\n i = <span class=\"Constant\">0</span> \\n<br />\\n Proc.new <span class=\"Statement\">do</span> \\n<br />\\n i += <span class=\"Constant\">1</span> \\n<br />\\n <span class=\"Statement\">case</span> \\n<br />\\n when i % <span class=\"Constant\">15</span> == <span class=\"Constant\">0</span> then <span class=\"Constant\">"FizzBuzz"</span> \\n<br />\\n when i % <span class=\"Constant\">5</span> == <span class=\"Constant\">0</span> then <span class=\"Constant\">"Buzz"</span> \\n<br />\\n when i % <span class=\"Constant\">3</span> == <span class=\"Constant\">0</span> then <span class=\"Constant\">"Fizz"</span> \\n<br />\\n <span class=\"Statement\">else</span> i \\n<br />\\n end \\n<br />\\n end \\n<br />\\nend \\n<br />\\n \\n<br />\\nfb = fizz_buzz_factory \\n<br />\\n \\n<br />\\n(<span class=\"Constant\">1..100</span>).to_a.each <span class=\"Statement\">do</span> \\n<br />\\n puts fb.call \\n<br />\\nend \\n<br />\\n<br />\\n));<br />\\n<br />\\n mrb_close(mrb);<br />\\n<br />\\n FreeLibrary(hmruby);<br />\\n <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n}<br />\\n</blockquote>\\n\\n単純に DLL をロードしてコールする物。mruby.h を使わずやりたかったので mrb_value を固定 16 バイトに。<br />\\n<br />\\n実行するとちゃんと FizzBuzz 出力されます。<br />\\nmrb_load_string の戻り値が構造体の実体なので、この DLL だけを使うにはおそらく FFI が書ける使える LL くらいしか無いと思いますが、遊ぶには十分だと思います。<br />\\n<br />\\nいい大人なので、ちゃんと発音しましょう。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mruby", | |
"published": "2013-02-06T18:03:00+09:00" | |
}, | |
{ | |
"title": "突然の死に備える Apache モジュール書いた。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20130205124719.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/c/20130205124719", | |
"summary": "\\nサーバを運用していらっしゃる方であれば、サービスの停止は死に値します。<br />\\n大事な事なのでもう一度言います。<br />\\n<br />\\n<h3>サーバを運用していらっしゃる方であれば、サービスの停止は死に値します。</h3>\\n<br />\\nサーバ管理者は皆、突然の死に備えるべきです。<br />\\n<br />\\nそんな過酷な場面に立ち向かうサーバ管理者の皆さんの苦労を少しでも軽減する為に、apache モジュールを書きました。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/mod_suddendeath\">mattn/mod_suddendeath - GitHub</a>\\n\\t<br />\\n\\t<p>突然の死!</p>\\n\\t<cite>https://github.com/mattn/mod_suddendeath</cite>\\n</blockquote>\\n\\nまずコンパイルしてインストールします。\\n\\n<blockquote class=\"code\">\\napxs -ci mod_suddendeath.c -lhttpd -lapr-1<br />\\n</blockquote>\\n\\nそして apache を再起動します。<br />\\n<br />\\nサービスが動作しているディレクトリの <code>.htaccess</code> に以下を書き込みます。<br />\\n<br />\\n\\n<blockquote class=\"code\">\\nSetHandler suddendeath<br />\\n</blockquote>\\n\\nすると\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/f5425cc91345b101.png\" title=\"突然の死\" />\\n</blockquote>\\n\\nこのようなメッセージがブラウザに出力されます。簡単ですね!メンテナンスに最適です。なお、メッセージを変える事も出来ます。<code>.htaccess</code> で<br />\\n\\n<blockquote class=\"code\">\\nSuddenDeathMessage 突然の死<br />\\nSetHandler suddendeath<br />\\n</blockquote>\\n\\n<code>SuddenDeathMessage</code> によるメッセージ指定も出来ますし\\n\\n<blockquote class=\"code\">\\nSuddenDeathFile /path/to/your/suddendeath.txt<br />\\nSetHandler suddendeath<br />\\n</blockquote>\\n\\nファイルでの指定も可能です!!<br />\\n<br />\\nもちろん改行をちゃんと判定していますので例えば\\n\\n<blockquote class=\"code\">\\n 突然の<br />\\n<br />\\nDanKogai Not Found<br />\\n</blockquote>\\n\\nこの様なテキストを <code>SuddenDeathFile</code> に設定すれば\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/1b84a62b99ccbc54.png\" title=\"突然のdankogai\" />\\n</blockquote>\\n\\nちゃんと余白を埋めて、幅も計算して出力してくれます!(utf-8で指定する必要があります)<br />\\n<br />\\nこれで万が一のサービスダウンやメンテナンスがあっても心配ありませんね!<br />\\nぜひお役立て下さい。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "apache, 突然の死", | |
"published": "2013-02-05T12:51:00+09:00" | |
}, | |
{ | |
"title": "Vim を mruby で操作する if_mruby 書いた。", | |
"link": "http://mattn.kaoriya.net/software/vim/20130129214258.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/vim/20130129214258", | |
"summary": "\\n現在 Vim は以下の LL言語による拡張をサポートしています。\\n\\n<ul>\\n\\t<li>Lua</li>\\n\\t<li>MzScheme</li>\\n\\t<li>Perl5</li>\\n\\t<li>Python2</li>\\n\\t<li>Python3</li>\\n\\t<li>Ruby1.8</li>\\n\\t<li>Ruby1.9</li>\\n\\t<li>TCL</li>\\n</ul>\\n\\n最近 mruby 熱が高いので if_mruby を書いてみた。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://gist.github.com/4662845\">vim7-if_mruby.diff</a>\\n\\t<br />\\n\\t<cite>https://gist.github.com/4662845</cite>\\n</blockquote>\\n\\n基本的な動作は if_ruby に合わせてあります。<del>Makefile は mingw32 用だけ手を加えています。</del>mingw32 と VC++ と configure && make もサポートしてます。MRUBY_ROOT という環境変数に mruby のリポジトリルートを指す必要があります。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Constant\">:mruby</span> (<span class=\"Constant\">1</span>..<span class=\"Constant\">100</span>).to_a.each{|<span class=\"Identifier\">x</span>| puts x}<br />\\n</blockquote>\\n\\nこんな事も出来ますし、if_ruby 同様に\\n\\n<blockquote class=\"code\">\\n<span class=\"Constant\">:mruby</span> <span class=\"Type\">VIM</span>::<span class=\"Type\">Window</span>::current.height = <span class=\"Constant\">3</span><br />\\n</blockquote>\\n\\nこんな事も出来ます。<br />\\n1点だけ移植出来なかった物があり、ruby には <code>rb_define_virtual_variable</code> という API があり、これを使うと変数の参照でC言語の関数が呼び出せるのですが、mruby にはこれ相当の物がありませんでした。<br />\\nメソッド名に「$」を含ませる事も出来ないので、結局 <code>$curwin</code> と <code>$curbuf</code> については <code>__curwin</code> と <code>__curbuf</code> という名称に変更しています。<br />\\n<br />\\n\\nおおよそ動くのですが\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/vim-jp/issues/issues/297\">if_mruby の可能性について - GitHub</a>\\n\\t<br />\\n\\t<p>Vim標準の外部インタフェースとして、if_rubyがありますが、素のRuby言語は言語組み込みを想定されていないためいろんな困難があります...</p>\\n\\t<cite>https://github.com/vim-jp/issues/issues/297</cite>\\n</blockquote>\\n\\nのコメントにも書いた通り、\\n\\n<blockquote class=\"quote\">\\nただし僕は現状vim-devに送るつもりはない。mrubyはダイナミックロード(require)をサポートしていないし、vimから使うmrubyに新しい機能が欲しくなったら<br />\\n<ul>\\n\\t<li>mruby に欲しい mrbgem を導入</li>\\n\\t<li>libmruby.a をビルド</li>\\n\\t<li>vim をビルド</li>\\n</ul>\\nを毎回しないといけない。<br/ >\\n</blockquote>\\n\\nという問題があるので、すぐさま vim-dev にパッチを送るつもりは無いです。<br />\\n<br />\\nVim に if_mruby が入るかどうかは、require が入るかどうかに掛かっているんですよ!Matz さん!(チラッチラッ)<br />\\n良かったら遊んで下さい。<br />\\n<br />\\n<b>追記</b><br />\\n<a href=\"https://github.com/mattn/mruby-require\">mruby-require</a> がいい感じに出来上がってきたので、vim-dev に送るかもです。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mruby, vim", | |
"published": "2013-01-29T21:45:00+09:00" | |
}, | |
{ | |
"title": "mruby でmrbgemsから別のmrbgemsのクラスを参照して継承する", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130129103808.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130129103808", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://onmessage.ws/wordpress/?p=745\">mrubyプチハッカソンに参加してきました</a>\\n\\t<br />\\n\\t<p>例えば、mattn_jpさんがmruby-uvを作っていらっしゃいます。私がその上にTCPServerClassを構築したい、と思ったときには、現状RubyのコードとしてUV::TCP.newするしか無いように感じますが、これをCから呼び出して、mrubyのTCPServerClassとしてexportしたいな、と。</p>\\n\\t<cite>http://onmessage.ws/wordpress/?p=745</cite>\\n</blockquote>\\n\\n例えば <a href=\"https://github.com/mattn/mruby-curl\">mruby-curl</a> は別の mrbgems である <a href=\"https://github.com/mattn/mruby-http\">mruby-http</a> の HTTP::Response を返しているが特別 require している訳ではない。mrb_class_get でルートネームスペースのモジュールもしくはクラスが取れるので、さらにそこから mrb_const_get で under なクラスが取れる。\\n\\n<blockquote class=\"code\">\\n<span class=\"Type\">struct</span> RClass* _class_http = mrb_class_get(mrb, <span class=\"Constant\">"HTTP"</span>);<br />\\n<span class=\"Type\">struct</span> RClass* _class_http_parser = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern(mrb, <span class=\"Constant\">"Parser"</span>)));<br />\\n</blockquote>\\n\\nこれはあくまで mruby が「HTTP::Parser」をどの様に解析しているのかを僕がコードを読んで同じ事をやっているだけなので、正しい(薦められるべき)使い方かどうかは分からない。<br />\\nこれを使って\\n\\n<blockquote class=\"code\">\\n<span class=\"Type\">struct</span> RClass* _class_my_parser = mrb_define_class_under(mrb, _class_http, <span class=\"Constant\">"MyParser"</span>, _class_http_parser);<br />\\n</blockquote>\\n\\nこの様にクラス定義すれば HTTP::Parser を継承した HTTP::MyParser を宣言できます。<br />\\nもちろん、mrbgems として同梱されていない場合は実行時エラーになります。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mruby", | |
"published": "2013-01-29T10:39:00+09:00" | |
}, | |
{ | |
"title": "CD-ROM トレイを取り出せる vim プラグイン、「eject.vim」作った。", | |
"link": "http://mattn.kaoriya.net/software/vim/20130121121002.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/vim/20130121121002", | |
"summary": "\\nvim 使ってると良く CD-ROM を取り出したくなりますよね。<br />\\nならないとしたら、今すぐこの記事を読むのをやめて病院に行って下さい。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/eject-vim\">mattn/eject-vim - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/eject-vim</cite>\\n</blockquote>\\n\\nインストールすると<br />\\n\\n<blockquote class=\"code\">\\n:Eject\\n</blockquote>\\n\\nというコマンドが追加されるので、実行するだけで CD-ROM トレイがゲロっと排出されます。<br />\\n便利ですね!<br />\\n皆さんもぜひ、使ってみて下さい。<br />\\n<br />\\n(今日の参考文献: <a href=\"http://d.hatena.ne.jp/hasegawayosuke/20130112/p1\">http://d.hatena.ne.jp/hasegawayosuke/20130112/p1</a>)<br />\\n<br />\\nなお、Windowsでしか動作しません。動作には <a href=\"https://github.com/mattn/libcallex-vim\">libcallex-vim</a> が必要です。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, eject, ネタ", | |
"published": "2013-01-21T12:10:00+09:00" | |
}, | |
{ | |
"title": "mruby-mysql 作った。", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130120012259.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130120012259", | |
"summary": "\\n以前、mruby-sqlite3 は作ったのでぜひ MySQL もやりたいなーと思いながら手を付けてなかったけどようやく重い腰をあげて書いた。<br />\\n\\n<blockquote class=\"quote\">\\n <a href=\"https://github.com/mattn/mruby-mysql\">mattn/mruby-mysql - GitHub</a>\\n <br />\\n <cite>https://github.com/mattn/mruby-mysql</cite>\\n</blockquote>\\n\\n動作は SQLite3 のと同じにしてあるつもりです。<br />\\nMySQL の拡張は何度か書いた事あったけど、レコードを弄る様な物は随分昔に触ったきりで思い出せないし、API がいろいろ新しくなっててハマった。<br />\\n最初、MYSQL_ROW を使って全部文字列でやれば良くね?と思ってたけど、結局ちゃんと MYSQL_BIND 使って書いた。<br />\\n<br />\\nこれで残すは PostgreSQL だけですが、実は PostgreSQL 使った拡張は今まで書いた事が無い。<br />\\n誰か作って下さい。<br />\\nこういうコードが動きます。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!mruby</span><br />\\n<br />\\ndb = <span class=\"Type\">MySQL</span>::<span class=\"Type\">Database</span>.new(<span class=\"Special\">'</span><span class=\"String\">localhost</span><span class=\"Special\">'</span>, <span class=\"Special\">'</span><span class=\"String\">root</span><span class=\"Special\">'</span>, <span class=\"Special\">''</span>, <span class=\"Special\">'</span><span class=\"String\">foo</span><span class=\"Special\">'</span>)<br />\\n<span class=\"Statement\">begin</span><br />\\n db.execute_batch <span class=\"Special\">'</span><span class=\"String\">drop table foo</span><span class=\"Special\">'</span><br />\\n db.execute_batch <span class=\"Special\">'</span><span class=\"String\">drop table bar</span><span class=\"Special\">'</span><br />\\n<span class=\"Statement\">rescue</span> <span class=\"Type\">RuntimeError</span><br />\\n<span class=\"Statement\">ensure</span><br />\\n db.execute_batch <span class=\"Special\">'</span><span class=\"String\">create table foo(id int primary key, text text, f float)</span><span class=\"Special\">'</span><br />\\n db.execute_batch <span class=\"Special\">'</span><span class=\"String\">create table bar(id int primary key, text text, f float)</span><span class=\"Special\">'</span><br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">delete from foo</span><span class=\"Special\">'</span>)<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into foo(id, text) values(?, ?)</span><span class=\"Special\">'</span>, <span class=\"Constant\">1</span>, <span class=\"Special\">'</span><span class=\"String\">foo</span><span class=\"Special\">'</span>)<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into foo(id, text) values(?, ?)</span><span class=\"Special\">'</span>, <span class=\"Constant\">2</span>, <span class=\"Special\">'</span><span class=\"String\">bar</span><span class=\"Special\">'</span>)<br />\\ndb.transaction<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into foo(text) values(?)</span><span class=\"Special\">'</span>, <span class=\"Special\">'</span><span class=\"String\">baz</span><span class=\"Special\">'</span>)<br />\\ndb.rollback<br />\\ndb.transaction<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into foo(text) values(?)</span><span class=\"Special\">'</span>, <span class=\"Special\">'</span><span class=\"String\">bazoooo!</span><span class=\"Special\">'</span>)<br />\\ndb.commit<br />\\n<br />\\ndb.transaction<br />\\n(<span class=\"Constant\">1</span>..<span class=\"Constant\">100</span>).each_with_index {|<span class=\"Identifier\">x</span>,<span class=\"Identifier\">i</span>|<br />\\n db.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into bar(id, text) values(?,?)</span><span class=\"Special\">'</span>, i, x)<br />\\n}<br />\\ndb.commit<br />\\n<br />\\ndb.execute(<span class=\"Special\">'</span><span class=\"String\">select * from bar</span><span class=\"Special\">'</span>) <span class=\"Statement\">do</span> |<span class=\"Identifier\">row</span>, <span class=\"Identifier\">fields</span>|<br />\\n puts row<br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\n#puts db.execute('select id from foo where text = ?', 'foo').next<br />\\n<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">delete from bar</span><span class=\"Special\">'</span>)<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into bar(id, text, f) values(1,</span><span class=\"Special\">\\'</span><span class=\"String\">bababa</span><span class=\"Special\">\\'</span><span class=\"String\">, NULL)</span><span class=\"Special\">'</span>)<br />\\ndb.execute_batch(<span class=\"Special\">'</span><span class=\"String\">insert into bar(id, text, f) values(2,</span><span class=\"Special\">\\'</span><span class=\"String\">bababa</span><span class=\"Special\">\\'</span><span class=\"String\">, 3.14)</span><span class=\"Special\">'</span>)<br />\\ndb.execute(<span class=\"Special\">'</span><span class=\"String\">select * from bar</span><span class=\"Special\">'</span>) <span class=\"Statement\">do</span> |<span class=\"Identifier\">row</span>, <span class=\"Identifier\">fields</span>|<br />\\n puts row<br />\\n<span class=\"Statement\">end</span><br />\\nrow = db.execute(<span class=\"Special\">'</span><span class=\"String\">select * from bar</span><span class=\"Special\">'</span>)<br />\\nputs row.fields<br />\\n<span class=\"Statement\">while</span> cols = row.next<br />\\n puts cols<br />\\n<span class=\"Statement\">end</span><br />\\nrow.close<br />\\n<br />\\ndb.close<br />\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mysql, mruby", | |
"published": "2013-01-20T01:30:00+09:00" | |
}, | |
{ | |
"title": "mruby で GUI!もう組み込み用途とは言わせない!mruby-fltk3 書いた。", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130116150605.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130116150605", | |
"summary": "\\n<img src=\"http://toilet.jpg.to/\" alt=\"toilet\" class=\"thumbnail-right\" />\\nmruby と言えば組み込み用途のイメージが高いですが、Windows で何度も ruby 拡張のビルドエラーを潜り抜けて来て、ある程度 ruby 拡張の仕組みも知っている僕としては mruby の方がソースが綺麗し精神衛生上良いと言いたいが、言ってしまうとどこかしらからかオノが飛んで来そうな昨今でございます。<br />\\n最近はmrubyで<a\\nhref=\"http://eleclog.quitsq.com/2013/01/toilet-tweet-bot.html\">ウォシュレットの噴出を監視するシステム</a>も登場し、「TOTO\\nさん、そろそろ本気で <b>mruby 組み込みウォシュレット</b> 考えてみませんか」と言いたくなる状況です。<br />\\nさて、そろそろ mruby にも GUI が欲しくなってきたので fltk3 を組み込んでみました。<br class=\"clearall\" />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/mruby-fltk3\">mattn/mruby-fltk3 - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/mruby-fltk3</cite>\\n</blockquote>\\n\\nmrbgems 化してあります。<br />\\nまぁまぁ忠実に fltk3 を移植してあります。まだ全ての Widget が書けた訳ではないけど、簡単なアプリケーションを書くくらいなら出来る様になってきたので報告がてら記事にしようと思いました。<br />\\n<br />\\nFLTK1 系を選んでも良かったのですが、FLTK1 は完全な utf-8 対応ではなく、かつ utf-8 対応した物はサードパーティプロダクトだったりします。fltk2 でも良かったのですが、どうやら最新は fltk3 という事で未来もある fltk3 を採用しました。<br />\\n全てのオブジェクトは <code>FLTK3</code> モジュール配下に入っています。<br />\\n<br />\\n例えばウィンドウを作るのであれば\\n\\n<blockquote class=\"code\">\\nwindow = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">DoubleWindow</span>.new(<span class=\"Constant\">0</span>, <span class=\"Constant\">0</span>, <span class=\"Constant\">100</span>, <span class=\"Constant\">100</span>, <span class=\"Special\">"</span><span class=\"Constant\">mruby-fltk3</span><span class=\"Special\">"</span>)<br />\\nwindow.show<br />\\n<span class=\"Type\">FLTK3</span>::run<br />\\n</blockquote>\\n\\nこんな感じに。ウィンドウにボタンを足すのであれば begin メソッドと end メソッドの中でインスタンスを生成します。<br />\\n\\n<blockquote class=\"code\">\\nwindow = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">DoubleWindow</span>.new(<span class=\"Constant\">0</span>, <span class=\"Constant\">0</span>, <span class=\"Constant\">100</span>, <span class=\"Constant\">100</span>, <span class=\"Special\">"</span><span class=\"Constant\">mruby-fltk3</span><span class=\"Special\">"</span>)<br />\\nwindow.begin<br />\\n button = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">Button</span>.new(<span class=\"Constant\">10</span>, <span class=\"Constant\">10</span>, <span class=\"Constant\">80</span>, <span class=\"Constant\">30</span>, <span class=\"Special\">"</span><span class=\"Constant\">click me!</span><span class=\"Special\">"</span>)<br />\\nwindow.end<br />\\nwindow.show<br />\\n<span class=\"Type\">FLTK3</span>::run<br />\\n</blockquote>\\n\\nbegin にブロックを取る場合はブロック内で begin/end を行います。\\n\\n<blockquote class=\"code\">\\nwindow = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">DoubleWindow</span>.new(<span class=\"Constant\">0</span>, <span class=\"Constant\">0</span>, <span class=\"Constant\">100</span>, <span class=\"Constant\">100</span>, <span class=\"Special\">"</span><span class=\"Constant\">mruby-fltk3</span><span class=\"Special\">"</span>)<br />\\nwindow.begin <span class=\"Statement\">do</span><br />\\n button = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">Button</span>.new(<span class=\"Constant\">10</span>, <span class=\"Constant\">10</span>, <span class=\"Constant\">80</span>, <span class=\"Constant\">30</span>, <span class=\"Special\">"</span><span class=\"Constant\">click me!</span><span class=\"Special\">"</span>)<br />\\n<span class=\"Statement\">end</span><br />\\nwindow.show<br />\\n<span class=\"Type\">FLTK3</span>::run<br />\\n</blockquote>\\n\\n画像も扱えるので、例えば\\n\\n<blockquote class=\"code\">\\nwindow = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">DoubleWindow</span>.new(<span class=\"Constant\">100</span>, <span class=\"Constant\">100</span>, <span class=\"Constant\">400</span>, <span class=\"Constant\">430</span>, <span class=\"Special\">"</span><span class=\"Constant\">mruby-fltk3</span><span class=\"Special\">"</span>)<br />\\nwindow.begin <span class=\"Statement\">do</span><br />\\n widget = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">Widget</span>.new(<span class=\"Constant\">10</span>, <span class=\"Constant\">10</span>, <span class=\"Constant\">380</span>, <span class=\"Constant\">400</span>)<br />\\n button = <span class=\"Type\">FLTK3</span>::<span class=\"Type\">Button</span>.new(<span class=\"Constant\">10</span>, <span class=\"Constant\">390</span>, <span class=\"Constant\">80</span>, <span class=\"Constant\">30</span>, <span class=\"Special\">"</span><span class=\"Constant\">load file</span><span class=\"Special\">"</span>)<br />\\n button.callback <span class=\"Statement\">do</span><br />\\n fn = <span class=\"Type\">FLTK3</span>::file_chooser(<span class=\"Special\">"</span><span class=\"Constant\">image file</span><span class=\"Special\">"</span>, <span class=\"Special\">"</span><span class=\"Constant\">*.{bm,bmp,gif,jpg,pbm,pgm,png,ppm,xbm,xpm}</span><span class=\"Special\">"</span>)<br />\\n image = fn ? <span class=\"Type\">FLTK3</span>::<span class=\"Type\">SharedImage</span>::get(fn) : <span class=\"Constant\">nil</span><br />\\n <span class=\"Statement\">if</span> image.w > widget.w || image.h > widget.h<br />\\n <span class=\"Statement\">if</span> image.w > image.h<br />\\n temp = image.copy(widget.w, widget.h * image.h / image.w)<br />\\n <span class=\"Statement\">else</span><br />\\n temp = image.copy(widget.w * image.w / image.h, widget.h)<br />\\n <span class=\"Statement\">end</span><br />\\n image.release<br />\\n image = temp<br />\\n <span class=\"Statement\">end</span><br />\\n widget.image = image<br />\\n widget.redraw<br />\\n <span class=\"Statement\">end</span><br />\\n<span class=\"Statement\">end</span><br />\\nwindow.show<br />\\n<br />\\n<span class=\"Type\">FLTK3</span>::run<br />\\n</blockquote>\\n\\nこれだけのコードで画像ビューワが出来上がり!<br />\\n\\n<blockquote>\\n<a href=\"http://mattn.kaoriya.net/images/mruby-fltk3.png\" class=\"lightbox\" title=\"mruby-fltk3\"><img src=\"http://mattn.kaoriya.net/images/mruby-fltk3-thumb.png\" alt=\"mruby-fltk3\" /></a>\\n</blockquote>\\n\\nなんだか mruby を組み込み用途以外で使ってるの、僕だけなんじゃないかと心配になって来ましたが負けません。戦います。<br />\\n役にたつかどうか分かりませんが、遊びたい方はどうぞ。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "fltk, fltk3, mruby", | |
"published": "2013-01-16T15:11:00+09:00" | |
}, | |
{ | |
"title": "TwitVim で個別に FavStar を見れる様にした。", | |
"link": "http://mattn.kaoriya.net/software/vim/20130111100019.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/vim/20130111100019", | |
"summary": "\\nTwitVim で「あーこの人のこの発言、バズってるんだろうな」と思った時に FavStar を見る事があるんだけど、FavStar は最新の fav/rt 一覧しか表示してなかったので過去の物を表示する事は出来なかった。僕的にニーズがあったのでツィート単位に表示出来る様にした。<br />\\nもちろん、TwitVim は一切触らない。やり方は以下の記事を参照。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.kaoriya.net/software/vim/20110728094347.htm\">Big Sky :: 他人が作ったVimScriptを一切触らず拡張する</a>\\n\\t<br />\\n\\t<p>普段twitterするときはtwitvimというvimscriptを使ってvimからやってるのだけど、たいがいこういうのって自分の思う機能が実装されていなかったり、違う実装になっていたりする...</p>\\n\\t<cite>http://mattn.kaoriya.net/software/vim/20110728094347.htm</cite>\\n</blockquote>\\n\\nまず FavStar を修正した。<br />\\n\\n<blockquote class=\"code\">\\nFavStar mattn_jp\\n</blockquote>\\n\\nという風にスクリーン名しか受け付けていなかったけど\\n\\n<blockquote class=\"code\">\\nFavStar mattn_jp XXXXXXX\\n</blockquote>\\n\\nでツィートIDも受け取れる様にした。そして\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! TwitVimShowFavStar<span class=\"Special\">()</span><br />\\n <span class=\"Statement\">silent</span>! <span class=\"Statement\">redir</span> <span class=\"Statement\">=></span> json<br />\\n <span class=\"Statement\">silent</span>! TwitVimShowCurbuffer<br />\\n <span class=\"Statement\">silent</span>! <span class=\"Statement\">redir</span> END<br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">curbuffer</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">eval</span><span class=\"Special\">(</span><span class=\"Identifier\">substitute</span><span class=\"Special\">(</span>json, <span class=\"Constant\">"\\n"</span>, <span class=\"Constant\">''</span>, <span class=\"Constant\">'g'</span><span class=\"Special\">))</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">id</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">get</span><span class=\"Special\">(</span>curbuffer<span class=\"Statement\">.</span>statuses, <span class=\"Identifier\">line</span><span class=\"Special\">(</span><span class=\"Constant\">'.'</span><span class=\"Special\">))</span><br />\\n <span class=\"Statement\">if</span> id <span class=\"Statement\">!=</span> <span class=\"Constant\">0</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">user</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">substitute</span><span class=\"Special\">(</span>curbuffer<span class=\"Statement\">.</span>buffer[<span class=\"Identifier\">line</span><span class=\"Special\">(</span><span class=\"Constant\">'.'</span><span class=\"Special\">)</span><span class=\"Statement\">-</span><span class=\"Constant\">1</span>], <span class=\"Constant\">':.*'</span>, <span class=\"Constant\">''</span>, <span class=\"Constant\">''</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">exe</span> <span class=\"Constant\">"FavStar"</span> <span class=\"Identifier\">user</span> <span class=\"Identifier\">id</span><br />\\n <span class=\"Statement\">endif</span><br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\nTwitVim からツィートIDを抜き取って FavStar コマンドに渡す。<br />\\nあとはこれのキーアサイン\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">nnoremap</span> <span class=\"Special\"><</span><span class=\"Special\">buffer</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">leader</span><span class=\"Special\">></span>F :call TwitVimShowFavStar()<span class=\"Special\"><</span><span class=\"Special\">cr</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\nキーアサインの入れ場所は上記の記事を見て下さい。<br />\\nこれで TwitVim を見てる最中に <code><leader>F</code> をタイプすれば個別の fav/rt が見れる様になりました。<br />\\nめでたしめでたし。<br />\\n\\n<blockquote>\\n <img src=\"http://go-gyazo.appspot.com/54f5a0ece3af7626.png\" alt=\"Yes, 高洲クリニック\" />\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "twitvim, vim", | |
"published": "2013-01-11T10:02:00+09:00" | |
}, | |
{ | |
"title": "CD-ROM トレイを取り出せる mrbgem、「mruby-eject」作った。", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130110212633.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130110212633", | |
"summary": "\\nmruby 使ってると良く CD-ROM を取り出したくなりますよね。<br />\\nならないとしたら、今すぐこの記事を読むのをやめて病院に行って下さい。<br />\\n<br />\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/mruby-eject\">mattn/mruby-eject - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/mruby-eject</cite>\\n</blockquote>\\n\\nインストールすると <code>eject</code> という命令が追加されるので\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!mruby</span><br />\\n<br />\\neject<br />\\n</blockquote>\\n\\nと書くだけで CD-ROM トレイがゲロっと排出されます。<br />\\n<br />\\n便利ですね!<br />\\n<br />\\n例えば mruby で sinatra っぽく書けるフレームワーク、mruby-sinatic を使って\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!mruby</span><br />\\n<br />\\nget <span class=\"Special\">"</span><span class=\"Constant\">/eject</span><span class=\"Special\">"</span> <span class=\"Statement\">do</span><br />\\n eject<br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\n<span class=\"Type\">Sinatic</span>.run<br />\\n</blockquote>\\n\\nこう書くと、ブラウザから <code>http://127.0.0.1:8888/eject</code> にアクセスするだけでイジェクト出来る様になります。<br />\\n皆さんもぜひ、使ってみて下さい。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mruby", | |
"published": "2013-01-10T21:27:00+09:00" | |
}, | |
{ | |
"title": "canything を win32 porting した。", | |
"link": "http://mattn.kaoriya.net/software/20130109190202.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/20130109190202", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://filmlang.org/soft/canything\">canything: CUIでAnything</a>\\n\\t<br />\\n\\t<p>コマンドラインからEmacs Anythingを使えるプログラムです。 zshの補完でも十分だが、Anythingのインターフェースの方がある場合にはすぐれているので作った。 パイプ専用なので汎用的に使えると思います。</p>\\n\\t<cite>http://filmlang.org/soft/canything</cite>\\n</blockquote>\\n\\nそう言えば昨日、canything を windows でも動かせるようにパッチ書いて pull-req 送って取り込まれた。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/keiji0/canything\">keiji0/canything - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/keiji0/canything</cite>\\n</blockquote>\\n\\n<br />\\n<blockquote class=\"code\">\\nls | canything | xargs cat<br />\\n</blockquote>\\n\\nこんな風にパイプで囲まれた時に pdcurses が初期化出来ないっていうエラーに悩まされたけど、<code>CreateConsoleScreenBuffer</code> で新しい端末バッファを作って <code>SetStdHandle</code> で割り当てて、かつ <code>CONIN$</code> を freopen してキー入力を stdin から取るという<a href=\"https://github.com/keiji0/canything/blob/master/canything.c#L64-L69\">荒技</a>を使って乗り越えた。<br />\\n上記の様な場合でもちゃんと動きます。<br />\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/3c3ac0aceb1f3d0f.png\" alt=\"canything\" />\\n</blockquote>\\n<br />\\n<b>追記</b><br />\\n共有読み込みモードにしないとckwでハングするらしい。<br />\\n<a href=\"https://github.com/mattn/canything/commit/8db3778814d4f39f140cc792fa442347011b2a1a\">パッチ</a>書いてpull-req送った。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "canything", | |
"published": "2013-01-09T19:03:00+09:00" | |
}, | |
{ | |
"title": "mruby 向け gem コマンド「mgem」を使ってみた。", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20130104162957.htm", | |
"id": "tag:mattn.kaoriya.net,2013:/software/lang/ruby/20130104162957", | |
"summary": "\\nあけましておめでとうございます。本年も宜しくお願い致します。<br />\\n今年も、皆さんの役にたたないプロジェクトの量産を目指し、一層の努力をして参る所存でございます。<br />\\n<br />\\nさて、正月あいだ masui さんが mruby のビルドシステムを cruby で書き換えてて、僕も親父のマシンに mingw32 やら msysgit やらを入れて深夜に試してたんですが、昨日今日でだいたい動くようになった感じです。mrbgem.rake には殆ど何も書かなくても良くなりました。<br />\\nmrbgem.rake には作者とライセンスを明記する部分があったので、これを期に僕の作った mrbgem のライセンスを統一して MIT にしました。<br />\\n今後これらが業務で使われる方がいらっしゃったとしても心配無用。<br />\\n<br />\\nmasui さんの pull-req には git 管理されたフォルダも自動でビルド対象にする機能が含まれていたんだけど、それに合わせたか bovi さんが mruby 向けの gem コマンド mgem を書いてくれてた。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/bovi/mgem\">bovi/mgem - GitHub</a>\\n\\t<br />\\n\\t<p>A program to manage GEMs in mruby</p>\\n\\t<cite>https://github.com/bovi/mgem</cite>\\n</blockquote>\\n\\nこのコマンドを\\n\\n<blockquote class=\"code\">\\ngem install mgem\\n</blockquote>\\n\\ngem コマンドからインストールすると\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/bovi/mgem-list\">bovi/mgem-list - GitHub</a>\\n\\t<br />\\n\\t<p>A list of all GEMs for mruby to be managed by mgem</p>\\n\\t<cite>https://github.com/bovi/mgem-list</cite>\\n</blockquote>\\n\\n<code>mgem-list</code> というプロジェクトで管理されている gem ファイルを元に所定の位置に git clone してくれます。<br />\\n\\n<blockquote class=\"code\">\\nmgem (Version 0.0.2) is a library manager for mruby<br />\\n<br />\\nUsage:<br />\\n mgem size How many GEMs are available?<br />\\n mgem list [active] List GEMs<br />\\n mgem info *pattern* Show detail information about a GEM<br />\\n mgem add *name* Activate a GEM<br />\\n mgem rm *name* De-Activate a GEM<br />\\n mgem search *pattern* Search for GEMs<br />\\n mgem config Generate a mruby build config including all active GEMs<br />\\n mgem update Update the list of GEMs<br />\\n<br />\\nWebsite:<br />\\n <a href=\"https://github.com/bovi/mgem\">https://github.com/bovi/mgem</a><br />\\n</blockquote>\\n\\nなかなな便利になったのではないでしょうか。最新版の mruby では build_config.rb に使う gem を明記する必要がありますが、それ用のコマンド(config)も用意されています。<br />\\n今のところ、この github プロジェクトが rubygems.org の様な中央リポジトリになっているので、自分の作った gem を登録するには bovi さんに pull-request を送ると良いです。<br />\\n<br />\\nちなみに現状の mgem-list の中身は、とても mattn 無双でした。<br />\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/43cd019089093090.png\" alt=\"mattn無双\" />\\n</blockquote>\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/B003YXPPD2/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51G2DqRgXiL._SL160_.jpg\" alt=\"Arduino イーサネットシールド\" class=\"awsxom-image\" />\\n<strong>Arduino イーサネットシールド</strong></a><br />\\n<br />\\nスイッチサイエンス / ¥ 3,650 ()<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n<br />\\n<br />\\n詳しい内容は bovi さんのページで...<br />\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mruby.sh/201301040627.html\">The mgem GEM - mruby.sh</a>\\n\\t<br />\\n\\t<p>How does it work To maintain a list of GEMs I created a repository called mgem-list . This repositor...</p>\\n\\t<cite>http://mruby.sh/201301040627.html</cite>\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mgem, mruby, mrbgems", | |
"published": "2013-01-04T16:33:00+09:00" | |
}, | |
{ | |
"title": "意外と知られていない github 技", | |
"link": "http://mattn.kaoriya.net/software/git/20121225171742.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/git/20121225171742", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://subtech.g.hatena.ne.jp/secondlife/20121225/1356421602\">github で git diff from..to を表示する - #生存戦略 、それは - subtech</a>\\n\\t<br />\\n\\t<p>で text/plain な diff が表示される。.. じゃなくて ... 。</p>\\n\\t<cite>http://subtech.g.hatena.ne.jp/secondlife/20121225/1356421602</cite>\\n</blockquote>\\n\\ngithub のコミットページ URL は、実は凄く良く出来ている。\\n例えば pull request のページ\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mruby/mruby/pull/605\">Add each Gem bundled data pointer in mrb_state by masuidrive - Pull Request #605 - mruby/mruby - GitHub</a>\\n\\t<br />\\n\\t<p>Showing 17 changed files with 183 additions and 36 deletions . Show Diff Stats Hide Diff Stats 5 &#x...</p>\\n\\t<cite>https://github.com/mruby/mruby/pull/605</cite>\\n</blockquote>\\n\\nこのページの URL に <code>.diff</code> を付けると text/plain な差分表示になる。<br />\\n<br />\\n<a href=\"https://github.com/mruby/mruby/pull/605.diff\">https://github.com/mruby/mruby/pull/605.diff</a><br />\\n<br />\\nまた <code>.diff</code> の代わりに <code>.patch</code> を付けるとメールアドレス入りのパッチファイル。<br />\\n<br />\\n<a href=\"https://github.com/mruby/mruby/pull/605.patch\">https://github.com/mruby/mruby/pull/605.patch</a><br />\\n<br />\\nつまりローカルリポジトリに pull request をマージするのは\\n\\n<blockquote class=\"code\">\\n# curl -s https://github.com/mruby/mruby/pull/605.patch | git am -\\n</blockquote>\\n\\nとやるだけでよいし cherrypick は pull request のうちの一つのコミットの URL を開いて <code>.patch</code> を足し、その URL で <code>git am -</code> すれば良い。<br />\\n\\n<blockquote class=\"code\">\\ncurl -s https://github.com/masuidrive/mruby/commit/70b422a6f240a201993e75935b55a8dd497eb098.patch | git am -\\n</blockquote>\\n\\nさらに「あーこの人の pull request、良いんだけど typo ってるなー。でもこの人、週末にしか push してこないよなー。いますぐ修正したいなー。でもこっちで直したらせかっくの contribute が無くなるなー。」って時には、この patch ファイルをダウンロードしてちょっと修正して <code>git am</code> すればよい。ちなみにこれやると相手のブランチが意味を成さなくなるのでマージしたら必要無くなる様なトピックブランチでやること。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "git, github", | |
"published": "2012-12-25T17:22:00+09:00" | |
}, | |
{ | |
"title": "最近の mruby 業界まとめ", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20121221135228.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/ruby/20121221135228", | |
"summary": "\\nトピックス\\n\\n<ul>\\n\\t<li>mrbgems が入った</li>\\n\\t<li>お前はどこのワカメじゃ</li>\\n\\t<li>ビルド方法が変わった</li>\\n\\t<li>mruby-uv mruby-http mruby-sinatic</li>\\n\\t<li>mruby-json</li>\\n\\t<li>mruby-sqlite3</li>\\n\\t<li>mruby-curl</li>\\n\\t<li>そして mruby-v8</li>\\n</ul>\\n\\n<h4>mrbgems が入った</h4>\\n\\nmruby に GEM っぽい物が入った。<br />\\nとは言ってもスタティックリンクなのでダイナミックローディングしてくれる訳じゃない。<br />\\nしかしながらパッケージを導入する上での取り決めが決まりつつあると言った感じ。<br />\\n使うには <code>MRUBY_ROOT</code> という環境変数を mruby のリポジトリトップに設定しておき、<code>MAKEFILE_4_GEM</code> を <code>$MRUBY/mrbgems/Makefiel4gem</code>\\nにしておくと良い。後者は要らなくなったかもしれない。<br />\\n具体的には\\n\\n<blockquote class=\"code\">\\n$MRUBY_ROOT/mrbgems/GEMS.active\\n</blockquote>\\n\\nというファイルに使う mrbgems のフォルダを一覧しておくとビルドの際に一緒にビルドおよびリンクしてくれるという物。<br />\\n\\n<blockquote class=\"code\">\\n$MRUBY_ROOT/mrbgems/g\\n</blockquote>\\n\\nの下に置く場合は絶対パスではなくフォルダ名だけで良い。<br />\\n\\nmrbgems には大きく2つあって、C言語で書く拡張と、ruby 形式で書く物がある。後者はビルド時にバイナリ化されてリンクされる。<br />\\nC言語で書く際のお手本としては <a href=\"https://github.com/mattn/mruby-md5\">mruby-md5</a> が良いと思う。<br />\\n<br />\\n\\n<h4>お前はどこのワカメじゃ</h4>\\n\\nmrbgems は bovi という人がパッチ書いて取り込まれたのだけど、既存の拡張をどうやって mrbgems 化するか聞いてたら「やってあげる」という神キタコレな運びとなって mruby-md5 を mrbgems 化して貰えた。その時の出来事が彼のブログに載っているのだが\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mruby.sh/201212101231.html\">mrbgems in HEAD - mruby.sh</a>\\n\\t<br />\\n\\t<cite>http://mruby.sh/201212101231.html</cite>\\n</blockquote>\\n\\n<blockquote class=\"code\">\\nassert(<span class=\"Special\">'</span><span class=\"Constant\">MD5 Hash for old example</span><span class=\"Special\">'</span>) <span class=\"Statement\">do</span><br />\\n <span class=\"Type\">MD5</span>::md5_hex(<span class=\"Special\">'</span><span class=\"Constant\">お前はどこのワカメじゃ</span><span class=\"Special\">'</span>) == <span class=\"Special\">"</span><span class=\"Constant\">43820f48a8506c8e2fae6f8558971920</span><span class=\"Special\">"</span><br />\\n<span class=\"Statement\">end</span><br />\\n</blockquote>\\n\\nまさか誰も僕のソースなんか見ないだろうと思って書いてたコードを使ってテストにしてくれました。恥ずかしい...<br />\\n<br />\\n\\n<h4>ビルド方法が変わった</h4>\\n\\nここ最近の大きな変更。<br />\\nこれまでは Makefile もしくは cmake でビルドしていたけど、CRuby と minirake というスクリプトを使ってビルドする仕組みが入りました。現在のルートにある Makefile はこれを呼び出しているだけです。<br />\\n<br />\\n\\n<h4>mruby-uv mruby-http mruby-sinatic</h4>\\n\\n以前から作ってましたが、Matz さんにアドバイスを貰って安定動作する様になりました。<br />\\n<br />\\n\\n<a href=\"https://github.com/mattn/mruby-uv\">https://github.com/mattn/mruby-uv</a><br />\\n<a href=\"https://github.com/mattn/mruby-http\">https://github.com/mattn/mruby-http</a><br />\\n<a href=\"https://github.com/mattn/mruby-sinatic\">https://github.com/mattn/mruby-sinatic</a><br />\\n<br />\\n\\nWindows のしょぼいマシンでもちょっとしたHTTPサーバ(example/server.rb)で 4000 req/sec は出ます。<br />\\nmruby-sinatic は<a href=\"http://mattn.kaoriya.net/software/lang/ruby/20120509211817.htm\">コレ</a>を mrbgems 化した物です。<br />\\n<br />\\n\\n<h4>mruby-json</h4>\\n\\n以前から JSON パーサが欲しかったので自分で書きました。<br />\\n<br />\\n\\n<a href=\"https://github.com/mattn/mruby-json\">https://github.com/mattn/mruby-json</a><br />\\n<br />\\n内部では <a href=\"http://mattn.kaoriya.net/software/lang/c/20121102175736.htm\">parson</a> を使ってます。<br />\\n2時間程度で作った物で<a href=\"http://togetter.com/li/424919\">メモリ開放漏れてました</a>が...<br />\\n<br />\\n\\n<h4>mruby-sqlite3</h4>\\n\\nこちらも自分で...<br />\\n<br />\\n\\n<a href=\"https://github.com/mattn/mruby-sqlite3\">https://github.com/mattn/mruby-sqlite3</a><br />\\n<br />\\n\\n<blockquote class=\"code\">\\ndb = <span class=\"Type\">SQLite3</span>::<span class=\"Type\">Database</span>.new(<span class=\"Special\">'</span><span class=\"Constant\">foo.db</span><span class=\"Special\">'</span>)<br />\\ndb.execute(<span class=\"Special\">'</span><span class=\"Constant\">select * from foo</span><span class=\"Special\">'</span>) <span class=\"Statement\">do</span> |<span class=\"Identifier\">row</span>, <span class=\"Identifier\">fields</span>|<br />\\n puts row<br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\nrow = db.execute(<span class=\"Special\">'</span><span class=\"Constant\">select * from bar</span><span class=\"Special\">'</span>)<br />\\nputs row.fields()<br />\\n<span class=\"Statement\">while</span> !row.eof?<br />\\n puts row.next()<br />\\n<span class=\"Statement\">end</span><br />\\nrow.close()<br />\\n</blockquote>\\n\\nこんな風に使います。<br />\\n<br />\\n\\n<h4>mruby-curl</h4>\\n\\nproxy 超えられて SSL も使える HTTP クライアントが欲しかったので書いた。<br />\\n<br />\\n\\n<a href=\"https://github.com/mattn/mruby-curl\">https://github.com/mattn/mruby-curl</a><br />\\n<br />\\n個人的にはかなり便利になった思う。<br />\\nHTTP::Response を返すので mruby-http が必要。<br />\\nmruby-json と mruby-curl を使って Gist をポストしてみました。\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!mruby</span><br />\\n<br />\\n<span class=\"Statement\">if</span> <span class=\"Identifier\">ARGV</span>.size != <span class=\"Constant\">1</span><br />\\n <span class=\"Statement\">raise</span> <span class=\"Special\">"</span><span class=\"Constant\">gist.rb [GIST_TOKEN]</span><span class=\"Special\">"</span><br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\nreq = <span class=\"Type\">HTTP</span>::<span class=\"Type\">Request</span>.new<br />\\nreq.method = <span class=\"Special\">"</span><span class=\"Constant\">POST</span><span class=\"Special\">"</span><br />\\nreq.body = <span class=\"Type\">JSON</span>::stringify({<br />\\n <span class=\"Special\">"</span><span class=\"Constant\">description</span><span class=\"Special\">"</span>=> <span class=\"Special\">"</span><span class=\"Constant\">We love mruby!</span><span class=\"Special\">"</span>,<br />\\n <span class=\"Special\">"</span><span class=\"Constant\">public</span><span class=\"Special\">"</span>=> <span class=\"Constant\">true</span>,<br />\\n <span class=\"Special\">"</span><span class=\"Constant\">files</span><span class=\"Special\">"</span>=> {<br />\\n <span class=\"Special\">"</span><span class=\"Constant\">file1.txt</span><span class=\"Special\">"</span>=> {<br />\\n <span class=\"Special\">"</span><span class=\"Constant\">content</span><span class=\"Special\">"</span>=> <span class=\"Special\">"</span><span class=\"Constant\">mruby is awesome!</span><span class=\"Special\">"</span><br />\\n }<br />\\n }<br />\\n})<br />\\nreq.headers[<span class=\"Special\">'</span><span class=\"Constant\">Authorization</span><span class=\"Special\">'</span>] = <span class=\"Special\">"</span><span class=\"Constant\">token </span><span class=\"Special\">#{</span><span class=\"Identifier\">ARGV</span>[<span class=\"Constant\">0</span>]<span class=\"Special\">}</span><span class=\"Special\">"</span><br />\\nreq.headers[<span class=\"Special\">'</span><span class=\"Constant\">Content-Type</span><span class=\"Special\">'</span>] = <span class=\"Special\">"</span><span class=\"Constant\">application/json</span><span class=\"Special\">"</span><br />\\n<span class=\"Type\">Curl</span>::<span class=\"Type\">SSL_VERIFYPEER</span> = <span class=\"Constant\">0</span><br />\\nres = <span class=\"Type\">Curl</span>::send(<span class=\"Special\">"</span><span class=\"Constant\"><a href=\"https://api.github.com/gists\">https://api.github.com/gists</a></span><span class=\"Special\">"</span>, req)<br />\\nputs <span class=\"Type\">JSON</span>::parse(res.body)[<span class=\"Special\">'</span><span class=\"Constant\">html_url</span><span class=\"Special\">'</span>]<br />\\n</blockquote>\\n\\nポストされた物がこちら。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://gist.github.com/4342903\">We love mruby!</a>\\n\\t<br />\\n\\t<p>#!mruby if ARGV . size != 1 raise \"gist.rb [GIST_TOKEN]\" end req = HTTP : :Request . new req . metho...</p>\\n\\t<cite>https://gist.github.com/4342903</cite>\\n</blockquote>\\n<br />\\n\\n<h4>そして mruby-v8</h4>\\n\\nそしてそろそろ誰も得しない物が作りたくなってくる悪い病気が。<br />\\n<br />\\n\\n<a href=\"https://github.com/mattn/mruby-v8\">https://github.com/mattn/mruby-v8</a><br />\\n<br />\\nmruby から javascript が呼べ、そしてその javascript から mruby が呼べる!<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!mruby</span><br />\\n<br />\\nv8 = <span class=\"Type\">V8</span>.new<br />\\nputs v8.eval(<span class=\"Special\">'</span><span class=\"Constant\">1+2</span><span class=\"Special\">'</span>)<br />\\n<br />\\nv8.add_func(<span class=\"Special\">"</span><span class=\"Constant\">plus</span><span class=\"Special\">"</span>) <span class=\"Statement\">do</span> |<span class=\"Identifier\">lhs</span>,<span class=\"Identifier\">rhs</span>|<br />\\n lhs + rhs<br />\\n<span class=\"Statement\">end</span><br />\\n<br />\\nputs v8.eval(<span class=\"Special\">"</span><span class=\"Constant\">plus(2,3)</span><span class=\"Special\">"</span>)<br />\\n</blockquote>\\n\\nすばらしいですね!<del>便利って言え</del><br />\\n<br />\\n<h4>まとめ</h4>\\n\\nmruby 面白いよ!みんなも mrbgems 作って遊びましょう!<br />\\n<br />\\n<b>追記</b><br />\\n\\n@matsumotory さんがちゃくちゃくと mruby 内臓ウォシュレット計画をすすめている。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://blog.matsumoto-r.jp/?p=3168\">人間とウェブの未来 - mruby-zabbixとmruby-growthforecastでデバイスやアプリケーションの監視並びに情報の可視化を実現</a>\\n\\t<br />\\n\\t<cite>http://blog.matsumoto-r.jp/?p=3168</cite>\\n</blockquote>\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/B00AIL6H9O/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51nV2V1oTjL._SL160_.jpg\" alt=\"今日から使える! 液晶マイコンボード付きmruby学習キット EAPL-Trainer mruby\" class=\"awsxom-image\" />\\n<strong>今日から使える! 液晶マイコンボード付きmruby学習キット EAPL-Trainer mruby</strong></a><br />\\n<br />\\n(株)アイ・エル・シー / ¥ 17,640 ()<br />\\n <br />\\n発送可能時間:通常1~2営業日以内に発送<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "mruby", | |
"published": "2012-12-21T13:53:00+09:00" | |
}, | |
{ | |
"title": "Go言語をWeb上で楽しめる Go Playground で SL 動かしてみた。", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20121213175242.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20121213175242", | |
"summary": "\\nGo Playground で time パッケージが有効になった。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://play.golang.org\">Go Playground</a>\\n\\t<br />\\n\\t<p>The Go Playground is a web service that runs on golang.org 's servers. The serv...</p>\\n\\t<cite>https://play.golang.org</cite>\\n</blockquote>\\n\\n公式発表\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://groups.google.com/d/topic/golang-nuts/JBsCrDEVyVE/discussion\">Time - Google Groups</a>\\n\\t<br />\\n\\t<cite>https://groups.google.com/d/topic/golang-nuts/JBsCrDEVyVE/discussion</cite>\\n</blockquote>\\n\\n<code>\\x0c</code> というコードを <code>fmt.Print()</code> で出力するとクリアされ、<code>fmt.Print()</code> や <code>fmt.Println()</code> を使って文字列を出力、<code>time.Sleep</code> を使ってアニメーション表示が出来る様になります。<br />\\nこういうの出来たら、これを試さない訳にはいかない!!!<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://play.golang.org/p/NOycgN2i6b\">Go Playground</a>\\n\\t<br />\\n\\t<cite>http://play.golang.org/p/NOycgN2i6b</cite>\\n</blockquote>\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/3ecca50f609b9094.png\" alt=\"goplayground\" />\\n</blockquote>\\n\\n皆さんも面白いの作ってみて下さい。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "go", | |
"published": "2012-12-13T17:54:00+09:00" | |
}, | |
{ | |
"title": "vim script でヒアドキュメント", | |
"link": "http://mattn.kaoriya.net/software/vim/20121213115657.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121213115657", | |
"summary": "\\nvim script には perl 等で見るヒアドキュメント\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">print</span> <span class=\"Constant\"><<"EOF"</span><span class=\"Constant\">;</span><br />\\n<span class=\"Constant\">hello</span><br />\\n<span class=\"Constant\">world</span><br />\\n<span class=\"Constant\">EOF</span><br />\\n</blockquote>\\n\\nこれを言語レベルではサポートしていない。しかしこのヒアドキュメントも一種の言語的な縛りであって、縛りの許容範囲次第では vim script でもヒアドキュメントっぽい事は出来る。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! <span class=\"Special\">s:</span>here_doc<span class=\"Special\">(</span>sfile, slnum<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">lines</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">readfile</span><span class=\"Special\">(</span><span class=\"Identifier\">a:sfile</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">return</span> <span class=\"Identifier\">iconv</span><span class=\"Special\">(</span><span class=\"Identifier\">join</span><span class=\"Special\">(</span>lines[<span class=\"Identifier\">a:slnum</span><span class=\"Statement\">+</span><span class=\"Constant\">1</span> :<span class=\"Normal\">index</span><span class=\"Special\">(</span>lines, <span class=\"Constant\">'endif'</span><span class=\"Special\">)</span><span class=\"Statement\">-</span><span class=\"Constant\">1</span>], <span class=\"Constant\">"\\n"</span><span class=\"Special\">)</span>, <span class=\"Constant\">'utf-8'</span>, &encoding<span class=\"Special\">)</span><br />\\n<span class=\"Statement\">endfunction</span><br />\\n<span class=\"Statement\">command</span>! <span class=\"Statement\">-</span><span class=\"PreProc\">nargs</span><span class=\"Statement\">=</span><span class=\"Type\">1</span> HereIf0 execute <span class=\"Identifier\">printf</span>(<span class=\"Constant\">'let %s = s:here_doc(expand("<sfile>"), expand("<slnum>"))'</span>, <span class=\"Special\"><</span><span class=\"Special\">q-args</span><span class=\"Special\">></span>)<br />\\n</blockquote>\\n\\n<code>HereIf0</code> というコマンドを定義し\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">scriptencoding</span> utf<span class=\"Statement\">-</span><span class=\"Constant\">8</span><br />\\n<br />\\nHereIf0 foo<br />\\n<span class=\"Statement\">if</span> <span class=\"Constant\">0</span><br />\\nはろー<br />\\nわーるど<br />\\n<span class=\"Statement\">endif</span><br />\\n<br />\\n<span class=\"Statement\">echo</span> <span class=\"Identifier\">foo</span><br />\\n</blockquote>\\n\\nこの様に実行すると foo という変数に <code>if 0</code> から <code>endif</code> までが入る。<code>HereIf0</code> から <code>if 0</code> までに行を入れてはならないし、<code>endif</code> を省略して書いたり後続コメントを書いてはいけない。あとファイルのエンコーディングが utf-8 決めうちになる。<br />\\nまぁこれも縛りと思えば納得出来る。(縛りすぎ)<br />\\n<br />\\nちなみに perl の __DATA__ セクションっぽいのは、随分昔にやってた。<br />\\n\\n<a href=\"http://mattn.kaoriya.net/software/vim/20080317150503.htm\">http://mattn.kaoriya.net/software/vim/20080317150503.htm</a><br />\\n<a href=\"http://subtech.g.hatena.ne.jp/motemen/20080324/1206337579\">http://subtech.g.hatena.ne.jp/motemen/20080324/1206337579</a><br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-12-13T12:00:00+09:00" | |
}, | |
{ | |
"title": "Go言語で出来た grep、jvgrep の高速化", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20121204180747.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20121204180747", | |
"summary": "\\n以前、こんな記事を書いた。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.kaoriya.net/software/lang/go/20110819203649.htm\">Big Sky :: 日本語grepが出来るjvgrepというのを作った。</a>\\n\\t<br />\\n\\t<cite>http://mattn.kaoriya.net/software/lang/go/20110819203649.htm</cite>\\n</blockquote>\\n\\n実は jvgrep を作った当初、処理がかなり遅かった。まぁ複数のエンコーディングを試すからしょうがないよね程度に思ってたけど、どうにか速くならないかと思い、処理の並行化を行ってパフォーマンスを向上させた。この記事はその時にやった改善策。<br />\\n<br />\\njvgrep は <code>-R</code> オプションや <code>**/*</code> で再帰検索する機能が付いているんだけど、これを行う場合\\n\\n<ul>\\n\\t<li>find</li>\\n\\t<li>grep</li>\\n</ul>\\n\\nという処理が走る事になる。\\nしかしながら結果の順番を守ろうと考えた場合、find と grep を安直に同時に走らせる訳にはいかなくなる。走らせると結果が交錯してしまうからだ。<br />\\nこういうのを行う場合、C言語だとFIFOキューとスレッドを作り、find 側が push、grep 側が pop を行う仕組みを作る。<br />\\nしかしながらメモリの増加を管理したり、grep 側が空きになった時に待機する処理ってのを考えると、C言語だと結構めんどくさかったりする。<br />\\n<br />\\nGo言語はこのあたりが非常に簡単に実装出来る様になっている。<br />\\n<br />\\nまず find 部と grep 部の処理を分割し、grep 部を FIFO キューに対して連続で呼び出せる様にする。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">func</span> GoGrep(ch <span class=\"Type\">chan</span> *GrepArg, done <span class=\"Type\">chan</span> <span class=\"Type\">int</span>) {<br />\\n <span class=\"Statement\">for</span> {<br />\\n arg := <-ch<br />\\n <span class=\"Statement\">if</span> arg == <span class=\"Statement\">nil</span> {<br />\\n <span class=\"Statement\">break</span><br />\\n }<br />\\n Grep(arg)<br />\\n }<br />\\n done <- <span class=\"Constant\">1</span><br />\\n}<br />\\n</blockquote>\\n\\nGrep が本体だが今回の話の本質ではないので省略。引数の ch に Grep が使う引数が飛び込んで来る。全ての grep 対象が完了するか途中終了する場合には find 側から nil を渡すというお約束にした。<br />\\nメインコントローラ側で、この FIFO となるチャネルを作る。\\n\\n<blockquote class=\"code\">\\nch := <span class=\"Statement\">make</span>(<span class=\"Type\">chan</span> *GrepArg)<br />\\ndone := <span class=\"Statement\">make</span>(<span class=\"Type\">chan</span> <span class=\"Type\">int</span>)<br />\\n</blockquote>\\n\\nなぜ二つチャネルを作っているかというと、find 側が先に終了してしまった場合にプログラムが終了しない様、待機する為で、上記の GoGrep の最後に 1 を渡している。\\nチャネルを作ったら GoGrep をバックグラウンドで起動する。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">go</span> GoGrep(ch, done)<br />\\n</blockquote>\\n\\nGo言語は関数呼び出しに <code>go</code> を付けるだけで非同期に実行してくれる。<br />\\n次に find 部。Go言語の filepath パッケージにはファイルが見つかる度にコールバック関数を呼び出してくれる Walk がある。<br />\\n\\n<blockquote class=\"code\">\\nfilepath.Walk(root, <span class=\"Type\">func</span>(path <span class=\"Type\">string</span>, info os.FileInfo, err <span class=\"Type\">error</span>) <span class=\"Type\">error</span> {<br />\\n <span class=\"Statement\">if</span> info == <span class=\"Statement\">nil</span> {<br />\\n <span class=\"Statement\">return</span> err<br />\\n }<br />\\n<br />\\n <span class=\"Comment\">// 以下 path に対する処理を行う。</span><br />\\n path = filepath.ToSlash(path)<br />\\n<br />\\n <span class=\"Comment\">// 検索対象外のパスにマッチする場合</span><br />\\n <span class=\"Statement\">if</span> ere != <span class=\"Statement\">nil</span> && ere.MatchString(path) {<br />\\n <span class=\"Comment\">// ディレクトリならば SkipDir を返して他のフォルダに移る</span><br />\\n <span class=\"Statement\">if</span> info.IsDir() {<br />\\n <span class=\"Statement\">return</span> filepath.SkipDir<br />\\n }<br />\\n <span class=\"Comment\">// ファイルならば以下の処理は行わない</span><br />\\n <span class=\"Statement\">return</span> <span class=\"Statement\">nil</span><br />\\n }<br />\\n<br />\\n <span class=\"Comment\">// ... 省略 ...</span><br />\\n<br />\\n <span class=\"Comment\">// 検索対象のファイルならば</span><br />\\n <span class=\"Statement\">if</span> fre.MatchString(path) {<br />\\n <span class=\"Comment\">// GoGrep が待っているチャネルにパラメータを渡す</span><br />\\n ch <- &GrepArg{pattern, path, <span class=\"Comment\">/* ... 省略 ... */</span>}<br />\\n }<br />\\n})<br />\\n</blockquote>\\n\\n検索対象のファイルが見つかった場合、先ほど作成した ch に Grep 引数を渡している。<br />\\nfind 側は全てのファイルを検索し終えたら grep 側に処理の終了を伝える。\\n\\n<blockquote class=\"code\">\\nch <- <span class=\"Statement\">nil</span><br />\\n</blockquote>\\n\\nそして grep の終了(done)を待つ。\\n\\n<blockquote class=\"code\">\\n<-done<br />\\n</blockquote>\\n\\n図解すると\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/e8352b2edd3896f8.png\" alt=\"jvgrep\" />\\n</blockquote>\\n\\nこんなイメージになる。find もフォルダを再帰的に検索すると結構重くなるので各処理を並行実行させる事でかなりのパフォーマンス向上が得られた。<br />\\n<br />\\n最初から find 部と grep 部が関数分けされていれば、もっと簡単に並行処理の実装が出来た事になる。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "jvgrep, go", | |
"published": "2012-12-04T18:18:00+09:00" | |
}, | |
{ | |
"title": "モテる Vim 使いに読み書き出来ないファイルなどなかったんだよ!", | |
"link": "http://mattn.kaoriya.net/software/vim/20121204090702.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121204090702", | |
"summary": "\\nVim Advent Calendar 2012 の 4 日目の記事です。<br />\\n<br />\\n<img src=\"http://go-gyazo.appspot.com/808546f74c2dffd9.png\" alt=\"!!!\" class=\"thumbnail-right\" />\\n<ul>\\n<li>「<em>やった!コンプガチャで Vim 出た!</em>」</li>\\n<li>「<em>だって前の彼氏、Vim 使いじゃなかったんだもん</em>」<li>「<em>マクドナルド店員「ご一緒に Vim など如何ですか?」</em>」</li>\\n</ul>\\nこんな言葉が聞かれる様になって随分と経ちました(要出典)。<br />\\n<br />\\n昨今、Vim はテキストエディタの枠を超え、アプリケーションプラットフォームへと変わりつつあります。<br />\\n<br />\\nvital.vim 等を使う事で簡単にアプリケーションを作る事も出来る様になりました。手前味噌ではありますが webapi-vim の一部も vital.vim に取り込まれています。<br />\\nこのブログでも結構取り上げていますが webapi-vim とは一体何か。名前の通り、Web Application Programming Intreface を扱えるライブラリです。<br class=\"clearall\" />\\n\\n<h2>webapi-vim とは</h2>\\n\\nwebapi-vim を使えば例えばこんな事が出来ます。<br />\\n<br />\\n<h4>HTTP で GET</h4>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Operator\">=</span> webapi#http#get<span class=\"Special\">(</span><span class=\"String\">"<a href=\"http://example.com\">http://example.com</a>"</span><span class=\"Special\">)</span><br />\\n</blockquote>\\n\\nres には以下の様な構造が返ります。\\n\\n<blockquote class=\"code\">\\n{<br />\\n "header": [<br />\\n "Content-Type: text/html",<br />\\n "Content-Length: 310"<br />\\n ],<br />\\n "content": <span class=\"String\">"<html> ....."</span><br />\\n}<br />\\n</blockquote>\\n\\nheader にはヘッダの配列、content には受信したデータが戻ります。<br />\\n引数にはパラメータを渡せます。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Operator\">=</span> webapi#http#get<span class=\"Special\">(</span><span class=\"String\">"<a href=\"http://google.com\">http://google.com</a>"</span>, <span class=\"Special\">{</span> <span class=\"String\">"q"</span>: <span class=\"String\">"vim"</span> <span class=\"Special\">}</span><span class=\"Special\">)</span><br />\\n</blockquote>\\n\\n<h4>HTTP で POST</h4>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Operator\">=</span> webapi#http#post<span class=\"Special\">(</span><span class=\"String\">"<a href=\"http://google.com\">http://google.com</a>"</span>, <span class=\"Special\">{</span> <span class=\"String\">"q"</span>: <span class=\"String\">"vim"</span> <span class=\"Special\">}</span><span class=\"Special\">)</span><br />\\n</blockquote>\\n\\nGET とほぼ同じインタフェースです。GET も同様ですが、第三引数 header を指定出来ます。<br />\\n\\n<h4>XML のパース</h4>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">dom</span> <span class=\"Operator\">=</span> webapi#xml#parse<span class=\"Special\">(</span><span class=\"String\">'<vim><vimer id="1">bram</vimmer></vim>'</span><span class=\"Special\">)</span><br />\\n</blockquote>\\n\\nDOM オブジェクトが返ります。以下の様な構造になっています。<br />\\n\\n<blockquote class=\"code\">\\n{<br />\\n "name": <span class=\"String\">"vim"</span>,<br />\\n "attr": {},<br />\\n "child": [<br />\\n {<br />\\n "name": <span class=\"String\">"vimmer"</span>,<br />\\n "attr": { <span class=\"String\">"id"</span>: 1 },<br />\\n "child": [<br />\\n "bram"<br />\\n ]<br />\\n }<br />\\n ]<br />\\n}<br />\\n</blockquote>\\n\\ndom からは以下の様に探索出来ます。<br />\\n\\n<blockquote class=\"code\">\\ndom.childNode(\"vimmer\")\\n</blockquote>\\n\\nこれで子ノードのうち vimmer ノードが1つだけ返ります。\\n\\n<blockquote class=\"code\">\\ndom.childNode(\"vimmer\", {\"id\": 1})\\n</blockquote>\\n\\nvimmer ノードのうち id 属性が 1 の物が1つだけ返ります。\\n\\n<blockquote class=\"code\">\\ndom.childNodes(\"vimmer\", {\"id\": 1})\\n</blockquote>\\n\\nvimmer ノードで id 属性が 1 の物が全て返ります。childNode/childNodes は子ノードだけですが、再帰的に検索する場合 find/findAll を使います。\\n\\n<blockquote class=\"code\">\\nnode.value()\\n</blockquote>\\n\\nノードをテキスト化します。上記で得た bram が入った vimmer ノードで value() を実行すると \"bram\" という文字列が得られます。<br />\\n\\n<blockquote class=\"code\">\\nnode.toString()\\n</blockquote>\\n\\nノードをXML化します。なお、属性はノードに対して attr というフィールドからディクショナリで参照出来ます。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">echo</span> <span class=\"Identifier\">node</span>.<span class=\"Identifier\">attr</span>[<span class=\"String\">"id"</span>]<br />\\n</blockquote>\\n\\n<h4>HTML のパース</h4>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">dom</span> <span class=\"Operator\">=</span> webapi#html#parse<span class=\"Special\">(...)</span><br />\\n</blockquote>\\n\\n扱い方は XML と同じです。<br />\\n\\n<h4>JSON のエンコード/デコード</h4>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">obj</span> <span class=\"Operator\">=</span> webapi#json#decode<span class=\"Special\">(</span>json<span class=\"Special\">)</span><br />\\n</blockquote>\\n\\nvim の値として扱えます。逆に\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">json</span> <span class=\"Operator\">=</span> webapi#json#encode<span class=\"Special\">(</span>obj<span class=\"Special\">)</span><br />\\n</blockquote>\\n\\nでエンコード出来ます。\\n\\nwebapi-vim にはこれ以外にも XMLRPC/JSONRPC/SOAP といったRPC、MD5/SHA1 といったハッシュ関数、OAuth もあります。詳しくはドキュメントを見て頂くか、サンプルや webaip-vim を使ったプロダクトのソースコードを参照して下さい。<br />\\n\\n<h2>metarw とは</h2>\\n\\nさて、いまごろ本題<br />\\n昨今のモテる Vim 使いはどんな物に対しても vim から読み書きを行います(要出典)。その代表例として vim-metarw という物もあります。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/kana/vim-metarw\">kana/vim-metarw - GitHub</a>\\n\\t<br />\\n\\t<p>Vim plugin: A framework to read/write fake:path</p>\\n\\t<cite>https://github.com/kana/vim-metarw</cite>\\n</blockquote>\\n\\nこれは kana さんが作ったフレームワークで、metarw 自身は vim からメタ情報を読み書きする土台のみを提供します。各 metarw プラグインは metarw のルールに従って実装コードを入れる事で vim と親和性の高いファイルの読み書きが出来るという物です。例えば vim-metarw-gist という物があります。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/emonkak/vim-metarw-gist\">emonkak/vim-metarw-gist ツキ GitHub</a>\\n\\t<br />\\n\\t<p>Vim plugin: metarw scheme for gist</p>\\n\\t<cite>https://github.com/emonkak/vim-metarw-gist</cite>\\n</blockquote>\\n\\nこれを使うと <code>:e gist:</code> で vim が持っているファイルエクスプローラと同じ見栄えで自分の gist 一覧が表示され、エンターを押すと gist のファイルが開かれ、<code>:w</code> で書き込めます。\\nなお Windows で metarw を使う場合には私の fork を使って下さい。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/vim-metarw\">mattn/vim-metarw - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/vim-metarw</cite>\\n</blockquote>\\n\\nここで metarw プラグインについて説明しましょう。<br />\\nvim-metarw プラグインを作る場合はまずプラグインフォルダを用意し、<code>autoload/metarw/プラグイン名.vim</code> というファイルを作ります。<br />\\nvim-metarw プラグインを満たす為には以下の実装を含んでいる必要があります。\\n\\n<blockquote class=\"code\">\\nmetarw#gdrive#read(fakepath)<br />\\nmetarw#gdrive#write(fakepath, line1, line2, append_p)<br />\\nmetarw#gdrive#complete(arglead, cmdline, cursorpos)<br />\\n</blockquote>\\n\\nまず read を説明します。metarw プラグインは fakepath で指定されたパスがディレクトリかどうかを判断し、ディレクトリであれば\\n\\n<blockquote class=\"code\">\\n['browse', [<br />\\n {"label": "ふー", "fakepath": "xxx:/foo"},<br />\\n {"label": "ばー", "fakepath": "xxx:/bar"}<br />\\n]]<br />\\n</blockquote>\\n\\nbrowse という結果と共にパス情報を返します。エラーが発生した場合には\\n\\n<blockquote class=\"code\">\\n['error', 'エラーメッセージ']<br />\\n</blockquote>\\n\\nを返します。ファイルであった場合には、既に metarw が用意したバッファにコンテンツを貼り付け、必要であれば filetype も変更して\\n\\n<blockquote class=\"code\">\\n['done', '']<br />\\n</blockquote>\\n\\nという結果を返します。write も同様に、fakepath で指定されたパスに対して現在のバッファの line1 行から line2 行のコンテンツを書き込みます。append_p の場合は追記になります。<br />\\n最後に complete は vim の補完と同じ仕組みになります。実際には、read の際にファイル一覧を作った結果の fakepath 部分を返せば良い事になります。<br />\\n<br />\\nここまで来れば誰でも metarw プラグインを作れる様になります。<br />\\n<br />\\n<h2>vim-metarw-gdrive でハードウェア境界を越えろ</h2>\\n\\n<img src=\"http://go-gyazo.appspot.com/7ae8b32993cf4b88.png\" alt=\"!!!\" class=\"thumbnail-left\" />\\n上記で説明した webapi-vim と、この vim-metarw を使い、<a href=\"https://drive.google.com/\">Google Drive</a> のファイルを読み書き出来る物を作ってみましょう。<br />\\n<br />\\n<blockquote>\\nなっ!?なんだってーーー!\\n</blockquote>\\n<br class=\"clearall\" />\\nまずは read で指定されたパスから属性情報を取り出す部分を作ります。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! <span class=\"Special\">s:</span>parse_incomplete_fakepath<span class=\"Special\">(</span>incomplete_fakepath<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span> <span class=\"Statement\">=</span> <span class=\"Special\">{}</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">fragments</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">split</span><span class=\"Special\">(</span><span class=\"Identifier\">a:incomplete_fakepath</span>, <span class=\"Constant\">'^\\l\\+\\zs:'</span>, !<span class=\"Constant\">0</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">len</span><span class=\"Special\">(</span>fragments<span class=\"Special\">)</span> <span class=\"Statement\"><=</span> <span class=\"Constant\">1</span><br />\\n <span class=\"Statement\">echoerr</span> <span class=\"Constant\">'Unexpected a:incomplete_fakepath:'</span> <span class=\"Identifier\">string</span><span class=\"Special\">(</span><span class=\"Identifier\">a:incomplete_fakepath</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">throw</span> <span class=\"Constant\">'metarw:gdrive#e1'</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span><span class=\"Statement\">.</span>given_fakepath <span class=\"Statement\">=</span> <span class=\"Identifier\">a:incomplete_fakepath</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span><span class=\"Statement\">.</span>scheme <span class=\"Statement\">=</span> fragments[<span class=\"Constant\">0</span>]<br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span><span class=\"Statement\">.</span>path <span class=\"Statement\">=</span> fragments[<span class=\"Constant\">1</span>]<br />\\n <span class=\"Statement\">if</span> fragments[<span class=\"Constant\">1</span>] <span class=\"Statement\">==</span> <span class=\"Constant\">''</span> <span class=\"Statement\">||</span> fragments[<span class=\"Constant\">1</span>] <span class=\"Statement\">=~</span> <span class=\"Constant\">'^[\\/]$'</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span><span class=\"Statement\">.</span>id <span class=\"Statement\">=</span> <span class=\"Constant\">'root'</span><br />\\n <span class=\"Statement\">else</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span><span class=\"Statement\">.</span>id <span class=\"Statement\">=</span> <span class=\"Identifier\">split</span><span class=\"Special\">(</span>fragments[<span class=\"Constant\">1</span>], <span class=\"Constant\">'[\\/]'</span><span class=\"Special\">)</span>[<span class=\"Statement\">-</span><span class=\"Constant\">1</span>]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">return</span> _<br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\n<a href=\"https://developers.google.com/drive/\">Google Drive SDK</a> の API リファレンスによると、Google Drive の API では各ファイルにパスでアクセスする事は出来ません。パスから特定のコンテンツを得たり保存を行う場合には、ノードIDに対して割り当てられた名称を取得し、例えば <code>/foo/bar/baz.txt</code> というパスのコンテンツを得る場合、実は bar というフォルダのIDだけ分かれば書き込める事になります。ただしラベルは同じノード内においても重複し得ます。なのでパス <code>/foo/bar/baz.txt</code> という情報から目的の <code>baz.txt</code> のコンテンツを得るには\\n\\n<ul>\\n\\t<li>\"root\" ノード直下のファイル一覧を調べ、ディレクトリかつラベルが foo の最初の物を探す</li>\\n\\t<li>foo 直下のファイル一覧を調べ、ディレクトリかつラベルが bar の最初の物を探す</li>\\n\\t<li>bar 直下のファイル一覧を調べ、ファイルかつラベルが baz.txt の最初の物を探す</li>\\n\\t<li>baz.txt のコンテンツをダウンロードする</li>\\n</ul>\\n\\nこいうめんどくさい手順を取る必要があります。たかがファイルを読みたいだけに4回 API アクセスが必要になります。どう考えてもおかし過ぎるし使っててイライラするだろうから、このプラグインで扱うパス情報は ID で行う事とし、ファイルブラウザで実際のファイル名からアクセスしてもらう事とします。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! metarw#gdrive#read<span class=\"Special\">(</span>fakepath<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span> <span class=\"Statement\">=</span> <span class=\"Normal\">s:parse_incomplete_fakepath</span><span class=\"Special\">(</span><span class=\"Identifier\">a:fakepath</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> _<span class=\"Statement\">.</span>path <span class=\"Statement\">==</span> <span class=\"Constant\">''</span> <span class=\"Statement\">||</span> _<span class=\"Statement\">.</span>path <span class=\"Statement\">=~</span> <span class=\"Constant\">'[\\/]$'</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">result</span> <span class=\"Statement\">=</span> <span class=\"Normal\">s:read_list</span><span class=\"Special\">(</span>_<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">else</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">result</span> <span class=\"Statement\">=</span> <span class=\"Normal\">s:read_content</span><span class=\"Special\">(</span>_<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">return</span> result<br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\nまずは先ほど作った parse_incomplete_fakepath に従い、ファイル一覧を読むのかファイルのコンテンツを読むのかを切り分けます。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! <span class=\"Special\">s:</span>read_list<span class=\"Special\">(</span>_<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">call</span> <span class=\"Normal\">s:load_settings</span><span class=\"Special\">()</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">result</span> <span class=\"Statement\">=</span> []<br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Statement\">=</span> webapi#json#<span class=\"Normal\">decode</span><span class=\"Special\">(</span>webapi#http#<span class=\"Normal\">get</span><span class=\"Special\">(</span><span class=\"Constant\">'<a href=\"https://www.googleapis.com/drive/v2/files\">https://www.googleapis.com/drive/v2/files</a>'</span>, <span class=\"Special\">{</span><span class=\"Constant\">'access_token'</span>: s:settings[<span class=\"Constant\">'access_token'</span>], <span class=\"Constant\">'q'</span>: <span class=\"Identifier\">printf</span><span class=\"Special\">(</span><span class=\"Constant\">"'%s' in parents"</span>, <span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>id<span class=\"Special\">)</span><span class=\"Special\">}</span><span class=\"Special\">)</span><span class=\"Statement\">.</span>content<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">has_key</span><span class=\"Special\">(</span>res, <span class=\"Constant\">'error'</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'error'</span>, <span class=\"Statement\">res</span><span class=\"Statement\">.</span>error<span class=\"Statement\">.</span>message]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">for</span> item <span class=\"Statement\">in</span> <span class=\"Statement\">res</span><span class=\"Statement\">.</span>items<br />\\n <span class=\"Statement\">if</span> item<span class=\"Statement\">.</span>labels<span class=\"Statement\">.</span>trashed <span class=\"Statement\">!=</span> <span class=\"Constant\">0</span><br />\\n <span class=\"Statement\">continue</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">title</span> <span class=\"Statement\">=</span> item<span class=\"Statement\">.</span>title<br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">file</span> <span class=\"Statement\">=</span> item<span class=\"Statement\">.</span>id<br />\\n <span class=\"Statement\">if</span> item<span class=\"Statement\">.</span>mimeType <span class=\"Statement\">==</span> <span class=\"Constant\">'application/vnd.google-apps.folder'</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">title</span> <span class=\"Statement\">.=</span> <span class=\"Constant\">'/'</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">file</span> <span class=\"Statement\">.=</span> <span class=\"Constant\">'/'</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">len</span><span class=\"Special\">(</span><span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>path<span class=\"Special\">)</span> <span class=\"Statement\">==</span> <span class=\"Constant\">0</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">file</span> <span class=\"Statement\">=</span> <span class=\"Constant\">'/'</span> <span class=\"Statement\">.</span> <span class=\"Statement\">file</span><br />\\n <span class=\"Statement\">else</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">file</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>path <span class=\"Statement\">.</span> <span class=\"Statement\">file</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">call</span> <span class=\"Identifier\">add</span><span class=\"Special\">(</span>result, <span class=\"Special\">{</span><br />\\n<span class=\"Special\"> \\</span> <span class=\"Constant\">'label'</span>: title,<br />\\n<span class=\"Special\"> \\</span> <span class=\"Constant\">'fakepath'</span>: <span class=\"Identifier\">printf</span><span class=\"Special\">(</span><span class=\"Constant\">'%s:%s'</span>, <span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>scheme, file<span class=\"Special\">)</span><br />\\n<span class=\"Special\"> \\</span> <span class=\"Special\">}</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">endfor</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'browse'</span>, result]<br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\nGoogle Drive API を使って、ノードID に属するファイルの一覧を取得しています。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! <span class=\"Special\">s:</span>read_content<span class=\"Special\">(</span>_<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">call</span> <span class=\"Normal\">s:load_settings</span><span class=\"Special\">()</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Statement\">=</span> webapi#json#<span class=\"Normal\">decode</span><span class=\"Special\">(</span>webapi#http#<span class=\"Normal\">get</span><span class=\"Special\">(</span><span class=\"Constant\">'<a href=\"https://www.googleapis.com/drive/v2/files/\">https://www.googleapis.com/drive/v2/files/</a>'</span> <span class=\"Statement\">.</span> webapi#http#<span class=\"Normal\">encodeURI</span><span class=\"Special\">(</span><span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>id<span class=\"Special\">)</span>, <span class=\"Special\">{</span><span class=\"Constant\">'access_token'</span>: s:settings[<span class=\"Constant\">'access_token'</span>]<span class=\"Special\">}</span><span class=\"Special\">)</span><span class=\"Statement\">.</span>content<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">has_key</span><span class=\"Special\">(</span>res, <span class=\"Constant\">'error'</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'error'</span>, <span class=\"Statement\">res</span><span class=\"Statement\">.</span>error<span class=\"Statement\">.</span>message]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">if</span> !<span class=\"Identifier\">has_key</span><span class=\"Special\">(</span>res, <span class=\"Constant\">'downloadUrl'</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'error'</span>, <span class=\"Constant\">'This file seems impossible to edit in vim!'</span>]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">resp</span> <span class=\"Statement\">=</span> webapi#http#<span class=\"Normal\">get</span><span class=\"Special\">(</span>res<span class=\"Statement\">.</span>downloadUrl, <span class=\"Constant\">''</span>, <span class=\"Special\">{</span><span class=\"Constant\">'Authorization'</span>: <span class=\"Constant\">'Bearer '</span> <span class=\"Statement\">.</span> s:settings[<span class=\"Constant\">'access_token'</span>]<span class=\"Special\">}</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> resp<span class=\"Statement\">.</span>header[<span class=\"Constant\">0</span>] <span class=\"Statement\">!~</span> <span class=\"Constant\">'200'</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'error'</span>, resp<span class=\"Statement\">.</span>header[<span class=\"Constant\">0</span>]]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">content</span> <span class=\"Statement\">=</span> resp<span class=\"Statement\">.</span>content<br />\\n <span class=\"Statement\">call</span> <span class=\"Identifier\">setline</span><span class=\"Special\">(</span><span class=\"Constant\">2</span>, <span class=\"Identifier\">split</span><span class=\"Special\">(</span><span class=\"Identifier\">iconv</span><span class=\"Special\">(</span>content, <span class=\"Constant\">'utf-8'</span>, &encoding<span class=\"Special\">)</span>, <span class=\"Constant\">"\\n"</span><span class=\"Special\">))</span><br />\\n<br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">ext</span> <span class=\"Statement\">=</span> <span class=\"Constant\">'.'</span> <span class=\"Statement\">.</span> <span class=\"Statement\">res</span><span class=\"Statement\">.</span>fileExtension<br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">has_key</span><span class=\"Special\">(</span>s:extmap, ext<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> &<span class=\"Statement\">filetype</span> <span class=\"Statement\">=</span> s:extmap[ext]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'done'</span>, <span class=\"Constant\">''</span>]<br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\nノードIDからコンテンツをダウンロードしています。ファイル名に拡張子がついていないので、拡張子からファイルタイプを決定する為にローカルにテーブルを保持しました。<br />\\nここで metarw を使う際の注意点があります。metarw の read 関数実装は <code>:r! ...</code> といった外部ファイルを読み込む事を想定しており、vim のデフォルト動作と同様に先頭行に空行が入れる必要があります。この空行は metarw 本体側で削除されるので、metarw プラグイン側が空白行を入れる必要があります。<br />\\n<br />\\nwrite も同様に API から行います。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">function</span>! <span class=\"Special\">s:</span>write_content<span class=\"Special\">(</span>_, content<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">call</span> <span class=\"Normal\">s:load_settings</span><span class=\"Special\">()</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">res</span> <span class=\"Statement\">=</span> webapi#json#<span class=\"Normal\">decode</span><span class=\"Special\">(</span>webapi#http#<span class=\"Normal\">post</span><span class=\"Special\">(</span><span class=\"Constant\">'<a href=\"https://www.googleapis.com/upload/drive/v2/files/\">https://www.googleapis.com/upload/drive/v2/files/</a>'</span> <span class=\"Statement\">.</span> webapi#http#<span class=\"Normal\">encodeURI</span><span class=\"Special\">(</span><span class=\"Identifier\">a:_</span><span class=\"Statement\">.</span>id<span class=\"Special\">)</span>, <span class=\"Identifier\">a:content</span>, <span class=\"Special\">{</span><span class=\"Constant\">'Authorization'</span>: <span class=\"Constant\">'Bearer '</span> <span class=\"Statement\">.</span> s:settings[<span class=\"Constant\">'access_token'</span>], <span class=\"Constant\">'Content-Type'</span>: <span class=\"Constant\">'application/octet-stream'</span><span class=\"Special\">}</span>, <span class=\"Constant\">'PUT'</span><span class=\"Special\">)</span><span class=\"Statement\">.</span>content<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> <span class=\"Identifier\">has_key</span><span class=\"Special\">(</span>res, <span class=\"Constant\">'error'</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'error'</span>, <span class=\"Statement\">res</span><span class=\"Statement\">.</span>error<span class=\"Statement\">.</span>message]<br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">return</span> [<span class=\"Constant\">'done'</span>, <span class=\"Constant\">''</span>]<br />\\n<span class=\"Statement\">endfunction</span><br />\\n<br />\\n<span class=\"Statement\">function</span>! metarw#gdrive#write<span class=\"Special\">(</span>fakepath, line1, line2, append_p<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">_</span> <span class=\"Statement\">=</span> <span class=\"Normal\">s:parse_incomplete_fakepath</span><span class=\"Special\">(</span><span class=\"Identifier\">a:fakepath</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">if</span> _<span class=\"Statement\">.</span>path <span class=\"Statement\">==</span> <span class=\"Constant\">''</span> <span class=\"Statement\">||</span> _<span class=\"Statement\">.</span>path <span class=\"Statement\">=~</span> <span class=\"Constant\">'[\\/]$'</span><br />\\n <span class=\"Statement\">echoerr</span> <span class=\"Constant\">'Unexpected a:incomplete_fakepath:'</span> <span class=\"Identifier\">string</span><span class=\"Special\">(</span><span class=\"Identifier\">a:incomplete_fakepath</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">throw</span> <span class=\"Constant\">'metarw:gdrive#e1'</span><br />\\n <span class=\"Statement\">else</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">content</span> <span class=\"Statement\">=</span> <span class=\"Identifier\">iconv</span><span class=\"Special\">(</span><span class=\"Identifier\">join</span><span class=\"Special\">(</span><span class=\"Identifier\">getline</span><span class=\"Special\">(</span><span class=\"Identifier\">a:line1</span>, <span class=\"Identifier\">a:line2</span><span class=\"Special\">)</span>, <span class=\"Constant\">"\\n"</span><span class=\"Special\">)</span>, &encoding, <span class=\"Constant\">'utf-8'</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">let</span> <span class=\"Identifier\">result</span> <span class=\"Statement\">=</span> <span class=\"Normal\">s:write_content</span><span class=\"Special\">(</span>_, content<span class=\"Special\">)</span><br />\\n <span class=\"Statement\">endif</span><br />\\n <span class=\"Statement\">return</span> result<br />\\n<span class=\"Statement\">endfunction</span><br />\\n</blockquote>\\n\\nこのプラグインは Google Drive に oauth2 で認証を行っています。初めて使う際には\\n\\n<blockquote class=\"code\">\\n:GdriveSetup\\n</blockquote>\\n\\nを実行し、ブラウザで表示されたコードを vim の <code>CODE:</code> 部にコピペして頂く必要があります。<br />\\nGoogle Drive の API、というか最近の Google の API は認証情報に揮発性があり、リフレッシュトークンという物を使って有効期限が切れたアクセストークンを再生成する必要があります。上記のコードには含まれませんがリポジトリでは401による再認証が行われます。<br />\\nそれでもエラーが出る場合は、お手数ですが再度\\n\\n<blockquote class=\"code\">\\n:GdriveSetup\\n</blockquote>\\n\\nを実行して認証を行って下さい。<br />\\nソースを github に置いてあります。興味のある方は覗いてみて下さい。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/vim-metarw-gdrive\">mattn/vim-metarw-gdrive ツキ GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/vim-metarw-gdrive</cite>\\n</blockquote>\\n\\n全て webapi-vim もそうですが vim スクリプトだけで組まれています。(ただしネットワーク通信部分だけは curl もしくは wget を使っています)<br />\\n<br />\\nさて実際に使ってみましょう。上記の認証を終わらせた後 <code>:e gdrive:</code> を実行します。<br />\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/d6b57a1bfc4d80d6.png\" alt=\"vim-metarw-gdrive1\" />\\n</blockquote>\\n\\nファイル一覧が表示されました。<br />\\nなんと都合よく「helloworld.cxx」なんてファイルがあるではありませんか!!!<br />\\nエンターキーを押します。<br />\\n<br />\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/2ca01104e579a845.png\" alt=\"vim-metarw-gdrive2\" />\\n</blockquote>\\n\\nおぉぉ...<br />\\n<br />\\nもちろん <code>:w</code> で保存する事も出来ますし、quickrun から直で実行する事も出来ます。<br />\\nファイルを作成する場合は、ファイルブラウザに表示されるパスを使って「:w gdrive:/XXXXXXXX/foo.txt」と実行して下さい。現在のバッファが指定のフォルダにアップロードされます。この場合、バッファは既にテンポラリに過ぎないので更新したい場合はファイルブラウザから開きなおして下さい。<br />\\n<br />\\n<h2>まとめ</h2>\\n\\nまとめると...\\n<blockquote>\\n<em>モテる Vimmer に読み書き出来ないファイルなど無かったんだよ!!</em>\\n</blockquote>\\nってことです。<br />\\n<br />\\n<b>追記</b><br />\\nモテる度合いには個人差がございます。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, metarw, gdrive, googledrive, webapi-vim", | |
"published": "2012-12-04T09:10:00+09:00" | |
}, | |
{ | |
"title": "grep で文字列を縦書きに変換", | |
"link": "http://mattn.kaoriya.net/software/linux/20121128204539.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/linux/20121128204539", | |
"summary": "\\ngrep の <code>-o</code> オプションを使うとマッチした部分だけ列挙してくれる。<br />\\n例えば\\n\\n<blockquote class=\"code\">\\n<div>foo</div><div>bar</div><br />\\n<div>baz</div><br />\\n</blockquote>\\n\\nというテキストファイル foo.txt に対して\\n\\n<blockquote class=\"code\">\\ngrep -o "<div[^>]*>[^<]*<\\/div>" foo.txt<br />\\n</blockquote>\\n\\nと実行すると\\n\\n<blockquote class=\"code\">\\n<div>foo</div><br />\\n<div>bar</div><br />\\n<div>baz</div><br />\\n</blockquote>\\n\\nが得られる。これを応用して\\n\\n<blockquote class=\"code\">\\necho 餃子の王将 | grep -o .<br />\\n</blockquote>\\n\\nとやると\\n\\n<blockquote class=\"code\">\\n餃<br />\\n子<br />\\nの<br />\\n王<br />\\n将<br />\\n</blockquote>\\n\\nが得られる。<br />\\n<br />\\n便利!!\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "grep", | |
"published": "2012-11-28T20:46:00+09:00" | |
}, | |
{ | |
"title": "pathogen やめた。", | |
"link": "http://mattn.kaoriya.net/software/vim/20121126180549.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121126180549", | |
"summary": "\\nいままでvimプラグインの管理には pathogen を使ってきたんだけど\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/tpope/vim-pathogen\">tpope/vim-pathogen - GitHub</a>\\n\\t<br />\\n\\t<p>pathogen.vim: manage your runtimepath</p>\\n\\t<cite>https://github.com/tpope/vim-pathogen</cite>\\n</blockquote>\\n\\nunbundle を使う事にした。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://snk.tuxfamily.org/log/vim-script-management-system.html\">Vim script management system - The Terminal Programmer</a>\\n\\t<br />\\n\\t<p>22 November 2011: I squashed my entire Vim configuration history while retaining the three branch ar...</p>\\n\\t<cite>http://snk.tuxfamily.org/log/vim-script-management-system.html</cite>\\n</blockquote>\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/sunaku/vim-unbundle\">sunaku/vim-unbundle ツキ GitHub</a>\\n\\t<br />\\n\\t<p>Activates Vim scripts (bundles) from isolated directories</p>\\n\\t<cite>https://github.com/sunaku/vim-unbundle</cite>\\n</blockquote>\\n\\n原理的には pathogen と一緒。ただし pathogen は bundle 配下のプラグインを全てロードしてしまう。なので C++ やる時でも <a href=\"http://mattn.kaoriya.net/software/vim/20121018212621.htm\">jedi-vim</a> をロードしてしまうし、perl やる時でも <a href=\"https://github.com/Rip-Rip/clang_complete\">clang_complete</a> をロードしてしまうし、python やる時でも <a href=\"https://github.com/c9s/perlomni.vim\">perlomni</a> をロードしてしまう。<br />\\n結構無駄なメモリ使ってるなーと思ったので、unbundle で管理する事にした。<br />\\nbundle ディレクトリ内のファイルタイプに依存したプラグインフォルダをごそっと以下の様に ftbundle ディレクトリ移動した。\\n\\n<blockquote class=\"code\">\\n+- ftbundle<br />\\n| +-cpp<br />\\n| | +-clang_complete<br />\\n| |<br />\\n| +-javascript<br />\\n| | +-jscomplete-vim<br />\\n| | +-jslint.vim<br />\\n| | +-vim-javascript<br />\\n| |<br />\\n| +-jsx<br />\\n| | +-jsx.vim<br />\\n| |<br />\\n| +-lisp<br />\\n| | +-slimv<br />\\n| |<br />\\n| +-markdown<br />\\n| | +-vim-markdown<br />\\n| |<br />\\n| +-perl<br />\\n| | +-perlomni.vim<br />\\n| | +-vim-perl<br />\\n| |<br />\\n| +-python<br />\\n| | +-jedi-vim<br />\\n| |<br />\\n| +-slim<br />\\n| +-vim-slim<br />\\n|<br />\\n+- bundle<br />\\n いままでのプラグイン...\\n</blockquote>\\n\\n計ってないけど、起動の体感速度があがった気がする。なお unbundle には明示的にロードするコマンドも用意されている。しばらく使おうと思う。あと問題があったらパッチも書くかな。<br />\\n<br />\\nP.S. sugyan さん、ももクロ紅白出場おめでとうございます。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, unbundle, pathogen", | |
"published": "2012-11-26T18:07:00+09:00" | |
}, | |
{ | |
"title": "Vim から sprunge.us にポスト", | |
"link": "http://mattn.kaoriya.net/software/vim/20121120213622.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121120213622", | |
"summary": "\\n普通に <code>:w !</code> で。<br />\\n\\n<blockquote class=\"code\">\\n:w !curl -F "sprunge=<-" <a href=\"http://sprunge.us\">http://sprunge.us</a><br />\\n <a href=\"http://sprunge.us/YGiV\">http://sprunge.us/YGiV</a><br />\\n<br />\\nPress ENTER or type command to continue<br />\\n</blockquote>\\n\\n実は curl の <code><-</code> という指定を知らなかった。いつも @ 指定でやってた。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-11-20T21:36:00+09:00" | |
}, | |
{ | |
"title": "コマンドラインからredmineを扱える「godmine」作った。", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20121119213020.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20121119213020", | |
"summary": "\\nredmineをwebで使っていると色々とイライラする事が多く、どうしてもコマンドラインから操作したくなった。<br />\\nしかしコマンドラインから redmine を操作できる物で気に入った物が無かったのでGo言語で自作するに至った。まずライブラリ\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/go-redmine\">mattn/go-redmine - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/go-redmine</cite>\\n</blockquote>\\n\\n残念ながら API は全て出揃ってなくて対応状況は以下の様な感じ。<br />\\n\\n<table border=\"1\">\\n\\t<tr>\\n\\t\\t<th>API</th>\\n\\t\\t<th align=\"right\">Implements</th>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Issues</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Projects</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Project Memberships</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Users</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Time Entries</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>News</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Issue Relations</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Versions</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Wiki Pages</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Queries</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Attachments</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Issue Statuses</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Trackers</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Enumerations</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Issue Categories</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Roles</td>\\n\\t\\t<td align=\"right\">100%</td>\\n\\t</tr>\\n\\t<tr>\\n\\t\\t<td>Groups</td>\\n\\t\\t<td align=\"right\">0%</td>\\n\\t</tr>\\n</table>\\n\\nとりあえず issues 関連は出来てるので、これを使うコマンドラインプログラムを書いた。\\n\\n<blockquote class=\"code\">\\n$ go get github.com/mattn/go-redmine/godmine\\n</blockquote>\\n\\n名前は中二病っぽいけど「godmine」という名前にした。<br />\\n使い方は、例えば issue の一覧であれば\\n\\n<blockquote class=\"code\">\\n$ godmine issue list\\n</blockquote>\\n\\nもしくは\\n\\n<blockquote class=\"code\">\\n$ godmine i l\\n</blockquote>\\n\\nissue の登録は\\n\\n<blockquote class=\"code\">\\n$ godmine issue create \"なんてこった\" \"大変だ!\"\\n</blockquote>\\n\\nみたいにするか\\n\\n<blockquote class=\"code\">\\n$ godmine issue append\\n</blockquote>\\n\\nで起動するテキストエディタ(環境変数EDITORを参照しunix改行コードが扱えるテキストエディタのみ使用可能)で\\n\\n<blockquote class=\"code\">\\n### Subject Here ###<br />\\n### Description Here ###<br />\\n</blockquote>\\n\\n上記の部分を書き換えて保存終了する。<br />\\n設定ファイルは ~/.config/godmine/settings.json に(Windows では %APPDATA%/godmine/settings.json)\\n\\n<blockquote class=\"code\">\\n{<br />\\n <span class=\"Constant\">\"endpoint\"</span>: <span class=\"Constant\">\"<a href=\"http://redmine.example.com\">http://redmine.example.com</a>\"</span>,<br />\\n <span class=\"Constant\">\"apikey\"</span>: <span class=\"Constant\">\"アクセスキー\"</span>,<br />\\n <span class=\"Constant\">\"project\"</span>: <span class=\"Constant\">1</span><br />\\n}<br />\\n</blockquote>\\n\\nの様に書く。<code>Project Id</code> は URL から調べて下さい。なお、環境変数 GODMINE_ENV を「foo」に設定すると「settings.foo.json」が読まれるので、複数のプロジェクトを扱う場合は\\n\\n<blockquote class=\"code\">\\n$ GODMINE_ENV=foo godmine issue append\\n</blockquote>\\n\\nとうい感じに使える。以下現状サポートしてるコマンド<br />\\n\\n<blockquote class=\"code\">\\ngotmine <command> <subcommand> [arguments]<br />\\n<br />\\nProject Commands:<br />\\n add a create project with text editor.<br />\\n $ godmine p a<br />\\n<br />\\n create c create project from given arguments.<br />\\n $ godmine p c name identifier description<br />\\n<br />\\n update u update given project.<br />\\n $ godmine p u 1<br />\\n<br />\\n show s show given project.<br />\\n $ godmine p s 1<br />\\n<br />\\n delete d delete given project.<br />\\n $ godmine p d 1<br />\\n<br />\\n list l listing projects.<br />\\n $ godmine p l<br />\\n<br />\\nIssue Commands:<br />\\n add a create issue with text editor.<br />\\n $ godmine i a<br />\\n<br />\\n create c create issue from given arguments.<br />\\n $ godmine i c subject description<br />\\n<br />\\n update u update given issue.<br />\\n $ godmine i u 1<br />\\n<br />\\n show s show given issue.<br />\\n $ godmine i s 1<br />\\n<br />\\n delete d delete given issue.<br />\\n $ godmine i d 1<br />\\n<br />\\n close x close given issue.<br />\\n $ godmine i x 1<br />\\n<br />\\n notes n add notes to given issue.<br />\\n $ godmine i n 1<br />\\n<br />\\n list l listing issues.<br />\\n $ godmine i l<br />\\n<br />\\nMembership Commands:<br />\\n show s show given membership.<br />\\n $ godmine m s 1<br />\\n<br />\\n list l listing memberships of given project.<br />\\n $ godmine m l 1<br />\\n<br />\\nUser Commands:<br />\\n show s show given user.<br />\\n $ godmine u s 1<br />\\n<br />\\n list l listing users.<br />\\n $ godmine u l<br />\\n</blockquote>\\n\\n管理者権限があればプロジェクトを消す事も出来ます。なんて怖い!<br />\\nissue の close(x) は、ステータス一覧の先頭から見て close にチェックされている最初のステータスで issue を閉じます。<br />\\n元はと言えば Windows で ruby の動作が遅すぎるのが嫌で作り始めましたが、linux でも動きます。<br />\\n<br />\\nまだ作り始めたばかりなので、欲しい機能があれば入れていくつもりです。<br />\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4863541171/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51ZzoXpsmqL._SL160_.jpg\" alt=\"基礎からわかる Go言語\" class=\"awsxom-image\" />\\n<strong>基礎からわかる Go言語</strong></a><br />\\n古川 昇<br />\\nシーアンドアール研究所 / ¥ 2,310 (2012-11-21)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4274068560/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51b4P511wTL._SL160_.jpg\" alt=\"アジャイルサムライ−達人開発者への道−\" class=\"awsxom-image\" />\\n<strong>アジャイルサムライ−達人開発者への道−</strong></a><br />\\nJonathan Rasmusson<br />\\nオーム社 / ¥ 2,730 (2011-07-16)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "redmine, golang", | |
"published": "2012-11-19T21:34:00+09:00" | |
}, | |
{ | |
"title": "vimでカーソルキーを使うと稀に発生するアレ", | |
"link": "http://mattn.kaoriya.net/software/vim/20121119204213.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121119204213", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://twitter.com/kanonji/statuses/270488019499356160\">Twitter / kanonji</a>\\n\\t<br />\\n\\t<img src=\"https://si0.twimg.com/profile_images/40688552/005_normal.jpg\" class=\"thumbnail-left\" />\\n\\t<p>vimでカーソルキーを使うと稀に発生する「E349: No identifier under cursor」がうざい。ググっても、このエラーメッセージの翻訳定義ばかり出てくるなぁ。TERM=ansiにすると出ないというブログエントリーは有ったけどxterm-colorがいいなぁ</p>\\n\\t<cite>https://twitter.com/kanonji/statuses/270488019499356160</cite>\\n</blockquote>\\n\\nアレっと言っても、僕はカーソルキー使わないから発生しないんだけど、調べてみた。<br />\\nまず E349 を調べる。<br />\\n\\n<blockquote class=\"code\">\\n# grep E349 *.c<br />\\nnormal.c:static char *e_noident = N_("E349: No identifier under cursor");<br />\\n</blockquote>\\n\\nE349 は e_noident という変数を使って発生させている。e_noident は同じく normal.c の中で2箇所から参照される。どちらもカーソル下のキーワードを探す際にキーワードとなり得る物が見つからなかった場合に発生する。<br />\\n試しに「-」という文字だけタイプしてその上で K (辞書を引くキー)をタイプすると、E349 が発生する。<br />\\nさて、ここでなぜ「vimでカーソルキーを使うと E349 が稀に発生する」のか。<br >\\nterminfo によると xterm ではカーソルキーの左 kl は <code>\\E[D</code> に割り当てられており、<code>:echo getchar()</code> によると vim ではシフトキーを押しながらカーソルキーの左を押すとこの <code>\\E[D</code> が投げられる。<br />\\n<br />\\n<a href=\"http://www.nethamilton.net/docs/termcap.html\">http://www.nethamilton.net/docs/termcap.html</a><br />\\n<a href=\"http://linux.die.net/man/5/termcap\">http://linux.die.net/man/5/termcap</a><br />\\n\\nこのキーシーケンスは xterm-color には登録されていないので\\n\\n<ul>\\n\\t<ol>ESC</ol>\\n\\t<ol>[</ol>\\n\\t<ol>D</ol>\\n</ul>\\n\\nの順に流れる。<code>:help [D </code> を見ると\\n\\n<blockquote class=\"code\">\\n[D Display all macro definitions that contain the macro<br />\\n under the cursor. Filenames and line numbers are<br />\\n displayed for the found lines. The search starts<br />\\n from the beginning of the file. {not in Vi}<br />\\n</blockquote>\\n\\nマクロを検索している。つまりカーソル直下のキーワードを探索しているのだ。<br />\\nゆえに、E349 が出るという事になる。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-11-19T21:01:00+09:00" | |
}, | |
{ | |
"title": "マルチプラットフォームな C++ 向けフォルダ変更監視ライブラリ「SimpleFileWatcher」", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20121114215710.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/c/20121114215710", | |
"summary": "\\nC++ で簡単にフォルダ監視出来るライブラリ無いかなーと思ってたら、手頃なのが見つかった。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://code.google.com/p/simplefilewatcher/\">simplefilewatcher - Simple, cross platform, object-oriented, file watcher and notifier library. - Google Project Hosting </a>\\n\\t<br />\\n\\t<p>SimpleFileWatcher is a C++ wrapper for OS file monitoring systems. Currently it uses Win32 ReadDirec...</p>\\n\\t<cite>https://code.google.com/p/simplefilewatcher/</cite>\\n</blockquote>\\n\\nしかもマルチプラットフォームでビルド出来て、さらに他のライブラリに依存しないのでとてもポータブル。<br />\\nWindows でも inotify を意識せずにコーディング出来ます。<br />\\n今日はこれと C++ で GNTP Growl する gntppp を使って、あるフォルダ配下のファイルが変更されたら Growl するアプリケーションを作ってみました。<br />\\nコンパイルには、Crypto++ と、boost が必要です。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/gntppp\">mattn/gntppp - GitHub</a>\\n\\t<br />\\n\\t<p>GNTP++: gntp client library writen in C++</p>\\n\\t<cite>https://github.com/mattn/gntppp</cite>\\n</blockquote>\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://www.cryptopp.com/\">Crypto++ Library 5.6.1 - a Free C++ Class Library of Cryptographic Schemes</a>\\n\\t<br />\\n\\t<p>Crypto++ Library is a free C++ class library of cryptographic schemes. Currently the library contains the following algorithms</p>\\n\\t<cite>http://www.cryptopp.com/</cite>\\n</blockquote>\\n\\nコードはとてもシンプル!<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><FileWatcher/FileWatcher.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><gntp.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><iostream></span><br />\\n<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> CryptoPP;<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> CryptoPP::Weak1;<br />\\n<br />\\ngntp* client;<br />\\n<br />\\n<span class=\"Type\">class</span> UpdateListener : <span class=\"Statement\">public</span> FW::FileWatchListener {<br />\\n<span class=\"Statement\">public</span>:<br />\\n UpdateListener() {}<br />\\n <span class=\"Type\">void</span> handleFileAction(<br />\\n FW::WatchID watchid,<br />\\n <span class=\"Type\">const</span> FW::String& dir,<br />\\n <span class=\"Type\">const</span> FW::String& filename,<br />\\n FW::Action action) {<br />\\n client->notify<DES, MD5>(<span class=\"Constant\">"changed"</span>, <span class=\"Constant\">"File Changed"</span>, filename.c_str());<br />\\n }<br />\\n};<br />\\n<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain(<span class=\"Type\">int</span> argc, <span class=\"Type\">char</span> **argv) {<br />\\n <span class=\"Statement\">if</span> (argc != <span class=\"Constant\">2</span>) {<br />\\n std::cerr << <span class=\"Constant\">"usage: "</span> << argv[<span class=\"Constant\">0</span>] << <span class=\"Constant\">" [directory]"</span> << std::endl;<br />\\n <span class=\"Statement\">return</span> -<span class=\"Constant\">1</span>;<br />\\n }<br />\\n<br />\\n FW::FileWatcher fileWatcher;<br />\\n client = <span class=\"Statement\">new</span> gntp(<span class=\"Constant\">"file change notifier"</span>, <span class=\"Constant\">""</span>);<br />\\n client->regist<DES, MD5>(<span class=\"Constant\">"changed"</span>);<br />\\n<br />\\n <span class=\"Statement\">try</span> {<br />\\n FW::WatchID watchID = fileWatcher.addWatch(<br />\\n argv[<span class=\"Constant\">1</span>], <span class=\"Statement\">new</span> UpdateListener(), <span class=\"Constant\">true</span>);<br />\\n<br />\\n <span class=\"Statement\">while</span>(<span class=\"Constant\">1</span>) {<br />\\n fileWatcher.update();<br />\\n }<br />\\n } <span class=\"Statement\">catch</span>(std::exception& e) {<br />\\n std::cerr << <span class=\"Constant\">"Exception has occurred: "</span> << e.what() << std::endl;<br />\\n }<br />\\n <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n}<br />\\n</blockquote>\\n\\n簡単ですね!<br />\\nmingw32 だと以下の様にコンパイルします。<br />\\n\\n<blockquote class=\"code\">\\ng++ -g -fpermissive -Iinclude -I.<br />\\n source/FileWatcher.cpp source/FileWatcherWin32.cpp<br />\\n filechangenotifier.cpp<br />\\n -lcryptopp -lws2_32<br />\\n -lboost_thread-mgw47-mt-1_50 -lboost_system-mgw47-mt-1_50<br />\\n</blockquote>\\n\\n<em>※実際は1行</em><br />\\n実行してファイルを置いてみる...\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/6d25286e4b585000.png\" alt=\"file change notifier\" />\\n</blockquote>\\n\\nおぉ...<br />\\n<br />\\nちょっとしたツールを作るには便利ですね。MITなので業務でも使えそうです。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "growl, simplefilewatcher, c++", | |
"published": "2012-11-14T21:58:00+09:00" | |
}, | |
{ | |
"title": "Go言語で isucon2 書いた。", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20121107165429.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20121107165429", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://blog.livedoor.jp/techblog/archives/67728751.html\">livedoor Techブログ : 自家製 #isucon2 のつくりかた</a>\\n\\t<br />\\n\\t<p>先日ISUCON2は幸いにも大好評のうちに終了しましたが、このお題および関係する話題をぜひ多くの人にも知っていただきたい! というかこのまま捨てるとかちょっともったいない! ということもあり、作業対象のアプリケーションコード、およびベンチマークツール一式を公開しています。</p>\\n\\t<cite>http://blog.livedoor.jp/techblog/archives/67728751.html</cite>\\n</blockquote>\\n\\nGo言語が途端に書きたくなったので、Go言語で isucon2 書いてみた。<br />\\nWAF として web.go を使ってますが、<code>go get</code> を実行すれば勝手にインストールされます。<br />\\n\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/go-isucon2\">mattn/go-isucon2 - GitHub</a>\\n\\t<br />\\n\\t<p>isucon2 written in go</p>\\n\\t<cite>https://github.com/mattn/go-isucon2</cite>\\n</blockquote>\\n\\n作ったばっかりなので、ベンチマーク取ったりはしてません。これからします。<br />\\n興味のある方どうぞ。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "isucon2, go", | |
"published": "2012-11-07T16:55:00+09:00" | |
}, | |
{ | |
"title": "vim で twitter stream", | |
"link": "http://mattn.kaoriya.net/software/vim/20121106200646.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121106200646", | |
"summary": "\\nbasyura さんが vimproc 使ったやつを書いてたのを、アプリっぽく仕上げただけ\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://d.hatena.ne.jp/basyura/20121104/p1\">vim で stream api - basyura!Cs blog</a>\\n\\t<br />\\n\\t<cite>http://d.hatena.ne.jp/basyura/20121104/p1</cite>\\n</blockquote>\\n\\ngithubに置いてます。vimprocが必要。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/streamer-vim\">mattn/streamer-vim - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/streamer-vim</cite>\\n</blockquote>\\n\\n<blockquote class=\"code\">\\n:Streamer\\n</blockquote>\\n\\nと起動すると、vimproc を使ってバックグラウンドでtwitter streamを取得し、タイトルバーに表示します。<br />\\nポーリングなのでもしかすると若干の負荷があるかも...という感じはしますが、updatetimeを使うハックよりは僕にとっては精神衛生的に好きです。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, twitter", | |
"published": "2012-11-06T20:08:00+09:00" | |
}, | |
{ | |
"title": "Sublime Text2 の複数カーソル?それVimでも出来るよ", | |
"link": "http://mattn.kaoriya.net/software/vim/20121105111112.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121105111112", | |
"summary": "\\nSublime Text2 の複数カーソル、なんかキャッチーだけど、それ Sakura でずいぶん前から出来てたし...。<br />\\nVim 使いは正規表現で一括置換するのでそもそも必要ない。<br />\\n<br />\\nとかいうと「それ実装できない言い訳じゃん」とか言われそうなのでかるーく作ってみた。(実装中途半端)<br />\\n<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/multi-vim\">mattn/multi-vim - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/multi-vim</cite>\\n</blockquote>\\n\\nなんですか!そのやる気のないプロジェクト名は!!!<br />\\n<br />\\nどんな風に動くかはこちらのページをご覧下さい。(デカいアニメーションgif注意)<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.github.com/multi-vim/\">http://mattn.github.com/multi-vim/</a>\\n\\t<br />\\n\\t<cite>http://mattn.github.com/multi-vim/</cite>\\n</blockquote>\\n\\n作り続けられる自信があまりありません。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-11-05T11:12:00+09:00" | |
}, | |
{ | |
"title": "C言語から使えるJSONパーサ、parson が思った以上に良い仕事をしている。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20121102175736.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/c/20121102175736", | |
"summary": "\\n前回は <a href=\"http://mattn.kaoriya.net/software/lang/c/20120822011026.htm\">JSMN</a> というのを試したけど、今度も matsuu さんのブクマから。。。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://kgabis.github.com/parson/\">parson</a>\\n\\t<br />\\n\\t<p>Lightweight json parser and reader written in C.</p>\\n\\t<cite>http://kgabis.github.com/parson/</cite>\\n</blockquote>\\n\\n特徴は\\n\\n<ul>\\n\\t<li>軽い (2ファイルだけ)</li>\\n\\t<li>単純なAPI</li>\\n\\t<li>ドット記法による json 値のアドレッシング (C言語の構造体やOO言語のオブジェクトに似た感じ。例: <code>\"objectA.objectB.value\"</code>)</li>\\n\\t<li>C89 コンパティブル</li>\\n\\t<li>テストスーツ</li>\\n</ul>\\n\\n前回の JSMN とは違い、メモリを動的に確保するタイプ。DOM の様にルートノードから探索を始め、最終的にルートノードを指定してメモリを開放する。<br />\\n今回もtwitterのタイムラインをパースしよう。\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><assert.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><string.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><memory.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><curl/curl.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\">"parson.h"</span><br />\\n<br />\\n<span class=\"Type\">typedef</span> <span class=\"Type\">struct</span> {<br />\\n <span class=\"Type\">char</span>* data; <span class=\"Comment\">// response data from server</span><br />\\n <span class=\"Type\">size_t</span> size; <span class=\"Comment\">// response size of data</span><br />\\n} MEMFILE;<br />\\n<br />\\nMEMFILE*<br />\\nmemfopen() {<br />\\n MEMFILE* mf = (MEMFILE*) malloc(<span class=\"Statement\">sizeof</span>(MEMFILE));<br />\\n <span class=\"Statement\">if</span> (mf) {<br />\\n mf->data = <span class=\"Constant\">NULL</span>;<br />\\n mf->size = <span class=\"Constant\">0</span>;<br />\\n }<br />\\n <span class=\"Statement\">return</span> mf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">void</span><br />\\nmemfclose(MEMFILE* mf) {<br />\\n <span class=\"Statement\">if</span> (mf->data) free(mf->data);<br />\\n free(mf);<br />\\n}<br />\\n<br />\\n<span class=\"Type\">size_t</span><br />\\nmemfwrite(<span class=\"Type\">char</span>* ptr, <span class=\"Type\">size_t</span> size, <span class=\"Type\">size_t</span> nmemb, <span class=\"Type\">void</span>* stream) {<br />\\n MEMFILE* mf = (MEMFILE*) stream;<br />\\n <span class=\"Type\">int</span> block = size * nmemb;<br />\\n <span class=\"Statement\">if</span> (!mf) <span class=\"Statement\">return</span> block; <span class=\"Comment\">// through</span><br />\\n <span class=\"Statement\">if</span> (!mf->data)<br />\\n mf->data = (<span class=\"Type\">char</span>*) malloc(block);<br />\\n <span class=\"Statement\">else</span><br />\\n mf->data = (<span class=\"Type\">char</span>*) realloc(mf->data, mf->size + block);<br />\\n <span class=\"Statement\">if</span> (mf->data) {<br />\\n memcpy(mf->data + mf->size, ptr, block);<br />\\n mf->size += block;<br />\\n }<br />\\n <span class=\"Statement\">return</span> block;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">char</span>*<br />\\nmemfstrdup(MEMFILE* mf) {<br />\\n <span class=\"Type\">char</span>* buf;<br />\\n <span class=\"Statement\">if</span> (mf->size == <span class=\"Constant\">0</span>) <span class=\"Statement\">return</span> <span class=\"Constant\">NULL</span>;<br />\\n buf = (<span class=\"Type\">char</span>*) malloc(mf->size + <span class=\"Constant\">1</span>);<br />\\n memcpy(buf, mf->data, mf->size);<br />\\n buf[mf->size] = <span class=\"Constant\">0</span>;<br />\\n <span class=\"Statement\">return</span> buf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain() {<br />\\n CURL* curl;<br />\\n MEMFILE* mf = <span class=\"Constant\">NULL</span>;<br />\\n <span class=\"Type\">char</span>* js = <span class=\"Constant\">NULL</span>;<br />\\n <span class=\"Type\">int</span> i;<br />\\n<br />\\n mf = memfopen();<br />\\n<br />\\n curl = curl_easy_init();<br />\\n curl_easy_setopt(curl, CURLOPT_URL, <span class=\"Constant\">"<a href=\"http://api.twitter.com/1/statuses/user_timeline.json?screen_name=otsune\">http://api.twitter.com/1/statuses/user_timeline.json?screen_name=otsune</a>"</span>);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);<br />\\n curl_easy_perform(curl);<br />\\n curl_easy_cleanup(curl);<br />\\n<br />\\n js = memfstrdup(mf);<br />\\n memfclose(mf);<br />\\n<br />\\n JSON_Value *root_value = json_parse_string(js);<br />\\n JSON_Array *tweets = json_value_get_array(root_value);<br />\\n <span class=\"Statement\">for</span> (i = <span class=\"Constant\">0</span>; i < json_array_get_count(tweets); i++) {<br />\\n JSON_Object *tweet = json_array_get_object(tweets, i);<br />\\n printf(<span class=\"Constant\">"</span><span class=\"Special\">%s</span><span class=\"Constant\">: </span><span class=\"Special\">%s</span><span class=\"Special\">\\n</span><span class=\"Constant\">"</span>,<br />\\n json_object_dotget_string(tweet, <span class=\"Constant\">"user.screen_name"</span>),<br />\\n json_object_dotget_string(tweet, <span class=\"Constant\">"text"</span>));<br />\\n }<br />\\n<br />\\n json_value_free(root_value);<br />\\n free(js);<br />\\n}<br />\\n</blockquote>\\n\\nなにこれ!めちゃ簡単。しかもソースを見たところユニコードに対応してる。そしてドット演算子、良いすね。JSON XPath の様ですね。ただ残念ながら JSON XPath の様に <code>..</code> でスキップする機能は無かったですが。<br />\\n<br />\\nしかしながらこれC言語の JSON パーサの中では、私が知る限り一番扱いやすいと思いますね。(C++は別です)<br />\\nMIT ライセンスなのでプロジェクトでも使って行きたいと思います。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "c, parson, json", | |
"published": "2012-11-02T18:01:00+09:00" | |
}, | |
{ | |
"title": "plackup の --path 引数", | |
"link": "http://mattn.kaoriya.net/software/lang/perl/20121030123904.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/perl/20121030123904", | |
"summary": "\\nplack を使ってて「サーバのサブフォルダを間借りして動かしたい」って事がたまにあるんだけど、そんな場合 nginx の設定でリバースプロキシに渡すって事をやります。\\n\\n<blockquote class=\"code\">\\nlocation /foo {<br />\\n try_files $uri $uri.html $uri/index.html @proxy-foo;<br />\\n}<br />\\n<br />\\nlocation @proxy-foo {<br />\\n proxy_pass <a href=\"http://localhost:5000\">http://localhost:5000</a>;<br />\\n proxy_set_header Host $http_host;<br />\\n}<br />\\n</blockquote>\\n\\nこの場合、通常の Plack アプリケーションだと <code>/</code> がアプリケーションルートになっているので404になってしまう。よって <code>app.psgi</code> とは別に\\n\\n<blockquote class=\"code\">\\n!perl<br />\\n<br />\\n<span class=\"Statement\">use strict</span>;<br />\\n<span class=\"Statement\">use warnings</span>;<br />\\n<span class=\"Statement\">use </span>Plack::Builder;<br />\\n<span class=\"Statement\">use </span>Plack::Util;<br />\\n<br />\\nbuilder {<br />\\n mount <span class=\"Constant\">'</span><span class=\"Constant\">/foo/</span><span class=\"Constant\">'</span> => Plack::Util::load_psgi(<span class=\"Constant\">'</span><span class=\"Constant\">app.psgi</span><span class=\"Constant\">'</span>);<br />\\n}<br />\\n</blockquote>\\n\\nの様な wrapper スクリプトを書く必要がありました。<br />\\nしかし先日、plackup に --path 引数が追加され\\n\\n<blockquote class=\"code\">\\n$ plackup --path /foo\\n</blockquote>\\n\\nと書くことで、自動的にマウントしてくれる機能が付きました。<br />\\nこれでいちいち wrapper スクリプトを書かずに済むようになりました。<br />\\n<br />\\n僕的に便利<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "perl, plack", | |
"published": "2012-10-30T12:40:00+09:00" | |
}, | |
{ | |
"title": "Vim から redmine を読み書き出来る vim-metarw プラグイン書いた。", | |
"link": "http://mattn.kaoriya.net/software/vim/20121029223557.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121029223557", | |
"summary": "\\n最近 yuroyoro さんが作った <a href=\"http://yuroyoro.hatenablog.com/entry/20120301/1330580453\" class=\"external\" target=\"_blank\">git issue</a> が便利でたまらない。コンソールから redmine や github の issue が操作できるし、全て CUI で完結出来る。<br />\\nしかしながら、どうしても「Vim で、しかも REST 的に redmine を扱いたい!」という欲望がおさえられず、作ってしまった。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/vim-metarw-redmine/\">mattn/vim-metarw-redmine - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/vim-metarw-redmine/</cite>\\n</blockquote>\\n\\nkana さんの vim-metarw 経由で redmine を読み書きできます。動作には vim-metarw が必要です。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/kana/vim-metarw\">kana/vim-metarw - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/kana/vim-metarw</cite>\\n</blockquote>\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:metarw_redmine_server</span> <span class=\"Statement\">=</span> <span class=\"Constant\">'<a href=\"https://your-redmine.example.com\">https://your-redmine.example.com</a>'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:metarw_redmine_apikey</span> <span class=\"Statement\">=</span> <span class=\"Constant\">'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'</span><br />\\n</blockquote>\\n\\nvimrc 等にこの様に設定しておけば使えます。<br />\\nredmine 側は「管理」→「設定」→「認証」→「RESTによるWebサービスを有効にする」をチェックし、「個人設定」からAPIキーを表示すれば見れます。<br />\\n<br />\\n<blockquote class=\"code\">\\n:e redmine:\\n</blockquote>\\n\\nとするとプロジェクト一覧\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/876079e899809ed5.png\" alt=\"project list\" />\\n</blockquote>\\n\\nプロジェクト一覧でエンターすると、チケットの一覧\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/9f5aa66e84b733fc.png\" alt=\"issue list\" />\\n</blockquote>\\n\\nさらにエンターすると\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/c6b8b0a9a09273ea.png\" alt=\"issue edit\" />\\n</blockquote>\\n\\nチケットが直接編集出来ます。status を閉じたりする場合、Close に相当する status の ID を覚えておく必要がありますが、「管理」→「チケットのステータス」から ID が分かるのでそこから知って下さい。<br />\\nこんなの喜ぶのは僕しかいないかも知れませんが、奇特な人へ。<br />\\n<br />\\nどうしてもこれを Windows から使いたいという、さらに奇特な人は vim-metarw を Windows でも動作する様にした私の fork をお使い下さい。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/vim-metarw\">mattn/vim-metarw - GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/vim-metarw</cite>\\n</blockquote>\\n<br />\\n<b>追記</b><br />\\n投稿の方法を書くのを忘れてました。<br />\\n<br />\\nタイトル1行、本文数行を書いて <code>:w redmine:/[プロジェクトID]</code> に書き込んで下さい。<br />\\n\\n\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4798121622/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51XuuxjNAaL._SL160_.jpg\" alt=\"Redmineによるタスクマネジメント実践技法\" class=\"awsxom-image\" />\\n<strong>Redmineによるタスクマネジメント実践技法</strong></a><br />\\n小川 明彦<br />\\n翔泳社 / ¥ 3,444 (2010-10-13)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "redmine, vim, metarw", | |
"published": "2012-10-29T22:39:00+09:00" | |
}, | |
{ | |
"title": "Github Notification API が出たので通知を Growl するの書いた。", | |
"link": "http://mattn.kaoriya.net/software/lang/perl/20121029154431.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/perl/20121029154431", | |
"summary": "\\nGithub Notification API が出ました。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/blog/1306-notifications-api\">Notifications API - GitHub</a>\\n\\t<br />\\n\\t<p>Recent posts in this category Notifications API technoweenie on October 26, 2012 Latest commit per d...</p>\\n\\t<cite>https://github.com/blog/1306-notifications-api</cite>\\n</blockquote>\\n\\n\\ngithub の通知を取得する場合、これまでは miyagawa さんが github growler でやっていた様に、ダッシュボードのRSSを使って自分のイベントを抽出しなければなりませんでしたが、Notification API を使う事で Github 上と同じ通知メッセージが取れる様になりました。<br />\\n今日は Perl で Github のメッセージを通知するアプリケーションを作ってみました。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#!perl</span><br />\\n<br />\\n<span class=\"Statement\">use strict</span>;<br />\\n<span class=\"Statement\">use warnings</span>;<br />\\n<span class=\"Statement\">use </span>LWP::UserAgent;<br />\\n<span class=\"Statement\">use </span>HTTP::Request;<br />\\n<span class=\"Statement\">use </span>Encode;<br />\\n<span class=\"Statement\">use </span>JSON;<br />\\n<span class=\"Statement\">use </span>Term::ReadKey;<br />\\n<span class=\"Statement\">use </span>Data::Deduper;<br />\\n<span class=\"Statement\">use </span>Growl::Any;<br />\\n<br />\\n<span class=\"Statement\">my</span> (<span class=\"Identifier\">$username</span>, <span class=\"Identifier\">$password</span>);<br />\\n<br />\\n<span class=\"Statement\">print</span> <span class=\"Constant\">"</span><span class=\"Constant\">Username: </span><span class=\"Constant\">"</span>;<br />\\n<span class=\"Statement\">chomp</span>(<span class=\"Identifier\">$username</span> = <span class=\"Identifier\"><STDIN></span>);<br />\\n<span class=\"Statement\">print</span> <span class=\"Constant\">"</span><span class=\"Constant\">Password: </span><span class=\"Constant\">"</span>;<br />\\nReadMode(<span class=\"Constant\">2</span>);<br />\\n<span class=\"Statement\">chomp</span>(<span class=\"Identifier\">$password</span> = ReadLine(<span class=\"Constant\">0</span>));<br />\\nReadMode(<span class=\"Constant\">0</span>);<br />\\n<span class=\"Statement\">print</span> <span class=\"Constant\">"</span><span class=\"Special\">\\n</span><span class=\"Constant\">"</span>;<br />\\n<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$ua</span> = LWP::UserAgent->new;<br />\\n<span class=\"Identifier\">$ua</span><span class=\"Identifier\">->ssl_opts</span>(<span class=\"Constant\">verify_hostname</span> => <span class=\"Constant\">0</span>);<br />\\n<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$req</span> = HTTP::Request->new(<span class=\"Constant\">'</span><span class=\"Constant\">POST</span><span class=\"Constant\">'</span>, <span class=\"Constant\">'</span><span class=\"Constant\"><a href=\"https://api.github.com/authorizations\">https://api.github.com/authorizations</a></span><span class=\"Constant\">'</span>);<br />\\n<span class=\"Identifier\">$req</span><span class=\"Identifier\">->content</span>(to_json {<br />\\n <span class=\"Constant\">scopes</span> => [<span class=\"Constant\">'</span><span class=\"Constant\">notifications</span><span class=\"Constant\">'</span>],<br />\\n <span class=\"Constant\">note</span> => <span class=\"Constant\">'</span><span class=\"Constant\">github-notification.pl</span><span class=\"Constant\">'</span>,<br />\\n <span class=\"Constant\">note_url</span> => <span class=\"Constant\">'</span><span class=\"Constant\"><a href=\"https://github.com/mattn/github-notification\">https://github.com/mattn/github-notification</a></span><span class=\"Constant\">'</span>,<br />\\n});<br />\\n<span class=\"Identifier\">$req</span><span class=\"Identifier\">->authorization_basic</span>(<span class=\"Identifier\">$username</span>, <span class=\"Identifier\">$password</span>);<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$res</span> = from_json <span class=\"Identifier\">$ua</span><span class=\"Identifier\">->request</span>(<span class=\"Identifier\">$req</span>)->decoded_content;<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$token</span> = <span class=\"Identifier\">$res</span><span class=\"Identifier\">->{</span><span class=\"Constant\">token</span><span class=\"Identifier\">}</span>;<br />\\n<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$dd</span> = Data::Deduper->new(<br />\\n <span class=\"Constant\">expr</span> => <span class=\"Statement\">sub </span>{<br />\\n <span class=\"Statement\">my</span> (<span class=\"Identifier\">$a</span>, <span class=\"Identifier\">$b</span>) = <span class=\"Identifier\">@_</span>;<br />\\n <span class=\"Identifier\">$a</span><span class=\"Identifier\">->{</span><span class=\"Constant\">id</span><span class=\"Identifier\">}</span> <span class=\"Statement\">eq</span> <span class=\"Identifier\">$b</span><span class=\"Identifier\">->{</span><span class=\"Constant\">id</span><span class=\"Identifier\">}</span><br />\\n },<br />\\n);<br />\\n<br />\\n<span class=\"Statement\">my</span> <span class=\"Identifier\">$growl</span> = Growl::Any->new(<br />\\n <span class=\"Constant\">appname</span> => <span class=\"Constant\">'</span><span class=\"Constant\">Github Notification</span><span class=\"Constant\">'</span>,<br />\\n <span class=\"Constant\">events</span> => [<span class=\"Constant\">'</span><span class=\"Constant\">notification</span><span class=\"Constant\">'</span>, <span class=\"Constant\">'</span><span class=\"Constant\">error</span><span class=\"Constant\">'</span>],<br />\\n);<br />\\n<br />\\n<span class=\"Statement\">while</span> (<span class=\"Constant\">1</span>) {<br />\\n <span class=\"Identifier\">$res</span> = <span class=\"Identifier\">$ua</span><span class=\"Identifier\">->get</span>(<span class=\"Constant\">"</span><span class=\"Constant\"><a href=\"https://api.github.com/notifications?access_token=\">https://api.github.com/notifications?access_token=</a></span><span class=\"Identifier\">$token</span><span class=\"Constant\">"</span>);<br />\\n <span class=\"Statement\">my</span> <span class=\"Identifier\">$items</span> = from_json decode_utf8 <span class=\"Identifier\">$res</span><span class=\"Identifier\">->decoded_content</span>;<br />\\n <span class=\"Statement\">for</span> (<span class=\"Identifier\">$dd</span><span class=\"Identifier\">->dedup</span>(<span class=\"Identifier\">$items</span>)) {<br />\\n <span class=\"Identifier\">$growl</span><span class=\"Identifier\">->notify</span>(<br />\\n <span class=\"Constant\">'</span><span class=\"Constant\">notification</span><span class=\"Constant\">'</span>,<br />\\n <span class=\"Identifier\">$_</span><span class=\"Identifier\">->{</span><span class=\"Constant\">subject</span><span class=\"Identifier\">}->{</span><span class=\"Constant\">title</span><span class=\"Identifier\">}</span>,<br />\\n <span class=\"Identifier\">$_</span><span class=\"Identifier\">->{</span><span class=\"Constant\">description</span><span class=\"Identifier\">}</span>,<br />\\n <span class=\"Identifier\">$_</span><span class=\"Identifier\">->{</span><span class=\"Constant\">repository</span><span class=\"Identifier\">}->{</span><span class=\"Constant\">owner</span><span class=\"Identifier\">}->{</span><span class=\"Constant\">avatar_url</span><span class=\"Identifier\">}</span>)<br />\\n }<br />\\n <span class=\"Statement\">sleep</span>(<span class=\"Identifier\">$res</span><span class=\"Identifier\">->header</span>(<span class=\"Constant\">'</span><span class=\"Constant\">X-Poll-Interval</span><span class=\"Constant\">'</span>) || <span class=\"Constant\">60</span>);<br />\\n}<br />\\n</blockquote>\\n\\n前半部分はトークンを取る処理で、パスワードは token を得る為だけに使っています。<br />\\n簡単ですね。これでどんなネタ振りも取りこぼす事無く反応出来ますね!<br />\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/5971971eab739c3c.png\" alt=\"github notification\" />\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "perl, growl, github, api", | |
"published": "2012-10-29T15:46:00+09:00" | |
}, | |
{ | |
"title": "プログラマブルなプロキシライブラリ goproxy", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20121023213646.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20121023213646", | |
"summary": "\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://d.hatena.ne.jp/sfujiwara/20121023/1350990163\">手軽に使える forward http proxy : stone, Tinyproxy - 酒日記 はてな支店</a>\\n\\t<br />\\n\\t<p>直接グローバルに繋がる経路をもたないホストから http アクセスしたいので http proxy を使いたい。Squidは定番ですが、もう少し手軽なのはなにかないかと思っていたところ twitter で教えていただきました。</p>\\n\\t<cite>http://d.hatena.ne.jp/sfujiwara/20121023/1350990163</cite>\\n</blockquote>\\n\\n本題からそれますが、go言語で小さいプロキシを使う場合に僕がお勧めしたいのが goproxy です。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/elazarl/goproxy\">elazarl/goproxy - GitHub</a>\\n\\t<br />\\n\\t<p>An HTTP proxy library for Go</p>\\n\\t<cite>https://github.com/elazarl/goproxy</cite>\\n</blockquote>\\n\\n\\ngoproxy 自身は実は実行モジュールを提供していません。ですので goproxy を使った実行モジュールは自分で作ります。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">package</span> main<br />\\n<br />\\n<span class=\"Statement\">import</span> (<br />\\n <span class=\"Constant\">"github.com/elazarl/goproxy"</span><br />\\n <span class=\"Constant\">"log"</span><br />\\n <span class=\"Constant\">"net/http"</span><br />\\n)<br />\\n<br />\\n<span class=\"Statement\">func</span> main() {<br />\\n proxy := goproxy.NewProxyHttpServer()<br />\\n proxy.Verbose = <span class=\"Statement\">true</span><br />\\n log.Fatal(http.ListenAndServe(<span class=\"Constant\">":8080"</span>, proxy))<br />\\n}<br />\\n</blockquote>\\n\\nこのソースを <code>proxy.go</code> という名前で保存して、<code>go build proxy.go</code> とすれば実行モジュールが出来上がります。<br />\\nポートを変えたいであったり、監視機能を付けたいという人は勝手にソースを弄ります。<br />\\ngoproxy はプログラマブルなプロキシです。なので例えば\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">package</span> main<br />\\n<br />\\n<span class=\"Statement\">import</span> (<br />\\n <span class=\"Constant\">"github.com/elazarl/goproxy"</span><br />\\n <span class=\"Constant\">"log"</span><br />\\n . <span class=\"Constant\">"net/http"</span><br />\\n <span class=\"Constant\">"regexp"</span><br />\\n <span class=\"Constant\">"time"</span><br />\\n)<br />\\n<br />\\n<span class=\"Statement\">func</span> main() {<br />\\n proxy := goproxy.NewProxyHttpServer()<br />\\n proxy.Verbose = <span class=\"Statement\">true</span><br />\\n re := regexp.MustCompile(<span class=\"Constant\">`^(www\\.)?2ch\\.net/?`</span>)<br />\\n proxy.OnRequest(goproxy.UrlMatches(re)).DoFunc(<br />\\n <span class=\"Type\">func</span>(r *Request, ctx *goproxy.ProxyCtx) (*Request, *Response) {<br />\\n h,_,_ := time.Now().Clock()<br />\\n <span class=\"Statement\">if</span> h >= <span class=\"Constant\">9</span> && h <= <span class=\"Constant\">18</span> {<br />\\n <span class=\"Statement\">return</span> r,goproxy.NewResponse(r,<br />\\n goproxy.ContentTypeText, StatusForbidden,<br />\\n <span class=\"Constant\">"就業時間中です。通報しました。"</span>)<br />\\n }<br />\\n <span class=\"Statement\">return</span> r, <span class=\"Statement\">nil</span><br />\\n })<br />\\n log.Fatal(ListenAndServe(<span class=\"Constant\">":8888"</span>, proxy))<br />\\n}<br />\\n</blockquote>\\n\\nこう書けば就業時間中の2ch閲覧禁止を行うプロキシが出来上がります。もちろん外部の設定を参照して制御を行うのも良いと思います。<br />\\nまた squid の様にキャッシュする事で高速に動作させる事も出来るかと思います。オリジナルのプロキシを作ってみたいという方は試してみる価値あるかと思います。<br />\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/486401096X/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51OBTgJsC3L._SL160_.jpg\" alt=\"プログラミング言語Goフレーズブック\" class=\"awsxom-image\" />\\n<strong>プログラミング言語Goフレーズブック</strong></a><br />\\nDavid Chisnall<br />\\nピアソン桐原 / ¥ 1,995 (2012-10-04)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "golang", | |
"published": "2012-10-23T21:37:00+09:00" | |
}, | |
{ | |
"title": "python 補完のVimプラグイン「jedi-vim」がスゲー", | |
"link": "http://mattn.kaoriya.net/software/vim/20121018212621.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121018212621", | |
"summary": "\\npythonの補完は、vimが標準で配布している物で事足りるかなーとか思ってたけど浅墓すぎた。<br />\\n今日見つけた jedi-vim は良い。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/davidhalter/jedi-vim\">davidhalter/jedi-vim - GitHub</a>\\n\\t<br />\\n\\t<p>Using the jedi autocompletion library for VIM.</p>\\n\\t<cite>https://github.com/davidhalter/jedi-vim</cite>\\n</blockquote>\\n\\n\\n何が良いって精度が良い。そして標準配布の pythoncomplete がモジュールとそのモジュール内関数しか補完出来ないのに比べ、jedi は評価値を補完出来る。<br />\\nそしてスゴイのが構文を仮実行しているのではなく、パースしている点。jedi というモジュールを使って、構文解析している。<br />\\n<br />\\n\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/davidhalter/jedi\">davidhalter/jedi - GitHub</a>\\n\\t<br />\\n\\t<p>Awesome autocompletion library for python. It works.</p>\\n\\t<cite>https://github.com/davidhalter/jedi</cite>\\n</blockquote>\\n\\nなので例えば\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">import</span> time<br />\\n<br />\\n<span class=\"Statement\">class</span> <span class=\"Identifier\">Foo</span>():<br />\\n <span class=\"Statement\">global</span> time<br />\\n asdf = time<br />\\n <br />\\n<span class=\"Statement\">def</span> <span class=\"Identifier\">asdfy</span>():<br />\\n <span class=\"Statement\">with</span> <span class=\"Identifier\">open</span>(<span class=\"Constant\">"foo.log"</span>, <span class=\"Constant\">"w"</span>) <span class=\"Statement\">as</span> f:<br />\\n f.write(<span class=\"Constant\">"fooooo"</span>)<br />\\n <span class=\"Statement\">return</span> Foo<br />\\n<br />\\nxorz = <span class=\"Identifier\">getattr</span>(asdfy()(), <span class=\"Constant\">'asdf'</span>)<br />\\nxorz.<br />\\n</blockquote>\\n\\nこんなコードを補完してもゴミファイルが出来たりしない。そして vim script で頑張る pythoncomplete に比べて速い!<br />\\n上のコードから\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/2e1cab0dab4d0ff6.png\" title=\"jedi1\" />\\n</blockquote>\\n\\nさらに関数のヒントまで表示される。\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/86d221c2ea8380d8.png\" title=\"jedi2\" />\\n</blockquote>\\n\\nただ1点だけハマりポイントがあって、この ftplugin はオフィシャルの pythoncomplete とバッティングし得る。先に jedi.vim が読まれる場合、後の pythoncomplete.vim を読ませない為に\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">autocmd</span> <span class=\"Type\">FileType</span> python <span class=\"Statement\">let</span> <span class=\"Identifier\">b:did_ftplugin</span> <span class=\"Statement\">=</span> <span class=\"Constant\">1</span><br />\\n</blockquote>\\n\\nこの様に <code>b:did_ftplugin</code> を設定してやる必要があった(これは後でpull-req送るかも)。また quickrun のキーアサイン <code><c-r></code> ともバッティングするので最終的には jedi の為に以下の設定をした。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:jedi#auto_initialization</span> <span class=\"Statement\">=</span> <span class=\"Constant\">1</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:jedi#rename_command</span> <span class=\"Statement\">=</span> <span class=\"Constant\">"<leader>R"</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:jedi#popup_on_dot</span> <span class=\"Statement\">=</span> <span class=\"Constant\">1</span><br />\\n<span class=\"Statement\">autocmd</span> <span class=\"Type\">FileType</span> python <span class=\"Statement\">let</span> <span class=\"Identifier\">b:did_ftplugin</span> <span class=\"Statement\">=</span> <span class=\"Constant\">1</span><br />\\n</blockquote>\\n\\nこのキーアサインは、関数名やクラス名をリネームする物で、名前変更後にインサートモードを抜けるとファイル内のシンボルが置き換えられる。調べてないが、構文解析しているので単なる置換ではなく正しいリネーム結果になるはず。試しに上記のコードで文字列内に xorz を埋め込み、xorz をリネームしてみたが文字列内の xorz が置き換わる事は無かった。すばらしい。<br />\\nその他、pydoc が見れる機能やジャンプ機能もある。しばらく使ってみようと思う。<br />\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4797371595/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51uQpDtF%2BdL._SL160_.jpg\" alt=\"みんなのPython 第3版\" class=\"awsxom-image\" />\\n<strong>みんなのPython 第3版</strong></a><br />\\n柴田 淳<br />\\nソフトバンククリエイティブ / ¥ 2,940 (2012-08-29)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, jedi", | |
"published": "2012-10-18T21:32:00+09:00" | |
}, | |
{ | |
"title": "zencoding-vim の Emmet サポートを始めます。", | |
"link": "http://mattn.kaoriya.net/software/vim/20121016183727.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121016183727", | |
"summary": "\\nしばらく zencoding-vim の emmet ブランチで開発し、落ち着いたら master にマージします。<br />\\n<br />\\n<h3 class=\"subtitle\">親参照</h3>\\n\\n<code>^</code> で親へ移動出来る様になってます。<br />\\n\\n<blockquote class=\"code\">\\n.header>.nav^.logo<br />\\n</blockquote>\\n\\nこれが\\n\\n<blockquote class=\"code\">\\n<span class=\"Identifier\"><</span><span class=\"Statement\">div</span><span class=\"Identifier\"> </span><span class=\"Type\">class</span><span class=\"Identifier\">=</span><span class=\"Constant\">"header"</span><span class=\"Identifier\">></span><br />\\n <span class=\"Identifier\"><</span><span class=\"Statement\">div</span><span class=\"Identifier\"> </span><span class=\"Type\">class</span><span class=\"Identifier\">=</span><span class=\"Constant\">"nav"</span><span class=\"Identifier\">></span><span class=\"Identifier\"></</span><span class=\"Statement\">div</span><span class=\"Identifier\">></span><br />\\n<span class=\"Identifier\"></</span><span class=\"Statement\">div</span><span class=\"Identifier\">></span><br />\\n<span class=\"Identifier\"><</span><span class=\"Statement\">div</span><span class=\"Identifier\"> </span><span class=\"Type\">class</span><span class=\"Identifier\">=</span><span class=\"Constant\">"logo"</span><span class=\"Identifier\">></span><span class=\"Identifier\"></</span><span class=\"Statement\">div</span><span class=\"Identifier\">></span><br />\\n</blockquote>\\n\\nこう展開されます。<code>^^</code> で複数階層登れます。<br />\\n\\n<br />\\n<h3 class=\"subtitle\">高度なCSS補完</h3>\\n\\nおそらくこれが emmet の最大の武器と思う。<br />\\nまず <code>m0.1</code> は\\n\\n<blockquote class=\"code\">\\nmargin: 0.1em;\\n</blockquote>\\n\\nに展開される。また <code>m2</code> は\\n\\n<blockquote class=\"code\">\\nmargin: 2px;\\n</blockquote>\\n\\nに、<code>m3p</code> は\\n\\n<blockquote class=\"code\">\\nmargin: 3%;\\n</blockquote>\\n\\nに展開される。本来ならば <code>z-index</code> の様に px 単位で無い物には単位を付けない様にしないといけないけど、この辺は後々やってく。<br />\\n\\n<br />\\n<h3 class=\"subtitle\">ベンダープレフィックス</h3>\\n\\n好き嫌いありそうな機能ですが...<br />\\n\\n通常 <code>bdrs8</code> が\\n\\n<blockquote class=\"code\">\\nborder-radius: 8px;\\n</blockquote>\\n\\nにされるが、頭に <code>-</code> を付けると\\n\\n<blockquote class=\"code\">\\n-bdrs8\\n</blockquote>\\n\\n<blockquote class=\"code\">\\n-webkit-border-radius: 8px;<br />\\n-moz-border-radius: 8px;<br />\\nborder-radius: 8px;<br />\\n</blockquote>\\n\\nと変換される。また、<code>lg(top,#fff,#000)</code> から\\n\\n<blockquote class=\"code\">\\nbackground-image: -webkit-gradient(top, 0 0, 0 100, from(#fff), to(#000));<br />\\nbackground-image: -webkit-linear-gradient(#fff, #000);<br />\\nbackground-image: -moz-linear-gradient(#fff, #000);<br />\\nbackground-image: -o-linear-gradient(#fff, #000);<br />\\nbackground-image: linear-gradient(#fff, #000);<br />\\n</blockquote>\\n\\nに変換される。<br />\\n<br />\\n<br />\\n興味ある人は emmet ブランチで人柱お願いします。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/zencoding-vim\">mattn/zencoding-vim ツキ GitHub</a>\\n\\t<br />\\n\\t<cite>https://github.com/mattn/zencoding-vim</cite>\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "emmet, vim, zencoding", | |
"published": "2012-10-16T19:18:00+09:00" | |
}, | |
{ | |
"title": "【勝手に添削】ftplugin マナー", | |
"link": "http://mattn.kaoriya.net/software/vim/20121015165001.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20121015165001", | |
"summary": "\\nちょっとだけ気になったので勝手に添削。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://d.hatena.ne.jp/gfx/20121014/1350233031\">Enhance jsx.vim to execute the current test method! - Islands in the byte stream</a>\\n\\t<br />\\n\\t<p>Enhance jsx.vim to execute the current test method! JSX compiler...</p>\\n\\t<cite>http://d.hatena.ne.jp/gfx/20121014/1350233031</cite>\\n</blockquote>\\n\\nvim script を紛らわしくしている物の一つに ftplugin と autoload がある。autoload は<a href=\"http://mattn.kaoriya.net/software/vim/20111202085236.htm\">この辺</a>読んで貰えると分かる。<br />\\nftplugin は現在のバッファにファイルタイプが適用されたタイミングで <code>ftplugin/ファイルタイプ名.vim</code> もしくは <code>ftplugin/ファイルタイプ名/任意ファイル名.vim</code> が読み込まれ実行される。つまりファイルタイプ固有の設定をする為のもの。<br />\\n上記の jsx.vim では、noremap 命令で t というキーに対して <code>call jsx#test_it()</code> という関数呼び出しをキーマップとして割り当てている。<br />\\n\\n<b>ftplugin/jsx.vim</b><br />\\n<blockquote class=\"code\">\\n<span class=\"Statement\">noremap</span> t :call jsx#test_it()<span class=\"Special\"><</span><span class=\"Special\">CR</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\ninoremap や nnoremap の様に先頭に i や n といったモードが付けられていないので、このキー設定は<del>インサートモード</del>意図しないシーケンスでも作用してしまう。(追記: noremap が作用するのは n/v/o で i は勘違いでした)<br />\\n正しくやるなら nnoremap であろう。<br />\\n<br />\\n次にこのマップにはバッファローカル指定が無い。つまり、<code>*.jsx</code> が読み込まれたタイミングで、グローバルのキー設定を行っている。行うべきは、現在開いている jsx ファイルのバッファに対してだけキーマップして欲しいので\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">nnoremap</span> <span class=\"Special\"><</span><span class=\"Special\">buffer</span><span class=\"Special\">></span> t :call jsx#test_it()<span class=\"Special\"><</span><span class=\"Special\">cr</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\nとなる。さらに、t というキーはとても短か過ぎる。固有ファイルタイプで、固有の機能を実行するキーマップにしては、識別として短か過ぎると言える。vimmer は良く使う機能を出来るだけ短いキーシーケンスで vimrc に設定している事が多い。なので t でランチャーぽい物を起動する設定をしている人であれば、キーがバッティングしてしまう事になる。<br />\\nこういった場合、<code><leader></code> を使う事がある。これは mapleader という変数名で割り当てられたキープレフィックスを使ってマップする機能で、例えば\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">nnoremap</span> <span class=\"Special\"><</span><span class=\"Special\">buffer</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">leader</span><span class=\"Special\">></span>t :call jsx#test_it()<span class=\"Special\"><</span><span class=\"Special\">cr</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\nこの様に設定すると、mapleader に対して何も設定していないのであれば <code>¥t</code> でマップが実行される。<br />\\n<br />\\nさて、一般的にプラグイン作者はこの様なキーバッティングを極力避けようとする。しかしながら上記の書き方では、キーが上書きされ気付かない内に書き換えられてしまい、不運な事故を生んでしまう。<br />\\nそこで、あえてエラーを発生させる為に unique 修飾を使う。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">nnoremap</span> <span class=\"Special\"><</span><span class=\"Special\">buffer</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">unique</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">leader</span><span class=\"Special\">></span>t :call jsx#test_it()<span class=\"Special\"><</span><span class=\"Special\">cr</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\nこれで完璧と言いたいが、vimmer の中にはデフォルトのキー設定を嫌う人もいる。<br />\\nそこで\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">if</span> !<span class=\"Identifier\">get</span><span class=\"Special\">(</span>g:, <span class=\"Constant\">'jsx_no_default_key_mappings'</span>, <span class=\"Constant\">0</span><span class=\"Special\">)</span><br />\\n<span class=\"Comment\"> " ここにキー設定を書く</span><br />\\n<span class=\"Statement\">endif</span><br />\\n</blockquote>\\n\\nこうしておけば、デフォルトのキー設定が嫌いな人は vimrc に\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:jsx_no_default_key_mappings</span> <span class=\"Statement\">=</span> <span class=\"Constant\">1</span><br />\\n</blockquote>\\n\\nと書くことでキー設定が行われない様になる。<br />\\n<br />\\nさてここまで書いた後でなんだが、vim には plug 修飾という物がある。<br/ >\\nvim では「<b>キー</b>」に対して「<b>処理</b>」をマップするのが一般的だが、これだと全てのユーザがキー設定の際に「<b>処理</b>」を書かないといけなくなる。これではプラグイン作者がインタフェースを気軽に変更出来なくなってしまう。そこで処理をインタフェースとして扱う為に生まれたのが plug 修飾だ。<br />\\nまず test_it に対するインタフェースを公開する。<br >\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">nnoremap</span> <span class=\"Special\"><</span><span class=\"Special\">silent</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">plug</span><span class=\"Special\">></span>(jsx-test) :<span class=\"Special\"><</span><span class=\"Special\">c-u</span><span class=\"Special\">></span>call jsx#test_it()<span class=\"Special\"><</span><span class=\"Special\">cr</span><span class=\"Special\">></span><br />\\n</blockquote>\\n\\nこれにより、ユーザ側は <code>(jsx-test)</code> という<b>インタフェースに対してのキーマップ</b>だけを行えば良いことになる。<br />\\n上記をそのまま使い、以下の様になる。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">if</span> !<span class=\"Identifier\">get</span><span class=\"Special\">(</span>g:, <span class=\"Constant\">'jsx_no_default_key_mappings'</span>, <span class=\"Constant\">0</span><span class=\"Special\">)</span><br />\\n <span class=\"Statement\">nmap</span> <span class=\"Special\"><</span><span class=\"Special\">unique</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">buffer</span><span class=\"Special\">></span> <span class=\"Special\"><</span><span class=\"Special\">leader</span><span class=\"Special\">></span>t <span class=\"Special\"><</span><span class=\"Special\">plug</span><span class=\"Special\">></span>(jsx-test)<br />\\n<span class=\"Statement\">endif</span><br />\\n</blockquote>\\n\\nここで nnoremap を使わず nmap になっているのには理由がある。nnoremap は <b>n</b>ormal <b>no</b>-<b>remap</b> を意味している。つまり、ノーマルモードで作用する、リマップ(別のマップへのマップ)を使用しないキーマップの設定となる。例えば t というキーに T を割り当てていた場合、通常のマップではリマップされるが、noremap だとされないという事になる。plug 修飾はマップの一部なので map を使って設定する必要があるという事になる。<br />\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4774147958/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/516K5O-bN8L._SL160_.jpg\" alt=\"Vimテクニックバイブル ~作業効率をカイゼンする150の技\" class=\"awsxom-image\" />\\n<strong>Vimテクニックバイブル ~作業効率をカイゼンする150の技</strong></a><br />\\nVimサポーターズ<br />\\n技術評論社 / ¥ 3,129 (2011-09-23)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-10-15T17:16:00+09:00" | |
}, | |
{ | |
"title": "Jekyll で GitHub みたいな Triple Backtick を使う。", | |
"link": "http://mattn.kaoriya.net/software/lang/ruby/20121011184445.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/ruby/20121011184445", | |
"summary": "\\n<a href=\"http://jekyllrb.com/\">Jekyll</a>を使っていていつも思うのが、githubの様な\\n\\n<blockquote class=\"code\">\\n```perl<br />\\nuse strict;<br />\\nuse warnings;<br />\\n<br />\\nwarn "foo";<br />\\n```<br />\\n</blockquote>\\n\\nという Triple Backtick が使えない事なんだけど、まぁこれは Markdown の仕様に準拠していない拡張なのでしょうがないと思いつつも、最近 github に慣れすぎていてイライラしてきた。Jekyll Plugin では Markdown の変換をプラグインとして書くことは出来ないので、<code>Jekyll::MarkdownConverter</code> の convert メソッドを上書きしてやるプラグイン(と呼べるかどうかはあるが)を書いた。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">module</span> <span class=\"Type\">Jekyll</span><br />\\n <span class=\"PreProc\">class</span> <span class=\"Type\">MarkdownConverter</span><br />\\n <span class=\"PreProc\">alias</span> <span class=\"Constant\">:old_convert</span> <span class=\"Constant\">:convert</span><br />\\n <br />\\n <span class=\"PreProc\">def</span> <span class=\"Identifier\">convert</span>(content)<br />\\n content.gsub!(<span class=\"Special\">/</span><span class=\"Special\">(?:</span><span class=\"Special\">^</span><span class=\"Special\">|</span><span class=\"Special\">\\n</span><span class=\"Special\">)</span><span class=\"Constant\">```</span><span class=\"Special\">(</span><span class=\"Special\">\\w</span><span class=\"Special\">*</span><span class=\"Special\">)</span><span class=\"Special\">\\n</span><span class=\"Special\">(</span><span class=\"Special\">.</span><span class=\"Special\">*?</span><span class=\"Special\">\\n</span><span class=\"Special\">)</span><span class=\"Constant\">```</span><span class=\"Special\">\\n</span><span class=\"Special\">/m</span>) <span class=\"Statement\">do</span> |<span class=\"Identifier\">text</span>|<br />\\n cls = <span class=\"Identifier\">$1</span>.empty? ? <span class=\"Special\">"</span><span class=\"Constant\">prettyprint</span><span class=\"Special\">"</span> : <span class=\"Special\">"</span><span class=\"Constant\">prettyprint lang-</span><span class=\"Special\">#{</span><span class=\"Identifier\">$1</span><span class=\"Special\">}</span><span class=\"Special\">"</span><br />\\n <span class=\"Special\">"</span><span class=\"Special\">\\n</span><span class=\"Constant\"><pre class=\\"</span><span class=\"Special\">#{</span>cls<span class=\"Special\">}</span><span class=\"Constant\">\\"><code></span><span class=\"Special\">#{</span><span class=\"Type\">CGI</span>.escapeHTML(<span class=\"Identifier\">$2</span>)<span class=\"Special\">}</span><span class=\"Constant\"></code></pre></span><span class=\"Special\">"</span><br />\\n <span class=\"Statement\">end</span><br />\\n old_convert(content)<br />\\n <span class=\"PreProc\">end</span><br />\\n <span class=\"PreProc\">end</span><br />\\n<span class=\"PreProc\">end</span><br />\\n</blockquote>\\n\\nこれを <code>_plugins/triple-backtick.rb</code> として入れておけば、Google Code Prettify が検知できるクラス名を付けてコード出力してくれ、みんな大好き <code>```</code> が使える様になって幸せになれる。<br />\\nちなみにこの方式を使って、maruku や redcloth で出力させたい場合はLiquidのコンバータまでさかのぼって上書きしないといけなくなるので諦めた。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "github, ruby", | |
"published": "2012-10-11T18:49:00+09:00" | |
}, | |
{ | |
"title": "Jekyll Meets Gitolite", | |
"link": "http://mattn.kaoriya.net/software/linux/20121011153625.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/linux/20121011153625", | |
"summary": "\\n<a href=\"http://jekyllrb.com/\">Jekyll</a>と<a href=\"https://github.com/sitaramc/gitolite\">Gitolite</a>を連携させたら思いのほか便利だったという話。<br >\\n以下は CentOS6 でやった履歴。まず jekyll をインストールする。これは rvm じゃなくて後で作る git ユーザから実行可能な物でないといけない(まぁパス通してもいいけど)。<br />\\n\\n<blockquote class=\"code\">\\n$ yum install git gitweb ruby rubygems<br />\\n$ gem install jekyll\\n</blockquote>\\n\\ngit ユーザを作る。\\n\\n<blockquote class=\"code\">\\n$ useradd git<br />\\n$ passwd git\\n</blockquote>\\n\\nssh でログイン出来る様にする。\\n\\n<blockquote class=\"code\">\\n$ vi /etc/sshd/sshd_config<br />\\n$ /etc/init.d/sshd restart\\n</blockquote>\\n<em>※AllowUsers に git を足す</em><br />\\n\\ngitolite のインストール。\\n\\n<blockquote class=\"code\">\\n$ su - git<br />\\n$ cp /tmp/trusted-key.pub foo.pub<br />\\n$ git clone <a href=\"https://github.com/sitaramc/gitolite.git\">https://github.com/sitaramc/gitolite.git</a><br />\\n$ `pwd`/gitolite/install -ln<br />\\n$ gitolite setup -pk foo.pub\\n</blockquote>\\n<em>※foo はメインで使うユーザ名にしておくと良い</em><br />\\n\\nリモートから gitolite-admin で blog を作る。\\n\\n<blockquote class=\"code\">\\n$ git clone git@server:gitolite-admin<br />\\n$ cd gitolite-admin<br />\\n$ vi conf/gitolite.conf\\n</blockquote>\\n\\n<blockquote class=\"code\">\\nrepo gitolite-admin<br />\\n RW+ = mattn<br />\\n<br />\\n#repo testing<br />\\n# RW+ = @all<br />\\n<br />\\nrepo blog<br />\\n RW+ = foo<br />\\n R = gitweb<br />\\n config gitweb.owner = foo<br />\\n config gitweb.description = blog\\n</blockquote>\\n\\n<blockquote class=\"code\">\\n$ git commit -a<br />\\n$ git push origin master\\n</blockquote>\\n\\nここでサーバ側に仕掛けを入れる。\\n\\n<blockquote class=\"code\">\\n$ su - git<br />\\n$ vi ~/repositories/blog.git/hooks/post-receive\\n</blockquote>\\n\\n<blockquote class=\"code\">\\n#!/bin/sh<br />\\n<br />\\nGIT_REPO=$HOME/repositories/blog.git<br />\\nTMP_GIT_CLONE=$HOME/tmp/blog<br />\\nPUBLIC_WWW=/var/www/blog<br />\\n<br />\\ngit clone $GIT_REPO $TMP_GIT_CLONE<br />\\ncd $TMP_GIT_CLONE && jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW<br />\\ncd ~ && rm -rf $TMP_GIT_CLONE<br />\\n<br />\\nfind $PUBLIC_WWW -type f -print0 | xargs -0 chmod 666<br />\\nfind $PUBLIC_WWW -type d -print0 | xargs -0 chmod 777<br />\\n<br />\\nexit\\n</blockquote>\\n\\nまたapacheでブログが見れる様にする。\\n\\n<blockquote class=\"code\">\\n$ su -<br />\\n$ mkdir /var/www/blog<br />\\n$ chmod 775 /var/www/blog<br />\\n$ chown git:git /var/www/blog<br />\\n$ vi /etc/httpd/conf/httpd.conf\\n</blockquote>\\n\\n<blockquote class=\"code\">\\nDocumentRoot \"/var/www/blog\"\\n</blockquote>\\n\\napacheグループから見れる様にする\\n\\n<blockquote class=\"code\">\\n$ usermod -a -G apache git\\n</blockquote>\\n\\nリモートから blog リポジトリをチェックアウト。\\n\\n<blockquote class=\"code\">\\n$ git clone git@server:blog\\n</blockquote>\\n\\nここから先は、<a href=\"http://mattn.kaoriya.net/software/lang/ruby/20090409185248.htm\">Jekyllで始める簡単ブログ</a>を読んでJekyllを設定して欲しい。<br />\\nさて、あとは記事を書いてgit addして、コミットそしてプッシュすれば自動的にサーバ側でjekyllが静的コンテンツを生成してくれ、ブログが公開される様になる。<br />\\n<br />\\nGitHub Pages ぽくなってウマー。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "gitolite, jekyll", | |
"published": "2012-10-11T15:41:00+09:00" | |
}, | |
{ | |
"title": "Google からの贈り物", | |
"link": "http://mattn.kaoriya.net/etc/20121007231549.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/etc/20121007231549", | |
"summary": "\\nまさかあの Google から、この僕にこんな物が届くとは思ってなかった。<br />\\n<br />\\n仕事に疲れて深夜に帰宅した僕は、テーブルに置かれた郵便物に気がついた。<br />\\n送り主は Google<br />\\n<br />\\n大きめの封筒だ。<br />\\n封筒を開けた瞬間、僕は一瞬引いた。<br />\\n<br />\\n緑色の何かが見えた。書類ではない。<a href=\"http://mattn.kaoriya.net/etc/20110830004849.htm\">ぬいぐるみ</a>でもない。<br />\\n<br />\\n「やばい」<br />\\n<br />\\n僕の脳によぎったその感覚は、疲れていた僕の体を一瞬にして変な気分に変えた。<br />\\n<br />\\n<p><a href=\"http://mattn.kaoriya.net/etc/20121007231549.htm\" title=\"Google からの贈り物を全文表示\" class=\"seemore\">続きを読む...</a></p>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "google, golang", | |
"published": "2012-10-07T23:35:00+09:00" | |
}, | |
{ | |
"title": "僕がboost::asioとboost::property_treeを使いHTTPプロキシ環境下で非同期にGoogle Search APIから検索するまでにやった、たった一つの事。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20120928210558.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/c/20120928210558", | |
"summary": "\\nタイトルなげーーーーーーーーーーー!<br />\\nプロキシ環境下でしか動きませんが、使いたい人は勝手に書き換えて下さい。<br />\\n<code>boost::bind</code> 使わずラムダだけでやってんの、オレオレルールだから気にした奴は負け。<br />\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#define _WIN32_WINNT </span><span class=\"Constant\">0x0501</span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><iostream></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><string></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><sstream></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><system_error></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/array.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/bind.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/regex.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/foreach.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/asio.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/system/error_code.hpp></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><boost/property_tree/json_parser.hpp></span><br />\\n<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> boost::asio;<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> boost::asio::ip;<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> boost::property_tree;<br />\\n<span class=\"Statement\">using</span> <span class=\"Type\">namespace</span> boost::system;<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain(<span class=\"Type\">int</span> argc, <span class=\"Type\">char</span>* argv[]) {<br />\\n <span class=\"Statement\">if</span> (argc == <span class=\"Constant\">1</span>) {<br />\\n std::cerr << <span class=\"Constant\">"usage: "</span> << argv[<span class=\"Constant\">0</span>] << <span class=\"Constant\">" [words]"</span> << std::endl;<br />\\n <span class=\"Statement\">return</span> -<span class=\"Constant\">1</span>;<br />\\n }<br />\\n<br />\\n <span class=\"Comment\">// リクエストする URL を作る</span><br />\\n std::string get_url =<br />\\n <span class=\"Constant\">"<a href=\"http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=\">http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=</a>"</span>;<br />\\n<br />\\n <span class=\"Statement\">for</span> (<span class=\"Type\">int</span> i = <span class=\"Constant\">1</span>; i < argc; i++) {<br />\\n std::string arg = argv[i];<br />\\n BOOST_FOREACH(<span class=\"Type\">auto</span> c, arg) {<br />\\n <span class=\"Statement\">if</span> ((c >= <span class=\"Constant\">'A'</span> && c <= <span class=\"Constant\">'Z'</span>) || (c >= <span class=\"Constant\">'a'</span> && c <= <span class=\"Constant\">'z'</span>) ||<br />\\n (c >= <span class=\"Constant\">'0'</span> && c <= <span class=\"Constant\">'9'</span>) ||<br />\\n c == <span class=\"Constant\">'-'</span> || c == <span class=\"Constant\">'_'</span> || c == <span class=\"Constant\">'.'</span> || c == <span class=\"Constant\">'~'</span>) {<br />\\n get_url += c;<br />\\n } <span class=\"Statement\">else</span> <span class=\"Statement\">if</span> (c == <span class=\"Constant\">' '</span>) {<br />\\n get_url += <span class=\"Constant\">'+'</span>;<br />\\n } <span class=\"Statement\">else</span> {<br />\\n std::stringstream ss;<br />\\n ss << <span class=\"Constant\">"%"</span> << std::hex << std::setw(<span class=\"Constant\">2</span>) <<<br />\\n std::setfill(<span class=\"Constant\">'0'</span>) << (<span class=\"Type\">int</span>) (c & <span class=\"Constant\">0xff</span>);<br />\\n get_url += ss.str();<br />\\n }<br />\\n }<br />\\n }<br />\\n<br />\\n <span class=\"Comment\">// HTTP_PROXY 環境変数からホスト名とポート番号を得る</span><br />\\n std::string http_proxy = std::getenv(<span class=\"Constant\">"HTTP_PROXY"</span>);<br />\\n boost::regex pattern(<span class=\"Constant\">"^(?:http://)?([^/]+):([0-9]+)"</span>);<br />\\n boost::match_results<std::string::const_iterator> it;<br />\\n <span class=\"Statement\">if</span> (!regex_search(http_proxy, it, pattern)) {<br />\\n std::cerr << <span class=\"Constant\">"プロキシを使っていません"</span> << std::endl;<br />\\n <span class=\"Statement\">return</span> -<span class=\"Constant\">1</span>;<br />\\n }<br />\\n<br />\\n io_service service;<br />\\n tcp::resolver resolver(service);<br />\\n<br />\\n <span class=\"Comment\">// ホスト名から名前解決を行う</span><br />\\n tcp::resolver::query resolver_query(<br />\\n std::string(it[<span class=\"Constant\">1</span>].first, it[<span class=\"Constant\">1</span>].second), <span class=\"Comment\">// ホスト名</span><br />\\n std::string(it[<span class=\"Constant\">2</span>].first, it[<span class=\"Constant\">2</span>].second) <span class=\"Comment\">// ポート番号</span><br />\\n );<br />\\n<br />\\n std::string data;<br />\\n resolver.async_resolve(<br />\\n resolver_query,<br />\\n [&](<span class=\"Type\">const</span> error_code& ec, tcp::resolver::iterator it) {<br />\\n <span class=\"Statement\">if</span> (ec) {<br />\\n std::cerr << ec.message() << std::endl;<br />\\n } <span class=\"Statement\">else</span> {<br />\\n <span class=\"Comment\">// プロキシに接続する</span><br />\\n tcp::socket socket(service);<br />\\n socket.async_connect(<br />\\n it->endpoint(),<br />\\n [&](<span class=\"Type\">const</span> error_code& ec) {<br />\\n <span class=\"Statement\">if</span> (ec) {<br />\\n std::cerr << ec.message() << std::endl;<br />\\n } <span class=\"Statement\">else</span> {<br />\\n <span class=\"Comment\">// プロキシに GET 命令を送信する</span><br />\\n std::string query = <span class=\"Constant\">"GET "</span>;<br />\\n query += get_url;<br />\\n query += <span class=\"Constant\">" HTTP/1.0</span><span class=\"Special\">\\r\\n\\r\\n</span><span class=\"Constant\">"</span>;<br />\\n<br />\\n async_write(<br />\\n socket,<br />\\n buffer(query.c_str(), query.size()),<br />\\n [&](<span class=\"Type\">const</span> error_code& ec, std::<span class=\"Type\">size_t</span> len) {<br />\\n <span class=\"Statement\">if</span> (ec) {<br />\\n std::cerr << ec.message() << std::endl;<br />\\n } <span class=\"Statement\">else</span> {<br />\\n boost::array<<span class=\"Type\">char</span>, <span class=\"Constant\">1024</span>> buf;<br />\\n std::stringstream ss;<br />\\n <span class=\"Comment\">// HTTP/1.0 なので切断までループ</span><br />\\n <span class=\"Statement\">while</span> (socket.is_open()) {<br />\\n socket.async_read_some(<br />\\n buffer(buf),<br />\\n [&](<span class=\"Type\">const</span> error_code& ec, std::<span class=\"Type\">size_t</span> len) {<br />\\n <span class=\"Statement\">if</span> (ec) {<br />\\n socket.close();<br />\\n } <span class=\"Statement\">else</span> <span class=\"Statement\">if</span> (len == <span class=\"Constant\">0</span>) {<br />\\n socket.close();<br />\\n } <span class=\"Statement\">else</span> {<br />\\n ss << std::string(buf.data(), len);<br />\\n buf.assign(<span class=\"Constant\">0</span>);<br />\\n }<br />\\n });<br />\\n service.run_one();<br />\\n }<br />\\n data = ss.str();<br />\\n <span class=\"Comment\">// ヘッダを取り除く</span><br />\\n std::<span class=\"Type\">size_t</span> pos = data.find(<span class=\"Constant\">"</span><span class=\"Special\">\\r\\n\\r\\n</span><span class=\"Constant\">"</span>);<br />\\n <span class=\"Statement\">if</span> (pos != std::string::npos) {<br />\\n data = data.substr(pos + <span class=\"Constant\">4</span>);<br />\\n }<br />\\n }<br />\\n });<br />\\n service.run_one();<br />\\n }<br />\\n });<br />\\n service.run_one();<br />\\n }<br />\\n });<br />\\n service.run_one();<br />\\n<br />\\n <span class=\"Statement\">if</span> (!data.empty()) {<br />\\n <span class=\"Comment\">// 結果で得られた JSON をパースする</span><br />\\n std::stringstream ss(data);<br />\\n ptree pt;<br />\\n read_json(ss, pt);<br />\\n<br />\\n <span class=\"Statement\">if</span> (pt.get<<span class=\"Type\">int</span>>(<span class=\"Constant\">"responseStatus"</span>) == <span class=\"Constant\">200</span>) {<br />\\n <span class=\"Comment\">// 結果配列でループしながら表示</span><br />\\n ptree& results = pt.get_child(<span class=\"Constant\">"responseData.results"</span>);<br />\\n BOOST_FOREACH(<span class=\"Type\">const</span> ptree::value_type& result, results) {<br />\\n std::string url = result.second.get<std::string>(<span class=\"Constant\">"url"</span>);<br />\\n std::string title = result.second.get<std::string>(<span class=\"Constant\">"titleNoFormatting"</span>);<br />\\n std::cout << url << std::endl << <span class=\"Constant\">" "</span> << title << std::endl;<br />\\n }<br />\\n }<br />\\n }<br />\\n <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n}<br />\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "google, asio, boost, json, c++", | |
"published": "2012-09-28T21:07:00+09:00" | |
}, | |
{ | |
"title": "バッチ ジョブを終了しますか (Y/N)?", | |
"link": "http://mattn.kaoriya.net/software/windows/20120920154016.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/windows/20120920154016", | |
"summary": "\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4434046683/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/41DYYQAGRDL._SL160_.jpg\" alt=\"ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか\" class=\"awsxom-image\" />\\n<strong>ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか</strong></a><br />\\nジュニア,ヘンリー・S. ウォーレン<br />\\nエスアイビーアクセス / ¥ 3,570 (2004-09)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n\\n<img src=\"http://go-gyazo.appspot.com/b7cdb5e76776b253.png\" title=\"バッチ ジョブを終了しますか (Y/N)?\" class=\"thumbnail-right\" />\\nWindows を UNIX っぽく使おうとすると、必ずお目にかかるであろうこのメッセージ。<br />\\nUNIX に慣れている人は、コマンドプロンプトを使いたがる。しかし全ての場合においてコンソールアプリケーションは有能では無いし、異常に長い引数は省略したい。Java VM で動く言語のクラスパス等はスクリプトに書きたいし、オフィシャルから Windows ユーザ向けに用意される物はだいたいバッチファイルだ。しかしながら Cygwin は標準提供物ではないし、嫌いだ。いや、<b>大嫌い</b>だ。<br />\\nそこで私達は一般的に、バッチファイルという一見便利そげで実は非情なまでに我々に独特の仕様を強要するDSLを頻繁に使う事になる。<br />\\n例えば Java VM 上で動く clojure を Windows 上で repl として使う場合、僕は以下の様なバッチファイルを「clj.bat」というファイル名にして使っている。<br class=\"clearall\" />\\n\\n<blockquote class=\"code\">\\n@<span class=\"Identifier\">echo</span><span class=\"Statement\"> off</span><br />\\n<span class=\"Identifier\">set</span><span class=\"Identifier\"> CLOJURE_EXT</span><span class=\"Statement\">=</span><span class=\"Identifier\">%USERPROFILE%</span>\\.clojure.d<br />\\n<span class=\"Identifier\">setlocal</span> enabledelayedexpansion<br />\\n<span class=\"Statement\">if</span><span class=\"Statement\"> defined</span> CLOJURE_EXT <span class=\"Statement\">for</span> <span class=\"Special\">%%</span>E in (<span class=\"Constant\">"</span><span class=\"Identifier\">%CLOJURE_EXT%</span><span class=\"Constant\">\\*"</span>) do <span class=\"Identifier\">set</span><span class=\"Identifier\"> CP</span><span class=\"Statement\">=</span><span class=\"Identifier\">!CP!</span>;<span class=\"Special\">%%</span>~fE<br />\\n<span class=\"Statement\">if</span><span class=\"Statement\"> not defined</span> CLOJURE_JAVA <span class=\"Identifier\">set</span><span class=\"Identifier\"> CLOJURE_JAVA</span><span class=\"Statement\">=</span>java<br />\\n<span class=\"Statement\">if</span><span class=\"Statement\"> exist</span> .clojure <span class=\"Statement\">for</span> <span class=\"Special\">/F</span> <span class=\"Special\">%%</span>E in (<span class=\"Constant\">".clojure\\*"</span>) do <span class=\"Identifier\">set</span><span class=\"Identifier\"> CP</span><span class=\"Statement\">=</span><span class=\"Identifier\">!CP!</span>;<span class=\"Special\">%%</span>~fE<br />\\n<span class=\"Identifier\">%CLOJURE_JAVA%</span> <span class=\"Identifier\">%CLOJURE_OPTS%</span> -cp <span class=\"Constant\">"</span><span class=\"Identifier\">%CP%</span><span class=\"Constant\">"</span> clojure.main -i <span class=\"Constant\">"</span><span class=\"Identifier\">%CLOJURE_EXT%</span><span class=\"Constant\">\\cljrc.clj"</span> <span class=\"Identifier\">%1</span> <span class=\"Identifier\">%2</span> <span class=\"Identifier\">%3</span> <span class=\"Identifier\">%4</span> <span class=\"Identifier\">%5</span> <span class=\"Identifier\">%6</span> <span class=\"Identifier\">%7</span> <span class=\"Identifier\">%8</span> <span class=\"Identifier\">%9</span> --repl<br />\\n</blockquote>\\n\\nこれは別に大した物ではないし、僕にとって心地よく動作している。<br />\\nしかしこの repl を終了しようと、UNIX ユーザでは当たり前の呪文、そう「CTRL-C」をタイプすると事態が急転する。<br />\\n\\n<blockquote class=\"code\">\\nC:\\temp>clj.bat<br />\\nClojure 1.4.0<br />\\nuser=><br />\\nバッチ ジョブを終了しますか (Y/N)?<br />\\n</blockquote>\\n\\n<strong>お前は俺が終了しろと言ったのが聞こえないのか?</strong><br />\\n<br />\\njava は既に終了してしまってるのにこれ以上バッチファイルの実行を継続する理由など無い! start を絡ませればメッセージを出さなくする事も出来るが、その start を含んだコマンドをバッチファイルに書いてしまったら堂々巡りだ!我々はコマンドプロンプトからコマンド名で実行したんだ!<br />\\n全世界の Windows ユーザがこの問題に悩んでいる。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://stackoverflow.com/questions/1234571/how-can-i-suppress-the-terminate-batch-job-in-cmd-exe\">How can I suppress the "terminate batch job" in cmd.exe - Stack Overflow</a>\\n\\t<br />\\n\\t<p>I'm looking for a mechanism for suppressing the \"Terminate batch job? (Y/N)\" invitation that I get whenever I press CTRL-C in a program started from a batch file...</p>\\n\\t<cite>http://stackoverflow.com/questions/1234571/how-can-i-suppress-the-terminate-batch-job-in-cmd-exe</cite>\\n</blockquote>\\n\\n中には cmd.exe にバイナリパッチを当てる人までいる。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://itsme.home.xs4all.nl/projects/misc/patching-cmdexe.html\">several useful patches for cmd.exe</a>\\n\\t<br />\\n\\t<p>how to find what to patch using a recent version of IDA, it is quite easy to find where to patch cmd...</p>\\n\\t<cite>http://itsme.home.xs4all.nl/projects/misc/patching-cmdexe.html</cite>\\n</blockquote>\\n\\n本来、CTRL-C をタイプしてプロセスを終了するという自由な行動が、非人道的な cmd.exe の仕様により不自由な操作を強要されている。(© EzoeRyou)<br />\\n<br />\\nこれを解決しようと色々考えたが、以下の方法が良いのではないかと思う。<br />\\nコマンドプロンプトをシェルの様に使う人はフルパスをタイプしないし、拡張子までタイプしない。例えば既述の「clj.bat」であれば「clj」とだけタイプする。拡張子を明示しない場合、Windows では PATHEXT 環境変数を ; で区切った順番に実行ファイルが探索される。通常、PATHEXT では「.bat」よりも「.exe」の方が先に来る。つまり「clj.bat」と同じ位置に「clj.exe」があれば、「clj.exe」が先に見つけられ実行される事になるのだ。<br />\\nであれば、その exe からバッチファイルを起動し、プロセスグループに加えてやれば CTRL-C が伝播するはず。なお且つ対話形式で起動しない様にすれば「バッチ ジョブを終了しますか (Y/N)?」というふざけたメッセージをお目にかかる事はない。<br />\\n<br />\\nよろしい、ならばコーディングだ。一番いい Vim を頼む。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><windows.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><string.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><stdio.h></span><br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nemsg() {<br />\\n <span class=\"Type\">char</span>* p = <span class=\"Constant\">NULL</span>;<br />\\n DWORD err = GetLastError();<br />\\n <span class=\"Statement\">if</span> (err == <span class=\"Constant\">0</span>) <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n FormatMessage(<br />\\n FORMAT_MESSAGE_ALLOCATE_BUFFER |<br />\\n FORMAT_MESSAGE_FROM_SYSTEM |<br />\\n FORMAT_MESSAGE_IGNORE_INSERTS,<br />\\n <span class=\"Constant\">NULL</span>, err, <span class=\"Constant\">0</span>, (LPTSTR)(&p), <span class=\"Constant\">0</span>, <span class=\"Constant\">NULL</span>);<br />\\n fputs(p, <span class=\"Constant\">stderr</span>);<br />\\n LocalFree((LPVOID)p);<br />\\n <span class=\"Statement\">return</span> err;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain(<span class=\"Type\">int</span> argc, <span class=\"Type\">char</span>* argv[]) {<br />\\n STARTUPINFO si = {<span class=\"Constant\">0</span>};<br />\\n PROCESS_INFORMATION pi = {<span class=\"Constant\">0</span>};<br />\\n <span class=\"Type\">int</span> r;<br />\\n <span class=\"Type\">char</span> *p, *t;<br />\\n t = p = strdup(GetCommandLine());<br />\\n <span class=\"Statement\">if</span> (!p) <span class=\"Statement\">return</span> -<span class=\"Constant\">1</span>;<br />\\n <span class=\"Statement\">if</span> (*p == <span class=\"Constant\">'"'</span>)<br />\\n <span class=\"Statement\">do</span> p++; <span class=\"Statement\">while</span> (*p && *p != <span class=\"Constant\">'"'</span>);<br />\\n <span class=\"Statement\">else</span><br />\\n <span class=\"Statement\">while</span> (*p && *p != <span class=\"Constant\">' '</span>) p++;<br />\\n <span class=\"Statement\">if</span> (!strncasecmp(p-<span class=\"Constant\">4</span>, <span class=\"Constant\">".exe"</span>, <span class=\"Constant\">4</span>))<br />\\n memcpy(p-<span class=\"Constant\">4</span>, <span class=\"Constant\">".bat"</span>, <span class=\"Constant\">4</span>);<br />\\n <span class=\"Statement\">else</span> {<br />\\n <span class=\"Type\">char</span> *comspec = getenv(<span class=\"Constant\">"COMSPEC"</span>), *b;<br />\\n <span class=\"Statement\">if</span> (!comspec) comspec = <span class=\"Constant\">"CMD"</span>;<br />\\n b = malloc(strlen(comspec) + <span class=\"Constant\">1</span> + <span class=\"Constant\">9</span> + strlen(t) + <span class=\"Constant\">5</span>);<br />\\n *b = <span class=\"Constant\">0</span>;<br />\\n strcat(b, comspec);<br />\\n strcat(b, <span class=\"Constant\">" /c call "</span>);<br />\\n strncat(b, t, (<span class=\"Type\">int</span>) (p-t));<br />\\n strcat(b, <span class=\"Constant\">".bat"</span>);<br />\\n strcat(b, p);<br />\\n free(t);<br />\\n t = b;<br />\\n }<br />\\n si.cb = <span class=\"Statement\">sizeof</span>(si);<br />\\n <span class=\"Statement\">if</span> (!CreateProcess(<br />\\n <span class=\"Constant\">NULL</span>, t, <span class=\"Constant\">NULL</span>, <span class=\"Constant\">NULL</span>, TRUE,<br />\\n CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,<br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Constant\">NULL</span>, &si, &pi))<br />\\n r = emsg();<br />\\n <span class=\"Statement\">else</span> {<br />\\n CloseHandle(pi.hThread);<br />\\n <span class=\"Statement\">if</span> (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)<br />\\n r = emsg();<br />\\n <span class=\"Statement\">else</span> {<br />\\n DWORD code = <span class=\"Constant\">0</span>;<br />\\n <span class=\"Statement\">if</span> (!GetExitCodeProcess(pi.hProcess, &code))<br />\\n r = emsg();<br />\\n <span class=\"Statement\">else</span> {<br />\\n r = (<span class=\"Type\">int</span>) code;<br />\\n CloseHandle(pi.hProcess);<br />\\n }<br />\\n }<br />\\n }<br />\\n free(t);<br />\\n <span class=\"Statement\">return</span> r;<br />\\n}<br />\\n</blockquote>\\n\\nソースファイルは「batter.c」として保存し、コンパイルする。<br />\\nコマンドラインの第一引数に「.exe」が付いていたら「.bat」に書き換え、付いていなかったら付け足し、CREATE_NEW_PROCESS_GROUP を指定してプロセスを起動する。<br />\\nこれをコンパイルして出来上がった batter.exe を、例えば「clj.bat」が置いてあるフォルダに「clj.exe」というファイル名てコピーする。<br />\\n<br />\\nでは新しいコマンドプロンプトを起動し、「clj」とタイプしよう...\\n\\n<blockquote class=\"code\">\\nC:\\temp>clj<br />\\nClojure 1.4.0<br />\\nuser=><br />\\n</blockquote>\\n\\nそして CTRL-C だ。<br />\\n\\n<blockquote class=\"code\">\\n^C<br />\\nC:\\temp><br />\\n</blockquote>\\n\\nやった。俺は「バッチ ジョブを終了しますか (Y/N)?」メッセージを倒した。<br />\\n今後「clj.bat」を好き放題に編集しても構わない。<br />\\n<br />\\n俺は勝った。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "windows", | |
"published": "2012-09-20T15:52:00+09:00" | |
}, | |
{ | |
"title": "SQLite で twitter のタイムラインを select する。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20120918225659.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/c/20120918225659", | |
"summary": "\\nちょっと前に PostgreSQL に関する記事を見た。最近 PostgreSQL がアツイらしい。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://www.pictnotes.jp/memo/archives/6\">PostgreSQLに興味がある人向けにまとめてみた。|PostgreSQL|お仕事メモ|Pictnotes</a>\\n\\t<br />\\n\\t<ul>\\n\\t\\t<li><strong>Q. </strong>FDWってなによ?</li>\\n\\t\\t<li><strong>A. </strong>FDW(Foreign Data Wrappe),外部データラッパっていうやつで、SQL/MED(Management of External Data)の規格の一つで簡単にいうと、PostgreSQLにQUERYを発行したら、あら不思議、外部の(たとえばMySQLとかCSV)データが取得できるという変態機能。<br />\\n\\t\\ttwitterAPIに変更あるらしいから今後はわからにけど、twitterのデータを取ってくるとかもできる。というかラッパーが用意されてる。(ちなみに使ってみたら楽しかったw)</li>\\n\\t</ul>\\n\\t<cite>http://www.pictnotes.jp/memo/archives/6</cite>\\n</blockquote>\\n\\nそれはワクテカ過ぎる...<br />\\nだがしかし SQLite3 でも出来る!きっと出来る!<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><string></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><sstream></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><sqlite3.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><sqlite3ext.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\"><curl/curl.h></span><br />\\n<span class=\"PreProc\">#include </span><span class=\"Constant\">"picojson.h"</span><br />\\n<br />\\n<span class=\"PreProc\">#ifdef _WIN32</span><br />\\n<span class=\"PreProc\"># define EXPORT __declspec(dllexport)</span><br />\\n<span class=\"PreProc\">#else</span><br />\\n<span class=\"PreProc\"># define EXPORT</span><br />\\n<span class=\"PreProc\">#endif</span><br />\\n<br />\\nSQLITE_EXTENSION_INIT1;<br />\\n<br />\\n<span class=\"Type\">typedef</span> <span class=\"Type\">struct</span> {<br />\\n <span class=\"Type\">char</span>* data; <span class=\"Comment\">// response data from server</span><br />\\n <span class=\"Type\">size_t</span> size; <span class=\"Comment\">// response size of data</span><br />\\n} MEMFILE;<br />\\n<br />\\nMEMFILE*<br />\\nmemfopen() {<br />\\n MEMFILE* mf = (MEMFILE*) malloc(<span class=\"Statement\">sizeof</span>(MEMFILE));<br />\\n <span class=\"Statement\">if</span> (mf) {<br />\\n mf->data = <span class=\"Constant\">NULL</span>;<br />\\n mf->size = <span class=\"Constant\">0</span>;<br />\\n }<br />\\n <span class=\"Statement\">return</span> mf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">void</span><br />\\nmemfclose(MEMFILE* mf) {<br />\\n <span class=\"Statement\">if</span> (mf->data) free(mf->data);<br />\\n free(mf);<br />\\n}<br />\\n<br />\\n<span class=\"Type\">size_t</span><br />\\nmemfwrite(<span class=\"Type\">char</span>* ptr, <span class=\"Type\">size_t</span> size, <span class=\"Type\">size_t</span> nmemb, <span class=\"Type\">void</span>* stream) {<br />\\n MEMFILE* mf = (MEMFILE*) stream;<br />\\n <span class=\"Type\">int</span> block = size * nmemb;<br />\\n <span class=\"Statement\">if</span> (!mf) <span class=\"Statement\">return</span> block; <span class=\"Comment\">// through</span><br />\\n <span class=\"Statement\">if</span> (!mf->data)<br />\\n mf->data = (<span class=\"Type\">char</span>*) malloc(block);<br />\\n <span class=\"Statement\">else</span><br />\\n mf->data = (<span class=\"Type\">char</span>*) realloc(mf->data, mf->size + block);<br />\\n <span class=\"Statement\">if</span> (mf->data) {<br />\\n memcpy(mf->data + mf->size, ptr, block);<br />\\n mf->size += block;<br />\\n }<br />\\n <span class=\"Statement\">return</span> block;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">char</span>*<br />\\nmemfstrdup(MEMFILE* mf) {<br />\\n <span class=\"Type\">char</span>* buf;<br />\\n <span class=\"Statement\">if</span> (mf->size == <span class=\"Constant\">0</span>) <span class=\"Statement\">return</span> <span class=\"Constant\">NULL</span>;<br />\\n buf = (<span class=\"Type\">char</span>*) malloc(mf->size + <span class=\"Constant\">1</span>);<br />\\n memcpy(buf, mf->data, mf->size);<br />\\n buf[mf->size] = <span class=\"Constant\">0</span>;<br />\\n <span class=\"Statement\">return</span> buf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_connect(sqlite3 *db, <span class=\"Type\">void</span> *pAux, <span class=\"Type\">int</span> argc, <span class=\"Type\">const</span> <span class=\"Type\">char</span> * <span class=\"Type\">const</span> *argv, sqlite3_vtab **ppVTab, <span class=\"Type\">char</span> **c) {<br />\\n std::stringstream ss;<br />\\n ss << <span class=\"Constant\">"CREATE TABLE "</span> << argv[<span class=\"Constant\">0</span>]<br />\\n << <span class=\"Constant\">"(id text, screen_name text, tweet text)"</span>;<br />\\n <span class=\"Type\">int</span> rc = sqlite3_declare_vtab(db, ss.str().c_str());<br />\\n *ppVTab = (sqlite3_vtab *) sqlite3_malloc(<span class=\"Statement\">sizeof</span>(sqlite3_vtab));<br />\\n memset(*ppVTab, <span class=\"Constant\">0</span>, <span class=\"Statement\">sizeof</span>(sqlite3_vtab));<br />\\n <span class=\"Statement\">return</span> rc;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_create(sqlite3 *db, <span class=\"Type\">void</span> *pAux, <span class=\"Type\">int</span> argc, <span class=\"Type\">const</span> <span class=\"Type\">char</span> * <span class=\"Type\">const</span> * argv, sqlite3_vtab **ppVTab, <span class=\"Type\">char</span> **c) {<br />\\n <span class=\"Statement\">return</span> my_connect(db, pAux, argc, argv, ppVTab, c);<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span> my_disconnect(sqlite3_vtab *pVTab) {<br />\\n sqlite3_free(pVTab);<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_destroy(sqlite3_vtab *pVTab) {<br />\\n sqlite3_free(pVTab);<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">typedef</span> <span class=\"Type\">struct</span> {<br />\\n sqlite3_vtab_cursor base;<br />\\n <span class=\"Type\">int</span> index;<br />\\n picojson::value* rows;<br />\\n} cursor;<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {<br />\\n MEMFILE* mf;<br />\\n CURL* curl;<br />\\n <span class=\"Type\">char</span>* json;<br />\\n<br />\\n mf = memfopen();<br />\\n curl = curl_easy_init();<br />\\n curl_easy_setopt(curl, CURLOPT_URL, <span class=\"Constant\">"<a href=\"http://api.twitter.com/1/statuses/public_timeline.json\">http://api.twitter.com/1/statuses/public_timeline.json</a>"</span>);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);<br />\\n curl_easy_perform(curl);<br />\\n curl_easy_cleanup(curl);<br />\\n<br />\\n picojson::value* v = <span class=\"Statement\">new</span> picojson::value;<br />\\n std::string err;<br />\\n picojson::parse(*v, mf->data, mf->data + mf->size, &err);<br />\\n memfclose(mf);<br />\\n<br />\\n <span class=\"Statement\">if</span> (!err.empty()) {<br />\\n <span class=\"Statement\">delete</span> v;<br />\\n std::cerr << err << std::endl;<br />\\n <span class=\"Statement\">return</span> SQLITE_FAIL;<br />\\n }<br />\\n<br />\\n cursor *c = (cursor *)sqlite3_malloc(<span class=\"Statement\">sizeof</span>(cursor));<br />\\n c->rows = v;<br />\\n c->index = <span class=\"Constant\">0</span>;<br />\\n *ppCursor = &c->base;<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_close(cursor *c) {<br />\\n <span class=\"Statement\">delete</span> c->rows;<br />\\n sqlite3_free(c);<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_filter(cursor *c, <span class=\"Type\">int</span> idxNum, <span class=\"Type\">const</span> <span class=\"Type\">char</span> *idxStr, <span class=\"Type\">int</span> argc, sqlite3_value **argv) {<br />\\n c->index = <span class=\"Constant\">0</span>;<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_next(cursor *c) {<br />\\n c->index++;<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_eof(cursor *c) {<br />\\n <span class=\"Statement\">return</span> c->index >= c->rows->get<picojson::array>().size() ? <span class=\"Constant\">1</span> : <span class=\"Constant\">0</span>;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_column(cursor *c, sqlite3_context *ctxt, <span class=\"Type\">int</span> i) {<br />\\n picojson::value v = c->rows->get<picojson::array>()[c->index];<br />\\n picojson::object row = v.get<picojson::object>();<br />\\n <span class=\"Type\">const</span> <span class=\"Type\">char</span>* p = <span class=\"Constant\">NULL</span>;<br />\\n <span class=\"Statement\">switch</span> (i) {<br />\\n <span class=\"Statement\">case</span> <span class=\"Constant\">0</span>:<br />\\n p = row[<span class=\"Constant\">"id"</span>].to_str().c_str();<br />\\n <span class=\"Statement\">break</span>;<br />\\n <span class=\"Statement\">case</span> <span class=\"Constant\">1</span>:<br />\\n p = row[<span class=\"Constant\">"user"</span>].get<picojson::object>()[<span class=\"Constant\">"screen_name"</span>].to_str().c_str();<br />\\n <span class=\"Statement\">break</span>;<br />\\n <span class=\"Statement\">case</span> <span class=\"Constant\">2</span>:<br />\\n p = row[<span class=\"Constant\">"text"</span>].to_str().c_str();<br />\\n <span class=\"Statement\">break</span>;<br />\\n }<br />\\n sqlite3_result_text(ctxt, strdup(p), strlen(p), free);<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_rowid(cursor *c, sqlite3_int64 *pRowid) {<br />\\n *pRowid = c->index;<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">int</span><br />\\nmy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {<br />\\n <span class=\"Statement\">return</span> SQLITE_OK;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">const</span> sqlite3_module module = {<br />\\n <span class=\"Constant\">0</span>,<br />\\n my_create,<br />\\n my_connect,<br />\\n my_bestindex,<br />\\n my_disconnect,<br />\\n my_destroy,<br />\\n my_open,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *)) my_close,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *, <span class=\"Type\">int</span>, <span class=\"Type\">char</span> <span class=\"Type\">const</span> *, <span class=\"Type\">int</span>, sqlite3_value **)) my_filter,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *)) my_next,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *)) my_eof,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *, sqlite3_context *, <span class=\"Type\">int</span>)) my_column,<br />\\n (<span class=\"Type\">int</span> (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) my_rowid,<br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_update</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_begin</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_sync</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_commit</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_rollback</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_findfunction</span><br />\\n <span class=\"Constant\">NULL</span>, <span class=\"Comment\">// my_rename</span><br />\\n};<br />\\n<br />\\n<span class=\"Type\">static</span> <span class=\"Type\">void</span><br />\\ndestructor(<span class=\"Type\">void</span> *arg) {<br />\\n <span class=\"Statement\">return</span>;<br />\\n}<br />\\n<br />\\n<br />\\n<span class=\"Type\">extern</span> <span class=\"Constant\">"C"</span> {<br />\\n<br />\\nEXPORT <span class=\"Type\">int</span><br />\\nsqlite3_extension_init(sqlite3 *db, <span class=\"Type\">char</span> **errmsg, <span class=\"Type\">const</span> sqlite3_api_routines *api) {<br />\\n SQLITE_EXTENSION_INIT2(api);<br />\\n sqlite3_create_module_v2(db, <span class=\"Constant\">"twitter_public_timeline"</span>, &module, <span class=\"Constant\">NULL</span>, destructor);<br />\\n <span class=\"Statement\">return</span> <span class=\"Constant\">0</span>;<br />\\n}<br />\\n<br />\\n}<br />\\n</blockquote>\\n\\npicojson を使うので適当に持ってきて下さい。<br />\\nこのソースを <code>sqlite3_twit.cxx</code> として\\n\\n<blockquote class=\"code\">\\n$ g++ -I. -g -o sqlite3_twit.dll -shared sqlite3_twit.cxx -lcurldll<br />\\n</blockquote>\\n\\nの様にコンパイルする。unix な人は... 調べて下さい。<br />\\nさて...\\n\\n<blockquote class=\"code\">\\n$ sqlite3<br />\\nSQLite version 3.7.14 2012-09-03 15:42:36<br />\\nEnter ".help" for instructions<br />\\nEnter SQL statements terminated with a ";"<br />\\n</blockquote>\\n\\nSQLiteのシェルに入ったら\\n\\n<blockquote class=\"code\">\\nsqlite> select load_extension("sqlite3_twit.dll");<br />\\nload_extension("sqlite3_twit.dll")<br />\\n----------------------------------<br />\\n<br />\\n</blockquote>\\n\\n拡張をロードして\\n\\n<blockquote class=\"code\">\\nsqlite> create virtual table tbl using twitter_public_timeline(id, screen_name, text);<br />\\n</blockquote>\\n\\n仮想テーブルを作る。あとは...<br />\\n\\n<blockquote class=\"code\">\\nsqlite> select * from tbl;<br />\\n <br />\\nid screen_name tweet <br />\\n------------------ ------------ --------------------------------------------------------------------------------------------- <br />\\n248056468924928000 sosomustafa2 الحياة بسيطه جدا لدرجة أن الابتسامه قد تجعلك محبوب جدا ♡"<br />\\n248056468727808000 nurulauliad Sekalinya dateng, dateng semua. Sekalinya pergi, pergi semua. Itu lah sebab kenapa hidup penuh pilihan. <br />\\n248056468421632000 ZaldivarSkat ¡HOY HOY HOY! Extreno de O.N.I.F.C de @RealWizKhalifa <br />\\n248056468291584000 chimpungdila Ciye! "@putuderism: Hey 1530 QL, i miss you so badly :'))" <br />\\n248056467767296000 44Velboo 268とかプロボウラー並の人がいる(^_^;) <br />\\n248056467154944000 kevintumongg Karepmu her RT @KurniawanHerdi: Mau banget ga mong? RT @kevintumonggi: @KurniawanHerdi folbeck her <br />\\n248056467045888000 rnbanyu Detik detik <br />\\n248056466739712000 iiiFoN [HD] The Voice Thailand : Week2 (Full Version) 16 Sep 2012: <a href=\"http://t.co/mRIaKDuy\">http://t.co/mRIaKDuy</a> via @youtube <br />\\n248056465582080000 CarbonQ8e ياكـــم نفـــسٍ عـــن هـــوا الحـــب طابـــت <br />\\n248056465166848000 WhoIsVARRI_ I'm just Boolin how i B Boolin ! <br />\\n248056463069696000 iSwiftCyrus Photo: <a href=\"http://t.co/qAcDMm1c\">http://t.co/qAcDMm1c</a> <br />\\n248056463048704000 IGORNOKALT Baixei o ringtone do gummy bear :9 <br />\\n248056462130176000 meowkikocel #MentionSomeoneVerySpecial @Mistacey :) <br />\\n248056462109184000 xFatehx just got back from NVBA , phhewww what a great match :D <br />\\n248056461912064000 snags17 「倭」を日本の蔑称として使いたがるのは、「現代では」、中国人より韓国<e4><ba><br />\\n248056461803008000 hendraMirvan RT @gadasianipar: RT @febrinacitra: Ket biyen nonton sketsa kok rak tau ngguyu blas to.... (‾▿‾") <br />\\n248056460972544000 _Azrie_ begitu lah gaya nya , online , tapi hanya memerhatikan TL. <br />\\n248056460557312000 imbaked_ This one of those morning were I smoke a blunt nd watch Kevin Hart <br />\\n248056459814912000 psanso + RT“@damiaborras: El rei diu que hem de remar tots… Deu tenir el Fortuna espatllat.”<br />\\nsqlite> <br />\\n</blockquote>\\n\\nキターーー!<br />\\n\\nもちろん\\n\\n<blockquote class=\"code\">\\nsqlite> select * from tbl where tweet like '%twitter%';<br />\\n<br />\\nid screen_name tweet<br />\\n------------------ ------------ -----------<br />\\n248059202780672000 Baby_Nandos_ New Twitter<br />\\n</blockquote>\\n\\nwhere区だって使えるんだぜ!public timeline速過ぎるから毎回違うテーブル内容なんだぜ!<br />\\n<br />\\nって事で、データベースは MySQL でも PostgreSQL でもなく、SQLite に決まり!<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4797354739/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51w28k89iJL._SL160_.jpg\" alt=\"新標準SQLite (オープンソースRDBMSシリーズ)\" class=\"awsxom-image\" />\\n<strong>新標準SQLite (オープンソースRDBMSシリーズ)</strong></a><br />\\n田中 ナルミ<br />\\nソフトバンククリエイティブ / ¥ 2,940 (2010-02-24)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "sqlite", | |
"published": "2012-09-18T23:03:00+09:00" | |
}, | |
{ | |
"title": "Go言語向けの ORM、gorp がなかなか良い", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20120914222828.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20120914222828", | |
"summary": "\\nそろそろWeb周りだけでなくDB周りも揃ってきて、本格的なアプリケーションが書ける様になってきました。<br />\\nDBを扱うには、SQLを実行する様な物は標準でサポートしていましたが、gorp を使うと極力SQLを書かずにデータベースを扱う事が出来ます。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/coopernurse/gorp\">coopernurse/gorp - GitHub</a>\\n\\t<br />\\n\\t<p>Go Relational Persistence I hesitate to call gorp an ORM.</p>\\n\\t<cite>https://github.com/coopernurse/gorp</cite>\\n</blockquote>\\n\\nまずエンティティとなる構造体を宣言します。ここでは Person という構造にします。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">type</span> Person <span class=\"Statement\">struct</span> {<br />\\n Id <span class=\"Type\">int32</span><br />\\n Name <span class=\"Type\">string</span><br />\\n}<br />\\n</blockquote>\\n\\n次に、データベースマッパーを作ります。\\n\\n<blockquote class=\"code\">\\ndb, err := sql.Open(<span class=\"Constant\">"sqlite3"</span>, <span class=\"Constant\">"./foo.db"</span>)<br />\\ndbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}<br />\\n</blockquote>\\n\\nドライバはSQLite3を使いましたが、MySQLとPostgreSQLもサポートしている様です。\\nなお、gorp では使えませんが、Go言語で使えるデータベースは以下のWikiにエントリされています。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://code.google.com/p/go-wiki/wiki/SQLDrivers\">SQLDrivers - go-wiki - SQL database drivers - Go Language Community Wiki - Google Project Hosting </a>\\n\\t<br />\\n\\t<p>SQL database drivers The database/sql and database/sql/driver packages are designed for using databa...</p>\\n\\t<cite>http://code.google.com/p/go-wiki/wiki/SQLDrivers</cite>\\n</blockquote>\\n\\n手前味噌ですが、SQLite3 と Oracle(OCI8)、Microsoft ADODB のドライバは僕が作った奴です。バグあったら教えて下さい。<br />\\n<br />\\nさて、データベースマッパーが出来たらテーブルと構造体の紐付けを行います。\\n\\n<blockquote class=\"code\">\\nt := dbmap.AddTableWithName(Person{}, <span class=\"Constant\">"person"</span>).SetKeys(<span class=\"Statement\">true</span>, <span class=\"Constant\">"Id"</span>)<br />\\nt.ColMap(<span class=\"Constant\">"Id"</span>).Rename(<span class=\"Constant\">"id"</span>)<br />\\nt.ColMap(<span class=\"Constant\">"Name"</span>).Rename(<span class=\"Constant\">"name"</span>)<br />\\n</blockquote>\\n\\nperson というテーブル名で Person 構造体を登録し、Id がキーである事を教えています。その後、カラム名のリネームも行っています。テーブルのフィールド名先頭が大文字とか気持ち悪いとか、UserName というフィールドが \"USER_NAME\" というカラムに割り当てたい場合に使います。<br />\\nこの後、テーブルを作ります。\\n\\n<blockquote class=\"code\">\\ndbmap.DropTables()<br />\\nerr = dbmap.CreateTables()<br />\\n</blockquote>\\n\\n今回は1つしかテーブルを扱っていませんが、一度に複数登録して一括で作成する事が多いと思います。<br />\\nではデータを登録しましょう。<code>dbmap.Insert</code> でも登録出来ますが、ここではトランザクションを使いましょう。<br />\\n\\n<blockquote class=\"code\">\\ntx, _ := dbmap.Begin()<br />\\n<span class=\"Statement\">for</span> i := <span class=\"Constant\">0</span>; i < <span class=\"Constant\">100</span>; i++ {<br />\\n tx.Insert(&Person{<span class=\"Constant\">0</span>, fmt.Sprintf(<span class=\"Constant\">"mattn%03d"</span>, i)})<br />\\n}<br />\\ntx.Commit()<br />\\n</blockquote>\\n\\n今度はデータを取得してみましょう。<code>dbmap.Get</code> でキーを指定して1行取得する事も出来ますし、<code>Select</code> を使う事も出来ます。<br />\\n\\n<blockquote class=\"code\">\\nlist, _ := dbmap.Select(Person{}, <span class=\"Constant\">"select * from person"</span>)<br />\\n<span class=\"Statement\">for</span> _, l := <span class=\"Statement\">range</span> list {<br />\\n p := l.(*Person)<br />\\n fmt.Printf(<span class=\"Constant\">"%d, %s</span><span class=\"Special\">\\n</span><span class=\"Constant\">"</span>, p.Id, p.Name)<br />\\n}<br />\\n</blockquote>\\n\\nなんだか便利になってきましたね。全体のコードは以下の通り。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">package</span> main<br />\\n<br />\\n<span class=\"Statement\">import</span> (<br />\\n <span class=\"Constant\">"database/sql"</span><br />\\n <span class=\"Constant\">"github.com/coopernurse/gorp"</span><br />\\n _ <span class=\"Constant\">"github.com/mattn/go-sqlite3"</span><br />\\n <span class=\"Constant\">"fmt"</span><br />\\n)<br />\\n<br />\\n<span class=\"Statement\">type</span> Person <span class=\"Statement\">struct</span> {<br />\\n Id <span class=\"Type\">int32</span><br />\\n Name <span class=\"Type\">string</span><br />\\n}<br />\\n<br />\\n<span class=\"Statement\">func</span> main() {<br />\\n db, err := sql.Open(<span class=\"Constant\">"sqlite3"</span>, <span class=\"Constant\">"./foo.db"</span>)<br />\\n <span class=\"Statement\">if</span> err != <span class=\"Statement\">nil</span> {<br />\\n <span class=\"Statement\">panic</span>(err.Error())<br />\\n }<br />\\n dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}<br />\\n t := dbmap.AddTableWithName(Person{}, <span class=\"Constant\">"person"</span>).SetKeys(<span class=\"Statement\">true</span>, <span class=\"Constant\">"Id"</span>)<br />\\n t.ColMap(<span class=\"Constant\">"Id"</span>).Rename(<span class=\"Constant\">"id"</span>)<br />\\n t.ColMap(<span class=\"Constant\">"Name"</span>).Rename(<span class=\"Constant\">"name"</span>)<br />\\n dbmap.DropTables()<br />\\n err = dbmap.CreateTables()<br />\\n <span class=\"Statement\">if</span> err != <span class=\"Statement\">nil</span> {<br />\\n <span class=\"Statement\">panic</span>(err.Error())<br />\\n }<br />\\n<br />\\n tx, _ := dbmap.Begin()<br />\\n <span class=\"Statement\">for</span> i := <span class=\"Constant\">0</span>; i < <span class=\"Constant\">100</span>; i++ {<br />\\n tx.Insert(&Person{<span class=\"Constant\">0</span>, fmt.Sprintf(<span class=\"Constant\">"mattn%03d"</span>, i)})<br />\\n }<br />\\n tx.Commit()<br />\\n<br />\\n list, _ := dbmap.Select(Person{}, <span class=\"Constant\">"select * from person"</span>)<br />\\n <span class=\"Statement\">for</span> _, l := <span class=\"Statement\">range</span> list {<br />\\n p := l.(*Person)<br />\\n fmt.Printf(<span class=\"Constant\">"%d, %s</span><span class=\"Special\">\\n</span><span class=\"Constant\">"</span>, p.Id, p.Name)<br />\\n }<br />\\n}<br />\\n</blockquote>\\n\\nGo言語もだんだん仕事で使えそうな言語になってきましたね。<br >\\n<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/4798100471/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/510T1Q7Z8EL._SL160_.jpg\" alt=\"図解 そこが知りたい!よくわかる実践データベース―基礎知識からインテグレーション業務に直結した応用知識まで (Tech & Bizシリーズ)\" class=\"awsxom-image\" />\\n<strong>図解 そこが知りたい!よくわかる実践データベース―基礎知識からインテグレーション業務に直結した応用知識まで (Tech & Bizシリーズ)</strong></a><br />\\n弓場 秀樹<br />\\n翔泳社 / (2001-08)<br />\\n <br />\\n発送可能時間:<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "golang, sqlite3, orm", | |
"published": "2012-09-14T22:31:00+09:00" | |
}, | |
{ | |
"title": "Go言語で jQuery ライクな操作が出来る goquery を試した。", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20120914184828.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20120914184828", | |
"summary": "\\nスクレイピング等を行う場合、スクリプト言語が大きく威力を発揮します。\\n例えばブログの様にタイトルと本文の組が反復される様なページをスクレイピングする場合\\n\\n<ul>\\n\\t<li>URLからHTMLを得る</li>\\n\\t<li>HTMLからDOMオブジェクトを得る</li>\\n\\t<li>エントリとなるDOMノードを検索する</li>\\n\\t<li>エントリノードでループする</li>\\n\\t<ul>\\n\\t\\t<li>エントリノードからタイトルとなるDOMノードを探索しテキストを得る</li>\\n\\t\\t<li>エントリノードから本文となるDOMノードを探索しテキストを得る</li>\\n\\t</ul>\\n</ul>\\n\\nこの様になるかと思います。こういった処理を一般的なコンパイル型言語を使って実行しようとすると\\n\\n<ul>\\n\\t<li>エラーチェック</li>\\n\\t<li>反復処理</li>\\n\\t<li>検索処理</li>\\n</ul>\\n\\nといったコードをゴリゴリ書かなければいけなかったりします。もちろんそれ専用のライブラリを使えば出来きますが、コンパイル型言語ではなかなか良い物がないのは事実です。javascriptに到っては jQuery を使えば簡単に出来ますが、コンパイル型言語向けのライブラリではどうしても jQuery の様に柔軟に操作が出来る物がありませんでした。<br />\\nしかし最近見つけた goquery は jQuery に似せており、コンパイル型言語でありながらも jQuery に似たコードを書く事が出来ます。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/PuerkitoBio/goquery\">PuerkitoBio/goquery - GitHub</a>\\n\\t<br />\\n\\t<p>goquery - a little like that j-thing, only in Go GoQuery brings a syntax and a set of feat...</p>\\n\\t<cite>https://github.com/PuerkitoBio/goquery</cite>\\n</blockquote>\\n\\nドキュメントは以下にあります。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://go.pkgdoc.org/github.com/puerkitobio/goquery\">goquery - GoPkgDoc</a>\\n\\t<br />\\n\\t<cite>http://go.pkgdoc.org/github.com/puerkitobio/goquery</cite>\\n</blockquote>\\n\\n今日はこれを使って、最近デザインを一新した <a href=\"https://favstar.fm\">favstar</a> のページをスクレイピングしてみました。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">package</span> main<br />\\n<br />\\n<span class=\"Statement\">import</span> (<br />\\n <span class=\"String\">"fmt"</span><br />\\n <span class=\"String\">"github.com/PuerkitoBio/goquery"</span><br />\\n <span class=\"String\">"strings"</span><br />\\n)<br />\\n<br />\\n<span class=\"Keyword\">func</span> main() {<br />\\n doc, _ := goquery.NewDocument(<span class=\"String\">"<a href=\"http://favstar.fm/users/mattn_jp/\">http://favstar.fm/users/mattn_jp/</a>"</span>)<br />\\n doc.Root.Find(<span class=\"String\">".fs-tweet"</span>).Each(<span class=\"Type\">func</span>(_ <span class=\"Type\">int</span>, s *goquery.Selection) {<br />\\n fmt.Println(s.Find(<span class=\"String\">".fs-tweet-text"</span>).Text())<br />\\n<br />\\n s.Find(<span class=\"String\">"div[data-type='favs']"</span>).Each(<span class=\"Type\">func</span>(_ <span class=\"Type\">int</span>, s *goquery.Selection) {<br />\\n fmt.Printf(<span class=\"String\">"FAV(%s): %s ...</span><span class=\"Special\">\\n</span><span class=\"String\">"</span>,<br />\\n s.Find(<span class=\"String\">"li.fs-total"</span>).Text(),<br />\\n strings.Join(s.Find(<span class=\"String\">"a"</span>).Map(<span class=\"Type\">func</span>(_ <span class=\"Type\">int</span>, s *goquery.Selection) <span class=\"Type\">string</span> {<br />\\n a, _ := s.Attr(<span class=\"String\">"title"</span>)<br />\\n <span class=\"Statement\">return</span> a<br />\\n }), <span class=\"String\">", "</span>))<br />\\n })<br />\\n s.Find(<span class=\"String\">"div[data-type='retweets']"</span>).Each(<span class=\"Type\">func</span>(_ <span class=\"Type\">int</span>, s *goquery.Selection) {<br />\\n fmt.Printf(<span class=\"String\">"RT (%s): %s ...</span><span class=\"Special\">\\n</span><span class=\"String\">"</span>,<br />\\n s.Find(<span class=\"String\">"li.fs-total"</span>).Text(),<br />\\n strings.Join(s.Find(<span class=\"String\">"a"</span>).Map(<span class=\"Type\">func</span>(_ <span class=\"Type\">int</span>, s *goquery.Selection) <span class=\"Type\">string</span> {<br />\\n a, _ := s.Attr(<span class=\"String\">"title"</span>)<br />\\n <span class=\"Statement\">return</span> a<br />\\n }), <span class=\"String\">", "</span>))<br />\\n })<br />\\n<br />\\n fmt.Println()<br />\\n })<br />\\n}<br />\\n</blockquote>\\n\\n短いですね!実行結果は以下の様になります。\\n\\n<blockquote class=\"code\">\\n今までで一番ひどい状況だったのは、火消しで参入したプロジェクトで「コードはどこにありますか」と聞いたら「まだ1行もない」という返事だった事かな。ウンコなコードすらなかった。<br />\\nFAV(129): @uk_ar, @tyru, @IKANZAKI01, @29_104, @rhythmredbeatbk, @puso_770, @Okayu_AS, @dolly380505 ...<br />\\nRT (203): @j24cape, @rhythmredbeatbk, @logicaldrive, @AnotherSpooky, @ChocolatGato, @dolly380505, @mousecollector, @yuji_developer ...<br />\\n<br />\\nそろそろ anonymous にお願いする団体、tanomimous (たのみます)が登場する予感。<br />\\nFAV(89): @yuji_, @kawauso, @chilalausunai, @_michiamolaura, @ItaiHenter, @a1t0o, @WizardOfPSG, @GearMann ...<br />\\nRT (227): @JiaYue, @OkibiWorksLabo, @AZliebeP, @mol_jhd, @omnibus889, @acubi_, @chibiyamaA112, @ken1479 ...<br />\\n<br />\\nGo言語はコルーチンをgoroutine(ゴルーチン)として実装したので F# にはぜひフルーチンとして実装してほしい。<br />\\nFAV(58): @hoo89, @takuan_osho, @shimozan, @ramusara, @JapTagussan, @wo_M, @TABERO, @sekimiya ...<br />\\nRT (85): @wtokuno, @cinnamon409g, @kazuta46, @ide_an, @2k0ri, @JapTagussan, @st_sady, @favstar50_ja ...<br />\\n<br />\\n俺「Vで始まってmで終わる言葉ってなーんだ」 彼女「えーとVi...、いわなきゃダメ?」 俺「ダーメ(・∀・)ニヤニヤ」 彼女「vimshell: shell on vim」 俺「え?」 彼女「vimshell」 俺「貴様まさか!」Shougo「そのまさかだ!ふははは!」<br />\\nFAV(76): @hakunyan01_p, @HCOOH_2, @__papix__, @econoholic, @ibukiwatermelon, @symmet, @azyobuzin, @tayashin ...<br />\\nRT (55): @monmon326, @bimalki, @A_ir_jun, @ImpureSilver11, @aragasu, @PowerPC7450, @kenkov, @yuscarlet_tkb ...<br />\\n<br />\\nEmacsユーザーに拡散されてるけど何か用?Vim愛好家いびって楽しい?ウチのバックにはShougoっていうヤバい変態がついてるから。覚悟しといてね。遊び半分でうちら怒らせると関係ない勉強会で歌っちゃうよ?【要出典】<br />\\nFAV(47): @nolze, @teotr, @sio2381, @nulltrashcan, @NA_geek, @yogata, @jiroukaja, @CD01_ ...<br />\\nRT (57): @takuan_v2, @dice_zu, @ucq, @nakj, @yoshikaw, @sgur, @yogata, @taniatsu ...<br />\\n<br />\\n「俺はVimmerだぞ」「おまえらとは格が違う」酔ってESCキーを連打、テキストファイルに暴行<br />\\nFAV(48): @takashiyoshida, @teriyaki0519, @toby_net, @komiyatatsh, @RATATATO, @2n_mit, @mugijiru, @cucmberium ...<br />\\nRT (53): @got4416, @JiaYue, @SkySh, @teokure_miku, @carme16d, @kuro_7_nyan, @mtk0308, @mayahu32 ...<br />\\n<br />\\n時間あったらコード書け。コード書いてる時間無かったらコード読め。コード読んでる時間無かったらアイデアを妄想しろ。アイデア妄想してる時間無かったら、君はこの業界に向いてない。<br />\\nFAV(41): @hutyao, @KazusanTw, @setoh2000, @kisaramatsui, @myu65_laurant, @kimuraya, @withgod, @tezzsy ...<br />\\nRT (52): @clicktx, @quoli_1289, @nu11p0_6477, @terra_75, @psycho_weirdo, @Guttyo, @satoapp, @masa711115 ...<br />\\n<br />\\n技術で有名になるには3つ方法がある。1つ目は人の気付かない物を見つける。2つ目は人が面倒臭がってやらない事をやる。3つ目は奇行に走る。<br />\\nFAV(39): @Cside_, @ym_428, @cpp_akira, @tyru, @Utori_2, @HEXwrench, @kagiminori, @hazeseki ...<br />\\nRT (53): @tenn_real, @2784k, @bleutruth, @tabihato, @kickun, @_baruth, @ico390, @tw0gm0w ...<br />\\n<br />\\n物凄く良い記事。僕も英語下手だけとバグ報告等してきたしこれからも変わらない。ちなみに僕はVimの作者にC言語が僕らの共通言語だって言われた。 / 酷い英語をもっとお願いします|gihyo.jp … 技術評論社 <a href=\"http://htn.to/kXmtNJ\">http://htn.to/kXmtNJ</a><br />\\nFAV(36): @ma_shimaro, @ramusara, @super_rti, @ryochack, @Pandora_Ovis, @sizenote, @chairisu, @rane_hs ...<br />\\nRT (44): @chairisu, @rezoolab, @nezucchi_bot, @PowerPC7450, @gu4, @amaika, @gakutarou, @justice_max ...<br />\\n<br />\\n昔いた会社の先輩がC言語のcharポインタのポインタを「キャラポイポイ」と言ってたのが未だに脳の片隅にいて消えない。<br />\\nFAV(33): @owatonmaster, @kashiken, @dooriver, @ussrmichi, @beikome, @umezawa_takeshi, @hop07, @ZeitungM ...<br />\\nRT (42): @yuki_B, @alto_colony, @idzuna_, @umezawa_takeshi, @hotwatermorning, @sempreff, @hop07, @hugakusan ...<br />\\n<br />\\ngo言語にどデカイ修正が入りました。今までエラーの型はos.Errorを使って来ましたがerrorというプリミティブな型に変更となります。おそらくエラーを扱っている全てのプログラムソースが影響します。 #golang<br />\\nFAV(19): @yoya, @mfks17, @neguse, @sanemat, @titoi2, @golangjp, @mataka, @ts7i ...<br />\\nRT (53): @noritaka_okabe, @yohgaki, @ttyokoyama, @zai2kun, @Desigrammer, @mattarijinsei, @xga, @tmybj ...<br />\\n<br />\\n伝説のプログラマと言えば昔、とある個人事業主に1人月程度の仕事を発注して、期日の5日前に打ち合わせしたいと言われたので呼んだら「仕様を確認しに来ました。まだ作ってません。」って言われた事があった。以後その個人事業主は会社で伝説になった。<br />\\nFAV(29): @takanori80, @jiikko, @ryo_dg, @tomatosuperyami, @ZeitungM, @tanabe_y, @mhiki, @tmd45 ...<br />\\nRT (42): @skychibi, @chibiyamaA112, @5Further, @7aguchi, @ryo_dg, @tori_555, @tanabe_y, @daybreak_dawn ...<br />\\n<br />\\n10年かけてC言語覚えた人より3年でC言語習得した人の方がすごいと思うし、「年数多い=良い」がいかにも「老舗=安心」大好きな日本人脳だな。海外に行くと「10年も掛かったの?」って言われそうだな。<br />\\nFAV(30): @wyveelix, @yustoris, @mohammedari, @Ramencozo, @m13979201, @nobyuki, @Candle0728, @GPS_NMEA ...<br />\\nRT (32): @ao_god, @junclowd, @Moosan63, @alucky0707, @RiO_2121, @noshi_296, @Todachii, @oyomeni_onihime ...<br />\\n<br />\\nたまに営業が「この案件COBOLが絡んでるから、出来るオッサン連れてくる」とか言ってるけど、いつか「この案件C言語が絡んでるから、出来るオッサン連れてくる」と言われる日が来る。そして呼ばれるのは君だ。<br />\\nFAV(20): @guldeen, @sst8024, @ayasanxxx, @nonakap, @gnue, @MatsumuraKs, @cobodo, @potechi_live ...<br />\\nRT (40): @DJ_HIKOZA, @sugo__, @guldeen, @Kazzforze, @ariaribababa, @osito_kuma, @toronei, @shunuhs ...<br />\\n<br />\\nUDID: 「You did」、日本語で「お前、やっちまったな」の意味<br />\\nFAV(26): @goya4, @IZUMI162i6, @Utori_Z, @hkoba, @seaki, @sleepydog_tsjp, @dw3w4at, @shintaks94 ...<br />\\nRT (34): @IZUMI162i6, @mizoken001, @alexielseraphin, @yokook, @daga_kotowaru, @nagowl, @lamaille_mayuko, @dw3w4at ...<br />\\n<br />\\nvim-jpはスキあらば暴走する数名のpatch書きと、いつもその暴走を止める1名で構成されていますが、暴走を止める人がいないとこうなります。 <a href=\"https://t.co/06BrJJtU\">https://t.co/06BrJJtU</a><br />\\nFAV(16): @hogedigo, @ikk775, @na4zagin3, @plaster, @h_east, @ToQoz, @giw, @glidenote ...<br />\\nRT (39): @kikuchan98, @rohinomiya, @na4zagin3, @yosida95, @teyosh, @ksaito8, @sol_ursus, @chiastolite ...<br />\\n<br />\\nVim人Tシャツ着た人とEmacs人Tシャツ着た人が街中ですれ違いに肩当たって一触即発みたいな映画観たい。 #仁義無きテキストエディタ<br />\\nFAV(25): @sayu2144, @_keichi_, @takehiro0740, @hecomi, @fu_ryukei, @EiM_GTPE_, @yoshihiro503, @todesking ...<br />\\nRT (28): @Mrk1869, @takehiro0740, @sasex3, @nihonhanako, @fu_ryukei, @mazda_six_wgn, @yoshihiro503, @k_somemo ...<br />\\n<br />\\nmrubyが人気 → mrubyの開発が盛んに → rubyを上回る性能 → rubyの中身をmrubyで入れ替え → 「俺、rubyがmrubyになる前から触ってたわー。」 #地獄のルビ沢<br />\\nFAV(12): @gengorou_game, @viperbjpn, @zerobase, @ne_sachirou, @murasaki8823, @hiroshiyui, @asip2k25, @numpad0 ...<br />\\nRT (41): @gengorou_game, @u1, @jacopen, @slm_sum, @atsu_kaya, @mizlogisan, @coddledegg, @snjx ...<br />\\n<br />\\n「vim はカスタマイズしない様に気をつけてる。」「vim は vi として使ってる。」って人は、我慢してるだけなんだ!本当は羨ましいんだ!vimrcを一日中弄っていたいんだ!そんな事気にせずこっちの世界に飛び込んでくればいいんだ!そして共に奏でよう!崩壊へのエチテュードを!<br />\\nFAV(22): @MomoVD, @koiwakawa, @ne_sachirou, @fks_sdk, @ndxbn, @ymnttt, @bleuscr, @mihyaeru21 ...<br />\\nRT (30): @luyikei, @guitarrapc, @fks_sdk, @ndxbn, @sig_P241, @ymnttt, @virusVer001, @bleuscr ...<br />\\n<br />\\n今すぐフォローすべき眼鏡っ娘エンジニア <a href=\"http://bit.ly/kgJWyE\">http://bit.ly/kgJWyE</a><br />\\nFAV(11): @pmakino, @kuririso, @T0SHI3, @mainyaa, @kenmoto0716, @taki345, @sans_helvetica, @clworld ...<br />\\nRT (40): @tetsuo6666, @N_YAMAMURA, @sayama_yuki, @shmorimo, @_iro, @ATA911, @ukstudio, @tomesode ...<br />\\n</blockquote>\\n\\nどうでしょう。結構 jQuery に似ていると思いませんか? Each や Map を使ってDOMノードを文字列配列に変えられるあたりかなり便利ですね。<br />\\nこれを goquery を使わず行おうと思うとこの量のコードでは済みませんし、ちょっと嫌になってきますね。今後もスクレイピングを行う際にはぜひ goquery を使って行きたいと思います。<br />\\n<div class=\"awsxom\">\\n<a href=\"http://www.amazon.co.jp/exec/obidos/ASIN/486401096X/ref=nosim/?tag=bigsky-22\">\\n<img src=\"http://ecx.images-amazon.com/images/I/51OBTgJsC3L._SL160_.jpg\" alt=\"プログラミング言語Goフレーズブック\" class=\"awsxom-image\" />\\n<strong>プログラミング言語Goフレーズブック</strong></a><br />\\nDavid Chisnall<br />\\nピアソン桐原 / ¥ 1,995 (2012-10-04)<br />\\n <br />\\n発送可能時間:在庫あり。<br />\\n<br class=\"clearall\" />\\n</div>\\n\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "jquery, goquery, golang", | |
"published": "2012-09-14T18:55:00+09:00" | |
}, | |
{ | |
"title": "Go言語版の foreman クローン、goreman(傲慢) 書いた。", | |
"link": "http://mattn.kaoriya.net/software/lang/go/20120913210841.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/go/20120913210841", | |
"summary": "\\nWebのお仕事をやってると、Webサーバのインスタンスと同時にワーカープロセスを起動する事も結構多く、ジョブキューサーバも含めて一括で起動したくなったりします。<br />\\nruby 製の <a href=\"http://rubygems.org/gems/foreman\" class=\"extenal\">foreman</a> という物を使うと Procfile というファイルに書かれた内容でプロセスを起動して、個別に上げたり落としたり出来る様になります。ただしwindowsでは重くて使えない(windows上のrubyどうにかしてる)し、kazeburoさんが作ってるperl製の<a href=\"https://metacpan.org/module/Proclet\" class=\"external\">Proclet</a>はParallel::Preforkがwindowsで動かないので困ってました。\\nここまで来たら自分で書くしかないかなーとか考えながら、C言語で書くの面倒臭いと思ったのでGo言語で書きました。<br /\\n名前は、foremanからパクってgoreman(傲慢)にしました。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"https://github.com/mattn/goreman\">mattn/goreman - GitHub</a>\\n\\t<br />\\n\\t<p>foreman clone written in go language</p>\\n\\t<cite>https://github.com/mattn/goreman</cite>\\n</blockquote>\\n\\n今のところ以下の様に動きます。<br />\\nまず以下の様なProcfileを用意します。\\n<blockquote class=\"code\">\\nweb1: plackup --port 5000<br />\\nweb2: plackup --port 5001<br />\\n</blockquote>\\nこのファイルのある場所で、\\n<blockquote class=\"code\">\\n$ goreman start\\n</blockquote>\\nとすると\\nProcfileにエントリされているプロセスを起動します。\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/e8f1a944b736da55.png\" alt=\"goreman1\" />\\n</blockquote>\\nこの様に色付きで標準出力されながら起動します。<br />\\n別の端末で\\n<blockquote class=\"code\">\\n$ goreman run stop web1\\n</blockquote>\\nとすると\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/6cd5924bde93fdb6.png\" alt=\"goreman2\" />\\n</blockquote>\\n停止し\\n<blockquote class=\"code\">\\n$ goreman run start web1\\n</blockquote>\\nとすると\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/745f038d667887b3.png\" alt=\"goreman3\" />\\n</blockquote>\\n再度web1に割り当てられたプロセスが起動します。<br />\\n<blockquote class=\"code\">\\n$ goreman run restart web1\\n</blockquote>\\nもあります。rpcの警告が出てるのはそのうち直します。<br />\\nWindows と Linux で動作します。<br />\\n今のところ、foreman の様に <code>.env</code> ファイルを読み込んだり、<code>.foreman</code> ファイルに従って起動したりはしていませんが、そのうちやるかもしれません。<br />\\n機能はまだまだですが、そのうち便利になってく気がします。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "golang", | |
"published": "2012-09-13T21:12:00+09:00" | |
}, | |
{ | |
"title": "ぼくが知ってる twitter じゃない", | |
"link": "http://mattn.kaoriya.net/web/20120829124325.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/web/20120829124325", | |
"summary": "\\nもう僕が知ってる twitter じゃなくなってきてる。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://www.itmedia.co.jp/news/articles/1208/17/news037.html\">Twitter、開発者向けガイドラインとAPI変更について説明 ユーザー数制限など厳しい内容 - ITmedia ニュース</a>\\n\\t<br />\\n\\t<p>米Twitterは8月16日(現地時間)、数週間後に予定しているTwitter APIのバージョン1.1へのアップデートと開発者向けガイドライン「Developer Rules of the Road」の改定について説明した。クライアントアプリのユーザー数に上限を設けるなど、サードパーティーにとって厳しい内容になっている。</p>\\n\\t<cite>http://www.itmedia.co.jp/news/articles/1208/17/news037.html</cite>\\n</blockquote>\\n\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://d.hatena.ne.jp/lynmock/20120828/p1\">Twitter のことと P3:PeraPeraPrv について - とかいろいろ</a>\\n\\t<br />\\n\\t<p>彼らはこのユーザーの「好みのクライアントアプリを選ぶ自由と権利」を奪うという決定をしました。</p>\\n\\t<cite>http://d.hatena.ne.jp/lynmock/20120828/p1</cite>\\n</blockquote>\\n\\nちょっと昔話をしようと思う。僕は 2007年4月から使い出してるので、結構古参の部類に入ると思う。gtktwitter という linux と windows で動く twitter クライアントをソース付きで公開した。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.kaoriya.net/software/twitter/20070412093406.htm\">Big Sky :: TwitterのGTKクライアント作りました</a>\\n\\t<br />\\n\\t<cite>http://mattn.kaoriya.net/software/twitter/20070412093406.htm</cite>\\n</blockquote>\\n\\n作った本人があまり力を入れていなかったというのもあり、gtktwitter はクライアントとしてではなく、どちらかというと WebサービスをC言語で扱う時のコード例として一部のユーザに広まった。<br />\\nその他、僕のブログには twitter API を使った物が数多くあり、その多くは今後動かなくなるかもしれない。<br />\\n当時の twitter の API 戦略は革新的だったしデータが溢れ出てくる泉だった。業界をリードしていた。そこらのWebエンジニアが味わう事が出来ないデータ量を twitter がどうさばいたかというのはデファクトスタンダードも覆す物であったと記憶している。\\n\\nその後、twitter はクライアントに「twitter」という文言を含める事を禁止し、basic認証も廃止した。\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.kaoriya.net/web/twitter/20100908165946.htm\">Big Sky :: TwitterのBasic認証廃止は約半分のデスクトップクライアントを殺した。</a>\\n\\t<br />\\n\\t<cite>http://mattn.kaoriya.net/web/twitter/20100908165946.htm</cite>\\n</blockquote>\\n\\ntwitter サポートに色々問い合わせ、エコシステムという時代の流れに納得した。<br />\\n\\n<blockquote class=\"quote\">\\n\\t<a href=\"http://mattn.kaoriya.net/web/twitter/20100910121212.htm\">Big Sky :: Twitterが考えるAPI認証とは</a>\\n\\t<br />\\n\\t<cite>http://mattn.kaoriya.net/web/twitter/20100910121212.htm</cite>\\n</blockquote>\\n\\n色々変わったが twitter はこのまま僕らエンジニアにとっての道しるべの一つになっていくのは揺ぎ無いと思っていた。しかし今の twitter もビジネス。twitter 自身が統制の取れない物は排除して当然だと思います。<br />\\n<br />\\nでも、僕の知ってた twitter はどこかに行ってしまった気がする。<br />\\nエンジニアがインターネットリソースを使って何かを試したい時、twitter は格好の題材だった。<br />\\ncurl コマンドでユーザとパスワードさえ指定すれば幾らでも動的なデータが得られ、REST構造の良い題材だった。<br />\\n今でもそれは変わらない。しかし今の twitter はどう見ても API を使わせない様に動いていると僕には感じられる。その内、API 有料なんて事になるんじゃないかと思ってもみる。<br />\\n認証が OAuth に変わって以来、簡単にインターネットリソースを使って何かする為の良い題材として twitter は少し遠のいた。もちろんbasic認証がプライバシーを守るに値する認証方法であるとは言わないが、こうやって過去を振り返ると twitter の API 戦略はここで役目を終えてしまったと言っていいだろう。<br />\\n<br />\\nこの事は Google についても同じ事が言えるな。もうあの頃の twitter では無くなってしまったのだ。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "twitter", | |
"published": "2012-08-29T12:49:00+09:00" | |
}, | |
{ | |
"title": "Ubuntu 12.04 の chromium-browser で一部の日本語が豆腐になる問題の解決方法", | |
"link": "http://mattn.kaoriya.net/software/ubuntu/20120825002034.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/ubuntu/20120825002034", | |
"summary": "\\n昨日のアップデートでfontconfigが更新された。その結果libfontconfigを使っているアプリケーションで一部のフォントファミリが豆腐状態になった。<br />\\nいろいろ調べてみた所\\n\\n<blockquote class=\"code\">\\n/etc/fonts/conf.avail/69-language-selector-ja-jp.conf\\n</blockquote>\\n\\nが\\n\\n<blockquote class=\"code\">\\n/etc/fonts/conf.d/69-language-selector-ja-jp.conf\\n</blockquote>\\n\\nにシンボリックリンクされていない事が分かった。<br />\\n\\n<blockquote class=\"code\">\\n$ sudo fontconfig-voodoo -af\\n</blockquote>\\n\\nを実行してログアウト後、ログインし直したら治った。<br />\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "ubuntu", | |
"published": "2012-08-25T00:27:00+09:00" | |
}, | |
{ | |
"title": "vim-powerline のモードインジケータを日本語にする方法", | |
"link": "http://mattn.kaoriya.net/software/vim/20120823214404.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/vim/20120823214404", | |
"summary": "\\n最近 pull-request した奴。\\n\\n<blockquote class=\"code\">\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_i</span> <span class=\"Statement\">=</span> <span class=\"String\">'挿入'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_R</span> <span class=\"Statement\">=</span> <span class=\"String\">'置換'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_n</span> <span class=\"Statement\">=</span> <span class=\"String\">'通常'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_v</span> <span class=\"Statement\">=</span> <span class=\"String\">'ビジュアル'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_V</span> <span class=\"Statement\">=</span> <span class=\"String\">'行ビジュアル'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_cv</span> <span class=\"Statement\">=</span> <span class=\"String\">'矩形ビジュアル'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_s</span> <span class=\"Statement\">=</span> <span class=\"String\">'選択'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_S</span> <span class=\"Statement\">=</span> <span class=\"String\">'行選択'</span><br />\\n<span class=\"Statement\">let</span> <span class=\"Identifier\">g:Powerline_mode_cs</span> <span class=\"Statement\">=</span> <span class=\"String\">'矩形選択'</span>\\n</blockquote>\\n\\n<blockquote>\\n<img src=\"http://go-gyazo.appspot.com/cb2d1714f05fdb27.png\" title=\"japanized-powerline\" />\\n</blockquote>\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim, powerline", | |
"published": "2012-08-23T21:44:00+09:00" | |
}, | |
{ | |
"title": "C言語から使えるJSONパーサ、JSMNを試してみた。", | |
"link": "http://mattn.kaoriya.net/software/lang/c/20120822011026.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/software/lang/c/20120822011026", | |
"summary": "\\nC++ だと picojson ばかり使っていて、JSON使うからC++かなという言語の選び方をしていたりしたのですが、今日matsuuさんのブクマ経由で見つけた。<br />\\n<br />\\n\\n<blockquote class=\"quote\">\\n <a href=\"http://bitbucket.org/zserge/jsmn\">jsmn</a>\\n <br />\\n <p>The minimalistic portable framework for parsing JSON data format.</p>\\n <cite>http://bitbucket.org/zserge/jsmn</cite>\\n</blockquote>\\n\\n特徴としては\\n\\n<ul>\\n <li>C98コンパチブル</li>\\n <li>動的なメモリアロケーションを行わない</li>\\n <li>可能な限り最小のオーバーヘッド</li>\\n <li>JSONのパースは1パス</li>\\n <li>libc も含め依存物がない</li>\\n <li>MITライセンス下で配布され、プロプライエタリなプロジェクトでも使える</li>\\n <li>単純で美しいデザイン</li>\\n</ul>\\n\\nといったところ。C言語で使える JSON パーサは実は以前にも <a href=\"http://mattn.kaoriya.net/software/lang/c/20080207205241.htm\">json-c</a> を試した事はあったのですが、あれは .c の拡張子ファイルを C++ 指定でビルドしているだけというゴニョゴニョなあれなので使い物になりませんでした。<br />\\nそんな中で見つけたこれは、実にシンプルで応用性がありそうなので記事にしたいと思います。ただし使用上の注意があるので使う人は要検討です。<br />\\nまずこの jsmn が提供する物はパーサのみ。しかもパース結果から得られるのは各トークンの位置と種別、データとして扱う際の開始終了位置のみです。えっそんなので使い物になるの?と思うかもしれませんが、実は用途によっては十分だったりもします。以下に例を示します。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Include\">#include </span><span class=\"String\"><assert.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><string.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><jsmn.h></span><br />\\n<br />\\n<span class=\"PreProc\">#define countof(x) (</span><span class=\"Operator\">sizeof</span><span class=\"PreProc\">(x)/</span><span class=\"Operator\">sizeof</span><span class=\"PreProc\">(x[</span><span class=\"Constant\">0</span><span class=\"PreProc\">]))</span><br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain() {<br />\\n jsmn_parser p;<br />\\n jsmntok_t tokens[<span class=\"Constant\">10</span>] = {<span class=\"Constant\">0</span>};<br />\\n <span class=\"Type\">char</span> buf[<span class=\"Constant\">256</span>];<br />\\n <span class=\"Type\">const</span> <span class=\"Type\">char</span>* js = <span class=\"String\">"{</span><span class=\"Special\">\\"</span><span class=\"String\">foo</span><span class=\"Special\">\\"</span><span class=\"String\">: </span><span class=\"Special\">\\"</span><span class=\"String\">bar</span><span class=\"Special\">\\"</span><span class=\"String\">, </span><span class=\"Special\">\\"</span><span class=\"String\">baz</span><span class=\"Special\">\\"</span><span class=\"String\">: [1,true]}"</span>;<br />\\n <span class=\"Type\">int</span> r;<br />\\n jsmn_init(&p);<br />\\n<br />\\n r = jsmn_parse(&p, js, tokens, countof(tokens));<br />\\n assert(r == JSMN_SUCCESS);<br />\\n<br />\\n /* 全体の型はOBJECT */<br />\\n assert(tokens[<span class=\"Constant\">0</span>].type == JSMN_OBJECT);<br />\\n<br />\\n /* 中のトークン数は4 */<br />\\n assert(tokens[<span class=\"Constant\">0</span>].size == <span class=\"Constant\">4</span>);<br />\\n<br />\\n /* 1つ目の型はSTRING */<br />\\n assert(tokens[<span class=\"Constant\">1</span>].type == JSMN_STRING);<br />\\n<br />\\n /* 1つ目の値は"foo" */<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[<span class=\"Constant\">1</span>].start, tokens[<span class=\"Constant\">1</span>].end - tokens[<span class=\"Constant\">1</span>].start);<br />\\n assert(!strcmp(buf, <span class=\"String\">"foo"</span>));<br />\\n<br />\\n /* 2つ目の型はSTRING */<br />\\n assert(tokens[<span class=\"Constant\">2</span>].type == JSMN_STRING);<br />\\n<br />\\n /* 2つ目の値は"bar" */<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[<span class=\"Constant\">2</span>].start, tokens[<span class=\"Constant\">2</span>].end - tokens[<span class=\"Constant\">2</span>].start);<br />\\n assert(!strcmp(buf, <span class=\"String\">"bar"</span>));<br />\\n<br />\\n /* 3つ目の型はSTRING */<br />\\n assert(tokens[<span class=\"Constant\">3</span>].type == JSMN_STRING);<br />\\n<br />\\n /* 3つ目の値は"baz" */<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[<span class=\"Constant\">3</span>].start, tokens[<span class=\"Constant\">3</span>].end - tokens[<span class=\"Constant\">3</span>].start);<br />\\n assert(!strcmp(buf, <span class=\"String\">"baz"</span>));<br />\\n<br />\\n /* 4つ目の型はARRAY */<br />\\n assert(tokens[<span class=\"Constant\">4</span>].type == JSMN_ARRAY);<br />\\n<br />\\n /* 4つ目のARRAYのトークン数は2 */<br />\\n assert(tokens[<span class=\"Constant\">4</span>].size == <span class=\"Constant\">2</span>);<br />\\n<br />\\n /* 5つ目の型はPRIMITIVE */<br />\\n assert(tokens[<span class=\"Constant\">5</span>].type == JSMN_PRIMITIVE);<br />\\n<br />\\n /* 5つ目の値は"1" */<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[<span class=\"Constant\">5</span>].start, tokens[<span class=\"Constant\">5</span>].end - tokens[<span class=\"Constant\">5</span>].start);<br />\\n assert(atoi(buf) == <span class=\"Constant\">1</span>);<br />\\n<br />\\n /* 6つ目の型はPRIMITIVE */<br />\\n assert(tokens[<span class=\"Constant\">6</span>].type == JSMN_PRIMITIVE);<br />\\n<br />\\n /* 6つ目の値は"true" */<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[<span class=\"Constant\">6</span>].start, tokens[<span class=\"Constant\">6</span>].end - tokens[<span class=\"Constant\">6</span>].start);<br />\\n assert(!strcmp(buf, <span class=\"String\">"true"</span>));<br />\\n}<br />\\n</blockquote>\\n\\n例を追って説明します。まず jsmn_parser を jsmn_init で初期化します。実際には構造体メンバに初期値を代入しているに過ぎません。<br />\\n初期化した jsmn_parser を jsmn_parse 引数に渡して JSON 文字列をパースします。この時、トークン数を渡す必要があります。このトークンは動的に確保されません。基本的に jsmn は内部でメモリを動的確保しません。これについての解決方法は後で説明します。<br />\\nパースされた結果はトークンの配列となります。そしてこのトークンは以下の内容で構成されます。<br />\\n\\n<ul>\\n <li>型</li>\\n <li>値を示す JSON 文字列の開始位置</li>\\n <li>値を示す JSON 文字列の終了位置</li>\\n <li>値が配列の場合のアイテム個数</li>\\n <li>値がオブジェクトの場合のキーおよび値の個数</li>\\n</ul>\\n\\nたとえば\\n\\n<blockquote class=\"code\">\\n{"foo": "bar", "baz": [1,true]}<br />\\n</blockquote>\\n\\nこの JSON をパースした場合、トークンは\\n\\n<table border=\"1\">\\n <tr><th>トークン</th><th>型</th><th>値</th></tr>\\n <tr><td>tokens[0]</td><td>JSMN_OBJECT</td><td>オブジェクト</td></tr>\\n <tr><td>tokens[1]</td><td>JSMN_STRING</td><td>\"foo\"</td></tr>\\n <tr><td>tokens[2]</td><td>JSMN_STRING</td><td>\"bar\"</td></tr>\\n <tr><td>tokens[3]</td><td>JSMN_STRING</td><td>\"baz\"</td></tr>\\n <tr><td>tokens[4]</td><td>JSMN_ARRAY</td><td>配列</td></tr>\\n <tr><td>tokens[5]</td><td>JSMN_PRIMITIVE</td><td>1</td></tr>\\n <tr><td>tokens[6]</td><td>JSMN_PRIMITIVE</td><td>true</td></tr>\\n</table>\\n\\n上記の様に、トークンは各識別毎に作られます。オブジェクトのキーおよび値もそれぞれのトークンとして格納されます。<br />\\njsmn_parse はトークンの量が不足している場合、エラー JSMN_ERROR_NOMEM を返します。例えば、どれだけの量のトークンが JSON 文字列として与えられるか分からない場合、トークンのサイズを広げる必要があります。この場合、jsmn ではパーサを再初期化する事なしに、トークンを広げて再度 jsmn_parse を実行する事でパースを続行出来る様になっています。<br />\\nただしどれだけの量が不足していたかは分からないので、適度な増減を考慮する必要があります。<br />\\n今日は試しに twitter のパブリックタイムラインをパースしてみました。<br />\\n\\n<blockquote class=\"code\">\\n<span class=\"Include\">#include </span><span class=\"String\"><assert.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><string.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><memory.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><curl/curl.h></span><br />\\n<span class=\"Include\">#include </span><span class=\"String\"><jsmn.h></span><br />\\n<br />\\n<span class=\"PreProc\">#define countof(x) (</span><span class=\"Operator\">sizeof</span><span class=\"PreProc\">(x)/</span><span class=\"Operator\">sizeof</span><span class=\"PreProc\">(x[</span><span class=\"Constant\">0</span><span class=\"PreProc\">]))</span><br />\\n<br />\\n<span class=\"Structure\">typedef</span> <span class=\"Structure\">struct</span> {<br />\\n <span class=\"Type\">char</span>* data; // response data from server<br />\\n <span class=\"Type\">size_t</span> size; // response size of data<br />\\n} MEMFILE;<br />\\n<br />\\nMEMFILE*<br />\\nmemfopen() {<br />\\n MEMFILE* mf = (MEMFILE*) malloc(<span class=\"Operator\">sizeof</span>(MEMFILE));<br />\\n <span class=\"Statement\">if</span> (mf) {<br />\\n mf->data = <span class=\"Constant\">NULL</span>;<br />\\n mf->size = <span class=\"Constant\">0</span>;<br />\\n }<br />\\n <span class=\"Statement\">return</span> mf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">void</span><br />\\nmemfclose(MEMFILE* mf) {<br />\\n <span class=\"Statement\">if</span> (mf->data) free(mf->data);<br />\\n free(mf);<br />\\n}<br />\\n<br />\\n<span class=\"Type\">size_t</span><br />\\nmemfwrite(<span class=\"Type\">char</span>* ptr, <span class=\"Type\">size_t</span> size, <span class=\"Type\">size_t</span> nmemb, <span class=\"Type\">void</span>* stream) {<br />\\n MEMFILE* mf = (MEMFILE*) stream;<br />\\n <span class=\"Type\">int</span> block = size * nmemb;<br />\\n <span class=\"Statement\">if</span> (!mf) <span class=\"Statement\">return</span> block; // through<br />\\n <span class=\"Statement\">if</span> (!mf->data)<br />\\n mf->data = (<span class=\"Type\">char</span>*) malloc(block);<br />\\n <span class=\"Statement\">else</span><br />\\n mf->data = (<span class=\"Type\">char</span>*) realloc(mf->data, mf->size + block);<br />\\n <span class=\"Statement\">if</span> (mf->data) {<br />\\n memcpy(mf->data + mf->size, ptr, block);<br />\\n mf->size += block;<br />\\n }<br />\\n <span class=\"Statement\">return</span> block;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">char</span>*<br />\\nmemfstrdup(MEMFILE* mf) {<br />\\n <span class=\"Type\">char</span>* buf;<br />\\n <span class=\"Statement\">if</span> (mf->size == <span class=\"Constant\">0</span>) <span class=\"Statement\">return</span> <span class=\"Constant\">NULL</span>;<br />\\n buf = (<span class=\"Type\">char</span>*) malloc(mf->size + <span class=\"Constant\">1</span>);<br />\\n memcpy(buf, mf->data, mf->size);<br />\\n buf[mf->size] = <span class=\"Constant\">0</span>;<br />\\n <span class=\"Statement\">return</span> buf;<br />\\n}<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nskip(jsmntok_t* tokens, <span class=\"Type\">int</span> off) {<br />\\n jsmntype_t t = tokens[off].type;<br />\\n <span class=\"Statement\">if</span> (t == JSMN_ARRAY || t == JSMN_OBJECT) {<br />\\n <span class=\"Type\">int</span> n, l = tokens[off++].size;<br />\\n <span class=\"Statement\">for</span> (n = <span class=\"Constant\">0</span>; n < l; n++)<br />\\n off = skip(tokens, off);<br />\\n } <span class=\"Statement\">else</span><br />\\n off++;<br />\\n <span class=\"Statement\">return</span> off;<br />\\n}<br />\\n<br />\\n<span class=\"Structure\">typedef</span> <span class=\"Structure\">struct</span> {<br />\\n <span class=\"Type\">char</span>* screen_name;<br />\\n <span class=\"Type\">char</span>* text;<br />\\n} tweet;<br />\\n<br />\\n<span class=\"Type\">int</span><br />\\nmain() {<br />\\n jsmn_parser p;<br />\\n jsmntok_t *tokens;<br />\\n <span class=\"Type\">size_t</span> len;<br />\\n <span class=\"Type\">char</span> buf[<span class=\"Constant\">1024</span>];<br />\\n CURL* curl;<br />\\n MEMFILE* mf = <span class=\"Constant\">NULL</span>;<br />\\n <span class=\"Type\">char</span>* js = <span class=\"Constant\">NULL</span>;<br />\\n <span class=\"Type\">int</span> i, j, k, count, off;<br />\\n tweet* tweets = <span class=\"Constant\">NULL</span>;<br />\\n<br />\\n mf = memfopen();<br />\\n<br />\\n curl = curl_easy_init();<br />\\n curl_easy_setopt(curl, CURLOPT_URL, <span class=\"String\">"<a href=\"http://api.twitter.com/1/statuses/public_timeline.json\">http://api.twitter.com/1/statuses/public_timeline.json</a>"</span>);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);<br />\\n curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);<br />\\n curl_easy_perform(curl);<br />\\n curl_easy_cleanup(curl);<br />\\n<br />\\n js = memfstrdup(mf);<br />\\n memfclose(mf);<br />\\n<br />\\n jsmn_init(&p);<br />\\n<br />\\n len = <span class=\"Constant\">5</span>;<br />\\n tokens = malloc(<span class=\"Operator\">sizeof</span>(jsmntok_t) * len);<br />\\n <span class=\"Statement\">if</span> (tokens == <span class=\"Constant\">NULL</span>) {<br />\\n perror(<span class=\"String\">"malloc"</span>);<br />\\n <span class=\"Statement\">goto</span> leave;<br />\\n }<br />\\n memset(tokens, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span>(jsmntok_t) * len);<br />\\n <span class=\"Statement\">while</span> (<span class=\"Constant\">1</span>) {<br />\\n <span class=\"Type\">int</span> r = jsmn_parse(&p, js, tokens, len);<br />\\n <span class=\"Statement\">if</span> (r == JSMN_SUCCESS) <br />\\n <span class=\"Statement\">break</span>;<br />\\n assert(r == JSMN_ERROR_NOMEM);<br />\\n len *= <span class=\"Constant\">2</span>;<br />\\n tokens = realloc(tokens, <span class=\"Operator\">sizeof</span>(jsmntok_t) * len);<br />\\n <span class=\"Statement\">if</span> (tokens == <span class=\"Constant\">NULL</span>) {<br />\\n perror(<span class=\"String\">"malloc"</span>);<br />\\n <span class=\"Statement\">goto</span> leave;<br />\\n }<br />\\n }<br />\\n<br />\\n off = <span class=\"Constant\">0</span>;<br />\\n count = tokens[off++].size;<br />\\n<br />\\n tweets = malloc(<span class=\"Operator\">sizeof</span>(tweet) * count);<br />\\n memset(tweets, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span>(tweet) * count);<br />\\n<br />\\n <span class=\"Statement\">for</span> (i = <span class=\"Constant\">0</span>; i < count; i++) {<br />\\n <span class=\"Type\">int</span> k1, k2;<br />\\n k1 = tokens[off++].size;<br />\\n <span class=\"Statement\">for</span> (j = <span class=\"Constant\">0</span>; j < k1 / <span class=\"Constant\">2</span>; j++) {<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[off].start, tokens[off].end - tokens[off].start);<br />\\n off++;<br />\\n <span class=\"Statement\">if</span> (!strcmp(buf, <span class=\"String\">"text"</span>)) {<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[off].start, tokens[off].end - tokens[off].start);<br />\\n tweets[i].text = strdup(buf);<br />\\n off++;<br />\\n } <span class=\"Statement\">else</span> <span class=\"Statement\">if</span> (!strcmp(buf, <span class=\"String\">"user"</span>)) {<br />\\n k2 = tokens[off].size;<br />\\n off++;<br />\\n <span class=\"Statement\">for</span> (k = <span class=\"Constant\">0</span>; k < k2 / <span class=\"Constant\">2</span>; k++) {<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[off].start, tokens[off].end - tokens[off].start);<br />\\n off++;<br />\\n <span class=\"Statement\">if</span> (!strcmp(buf, <span class=\"String\">"screen_name"</span>)) {<br />\\n memset(buf, <span class=\"Constant\">0</span>, <span class=\"Operator\">sizeof</span> buf);<br />\\n strncpy(buf, js + tokens[off].start, tokens[off].end - tokens[off].start);<br />\\n tweets[i].screen_name = strdup(buf);<br />\\n off++;<br />\\n } <span class=\"Statement\">else</span><br />\\n off = skip(tokens, off);<br />\\n }<br />\\n } <span class=\"Statement\">else</span><br />\\n off = skip(tokens, off);<br />\\n }<br />\\n }<br />\\n<br />\\n <span class=\"Statement\">for</span> (i = <span class=\"Constant\">0</span>; i < count; i++) {<br />\\n printf(<span class=\"String\">"</span><span class=\"Special\">%s</span><span class=\"String\">: </span><span class=\"Special\">%s</span><span class=\"Special\">\\n</span><span class=\"String\">"</span>, tweets[i].screen_name, tweets[i].text);<br />\\n }<br />\\n<br />\\n <span class=\"Statement\">for</span> (i = <span class=\"Constant\">0</span>; i < count; i++) {<br />\\n free(tweets[i].screen_name);<br />\\n free(tweets[i].text);<br />\\n }<br />\\n free(tweets);<br />\\n<br />\\n<span class=\"Statement\">leave</span>:<br />\\n <span class=\"Statement\">if</span> (js) free(js);<br />\\n <span class=\"Statement\">if</span> (tokens) free(tokens);<br />\\n}<br />\\n</blockquote>\\n\\n出力結果から分かる通り、実は jsmn はまだ <code>\\uXXXX</code> という文字列リテラルをパース出来ません。よって twitter のタイムライン上に流れるユニコード文字列は全てエスケープされたまま表示されます。<br />\\nちょっと癖があるのでフラットな JSON であれば十分役立つのですが、twitter のタイムラインの様にオブジェクト構造がネストされた物になると扱う側が常にメモリを意識しなければならないので途端に難易度があがります。<br />\\n例えばキーと値がベタに決まっていて、ネストも無いような JSON であれば少しは使い道はあるかもしれませんね。<code>\\uXXXX</code> リテラルがサポートされればもう少し使い道が出てくるかもしれません。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "C, json", | |
"published": "2012-08-22T01:14:00+09:00" | |
}, | |
{ | |
"title": "Vim人(ゔぃむんちゅ)", | |
"link": "http://mattn.kaoriya.net/etc/20120812233650.htm", | |
"id": "tag:mattn.kaoriya.net,2012:/etc/20120812233650", | |
"summary": "\\nKoRoNさんから贈り物届いた。<br />\\n\\n<blockquote>\\n<img src=\"http://mattn.kaoriya.net/images/spartan-vim1.png\" alt=\"spartan-vim1\" />\\n</blockquote>\\n<br />\\n\\n<blockquote>\\n<img src=\"http://mattn.kaoriya.net/images/spartan-vim2.png\" alt=\"spartan-vim2\" />\\n</blockquote>\\n\\nTシャツとスパルタンVim 2.0を頂きました。ありがとうございます!<br />\\n予想だにしなかった内容にガクブルです。\\n", | |
"author": "mattn (mattn.jp@gmail.com)", | |
"category": "vim", | |
"published": "2012-08-12T23:51:00+09:00" | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment