1 セットアップ
現在、Railsプラグインはジェムとして構築されます。ジェム化されたプラグインと呼ばれます。必要に応じて、RubyGemsとBundlerを使用して異なるRailsアプリケーション間で共有することができます。
1.1 ジェム化されたプラグインの生成
Railsには、ダミーのRailsアプリケーションを使用して統合テストを実行する機能を備えた、あらゆる種類のRails拡張を開発するためのスケルトンを作成するrails plugin new
コマンドが付属しています。次のコマンドでプラグインを作成します:
$ rails plugin new yaffle
ヘルプを表示するには、使用方法とオプションを確認してください:
$ rails plugin new --help
2 新しく生成されたプラグインをテストする
プラグインが含まれているディレクトリに移動し、yaffle.gemspec
を編集してTODO
の値が含まれる行を置き換えます:
spec.homepage = "http://example.com"
spec.summary = "Summary of Yaffle."
spec.description = "Description of Yaffle."
...
spec.metadata["source_code_uri"] = "http://example.com"
spec.metadata["changelog_uri"] = "http://example.com"
その後、bundle install
コマンドを実行します。
bin/test
コマンドを使用してテストを実行し、次のように表示されるはずです:
$ bin/test
...
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
これにより、すべてが正しく生成され、機能の追加を開始する準備が整いました。
3 コアクラスの拡張
このセクションでは、Railsアプリケーションのどこからでも利用できるStringにメソッドを追加する方法について説明します。
この例では、Stringにto_squawk
という名前のメソッドを追加します。まず、いくつかのアサーションを持つ新しいテストファイルを作成します:
# yaffle/test/core_ext_test.rb
require "test_helper"
class CoreExtTest < ActiveSupport::TestCase
def test_to_squawk_prepends_the_word_squawk
assert_equal "squawk! Hello World", "Hello World".to_squawk
end
end
テストを実行するには、bin/test
を実行します。このテストは失敗するはずです。なぜなら、to_squawk
メソッドを実装していないからです:
$ bin/test
E
Error:
CoreExtTest#test_to_squawk_prepends_the_word_squawk:
NoMethodError: undefined method `to_squawk' for "Hello World":String
bin/test /path/to/yaffle/test/core_ext_test.rb:4
.
Finished in 0.003358s, 595.6483 runs/s, 297.8242 assertions/s.
2 runs, 1 assertions, 0 failures, 1 errors, 0 skips
素晴らしい - これで開発を開始する準備が整いました。
lib/yaffle.rb
にrequire "yaffle/core_ext"
を追加します:
# yaffle/lib/yaffle.rb
require "yaffle/version"
require "yaffle/railtie"
require "yaffle/core_ext"
module Yaffle
# Your code goes here...
end
最後に、core_ext.rb
ファイルを作成し、to_squawk
メソッドを追加します:
# yaffle/lib/yaffle/core_ext.rb
class String
def to_squawk
"squawk! #{self}".strip
end
end
メソッドが期待どおりの動作をするかテストするには、プラグインディレクトリからbin/test
でユニットテストを実行します。
$ bin/test
...
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
これを実際に確認するために、test/dummy
ディレクトリに移動し、bin/rails console
を起動して鳴き声を聞いてみましょう:
irb> "Hello World".to_squawk
=> "squawk! Hello World"
4 Active Recordに"acts_as"メソッドを追加する
プラグインでよく使われるパターンは、モデルにacts_as_something
というメソッドを追加することです。この場合、Active Recordモデルにsquawk
メソッドを追加するacts_as_yaffle
というメソッドを作成したいと思います。
まず、次のようなファイルをセットアップします:
# yaffle/test/acts_as_yaffle_test.rb
require "test_helper"
class ActsAsYaffleTest < ActiveSupport::TestCase
end
# yaffle/lib/yaffle.rb
require "yaffle/version"
require "yaffle/railtie"
require "yaffle/core_ext"
require "yaffle/acts_as_yaffle"
module Yaffle
# Your code goes here...
end
# yaffle/lib/yaffle/acts_as_yaffle.rb
module Yaffle
module ActsAsYaffle
end
end
4.1 クラスメソッドを追加する
このプラグインでは、モデルに last_squawk
という名前のメソッドが追加されていることを期待しています。ただし、プラグインのユーザーは、すでに last_squawk
という名前のメソッドをモデルに定義して、他の用途で使用しているかもしれません。このプラグインでは、yaffle_text_field
というクラスメソッドを追加することで、名前を変更できるようにします。
まず、望む動作を示す失敗するテストを書いてください。
# yaffle/test/acts_as_yaffle_test.rb
require "test_helper"
class ActsAsYaffleTest < ActiveSupport::TestCase
def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
assert_equal "last_squawk", Hickwall.yaffle_text_field
end
def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
assert_equal "last_tweet", Wickwall.yaffle_text_field
end
end
bin/test
を実行すると、次のようになります。
$ bin/test
# Running:
..E
Error:
ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet:
NameError: uninitialized constant ActsAsYaffleTest::Wickwall
bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8
E
Error:
ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk:
NameError: uninitialized constant ActsAsYaffleTest::Hickwall
bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4
Finished in 0.004812s, 831.2949 runs/s, 415.6475 assertions/s.
4 runs, 2 assertions, 0 failures, 2 errors, 0 skips
これにより、テストしようとしているモデル(Hickwall と Wickwall)が存在しないことがわかります。ダミーのRailsアプリケーションでこれらのモデルを簡単に生成できます。test/dummy
ディレクトリから次のコマンドを実行します。
$ cd test/dummy
$ bin/rails generate model Hickwall last_squawk:string
$ bin/rails generate model Wickwall last_squawk:string last_tweet:string
次に、ダミーアプリケーションに必要なデータベーステーブルを作成するために、ダミーアプリケーションに移動してデータベースをマイグレーションします。まず、次を実行します。
$ cd test/dummy
$ bin/rails db:migrate
ここで、Hickwall と Wickwall モデルを変更して、yaffle のように動作するようにします。
# test/dummy/app/models/hickwall.rb
class Hickwall < ApplicationRecord
acts_as_yaffle
end
# test/dummy/app/models/wickwall.rb
class Wickwall < ApplicationRecord
acts_as_yaffle yaffle_text_field: :last_tweet
end
また、acts_as_yaffle
メソッドを定義するためのコードを追加します。
# yaffle/lib/yaffle/acts_as_yaffle.rb
module Yaffle
module ActsAsYaffle
extend ActiveSupport::Concern
class_methods do
def acts_as_yaffle(options = {})
end
end
end
end
# test/dummy/app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
include Yaffle::ActsAsYaffle
self.abstract_class = true
end
その後、プラグインのルートディレクトリに戻り、bin/test
を使用してテストを再実行します。
$ bin/test
# Running:
.E
Error:
ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk:
NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974ebbe9d8>
bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4
E
Error:
ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet:
NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974eb8cfc8>
bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8
.
Finished in 0.008263s, 484.0999 runs/s, 242.0500 assertions/s.
4 runs, 2 assertions, 0 failures, 2 errors, 0 skips
もう少しで完成です... これでテストが成功するようにするために、acts_as_yaffle
メソッドのコードを実装します。
# yaffle/lib/yaffle/acts_as_yaffle.rb
module Yaffle
module ActsAsYaffle
extend ActiveSupport::Concern
class_methods do
def acts_as_yaffle(options = {})
cattr_accessor :yaffle_text_field, default: (options[:yaffle_text_field] || :last_squawk).to_s
end
end
end
end
# test/dummy/app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
include Yaffle::ActsAsYaffle
self.abstract_class = true
end
bin/test
を実行すると、すべてのテストが成功するはずです。
$ bin/test
...
4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
4.2 インスタンスメソッドを追加する
このプラグインは、acts_as_yaffle
を呼び出すすべての Active Record オブジェクトに squawk
というメソッドを追加します。squawk
メソッドは、データベースのフィールドの値を単純に設定します。
まず、望む動作を示す失敗するテストを書いてください。
# yaffle/test/acts_as_yaffle_test.rb
require "test_helper"
class ActsAsYaffleTest < ActiveSupport::TestCase
def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
assert_equal "last_squawk", Hickwall.yaffle_text_field
end
def test_a_wickwalls_yaffle_text_field_should_be_last_tweet
assert_equal "last_tweet", Wickwall.yaffle_text_field
end
def test_hickwalls_squawk_should_populate_last_squawk
hickwall = Hickwall.new
hickwall.squawk("Hello World")
assert_equal "squawk! Hello World", hickwall.last_squawk
end
def test_wickwalls_squawk_should_populate_last_tweet
wickwall = Wickwall.new
wickwall.squawk("Hello World")
assert_equal "squawk! Hello World", wickwall.last_tweet
end
end
テストを実行して、最後の2つのテストが「NoMethodError: undefined method `squawk'」というエラーで失敗することを確認し、次に acts_as_yaffle.rb
を次のように更新します。
# yaffle/lib/yaffle/acts_as_yaffle.rb
module Yaffle
module ActsAsYaffle
extend ActiveSupport::Concern
included do
def squawk(string)
write_attribute(self.class.yaffle_text_field, string.to_squawk)
end
end
class_methods do
def acts_as_yaffle(options = {})
cattr_accessor :yaffle_text_field, default: (options[:yaffle_text_field] || :last_squawk).to_s
end
end
end
end
# test/dummy/app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
include Yaffle::ActsAsYaffle
self.abstract_class = true
end
最後に、bin/test
を実行し、次のようになるはずです。
$ bin/test
...
6 runs, 6 assertions, 0 failures, 0 errors, 0 skips
注意: モデル内のフィールドに書き込むために write_attribute
を使用する例は、プラグインがモデルとやり取りする方法の一例であり、常に適切なメソッドではありません。たとえば、次のようにも書くことができます。
ruby
send("#{self.class.yaffle_text_field}=", string.to_squawk)
5 ジェネレータ
ジェネレータは、プラグインのlib/generators
ディレクトリに作成することで、簡単にgemに含めることができます。ジェネレータの作成に関する詳細な情報は、ジェネレータガイドを参照してください。
6 Gemの公開
開発中のGemプラグインは、Gitリポジトリから簡単に共有することができます。Yaffle gemを他の人と共有するには、コードをGitリポジトリ(GitHubなど)にコミットし、対象のアプリケーションのGemfile
に行を追加します。
gem "yaffle", git: "https://github.com/rails/yaffle.git"
bundle install
を実行した後、アプリケーションでgemの機能が利用できるようになります。
Gemを正式リリースとして共有する準備ができたら、RubyGemsに公開することができます。
また、BundlerのRakeタスクを利用することもできます。以下のコマンドで一覧を表示できます。
$ bundle exec rake -T
$ bundle exec rake build
# yaffle-0.1.0.gemをpkgディレクトリにビルドします
$ bundle exec rake install
# yaffle-0.1.0.gemをビルドしてシステムのgemにインストールします
$ bundle exec rake release
# タグv0.1.0を作成し、yaffle-0.1.0.gemをビルドしてRubygemsにプッシュします
RubyGemsへのgemの公開に関する詳細な情報については、gemの公開を参照してください。
7 RDocドキュメント
プラグインが安定しており、デプロイする準備が整ったら、他の人のためにもドキュメントを作成しましょう!幸いなことに、プラグインのドキュメントを作成するのは簡単です。
最初のステップは、READMEファイルを詳細な情報で更新することです。含めるべきいくつかの重要な情報は次のとおりです。
- あなたの名前
- インストール方法
- アプリケーションに機能を追加する方法(一般的な使用例のいくつか)
- ユーザーの助けになる警告、注意点、またはヒント
READMEが完成したら、開発者が使用するすべてのメソッドにRDocコメントを追加します。また、公開APIに含まれないコードの部分には通常、# :nodoc:
コメントを追加することが慣例です。
コメントが準備できたら、プラグインディレクトリに移動して次のコマンドを実行します。
$ bundle exec rake rdoc
7.1 参考文献
フィードバック
このガイドの品質向上にご協力ください。
タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。
不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。
修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください。
そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。