今回のあらすじ
Flex のドキュメントを、オフライン時にも使えるようにしようと企んだ nanki は、coderepos:chm-generators を手にいれ chm ファイル作ってみるが、サイズが150MBもあるので、Chemr 本体に手を加えて、gzip 圧縮に対応することによって無事50MBにまでスリム化することに成功する。が、よく使うリファレンス群はそもそもサイズが5MB程度なので、たいして役に立たないことに気がつき衝撃を受ける。
これは巨大な chm を作って対抗するしかない、とマシンにインストールされた全ての gem の rdoc をchm 化するが、今度はインデックスが大きすぎるためか検索がもたつくことに気付く。
「これでは仕事ができない!」
不当な怒りに燃えた nanki は、よりよい開発環境を手に入れるために Chemr に改造を施し、高速化することを決意したのだった。
果たして戦いの果てに未来はあるのか!?
結果
一回のインクリメンタル検索処理あたり、0.3~1秒程度かかっていたのが100倍くらい速くなった。 体感では100倍とはわからないが、もたつきが感じられないレベルになった。
インデックスの最初の二文字を抜き出してHashで持ち、検索文字列の最初の二文字でO(1)でしぼりこむ仕組み。
高速化の恩恵は最初の数文字の偏りに大きく依存すると思うけど、そもそもそんな状況では、インクリメンタル検索が快適ではないので気にしないこと。
!DOCTYPE 宣言があると外部CSSが効かない(詳細不明)問題とか、ruby-cocoaでsize/countが無限再帰になる問題とか、Chmerとtypoする問題などにも嵌って大変だった。
その後、バージョン違いがたくさん(railsだけで5個くらい)あったgemを削除しまくったので、普通に速くなってあんまり意味がない。
gem を300種類くらい入れて複数のバージョンを保持しているような人しか恩恵が得られないかも。
ちなみに、もたつきが気になるというのは、僕のタイプ速度より速く、キーリピートより遅いくらい。つまり全然支障はない。
codereposのは古いっぽい…?
参考:
僕はあんまり携帯HTMLをいじらないけど、タイトルのような問題があるという話はよく聞く。
また、CSSにはスコープの概念がないので、TinyMCEなどのWYSIWYGエディタを使っていると、Wordなどから<style>タグを含む断片が貼付けられて、ページ全体のスタイルに影響を与えてしまう、などといったことが起こる。
こういった問題への対応策として、CSSのインライン化が有効に働きそうなので、調べてみた。 参考に挙げているが、Perl/PHP では、こういったライブラリが存在しているらしい。
我らが(?)Rubyはというと、(最近遊びでCSSParserを書いたので、なければ作ろうと思ってたけど)やっぱり存在していて、これが結構便利そう。
しかし、こんな名前で公開されても…。見ても気付かないよ…
インストール
$ sudo gem install tamtam
コードがドキュメント、とばかりに、主要な部分を読んでみた。 使い方を見てみよう。
使い方
TamTam.inline
:css => '.a { background-color:red }',
:body => "<div class='a'></div>"
#=> "<div class="a" style="background-color: red;"></div>"素晴らしい。
また、:documentを使うことによって、HTML内の<style>タグの内容をそのまま使うこともできる。
TamTam.inline
:document => "<style>.a { background-color:red }</style><div class='a'></div>"
#=> "<style>.a { background-color:red }</style><div class="a" style="background-color: red;"></div>"スタイルを適用した後の余計なclass属性は、元から存在するclass名と衝突するかもしれない。
そんなあなたには、:prune_classes => trueというそれらしいオプションがあるのだが、
バグなのか何なのか、スタイルを適用する前にclassを全部取りさってしまうので(僕の)望む動きとは違うようだ。
TamTam.inline
:document => "<style>.a { background-color:red }</style><div class='a'></div>",
:prune_classes => true
#=> "<style>.a { background-color:red }</style><div></div>"
# 適用されてない!携帯電話…
携帯電話用に使う場合、<link>タグを認識する部分を自分で書かないといけない。
それと、聞いた話では、携帯電話の場合は通信量を減らすために、style='background-color: …'よりも、bgcolor='…'が好まれるそうだ。
CSSだけでは属性を指定するという使い方は出来ないので、その場合も独自に拡張する必要がありそうではある。
参考:
Canvasを使ったWii用ゲームを作ってみた (Kanasansoft Web Lab.)
Nintendo Wii に載っているOpera にはWii Remote APIなるものがあって、WiiリモコンとCanvasを使って色々できる。
うちには、OperaもWii のコントローラ(だけ)もあるのに、kanasan の力作が遊べないなんて!ありえない!
というわけで、Wii Remote API のふりをするコードを書いてみた。
WiiFake: emulate Wii Remote API on Mac OS X. from NANKI Haruo on Vimeo.
requires at runtime
- WiiRemote.framework from DarwinRemote Project
- Ruby
- Ruby/Cocoa
- Flash Player Plugin
How to use.
- Copy WiiRemote.framework to your ~/Library/frameworks/ directory.
- WiiFake を落としてくる。
- Wii リモコンの 1 2 keyを押したままサーバを起動する。
$ ruby server.rb - このbookmarkletを起動 WiiRemote bookmaklet
- 必要に応じてページの初期化処理を呼び出す。
(上記kanasanのページだと、javascript:initialize())
仕組み
bookmarklet で読み込んだ WiiProxy.swf から localhostに立てたRubyサーバに繋いで、JSON形式で受け取った情報を、javascriptの世界に渡しているだけです。
テスト
Safariでしかテストしてない;;
画質のテストのため、同じムービーをYoutubeにもアップロードしてみた。
参考:

TreetopというRubyで書かれたpackrat parserがある。
その文法ファイルをsyntax highlightするvim. これがなきゃ始まらない。
参考:
portなどでopencvを入れて、普通にやるとcxcore.h がないとか文句言われるので、
⿶ sudo gem install opencv -- --with-opencv-include=/opt/local/include/opencv
とやったらいけた。
参考:
purl にGyazoモジュールを追加しました。
デフォルト環境にはロードされないので、自分でロードする必要があります。
Purl::Purl.new のあたり。
# app/controllers/purl_controller.rb
class PurlController < ApplicationController
caches_page :filter
def filter
begin
result = Purl::StackMachine.new(
params[:commands], Purl::Purl.new{|p| p.load_feature Purl::Features::Gyazo}).run
send_data(result[-2], :type => result[-1], :disposition => 'inline')
rescue => e
render :status => 500, :text => 'error'
end
end
endコード例
/purl/(a7d96c2ff64900f507ef9c8dab99f983):gyazo:5:round:5:5:5:5:extend:5:dropshadow:to.png
:gyazo:5:round:5:5:5:5:extend:5:dropshadow:to.png)
参考:
Rails pluginとして動く言語、purlを公開しました。
purl はクライアントサイドから柔軟な画像処理を行うために開発されました。 サムネイルの生成などを行うプラグインはいくつかありますが、そのどれよりも強力で汎用性、拡張性があります。
セットアップ
Rails2.1以上では、
$ script/plugin install git://github.com/nanki/purl.git
それ未満では、
$ git clone git://github.com/nanki/purl.git -- vendor/plugins/purl
gitが無い環境なら、githubのdownloadからファイルを落として、vendor/plugins/ に配置してください。
依存ライブラリ
- 必須: ImageMagick, rmagick
- あった方がいい: cairo, rcairo
その他
purl のデフォルトの環境では、画像の保存にデータベースを利用します。 imagesテーブルに、blob型のdataカラムを追加してください。
# app/models/image.rb
class Image < ActiveRecord::Base
attr_readonly :data
endその上で、ImageController#upload などに以下のように記述します。
# app/controllers/image_controller.rb
class ImageController < ApplicationController
def upload
Image.create(:data => params[:data].read)
end
endさらに、config/routes.rbを書き替え、purl が実行されるようにします。 書く場所は先頭に近い方がいいと思います。
# config/routes.rb
map.connect 'purl/:commands',
:controller => 'purl', :action => 'filter', :commands => /.*/# app/controllers/purl_controller.rb
class PurlController < ApplicationController
caches_page :filter
def filter
begin
result = Purl::StackMachine.new(
params[:commands], Purl::Purl.new).run
send_data(result[-2], :type => result[-1], :disposition => 'inline')
rescue => e
render :status => 500, :text => 'error'
end
end
endそんなこんなでセットアップは終わり。
言語
purl はURL上で記述されることを前提としています。 常にワンライナーであれ!
文法
purl は逆ポーランド記法を採用しています。 データと命令を書かれた順番にスタックマシンにプッシュしていき、命令が実行された結果がスタックマシン上につまれていきます。 命令列は最初に:で区切られ、数字としてパースできるものは数字へ、()で囲われた部分は文字列へと変換されます。
ポリシー
デフォルトで用意される全ての命令は、外部の値に依存しません。 つまり、命令列が決まれば実行結果は確定します。 このポリシーにより、全ての実行結果がキャッシュ可能になります。
サンプルコード
画像をそのまま表示
次の例では、load はスタック上に既にある数字1を消費して、ID=1のImage#dataをデータベースからロードして、スタック上にプッシュします。 to.png では、スタック上の画像データをPNG形式のバイト列に変換し、mimetypeとともにスタック上に積みます。
/purl/1:load:to.png

画像の形式を変換
次の例では、画像をGIF形式に変換しています。
/purl/1:load:to.gif

画像のリサイズ
次の例では、画像を100x100にリサイズしています。 リサイズ用の命令は、何種類か用意されており、高さを一定に保つ resize.heightや、上限を指定する、resize.upto などがあります。
/purl/1:load:100:100:resize:to.png

画像の合成
次の例ではふたつの画像を合成しています。
/purl/1:load:9:load:composite:to.png

次の例では順番を入れ替えています。
/purl/1:load:9:load:swap:composite:to.png

コメント
スタックに積んだ後すぐにpopすると、単純に無視されるので、コメントとして使えます。 キャッシュのライフサイクルコントロールなどに使えると思います。
/purl/1:load:(daily):pop:to.png
図形の描画
詳しくは解説しませんが、試験的にcairoの描画機能をベースにした図形描画命令を用意しています。 ctx命令で、指定したサイズのcairoコンテキストを準備し、xtc命令で実際にサーフェースへの描画を実行します。
/purl/80:80:ctx:40:40:moveto:40:40:40:-20:20:arc.ccw:1:0.3:0:rgb:fill:60:20:4:circle:0:0:0:rgb:fill:xtc:to.png

制限
実行結果をファイルとしてキャッシュする場合、ファイルシステムによる字数制限を受けます。
拡張
拡張は命令モジュールの追加という形で行います。 詳しくはソースコード見てください。
今後
- 無名関数的なもの。
- 外部から直接呼び出せない命令とか?
- エラーメッセージとか?
参考:
netswitch! | 今日の.zshrc - cheat 補完 の補完関数だけど、なんだか遅いなと思ってたら間違いがあって、毎回cheatコマンドを実行していた。
元エントリ中のコードは修正済みだが、差分は以下の通り。
- echo $*[1,-2] | sed -e 's/^/compadd /g' > ~/.zsh/completion/$*[-1] + eval $*[1,-2] | sed -e 's/^/compadd /g' > ~/.zsh/completion/$*[-1] - completion_list `cheat sheets | grep -v All` _cheat + completion_list 'cheat sheets | grep -v All' _cheat
遅さに困ってた人ごめんなさい。
cheatsheet を集めた cheat という gem があって、たまに便利である。
გ gem install cheat გ cheat assertions assertions: # Credit: http://nubyonrails.com/articles/ruby-rails-test-rails-cheat-sheet # Use 'cheat assert_raise' for more details # Standard Ruby Assertions assert boolean assert_equal expected, actual assert_raise *args assert_raises *args, &block … …
cheat自身の使い方は
გ cheat cheat
どんなcheatsheetがあるのかは
გ cheat sheets
で見られる。
なんだけど、数が多すぎてもうどうしようもないので、さらに便利にするために、zshの補完を使ってみた。
見よう見まね。
completion_list () {
mkdir -p ~/.zsh/completion
if [ ! -f ~/.zsh/completion/$*[-1] ]; then
eval $*[1,-2] | sed -e 's/^/compadd /g' > ~/.zsh/completion/$*[-1]
fi
`cat ~/.zsh/completion/$*[-1]`
}
_cheat () {
completion_list 'cheat sheets | grep -v All' _cheat
}
compdef _cheat cheatcompletion_list は一応再利用できるようにしてあるけど、ちゃんと調べたら既にありそうだ。
追記:
いつまでたってもassertionsの内容が古いままだなぁと思っていたら、キャッシュしてた。
გ cheat --new
でキャッシュをクリア。
"#{"/*"}"
Ruby Code.
__END__
*/
JavaScipt Code."#{"/*"}"
Ruby Code.
__END__
*/
JavaScipt Code.他にもあると思うけど。
こういうのどうやって探したらいいんだろう。
追記:
たった二つから使っていいのかわからないが、polyglotと呼ぶらしい。