Rails Guides のプラグインの作り方を実行していく俺手順(1)

参照: The Basics of Creating Rails Plugins

上記のドキュメントは現時点で work n progress な状態で(当たり前だけれど)親切な書き方はされていないし、情報にも抜けがあるように見える。実際に試して、動く手順をメモしていく。利用している環境はちょっとバージョンが古い等あるんだけれど、流れを確認するだけなので気にしない。

準備

先ずは下準備。手軽な sqlite 環境で環境を整える。rvm +pow利用が前提。システムの gem を汚さないように gemset も分ける。また今回は gem にすることは考えず、vendor/plugins 以下にプラグインを実装していくやり方。

$ rails new rails3-plugin
$ cd ~/.pow
$ ln -s ~/rails3--plugin .

$ cd
$ rvm gemset create rails3-plugin
'rails3-plugin' gemset created (/Users/hogehoge/.rvm/gems/ruby-1.9.2-p290@rails3-plugin).
$ echo 'rvm 1.9.2-p290@rails3-plugin' > rails3-plugin/.rvmrc
$ cd rails3-plugin
==============================================================================
= NOTICE                                                                     =
==============================================================================
= RVM has encountered a new or modified .rvmrc file in the current directory =
= This is a shell script and therefore may contain any shell commands.       =
=                                                                            =
= Examine the contents of this file carefully to be sure the contents are    =
= safe before trusting it! ( Choose v[iew] below to view the contents )      =
==============================================================================
Do you wish to trust this .rvmrc file? (/Users/hogehoge/repos/rails3/rails3-plugin/.rvmrc)
y[es], n[o], v[iew], c[ancel]> y
$ gem install bundler --no-ri --no-rdoc
$ bundle install
Fetching source index for http://rubygems.org/
(以下略)
$ rake db:migrate
$ rake test

yaffle プラグインの作成。

$ rails generate plugin yaffle
      create  vendor/plugins/yaffle
      create  vendor/plugins/yaffle/MIT-LICENSE
      create  vendor/plugins/yaffle/README
      create  vendor/plugins/yaffle/Rakefile
      create  vendor/plugins/yaffle/init.rb
      create  vendor/plugins/yaffle/install.rb
      create  vendor/plugins/yaffle/uninstall.rb
      create  vendor/plugins/yaffle/lib
      create  vendor/plugins/yaffle/lib/yaffle.rb
      invoke  test_unit
      inside    vendor/plugins/yaffle
      create      test
      create      test/yaffle_test.rb
      create      test/test_helper.rb
$ rake test:plugins
$ cd vendor/plugins/yaffle/
$ rake test
Loaded suite /Users/hogehoge/.rvm/gems/ruby-1.9.2-p290@rails3-plugin/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started
.
Finished in 0.613646 seconds.

1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 62222

準備は続く。

プラグインディレクトリ直下にある init.rb をいじる。plugin として動作する際、最初にこのファイルが読み込まれるようだ。plugin を生成すると、プラグインと同名のファイルが lib/ 直下に作成されているのでこれを require するようにしておく。この例で言うと lib/yaffle.rb で、プラグインとしての初期化処理などはこの yaffle.rb で行うのが慣例と言うことかな。これはプラグインの構成によって違うんだろうな。

取り敢えず、require するようにだけしておく。

cd vendor/plugins/yaffle
vi init.rb
require "yaffle"

準備というより決めの問題なんだけれども、テストをどのようにするか決めておく必要がある。少なく十テストの実行方法が2パターンあるようだ。rails の test:plugins を利用する方法と、プラグインディレクトリ内で rake test する方法。最小構成にしたいと考えると、そもそもダミーの rails 環境なんか要らなくて、rails generate plugin で作成したディレクトリの中で rake test すれば良いと思うのだけれど、RAILS_ROOT 上で rake test:plugins した場合とプラグインディレクトリ内で rake test した場合の挙動が微妙に違う(ーー;

今回は慣れているやり方、つまり RAILS_ROOT 上で rake test:plugins を実行する方でやってみる。因みに特定のプラグインのテストのみを行う場合には rake test:plugins PLUGIN=hogehoge とすれば hogehoge プラグインのみテストを実行できるようだ。今回の場合は rake test:plugins PLUGIN=yaffle と言うことになる。

これで大体準備が完了。

プラグイン機構を通じての String クラスの拡張

3 Extending Core Classess から、これを利用して元のクラスを拡張していくなどの作業をして行く。先ずは String クラスに to_squawk メソッドを追加する。最初にテストを書く。

vi test/core_ext_test.rb
require 'test_helper'

class CoreExtTest < Test::Unit::TestCase
  def test_to_squawk_prepends_the_word_squawk
    assert_equal "squawk! Hello World", "Hello World".to_squawk
  end
end

これでテストを実行するが当然失敗する。(因みに自分は vim 使うので、vim のコマンドモードから :! (cd ../../../; rake test:plugins PLUGIN=yaffle) してプラグインを実行している)

Loaded suite /Users/hogehoge/.rvm/gems/ruby-1.9.2-p290@rails3-plugin/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started
E.
Finished in 0.695106 seconds.

  1) Error:
test_to_squawk_prepends_the_word_squawk(CoreExtTest):
NoMethodError: undefined method `to_squawk' for "Hello World":String
    /Users/hogehoge/repos/rails3/rails3-plugin/vendor/plugins/yaffle/test/core_ext_test.rb:5:in `test_to_squawk_prepends_the_word_squawk'

2 tests, 1 assertions, 0 failures, 1 errors, 0 skips

Test run options: --seed 54426
rake aborted!
Command failed with status (1): [/Users/hogehoge/.rvm/rubies/ruby-1.9.2-p290/bin...]

Tasks: TOP => test:plugins
(See full trace by running task with --trace)

ガイドによると、これで開発の準備が出来たとのこと。未実装のコードに対するテストを最初に書くというのを実践しているわけですね。

さて、最初に lib/yaffle.rb で lib//core_ext を require しろとのこと。ってコード見たら違うな…。lib/yaffle/core_ext をrequire していますね。

vi lib/yaffle.rb
require 'yaffle/core_ext'

module Yaffle
end

最後に lib/yaffle/core_ext.rb で to_squawk メソッドを実装する。というか、yaffle ディレクトリ作るから module Yaffle していたのね。ガイドにはmkdir しろっていう指定は無い。実際この時点でこの module が必要かは怪しい所なんだけどw、後々使うようなので大人しくしたがっておく。

mkdir lib/yaffle
vi lib/yaffle/core_ext.rb
String.class_eval do
  def to_squawk
    "squawk! #{self}".strip
  end 
end

これでテストを実行して成功

Loaded suite /Users/hogehoge/.rvm/gems/ruby-1.9.2-p290@rails3-plugin/gems/rake-0.9.2.2/lib/rake/rake_test_loader
Started
..
Finished in 0.757923 seconds.

2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 11068

実際の挙動を見るには RAILS_ROOT で console して to_squawk を実行してみれば良い

(cd ../../../; rails console)
Loading development environment (Rails 3.0.10)
ruby-1.9.2-p290 :001 > "Hello World".to_squawk
 => "squawk! Hello World"

今回は取り敢えずここまで。