ruby Archive
YouTubeの音声をiTunesに転送する
年の瀬になんかちゃっちゃと作りたかったので、単機能musicalみたいなtaifuというスクリプトを書きました。
これは何?
YouTubeでかっこういい動画を見つけたときに、iTunesで音だけでも聴きたい!な時は割とあるかと思いますが、それを実現するスクリプトです。実行権限を追加して
taifu http://www.youtube.com/watch?v=KPWfBfFFrwsx
で、wavデータを標準のエンコーダ設定でエンコードして何事もなかったようにiTunesに追加します。(要VLC.app)
タグ情報はどうなってるの?
「TAIFU_NAME」「TAIFU_ARTIST」「TAIFU_ALBUM」の名前でタグ付けされているので、iTunes上から「TAIFU」で検索したら追加された曲が見つかるはずです。あとは自分の好みのタグ情報に更新ください。オプションで渡すことも考えたけど、iTunes上で編集したほうが楽だったのでやめました。
「あーこれいつでも聴いていたいな〜」なものを見つけたとき、ご利用ください!
rb-appscriptを利用してwavデータを自動的にiTunesにタグ情報付きでエンコード、ライブラリに追加
musical 0.0.2リリース
musicalの0.0.2をリリースしました。(インストールなんかの細かい話はこちら)
リッピングしたwavデータを自動的にiTunesのエンコード設定(mp3/AAC/Appleロスレス...)に従ってエンコードし、アーティスト名とDVDタイトル名を与えることでタグ情報付きでライブラリに追加します。たとえばDVDをドライブに入れた状態で、次のように実行します。
musical --title "TOUR あいのわ" --artist ハナレグミ
そうすると、
- チャプタごとにvobでリッピング
- wavに変換
- iTunesライブラリにwavを追加
- エンコード設定に従ってタグ付きでエンコード
の順に処理がすすみ、最終的にはiTunesのライブラリにこのように取り込まれます。
各チャプタのタイトルは今は自動にタグ付けする仕組みはないので、そこは自前で編集を。ここもうまく自動化したいのですが、DVD自身にはトラック情報を持っていないので、amazonなりから情報をうまく吸い出すなりいい方法を模索してます。
--title, --artistを与えない場合は、それぞれ「LIVE」「ARTIST」の名前でタグ付けされます。また、半角スペースを挟む情報の場合(上の例だと、「TOUR あいのわ」)は、「"」と「"」で囲って渡してあげます。
rubyからiTunesを操作
iTunesを操作する処理については、rb-appscriptを利用しています。rb-appscriptは、AppleEventをブリッジしてrubyから扱えるようにしたライブラリで、AppleScriptに対応したアプリケーションは、全て制御することができます。
一見、すごく便利で万能すぎるように思えるんですけど、ドキュメントが全くないのが辛いとこ。(単純にファイルをライブラリに追加するだけでも相当苦労しました。) 基本的に、method_missingで実装されているので、APIを把握してないと何も開発できません。。最初は、AppleScriptのAPIをdeveloper.apple.comからAPIを探しまくってたのですが、全然見つからなくて途方に暮れてたら意外にも手元にすでに存在してました。
「アプリケーション」「ユーティリティ」から「Appleスクリプトエディタ」を起動し、「ウィンドウ」>「ライブラリ」から「iTunes」を選択すると、AppleScript用のAPIが表示されます。(ちなみに裏技的に、Appleスクリプトエディタのアイコンに、iTunesのアイコンをD&Dしてもこのライブラリウィンドウは起動します。すごい使いづらいですけど。。)
これを元に、上で述べたファイルを追加+エンコードの基本的な操作をまとめるとこんなかんじになります。
見てわかる通り、割と直感的な操作が可能になっていると思います。基本的にはgetで情報を取得、setで更新し、このときにAppleEventが発行されています。(なので、できるだけget/setの数は減らすほうがイベント発行の節約になって、パフォーマンスが上がる)
また、普段irbやpryなんかで簡単な操作をしているときに、APIを確認するまでもなく、ざっとプロパティを確認することくらいはもうちょっと手軽な方法で確認できます。ASDictionaryをインストールしておくと、各オブジェクトに対してhelpメソッドを利用できます。たとえば、現在iTunes上で選択中のトラック、current_trackには次のようなプロパティが存在することを確認できます。
$ pry
[1] pry(main)> require 'appscript'
=> true
[2] pry(main)> include Appscript
=> Object
[3] pry(main)> its = app("iTunes.app")
=> app("/Applications/iTunes.app")
[4] pry(main)> its.current_track
=> app("/Applications/iTunes.app").current_track
[5] pry(main)> its.current_track.help
==============================================================================
Help (-t)
Reference: app("/Applications/iTunes.app").current_track
------------------------------------------------------------------------------
Description of reference
Property: current_track (r/o) : track -- the current targeted track
Terminology for track class
Class: track -- playable audio source
Plural:
tracks
Inherits from:
item (in iTunes Suite)
Properties:
container (r/o) : reference -- the container of the item
id_ (r/o) : integer -- the id of the item
index (r/o) : integer -- The index of the item in internal application order.
name : unicode_text -- the name of the item
persistent_ID (r/o) : string -- the id of the item as a hexidecimal string. This id does not change over time.
album : unicode_text -- the album name of the track
album_artist : unicode_text -- the album artist of the track
album_rating : integer -- the rating of the album for this track (0 to 100)
album_rating_kind (r/o) : :user / :computed -- the rating kind of the album rating for this track
artist : unicode_text -- the artist/source of the track
bit_rate (r/o) : integer -- the bit rate of the track (in kbps)
bookmark : short_float -- the bookmark time of the track in seconds
bookmarkable : boolean -- is the playback position for this track remembered?
bpm : integer -- the tempo of this track in beats per minute
category : unicode_text -- the category of the track
comment : unicode_text -- freeform notes about the track
compilation : boolean -- is this track from a compilation album?
composer : unicode_text -- the composer of the track
database_ID (r/o) : integer -- the common, unique ID for this track. If two tracks in different playlists have the same database ID, they are sharing the same data.
date_added (r/o) : date -- the date the track was added to the playlist
description : unicode_text -- the description of the track
disc_count : integer -- the total number of discs in the source album
disc_number : integer -- the index of the disc containing this track on the source album
duration (r/o) : short_float -- the length of the track in seconds
enabled : boolean -- is this track checked for playback?
episode_ID : unicode_text -- the episode ID of the track
episode_number : integer -- the episode number of the track
EQ : unicode_text -- the name of the EQ preset of the track
finish : short_float -- the stop time of the track in seconds
gapless : boolean -- is this track from a gapless album?
genre : unicode_text -- the music/audio genre (category) of the track
grouping : unicode_text -- the grouping (piece) of the track. Generally used to denote movements within a classical work.
kind (r/o) : unicode_text -- a text description of the track
long_description : unicode_text
lyrics : unicode_text -- the lyrics of the track
modification_date (r/o) : date -- the modification date of the content of this track
played_count : integer -- number of times this track has been played
played_date : date -- the date and time this track was last played
podcast (r/o) : boolean -- is this track a podcast episode?
rating : integer -- the rating of this track (0 to 100)
rating_kind (r/o) : :user / :computed -- the rating kind of this track
release_date (r/o) : date -- the release date of this track
sample_rate (r/o) : integer -- the sample rate of the track (in Hz)
season_number : integer -- the season number of the track
shufflable : boolean -- is this track included when shuffling?
skipped_count : integer -- number of times this track has been skipped
skipped_date : date -- the date and time this track was last skipped
show : unicode_text -- the show name of the track
sort_album : unicode_text -- override string to use for the track when sorting by album
sort_artist : unicode_text -- override string to use for the track when sorting by artist
sort_album_artist : unicode_text -- override string to use for the track when sorting by album artist
sort_name : unicode_text -- override string to use for the track when sorting by name
sort_composer : unicode_text -- override string to use for the track when sorting by composer
sort_show : unicode_text -- override string to use for the track when sorting by show name
size (r/o) : integer -- the size of the track (in bytes)
start : short_float -- the start time of the track in seconds
time (r/o) : unicode_text -- the length of the track in MM:SS format
track_count : integer -- the total number of tracks on the source album
track_number : integer -- the index of the track on the source album
unplayed : boolean -- is this track unplayed?
video_kind : :none / :movie / :music_video / :TV_show -- kind of video track
volume_adjustment : integer -- relative volume adjustment of the track (-100% to 100%)
year : integer -- the year the track was recorded/released
Elements:
artworks -- by index
==============================================================================
=> app("/Applications/iTunes.app").current_track
実際は、さきほどのAppleスクリプトエディタのヘルプ情報から引っ張ってきて表示しているだけですが、都度手元で確認できるのは便利です。ざっとAPI全体を眺めて把握した上で、手元で動かしながら動作を確認するのが開発を進める方法として良さそうです。
今後の予定
当面、次の内容くらいはどうにかしたいです。
- iTunesのライブラリに追加したとき、変換前のwavファイルをライブラリ上から削除
- 副音声の扱いを制御
- テストを追加
- トラック名を自動追加
あとrb-appscriptめちゃめちゃ可能性を感じるので、こいつでもうちょっと遊んでみたいですね。API見ているだけでムフムフします。。!
DVDデータをチャプタ毎にリッピング/wav変換するLionに対応したgem 'musical'
musicalというgemを作りました。
これは何?
「Mac OSXでライブDVDをmp3ファイルに変換」にも書いたのですが、僕はアーティストのライブDVDを買って思う存分鑑賞した後は、mp3/AACに変換してiTunes/iPhoneで聴くという楽しみ方をよくしています。 ところが、この変換の際に肝である0SExというソフトがMac OSX 10.7(Lion)になってから動かなくなりました。理由は明確で、0SExはPPC用にビルドされたバイナリなのでRosetta上では動作していたのですが、LionになってRosettaが取り除かれてしまったことで動作しなくなりました。Rosettaの代用品も存在せず、途方に暮れていたのですが、既存のソフトウェアの組み合わせでなんとかできることがわかったので、自分が使いやすい形にmusicalというgemの形でまとめてみました。
musicalができることが単純で、
- チャプタごとのリッピング
- チャプタごとのwavファイルの変換
- (オプションとして)タイトル/チャプタ情報の出力
だけです。個人的には2.のwavの変換を行ったあとに、iTunesにD&DでAACに変換を行っているので、ここまでの処理を行おうか迷ったのですが、利用する音声フォーマットは個々人に任せたほうがいいと思ったので、wav変換までで止めています。
(2011.11.27 追記) 0.0.2でiTunesの設定に従ってエンコード、ライブラリ追加まで行えるようにしました
インストール
必要ソフトウェアのインストール
musicalはバックエンドでdvdbackup, ffmpegを利用しているので、これらをインストールしておきます。homebrewでインストールできます(後述しますが、ちょっと罠があります)。
brew install dvdbackup brew install ffmpeg
gemのインストール
毎度おなじみの
gem install musical
で、OKです。
利用方法
一番シンプルなのは、DVDドライブにDVDを入れた状態で
musical
だけで、カレントディレクトリにチャプタ毎にwavファイルができあがります。
wavはいらない!リッピングだけでいいんだけど
musical --ignore-convert-sound
で、リッピングだけ行い、wavへの変換は行いません。
保存する場所を変更したいんだけど
musical --output=save/to/path --title=DVD_title
--output, --titleオプションを利用できます。オプションについては--helpでご確認ください。
musical --infoが何も表示されないんだけど
DVDにプロテクトがかかっているので、Fairmountなどを使って、ディスクイメージとしてマウントすれば大丈夫です。
ライブラリのインストール時の注意
dvdbackup
brew installで簡単にいく。。と思いきや、依存パッケージのlibdvdreadのインストールでコケました。これは単純にURLが変更になっていたので、
brew edit libdvdread
して、
@@ -3,7 +3,7 @@ require 'formula' class Libdvdread < Formula homepage 'http://www.dtek.chalmers.se/groups/dvd/' # Official site is down; use a mirror. - url 'http://www.mplayerhq.hu/MPlayer/releases/dvdnav/libdvdread-4.1.3.tar.bz2' + url 'http://www.mplayerhq.hu/MPlayer/releases/dvdnav-old/libdvdread-4.1.3.tar.bz2' md5 '6dc068d442c85a3cdd5ad3da75f6c6e8' depends_on 'libdvdcss' => :optional
こんなかんじで編集した後、brew install libdvdreadしなおしたら大丈夫です。
ちなみにこの内容は(人生初の)pull requestを送ってみたので、もしかしたら今後は取り込まれるかもしれませんね。
(2011.11.11追記) pull requestは取り込まれたので、brew updateしたらformulaを編集しなくてもインストールできると思います。
ffmpeg
これもbrew installで簡単にいく。。と思いきや、最新のXcodeでgccが無くなった + pod2manの実行権限がなぜか無くなっていたことでかなりハマりました。あらかじめgccをインストールしなおした上で、こんなかんじでインストール可能です。
# 関連するものを含めて、一度アンインストール brew uninstall --force `brew deps ffmpeg` # なぜか実行権限無くなっていたので再設定 sudo chmod +x /usr/bin/pod2man # gccの利用を指定 brew install --use-gcc ffmpeg
基本的にこれでいけるはずなんですけど、依存関係上一緒にインストールされるlibxvid, libmp3lameあたりでコケた場合(実際、別のLionのマシンで試したらコケた)は、最悪これらのインストールをスキップしても大丈夫です。brew edit ffmpegで
depends_on 'yasm' => :build
...
#depends_on 'lame' => :optional
...
#depends_on 'xvid' => :optional
...
#args << "--enable-libmp3lame" if Formula.factory('lame').installed?
...
#args << "--enable-libxvid" if Formula.factory('xvid').installed?
こんなかんじでコメントアウトたらビルドも通り、動作が確認できました。
最後に
当然ながら、本gemは著作権違反の手助けをするためのものではありません。自身の責任の元、ご利用ください。
MacRubyとLLVMを導入してRubyでネイティブGUIアプリを作る
(2011/1/23 23:00追記) macrubycはLLVMから入れなくてもmacrubyをインストールするだけで一緒にインストールされます。下記内容は誤りを含んでいますのでご注意ください。ご指摘いただいたwatson1978さん、ありがとうございました。
最近Macアプリケーションが気になっていて、Cocoa周りの話を調べています。その一環でRubyでMacアプリを作る方法についての話です。
MacRuby
Mac上でRubyでアプリケーションを作る場合、最初からインストールされてあるRubyCocoaと、最近盛り上がっているMacRubyの2通りの手段があります。 どちらもCocoaを含むいろんなフレームワークをRubyから直接叩けるのですが、RubyCocoaはプロキシオブジェクトを介してCocoaフレームワークを叩くのに対して、MacRubyはプロキシを必要とせずに直接Objective-Cのメソッドにアクセスできるのが大きな特徴です。 実装方法として、MacRubyはRubyランタイムからObjective-Cのランタイム関数を直接呼び出すことで実現しているようです。 感覚的に考えてもRubyCocoaと比べて、MacRubyの方がパフォーマンスが大きく改善されていることが期待できるので、MacRubyで遊んでみたいと思います。
rvmの利用
MacRubyの本家サイトにはインストーラのpackageファイルがあるのですが、もっと手軽に試してみるにはrvmの利用がおすすめです。rvmは複数のRubyを共存させるツールで、いろんなバージョンのRubyを切り替えて使いたいときは必須ツールです。 同僚のmirakuiさんが詳しい記事を書いているので、rvm自身のインストールなど詳細な情報はそちらを参照ください。
ではMacRubyをrvmでインストールしてみます。MacRubyの最新バージョンは2011年1月22日現在で0.8なのですが、rvmのバージョンを最新にしないとバージョン指定でインストールできないようです。
$ rvm update --head $ rvm reload $ rvm install macruby-0.8 $ rvm use macruby-0.8
バージョンを確認してみて、次のような出力が得られるとインストール成功です。
$ ruby -v MacRuby 0.8 (ruby 1.9.2) [universal-darwin10.0, x86_64]
あとGUI系のライブラリを利用するためにHotCocoaのgemもインストールしておきます。
$ gem install hotcocoa
Hello World!
まずは簡単なHello Worldアプリをつくってみます。「ruby hello_world.rb で」ウィンドウ上にボタンを表示し、ボタンクリックでHello Worldをputsさせます。
MacRubyはKernelモジュールにframeworkメソッドを追加しているので、このメソッドでCocoa機能を呼び出します。 あとのコードも大体読めばわかる程度のレベルだとおもいます。Objective-Cだと抵抗あるRubyエンジニアもこれだとMacアプリも怖くないですね!
MacRubyコンパイラを利用してネイティブアプリ化する
このままだとただのRubyスクリプトなので、これをネイティブアプリ化します。
(2011/1/23 23:00追記、macrubycはmacrubyに梱包されているので、LLVMからインストールする必要はありません。一応、備忘録のために導入方法だけ残しておきます。)
ネイティブアプリ化を行うためには、LLVMが提供するツールのmacrubycを利用します。macrubycはMacRubyをインストールするだけだと使えないので、LLVMのビルド、インストールが必要です。
LLVMはバージョンに依存するようで、僕の場合はrvmのサイトの内容を参考にして、次の手順で導入できました。
$ svn co -r 106781 https://llvm.org/svn/llvm-project/llvm/trunk llvm-trunk $ cd llvm-trunk $ env UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" CC=/usr/bin/gcc CXX=/usr/bin/g++ ./configure --enable-bindings=none --enable-optimized --with-llvmgccdir=/tmp $ env UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" CC=/usr/bin/gcc CXX=/usr/bin/g++ make -j2 $ sudo env UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" CC=/usr/bin/gcc CXX=/usr/bin/g++ make install
makeのときに追加しているj2オプションの「2」の値はビルドを行うCPUのコア数に合わせて最適化を行ってみてください。なお、このビルドは1時間近くかかるので、時間があるときに試すのをおすすめします。
$ which macrubyc /usr/local/bin/macrubyc
のようにエラーがなく結果が返ってくればインストール成功です。
では、早速先ほどつくったhello_world.rbをコンパイルしてみましょう。コンパイルは簡単で次のコマンドでコンパイルできます。
$ macrubyc hello_world.rb -o hello_world
これでhello_worldという名前の実行可能ファイルができるので、
$ ./hello_world
で、実行できます。無事、ウィンドウが表示されましたね!
まとめ
rvmでMacRubyは簡単に導入することができるので、Objective-Cを諦めていて人もRubyで手軽にMacアプリの作成を試すことが確認できました。 また、LLVMを導入することでネイティブアプリも作成することができるので、RubyでのMacアプリケーション開発の可能性の大きさも伺えますね!
redisでユーザをfollowしたときにTimeLineをsortして再構築
前回のつづき。
課題の1つに挙げてた中で、「Followした瞬間に、そのユーザの過去のTweetを自分のTLに追加できていない」というのがありましたが、こんなかんじでいいのかな。自分のTLに他人のTLを混ぜて、sortしてstoreし直し。(redis-rbが0.2.0じゃないと動かないかも)
def merge_timeline(user_id)
my_id = @login_user[:id]
return if @redis.type?("uid:#{user_id}:posts") == "none"
user_statuses = @redis.lrange("uid:#{user_id}:posts", 0, 100)
user_statuses.each do |status|
@redis.lpush("uid:#{my_id}:home", status)
end
@redis.sort("uid:#{my_id}:home", :order => "desc alpha", :store => "uid:#{my_id}:home")
end
でも、そうしたあとにremoveしたときにまた再構築し直さないと駄目なことに気づいた。。と、いうかremove面倒ですねぇ、どうするんだろう。泥臭く全statusを走査し直しなのか、それとも順序付Setとか使えば楽にremoveできるのかな。また考え直しです。
あと、このupdateについて、github上のRedTweetのコードもpushし直してますので、興味ある方はご確認ください。
redisとRailsでTwitterクローン「RedTweet」を作りました
前回「Mac OSXにredisをインストール」で、redisを動かす環境まではできたので、せっかくなんでテスト的に何かサービスを作ってみよう、ということでTwitterクローンのRedTweetを作ってみました。
redisを使ったTwitterクローンは、PHP版のRetwisと、それをSinatraで書き直したRetwis-RBがあるのですが、サンプルコードはいくらっても世の中に少しは役立つだろうと思ってRails版で実装してみました。オンラインで動作できる環境はないので、git cloneしてscript/serverで手元の起動で確認ください、、と投げやり気味ですみません。とりあえず次の項目は一通り実装しています。
- ユーザID発行
- Login / Logout
- Follow / Remove
- 自分のTimeline, Public Timeline, 各ユーザのTimelineの閲覧
ちなみにRedTweetって名前はRedisとTweetを混ぜて直感でつけた名前で、git pushしたあとで同じ名前のサイトがあることが発覚したくらい直感でつけた名前です。
目的
さて、今回はまじめにTwitterクローンを作ることが目的ではなくて、実際は、次の項目を目的として実装してみました。
- Retwisのデザインを読んで、それに従って一通り実装してみる
- redisのAPIの仕様を学ぶ
- RDBを一切使わない、NoSQLでWebサービスを作るためのノウハウを身につける
結局全て似通った話になるのですが、上記のデザイン仕様書はTwitter的なサービスを作り上げることで、KVSをどのように利用すればいいのか、がかなり分かりやすく説明されてあるので、いい勉強になりました。また、ユーザ情報はString, 各TLはList, Following/FollowerをSetで管理することで、redisの主要なAPIを網羅できたことも、redisの学習に役立ちました。
と、同時に課題もすでに見えていて、
- スケーリングがどこまでできるかはまだ手元で理解できていない
- やっぱりActiveRecord的にラップしたライブラリは必須
- Followした瞬間に、そのユーザの過去のTweetを自分のTLに追加できていない
なんかが今の段階で挙げられます。1.はテストデータを作ることで解決するはず。2.はやっぱりmustだなぁ、と思えるところまでははっきりした理解で、ユーザ名をIDから引くときなど毎回決まったprefixがついたkeyから探索するのは冗長すぎてやってられません。OhmというHashとObjectのマッピングライブラリもあるので、このあたりも1度使ってみたほうが良さそうだな、というところ。3.はFollowした瞬間に一定数TweetをListにLPUSHして、そのlistの中でSORTすればいいのかな??正直、SORTまだよくわかってません。
まとめ
というわけで、課題は多いものの、redisとRailsで最低限の動作をするものは実装できました。NoSQLでもサービスを作り上げることは理解できたので、Ohmなど、他のライブラリも使ったりすることで、 redisの利点をもっと伸ばして理解を深めたいな、というところですね。
Mac OSXにredisをインストール
Tokyo Cabinet / Tokyo Tyrantに代表されるKey-Value Storage,いわゆるKVSは多くのプロダクトが乱立してなかなか違いを理解するのも難しい状況になりつつあるのですが、ここ数日はredisに注目をしています。redisとは何ぞやというと、公式サイトには次のような特徴が挙げられています。
- memcachedのようないわゆるKVS
- valueにはStringだけではなく、List, Setも利用できる
- データに対するpush/pop, add/removeのような操作はすべてatomicな操作
- 通常はメモリ上で動作するが、定期的にデータをディスクに書き出す(常に書き出すような設定も可能)
- Master-Slaveのレプしケーションをサポート
- Ruby, Python, Perl, Java...などの各言語のバインディングを用意
と、かなり豪華なスペックで、なんでもかかってこい!なプロダクトです。国内の利用例はまだ聴いた事無いですが、海外ではgithubやCraigslistが採用したことでここ最近有名になってきました。
さて、そんなredisの開発環境を整えてみたいと思います。環境はMac OSX 10.5。
redisのインストール
ソースコードから入れてもいいのですが、Macの場合は、MacPortsでインストール可能です。
$sudo port -d sync
で、インストールリストを最新の状態にしておいて
$sudo port install redis
で、インストールされる、、はずなのですが、僕の環境だと途中で止まりました。
$ sudo port install redis ---> Fetching redis ---> Attempting to fetch redis-1.2.2.tar.gz from http://redis.googlecode.com/files/ ---> Verifying checksum(s) for redis ---> Extracting redis ---> Configuring redis ---> Building redis ---> Staging redis into destroot ---> Creating launchd control script ########################################################### # A startup item has been generated that will aid in # starting redis with launchd. It is disabled # by default. Execute the following command to start it, # and to cause it to launch at startup: # # sudo launchctl load -w /Library/LaunchDaemons/org.macports.redis.plist ########################################################### ---> Installing redis @1.2.2_0 ---> Activating redis @1.2.2_0 Error: Target org.macports.activate returned: couldn't open "/opt/local/var/log/redis.log": no such file or directory Error: Status 1 encountered during processing.
なんかlogディレクトリがないみたいなので、ディレクトリ作成してから一度アンインストールしてやりなおしてみます。
$ sudo mkdir /opt/local/var/log $ sudo port uninstall redis $ sudo port install redis ================================================================== * To start up a redis server instance use this command: * * redis-server /opt/local/etc/redis.conf * ================================================================== ---> Cleaning redis
これで、インストールできました。サービスに登録したい場合は、途中のログに書いてあるとおり、
sudo launchctl load -w /Library/LaunchDaemons/org.macports.redis.plist
で、OKです。
Rubyのバインディングのインストール
僕は普段Rubyを使うので、Rubyのバインディングもあわせてインストールしてみることにします。gemでインストール可能です。
sudo gem install redis
redisの起動
redisを起動するときは、redis-serverを実行します。MacPortsでインストールした場合、/opt/local/bin にバイナリがインストールされてあるので
sudo /opt/local/bin/redis-server /opt/local/etc/redis.conf
で、起動します。confの中には、起動するときのポート番号や、ディスクに書き出すタイミングや条件などの設定項目があります。(ちなみに、起動時に設定ファイルのパスを与えていますが、これはビルド時?に設定しておけば、実行時に与える必要は無いようです。ただ、MacPorts利用時もそれが可能なのかどうか?は不明です)
では、実際に動作を確認してみたいとおもいます。確認するときは、redis-serverと同じ場所にあるredis-cli, またはtelnetで6379に対して接続してコマンドを入力します。(今回はtelnetで接続して生のコマンドを叩いて確認してみます)ValueをStringとして扱うときは、
set
set foo 3 bar +OK get foo $3 bar
listとして扱うときは、lpush
lpush artists 8 fishmans +OK lpush artists 9 clammbon +OK lpush artists 7 polaris +OK lrange artists 0 -1 *3 $7 polaris $8 clammbon $8 fishmans
Listの要素追加もStringの要素追加と同じでO(1)で実現できるのがredisのポイントですね。実際の細かなコマンドの仕様については、リファレンスを参照ください。
ここまでざっと環境構築まで確認できたので、次回はもうすこしredisを使い倒してその結果をまとめたいと思います。
CakePHPとRuby on Railsの違い
最近、仕事でRailsを使い始めたので、今までよく使っていたCakePHPとどこが一緒でどこが違うのかをざっくりまとめてみました。まだRailsは勉強中なので、理解が不十分だったり間違っている箇所もあるかと思いますが、それらの点についてはコメントなどでご教授いただければ幸いです。
Controller
CakePHPの場合、任意のアクションにおいて、/users/show/katsuma のように、URLで「/」で区切られているものは、アクション以降の文字列も勝手に引数に分けてくれます。なので、アクション側の定義で
function show($id, $name)
のように引数を分けて定義しておいてあげれば、勝手に値が割り当てられることになります。
Railsの場合はconfig/routes.rbで振り分け方法を定義しておいてあげる必要があります。上の例だと
map.connect 'users/show/:id/:name', :controller => 'users', :action => 'show'
こんな感じになるでしょうか。
一方で、Railsの場合、routes.rbはものすごい強力で、map.connetのかわりに好きな名前のメソッドを指定するだけで「(名前)_url」で指定したcontroller, actionなどを含むURLを作成することなんかできたりします。たとえば
ActionController::Routing::Routes.draw do |map| map.berryz '', :controller => "berryz", :action=> "show" end
こんな感じにroutes.rbで定義しておいた上で、
berryz_url(:id => 'miyabi')
で呼び出すと、
http://localhost:3000/berryz/show/miyabi
を意味することになります。Railsすごい。。。!
また、GETで引数指定で渡ってきたも、routes.rbで指定された引数も、すべて param[:hoge]のシンボル指定で取得できるのも特徴でしょうか。
ApplicationController
CakePHPの場合、任意のControllerクラスの継承元であるApplicationControllerは "app/" ディレクトリ直下に "application_controller.php" の名前で設置されます。
Railsの場合は、"app/controllers/" の中に "application.rb"の名前で設置され、その場所と名前が微妙に異なります。
この名前については、これ規約からも外れてるよなぁ。。と思ってたら、どうやらRails 2.3.0からは"application_controller.rb"に名前が変わるようですね。詳しい話はこちらに書いてました。(参照元:そういえば ApplicationController ってファイル名の規約を守ってなかったんだな)
View(レイアウト)
CakePHPの場合、大枠のレイアウトはviews/layouts/default.ctp に、そのレイアウトのHTMLを記述します。
Railsの場合は、views/layouts/application.rhtmlに記述することになり、その名前は異なります。統一性の観点から言うと、Railsのこの名前の方が個人的には好きです。
部分テンプレート
CakePHPの場合、部分テンプレート(element)は、views/elements/ 以下に header.ctp の名前で保存しておきます。elementの呼び出す場合は、View側で
$this->element('header')
の、ように呼び出します。
Railsの場合は、特定のcontroller内での共通テンプレート、全controllerでの共通テンプレートとそれぞれ別に分けることができます。 前者の場合は、 views/user/_header.rhtml のように、"views/controller名/_{部分テンプレート名}.rhtml"の形式になります。 逆に後者の場合、views/shared/_header.rhtmlのように、"views/shared/_{部分テンプレート名}.rhtml" の形式になります。
部分テンプレートの呼び出し方は、前者の場合は、<%=render :partial=>'header'/> のように、後者の場合は :partialで指定する値が"shared/header"のようになります。
この点については、Railsはここまで細かい指定がなくてもいいのにな、、と思います。Cakeの方が直感的な規約だし、呼び出し方も簡単かな、と。
Filter
Cake,Railsともにcontrollerにおいて、その前後にフィルタをかけることが可能です。いわゆるbeforeFilter, afterFilterですね。 Cakeでは特定のController、またはApplicationControllerにおいてbeforeFilter/afterFilterアクションを定義しておくことで、そのフィルタを通すことが可能です。
Railsの場合、フィルタにはメソッドはもちろんですが、クラス、ブロックの3つのレベルで指定可能です。また、複数のフィルタが定義されている場合は、その定義された順番にフィルタが適用されます。
このRailsの細かな指定は凄い、としか言いようがないかんじ。特にブロックで渡すことができる柔軟性は使いこなせばすごく便利そうな印象です。(まだ自分はそこまで使いこなせてません)
静的ファイル
CakePHPの場合、画像やCSSファイルなど、静的ファイル(や、routes.phpのルーティングに外れるもの)は、"webroot/" 以下に設置しておけばOKです。
逆に、Railsの場合は、"public" ディレクトリに設置することになり、そのディレクトリ名が異なっています。
これについては、Railsを意識しまくったCakeとしては、どうしてここの名前だけ変えたのかはよく分かりません。。。
まとめ
ざっと目につきやすい相違点をまとめてみました。Railsについてはまだまだ触り始めたばかりなので、相違点はまだまだあるでしょうし、注意して理解を深めて行きたいと思います。 また、今回こうやって相違点を考えていくことで、むしろお互いの理解が深まるんじゃないかな、とも思っています。
ちなみに、チュートリアルについて、book.cakephp.orgは日本語化されてるわけですが、guides.rubyonrails.orgは日本語化されてないんでしょうか?? すごくよくまとまってそうなので、できれば日本語で読んでみたいのですが。。
Rubyでブックマークカウンタの修正スクリプト書きました
(追記 : 2009/02/12) ソースはgithubでホスティングすることにしました。
ここ最近、このBlogで使ってるソーシャルブックマークカウンタで、deliciousの数がぜんぜん動いていませんでした。どうもドメイン変わった時期の前後あたりから、APIでかえってくるJSONのパースにコケているようで、Perlのモジュールの手を出す方法がさっぱり分からなかったので途方に暮れてました。で、暮れてばっかりだとアレなのでRubyの勉強がてら修正スクリプト書いてみました。超素人コードですけど。
仕掛けは単純で、プラグインをインストールするとmt_bookmark_countってテーブルができるので、そこのbookmark_count_delicous_counter, bookmark_count_total_counterをがしがしupdateさせてるだけです。deliciousのAPIへはまとめて15個URLづつリクエスト投げてます。13, 32行目あたりのDB情報、URL情報を適当に直したら動くんじゃないかな、と思います。
ただ、このBlogのMTもバージョンは超古くて3.3とかだし最近のMTのバージョンでこのプラグインが動くかどうかも定かではないです。。あくまでオレオレパッチ。もしご利用されたい方がいらしたら使ってみてください。要MySQL/Rubyですが、次のサイトに従ってインストールすると楽にできました。
動かし方は上のリンクの圧縮ファイルを解凍し、ruby delicious.rb で動くと思います。あとはサイトを丸ごと再構築すればdeliciousのカウンタも反映されるはずです。
まともにRubyでコード書いたの初めてだったですけど、個人的にはPerlよりも書きやすかったかも。割とさくさく書けて楽しかったです。さらっとツール書くのは便利ですね。
Mac OSXで初めてのRubyを始めてみました
Rubyの勉強を始めてみたくなったので、O'REILLYの「初めてのRuby」
を購入してみました。MacPortsで最新版のRubyを導入しつつ、1章から読み進めているのですが、早速ハマったところがあるのでそのメモを残しておきたいと思います。
Ruby1.9の導入
MacPortsでruby19の名前でインストールできます。
sudo port -d install ruby19
/usr/bin/ruby には、元からインストールされているrubyが入っているので、これをMacPortsでインストールしたものと入れ替えます。(シンボリックリンク張り替えちゃったけどこれでいいのかな?ruby_selectみたいのないのかな)
cd /usr/bin sudo mv ruby ruby.org sudo ln -s /opt/local/bin/ruby1.9 ruby
ruby --version
と、入力して
ruby 1.9.1 (2008-10-28 revision 19983) [i386-darwin9]
こんなかんじの出力になればOKだと思います。
日本語(マルチバイト)の利用
1.5.4制御式のあたりについて。通常だとマルチバイト文字の利用でエラーがでちゃいます。たとえば
p "こんにちわ!こんにちわ!><"
で、
odd.rb:8: invalid multibyte char (US-ASCII) odd.rb:8: syntax error, unexpected $end, expecting keyword_end
などとエラー文が出力されてしまいます。 これは、次のように冒頭に利用するエンコード方式をコメントで書けばOK
#!/usr/bin/ruby
を
#!/usr/bin/ruby # coding: UTF-8
に変更すればOK。
tkパッケージの利用
1.5.5のコールバックのあたりの話。実は冒頭のインストール方法だとtkパッケージがインストールされていないため、利用できません。(require文でコケる) なので、tkパッケージを有効にして入れ直します。variantsオプションで有効なインストールオプションを確認します。
$ port variants ruby19
ruby19 has the variants:
universal
c_api_docs: Generate documentation for Ruby C API
tk: Build using MacPorts Tk
mactk: Build using MacOS X Tk Framework
tk, mactkと似たようなものが2つあります。これ両方有効にしてインストールするとコケちゃいます。とりあえずmactkの方を有効にしてインストールしなおし。
sudo port install ruby19 +c_api_docs +mactk
ところがこれだとエラーでコケます。
Error: The following dependencies failed to build: doxygen graphviz pango urw-fonts
いろいろビルドに失敗しているみたいなので全部個別にインストール。
sudo port install urw-fonts sudo port install pango sudo port install graphviz sudo port install doxygen
この上で、もう一度インストールしなおし。
sudo port install ruby19 +c_api_docs +mactk
これで次のrequire文でコケません。
require "tk"
まとめ
ちょっとづつRubyもわかってきました。これから毎日1章づつくらいのペースで進めていきたいとおもいますよ!
