Sinatra AssetPackを試してみた

あるいは Kanazawa.rb meetup #23 に参加してきました。

何をしたかったか

  1. 現状では明らかに Rails に向いていないプロジェクトがある
  2. ホスティングはクラウドにしようと思うので、環境を先に決める必要がある
    • PHP でやるとか Ruby でやるとか
  3. 将来的には Rails で裏側をいじる必要あると思うんだけど、現状は表側だけで動けばいいし、Sinatra 使ってゴーじゃないか
  4. JS ヘビーになるし Sass も使いたいので Rails で言う Asset Pipeline 的なものは欲しい
  5. 「手間」は少なければ少ないほどよい

試した

  1. sprockets + sprockets-helpers
  2. sinatra-assetpack

Asset Pipeline が Sprockets を利用しているのは知っていたので Sprockets + Sprockets-Helpers がいちばん自分の既存の知識に近くて素朴な形になるんじゃないかと思って試してみたけど、結論から言うと自分の手には負えなかった。sprockets-helpers の提供する javascript_tag の展開するパスがどうしても思ったものにならない。 /assets/javascripts/application.js になってほしいのに /assets/application.js になったり /javascripts/javascripts/application.js になったり。中のコードをざっと眺めた感じでは正しく機能しそうに見えるんだけど。

実際に sprockets + sprockets-helpers でやってるというブログもいくつか見つけていたのだが、ダメだった。残念。

次に Sinatra AssetPack を試した。これは Rails の Asset Pipeline のようなものを Sprockets を利用せずに Sinatra 独自に実現するもの。後で気づいたけど、Sinatra のサイトで紹介されているのはこの方法なので、当然こっちの方がうまくいきやすそうである…。

Sinatra Recipes - Asset Management - Sinatra Assetpack

Sinatra AssetPack と Sprockets の比較

Sprockets は JavaScript ファイル、CSS ファイルの中に依存性を記述し、それを Sprockets が解決するという形なのだが、Sinatra AssetPack は Sinatra アプリ側に依存性を記述する。使い方としてはここがいちばん違う。書き方としてはこんな感じになる。

assets do
  serve '/assets/javascripts', from: 'assets/javascripts'

  js :app, '/javascripts/appication.js', [
    '/assets/javascripts/a.js',
    '/assets/javascripts/b.js'
  ]

  js_compression :jsmin
end

いろいろなJSライブラリを使いたいお

と思ったのならBowerを使うのがよさそう。

Bower

うーんイマドキ。

※ Rails には http://rails-assets.org/ という選択肢もあるけど、あれも結局 Bower 依存なので、Bower がいいんだろなという感じ。このように自分はすでに Rails で学んだ知識をもとにいろいろ類推して考える傾向にあるが、Rails にはいろいろな知が集まってくるので、この方法はとても効率がよいと考えている。Bower も名前は知っていてもピンと来ていなかったが、rails-assets のおかげで、ストンと理解できるようになった。

bower_components/ 以下の目的の JavaScript ファイルを上の依存ファイルの Array の中に納めてやればよい。

例えば jQuery 1.x を使いたかったら以下のような感じ。

bower.json

{
  "name": "myproj",
  "dependencies": {
    "jquery": "1.10"
  }
}

で、

bower install

これで試した時点で jQuery 1.10.2 が入る。

Sinatra AssetPack 側は以下のように bower_components も扱えるようにしてやる。

assets do
  serve '/assets/javascripts', from: 'assets/javascripts'
  serve '/bower_components',   from: 'bower_components'

  js :app, '/javascripts/appication.js', [
    '/assets/javascripts/a.js',
    '/assets/javascripts/b.js',
    '/bower_components/jquery/jquery.min.js'
  ]

  js_compression :jsmin
end

※ なんで 1.10 にしてあるかというと以下の production を試した時に 1.11 だとエラーになってしまうから。

Sinatra AssetPack でもう少し遊んでみて気づいたこと

  • rackup –env production で Asset Pipeline のように一つの JS にまとめてくれる
  • rake task も用意してあるので、いい具合に Rakefile に設定してやると rake assetpack:build が利用できる
  • rake assetpack:build すると coffee -> js 変換後のファイル、およびこれらを全部ひとまとめにした ファイルを生成してくれる
  • この生成済みのファイルがある場合はこれをそのまま serve してくれる
  • ない場合は動的に変換し、変換済みのコードをメモリにキャッシュして serve してくれる
  • jsmin は obsolete なので他のもの使った方がよいらしい

まとめ

とりあえずこれでフロントヘビーなプロジェクトでも手軽に PaaS に対応したサーバを用意しつつ、Rails の Asset Pipeline のように少ない手間で CoffeeScript や Sass などの恩恵に与ることができるようになった。よかった。

例えばこれが PaaS が node.js に対応しているならイマドキのフロントエンドっぽく全部 node.js で、bower + grunt

  • なんちゃらな感じで賄うこともできると思うんだけど、今回は Ruby か PHP というのが条件なので、Ruby を選択したうえでどうにかするという方針で調べた結果、Sinatra + Sinatra AssetPack という形になった。

結論 : 下手にググらずに本家ドキュメント読め。

The Final RubyKaigiに途中参加してきた

日本Ruby会議2011(7月16日〜18日)

諸般の事情により2日目から3日目の途中までという形にはなったけれども、最後の RubyKaigi に参加してきた。もちろんせっかくだからというミーハーな理由で。

聞いた話

  • テスト
  • RubyKaigi

を中心に聞いた。この二つは単純に今の興味の中心だから。

もう一つ、若い人の話を聞きたかったので同時開催のアンカンファレンスの方にもちょっと顔を出したりしていた。これは、

もうぼくはおっさんだからだ。

笑うところじゃないよ。おっさんが自分のために答えを探しにだけ Kaigi に出るのはどうなんだろうという思いもあったんだ。「この人に話を聞いてほしいと思われるようにならなきゃなー」となんとなく思っている。そうでなきゃぼくは若い人から何かを吸収する機会を失ってしまう。それはとても怖いことだ。

出会った人

ちょっと全部は書けないので抜粋で。

ネットだけの15年来の知り合いというか師匠に会うことができた。これはすごいことだった。会えても何の不思議もないのに、予期せぬ出来事だった。ぼくの師匠は普通に歩いていました。

もう一つ、E和の人にお会いできた。これは会えたらいいなと思っていた人たちだったし、スタッフだから会えるに決まってると思っていた。ありがとう、ぼくがこの間 Rails アプリを仕上げることができたのはあなたたちのおかげです。(いや、他にも目標や憧れの人はいたし、参考になる情報をくれた人もいっぱいいたし、その人たちの中の何人かにもお会いできましたけど。)そして普段追っかけをしてる人たちに「会えて嬉しい」と言ってもらえたことがとても嬉しかった。

そしてこの日記を参考にしてると言ってくれる人にも何人か出会えた。なんだか不思議な感じだった。割といいリアクションをくれる人が多かった。

この日記で使っている tDiary のたださんにもお会いした。本物のモヒカンだった(笑)

ついでじゃないけど !tDiary会議にも参加した。tDiary の先端は After Rails な世界の恩恵に与るために最初の学習コストが上がってしまってるんだな、やっぱり、とか思ったりした。

考えたこと

最近の悩み

考えたら…。そうだなぁ、多少金も時間も掛かってその捻出にもコストが掛かったとしても、イベントには出た方が単純にいいね。小遣い制なら天引きしてもらえばいいというくらいに出ておいた方がいい。そしてできればそのイベントは単なるセミナーじゃない方がいい。泊まれるなら泊まって懇親会に出た方がいい。

今回の Kaigi、ミーハーな理由と最初に書いたけれど、裏のテーマもあった。

  • Kaigiやコミュニティとはつまりなんなのだろう
  • 自分は何がしたいのだろう、あるいは何が不満なのだろう
  • 自分にできることはなんだろう

要するに悩んでいた。

悩みには二種類あったことに Kaigi に参加して気づいた。

  1. 職場内の話
  2. 地域の話

これ以上は長くなるので控えるけど、この二つは似ているようで違う話なんだと気づけたことは間違いなく収穫だった。自分の周りの環境という意味ではよく似ているが、だいぶ違う話になるはずだ。

発表のチャンスは多い方がいい

今回のRubyKaigiには

  • 講演
  • LT
  • アンカンファレンス

の4つの発表のチャンスがあった。これ実はすごいことだと思う。チャンスが多い。ハードルも下げやすい。

発表しちゃうと懇親会のネタができる。出会いやすい。

まぁ人数が多いからチャンスを増やすことができるってのもあるけど。

感じたこと

Rubyistたちはみな楽しそうだった。kakutaniの口からRubyKaigiなくてもなんとかなんじゃね?という言葉が出たからなのか、みんなそんなに不安は感じてなかったんじゃないか。

知らない人がたくさんいた。しかもあの場にいたRubyistは全Rubyistのごく一部に過ぎないのかと思うと、なんだか不思議な感じだ。家に帰ってきたので、もう自分の目の前にはあんなに楽しそうにRubyistがぎゅうぎゅうになっちゃってるような状況は存在しない。でも集めると場所の確保に困っちゃうくらいにはいるってことは実感できた1。しかも彼らはイヤイヤRuby書いてるわけじゃないし、マゾなんじゃないかってくらいにテスト環境、テストデータについて真剣だったり、ライブラリやプロトコルの実装を大真面目に語れるし、改善もできるし、ドキュメント書くし、サービスをホストする。ちょっとゆるいとこもあるけど。

なんだろう、あれは。あそこは地続きだよね。いや、国内という意味じゃなくて、Rubyistの歩く道としてジェット機とか乗らなくても続いてるはずの場所なんだ。

実は今でも自分をRubyistと名乗ることには躊躇する。コミッタでもなければ代表作もない。でもRubyKaigi参加したことあるよ、って今後言えるようにはなった。自分に自信がなくてもKaigiのブランドは使える。便利。いやいや、冗談だけど。

ちょっとだけ安心したのは間違いない。少なくともあの場にいることに違和感はなかった。まぁRubyKaigi出るのにRubyistである必要なんてないし、何の資格も要らないんだけど。ビビっててもそうでなくても関係ないし、スピーカーもけっこう緊張してて、別に違う世界の人じゃない。あーやっぱりそんなにみんな違わないんだなーって思った。これは小さな再確認だけど、確実に前進だと思う。少なくとも自分に対してはみんな同じだと言えるし、他の人にも言ってあげられると思う。

ありがとうRubyKaigi

「モヤモヤしてるんです」と、ぼくはあんなに楽しい場でkakutaniに愚痴っていた。彼は「難しいんすよね」と言ってくれた。難しいと実感していた。これは実は大きな意味があった。自分がやっていることが難しいことなのか単に自分の力不足なのか、それとも環境の問題なのか、もう分からなくなってしまっていたからだ。

難しいことならそういう覚悟でやればいい。できなくても仕方ないさ、だって難しいんだから。自分のせいでも周りのせいでもない。だって難しいんだから。

難しくてもより良い方向を目指すチャレンジは誰にでもできる。継続できるか分からないし成功するか分からないけど、そういう種類のものであるという認識、覚悟とともにあればよい。成功しないとへこむけど、仕方ないさ、だって難しいんだから。

それとは別に「やればできること」は始めてしまえばよい。完璧なテストは書けなくても、自動テスト可能な状態を一度は目指してみることはいつでも始められるチャレンジだ。完璧な状態である必要はない。不安が減ればよい。

これは自分だけかもしれないけど、成功した話ばかりを追いかけると、成功しない自分を追い込んでしまうことがあるように思う。それはいいことじゃない。成功しなかった事実は受け止める必要があるけど、へこむことは必要なことじゃない。

面白いことに、Ruby は未だに導入にすらゴチャゴチャとした理由の要る言語だ。これってつまり Rubyist の多くは悩んでるってことじゃないか? えーとつまりあいつらみんな悩んでんだな。こう思うと、これはなんか変な話だけど自信がつくよね。だってみんな悩んでんだもん。おれだけじゃねーもん。

自分が Ruby を触り始めた頃にはそれほど仕事を語ることってなかったように思う。でも今は堂々と仕事の話をする人が多い。そしてたぶんそこには悩みはある。

ぼくは「ぼっち」だと思っていたし、現実の戦場ではやはり「ぼっち」だ。でも、ぼくの仲間は実在していた。同じ言語やライブラリを使っているとか、同じ楽しさを知っているとか、そういう意味でも仲間だけれど、たぶん似たような悩みを抱えたという意味でも仲間なんじゃないか。ある人は Ruby の仕事をしたいから転職したし、ある人は独立したし、ある人は起業したし、ある人は説得した。そこには少なからず悩みはあったと思う。そりゃそうだ。Ruby はたのしいし、仕事をたのしくするけど、仕事が「たのしい」ばかりのはずはない。

ぼくは今回、感極まっていない。Matz のキーノートも聞いていない2。でも収穫はあった。ありがとう。また行きます。RubyKaigi じゃなくても。そう思える程度には、迷ったり悩むだけではなくなったと思う。簡単に吹っ切れたとは言えないけど、たぶん一歩、あるいは半歩、いやもっと小さい歩幅かもしれないけど、前進したんじゃないかな。

そう思いたい。

  1. yugui本も売れてたのでまだ入門したての人も多いかもしんないけど。 

  2. 帰りの飛行機の関係です。聞く気がなかったわけじゃないよ。 

Bundler 0.9.26 を触ってみた

あぁ、快適だ。例え Windows でも画面もキーボードも小さくても、Emacs バインドで書ける喜び1

Bundler との出会い

先日、pear packageでアプリの依存ライブラリを管理するようにし始めたわけですが、もとはと言えばこれは jruby-appengine を調べていたときに知った

Bundlerがめっちゃ便利そう

というところからスタートしています。

もともと依存パッケージは管理する必要があると感じていたわけですが、とりあえずリストアップして README 辺りに書いてありゃいいのかなぁとか軟弱なことを思ったりしていました2。しかし jruby-appengine を調べたときには

  • 必要な gem も含めて全部勝手に deploy されてるらしい
  • bundle っていう gem がなにやら超絶便利らしい

ということを知り、どうにか勉強しなきゃと思っているうちにまた半年が経っていました3

インストールと基本的な使い方

Bundler: The best way to manage Ruby applications

gem install bundler
bundle help

ですね。

Bundler でできること

  • 依存している gem package を Gemfile というファイルで管理できる4
  • Gemfile をもとに bundler が download、install を行うことができる
  • download した *.gem パッケージを cache することができる ( bundle package )
    • install の際には gem server だけでなく、この cache も利用することができる
  • local にも remote にも Bundler を入れておくことで、deploy 時に自動的に依存 gem も更新することができる
  • Bundler を利用したライブラリの読み込みのサポート ( Bundler.setup )

Bundler: The best way to manage Ruby applications

この辺に書いてあるのですが、group に分けておいた gem package 群を必要に応じて require することができるようです。例えば test 用のライブラリは開発環境でだけ読み込む、といったことを個別に記述することなく Bundler.setup だけで実現できる。らしいです。自分はそこまでたどり着いてはいないのですが。

deploy ツールと連携して remote の gem を管理する

実は当初、bundle package でできる cache/*.gem さえあればいいのかと勘違いしていました。でもそんなことないですよね。そりゃそうだ。実際には

bundler を使って gem をインストールする際に cache/*.gem があれば gem サーバを見にいかなくて済むよ

という話でしかありません。

また、remote での gem のインストールも Bundler によって自動化されるのではなく、

remote にインストールされている Bundler を呼んでくれる deploy ツールによって実現されています。

そりゃそうか。

そりゃそうかの連続。そりゃそうかの連続なんだけど、この仕組みを思いついた人はやっぱり頭いいなぁ。

逆に言うと deploy ツールがない場合は開発環境の準備が多少楽になるよ、程度の意味しかありません。たぶん。まぁそれも重要なんですけど。依存パッケージをいちいち調べたり、動かし始めてからアレがないコレがないという状態になるのはとてもイライラしますから。

Bundler 1.0 へ

ROADMAP というファイルを読むと、今後は 0.10, 1.0 と進んでいくようで、0.9 からは API は変更しない模様。逆に言うと 0.9 の間は変更し放題かな? 実際、0.9.4 と 0.9.5 の間に断絶があるらしいです。

他の環境への応用を考える

Ruby で deploy ツールと言えばもちろん Capistrano 系になるわけですが、これらは基本的に shell アクセスを要求します。repository からコードを取得してサーバを再起動するまで全自動で行います。スバラシイ。

では shell アクセスが不可能な場合はどうしたらよいのでしょう。例えばレンタルサーバでの CGI や PHP 開発では?

PHP の場合は

  • include_path さえ通っていれば、ライブラリの読み込みはできる
  • include_path は .htaccess からスタートするアプリケーション動作の流れの中で定義できる
  • Pear package は pure PHP で書かれていることが保証されており、単に extract しただけで使える
  • Pear package は gem のように複数バージョンを管理することはできない

という感じなので、

  1. 指定の package を取得してきて
  2. package を extract して
  3. アプリケーションのコードと一緒に put

できるだけでいいはずです。例えばこの最低限度の機能が実現できれば deploy ツールがなくてもアプリケーションとその依存パッケージを同時に deploy できます。

pecl とか使う場合は build もサーバの再起動も必要になるので話は変わってきますが、星の数ほどあるレンタルスペースベースの小規模 PHP 案件はこれで十分ですし、小規模こそ、この辺りの作業に掛ける手間は減らすべきです5

やっぱり PHP にこそ欲しいですねぇ、これ。

参考

  1. 下書きを netbook + Evernote で書きました。 

  2. 一方で、システムを丸ごと再現する際には個々のアプリの情報なんか知ったこっちゃなくて、結局何が要るの?ということで現在入っている pear の list をもとに手作業で入れ直しとかするんですよね。これも非常にダサいです。 

  3. このときの様子は delicious 上にしか残っていません。 

  4. 名前は変更できる 

  5. そうでないと数をこなせない 

TC/TT の gem ができてる

Twitter しか見てなかった RubyKaigi の様子で知った。

09:49:55 <tdtds> Tokyo Cabinet/Tyrantのgemはうれしいなぁ #rubykaigi

なんですって!

$ gem search -r tokyo

*** REMOTE GEMS ***

careo-tokyocabinet
careo-tokyotyrant

のことかな。もちろん良い子のみんなは

gem sources -a http://gems.github.com

してるよね!

PHP 4 からの移行の手だて

例によって未来の日記を書く。

そうはいっても移行は簡単ではない - よくきたblog

今回はほぼ全面的に賛成。

問題は大きく分けて二つで、

  1. 現在動いているものを PHP 5 に移行させるためには基本的に PHP 4 でも 5 でも問題なく動くようにしないと移行できない
  2. つまり両方の検証環境を用意しないといけない

かな。

で、1 だけでも大変なんだけど、実は 2 がかなり大変。つまり、4 から 5 へのアップグレード自体が不可能なケースもあり得るので、システムのダウンタイムをどれだけ短くしたうえでリプレイスを行うか、という判断が必要になることがある。これはもはや開発者だけの話では済まない。

例えば Apache を変更せずに済むなら二つのバージョンの違う mod_php を抱えた Apache を別ポートで動かして rewrite するだけで対応できる場合もあるし、Apache そのもののバージョンや関連するライブラリの影響で、jail や VPS のような環境を用意して移行準備をしなければいけない場合もあるだろうし、極端な話 OS の根っこから入れ直しになる場合もある。IP アドレスも機械も潤沢に余ってて何の苦労もないならまったく別な機械を新規に立てて新しい環境をガシガシ作ってそのまま移行すればいいけど、そうでなかったら?

ただ、常に二つ以上のバージョンを動かせる用意はしておくべきだよね、とは思う。そのとき、常に物理的に別な機械を用意できるとは限らないので、仮想化の技術は絶対にあった方がいいなと思った。新しい環境の準備が楽だし。あと自動でバージョンが上がって自動で動作チェックを行うような仕組みを用意できるならしておくといいね。ここまでできてるところはかなりレベル高いと思う。できればそういうところで働きたいもんだ。

ところで、「もっと洗練された開発環境」って具体的になんだろう、ドキドキ。

PHP 4.4.0 か

またもやのファイルアップロード周りのバグや segmentation fault やら無限ループやらの修正がほとんど。4.3.x じゃないのは SORT_LOCALE_STRING フラグの追加が入ったのが大きいのかな?

http://nx.eth.jp/hiki.cgi?PHP-Changes-4.4.0

Real Legacy Software Archive

へー。

OS X 用の RealPlayer 10 が落ちまくりで何もできないので旧版を探していたら、本家にあったのね。なかなかよいじゃん。しかし Mac には Real Alternative とか QuickTime Alternative とかないのがちょっとつらいな。Windows Media はすこぶる順調に動いている。さすが MS の Mac 部隊は Real とは違う。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm