1 設定
目前,Rails 插件是以 gem 的形式建置,即gemified 插件。如果需要,它們可以使用 RubyGems 和 Bundler 在不同的 Rails 應用程式之間共享。
1.1 產生一個 Gemified 插件
Rails 隨附 rails plugin new
命令,該命令會建立一個骨架,用於開發任何類型的 Rails 擴展,並能夠使用虛擬 Rails 應用程式執行整合測試。使用下列命令建立您的插件
$ 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 擴展核心類別
本節將說明如何將方法新增至 String,該方法將在您的 Rails 應用程式中的任何地方可用。
在此範例中,您將新增一個名為 to_squawk
的方法至 String。首先,建立一個新的測試檔案,其中包含一些斷言
# 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 將 "acts_as" 方法新增至 Active Record
插件中常見的模式是將名為 acts_as_something
的方法新增至模型。在此案例中,您想要撰寫一個名為 acts_as_yaffle
的方法,該方法會將 squawk
方法新增至您的 Active Record 模型。
首先,設定您的檔案,讓您具有
# 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)。我們可以透過從 test/dummy
目錄執行以下命令,輕鬆地在我們的「虛擬」Rails 應用程式中產生這些模型
$ 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
然後,您可以返回您插件的根目錄 (cd ../..
),並使用 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 新增實例方法
此插件會將名為 'squawk' 的方法新增至任何呼叫 acts_as_yaffle
的 Active Record 物件。 '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
執行測試,以確保最後兩個測試因包含「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
寫入模型中的欄位只是插件如何與模型互動的一個範例,而且並非總是適合使用的方法。例如,您也可以使用
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
# Build yaffle-0.1.0.gem into the pkg directory
$ bundle exec rake install
# Build and install yaffle-0.1.0.gem into system gems
$ bundle exec rake release
# Create tag v0.1.0 and build and push yaffle-0.1.0.gem to Rubygems
若要瞭解更多關於發佈 gem 至 RubyGems 的資訊,請參閱:發佈你的 gem。
7 RDoc 文件
一旦你的外掛程式穩定,並且準備好部署,請幫大家一個忙,將其文件化!幸運的是,撰寫外掛程式的文件很容易。
第一步是更新 README 檔案,其中包含有關如何使用你的外掛程式的詳細資訊。以下是一些需要包含的重點:
- 你的姓名
- 如何安裝
- 如何將功能新增至應用程式(幾個常見用例的範例)
- 可能可以幫助使用者並節省時間的警告、注意事項或提示
一旦你的 README 內容完善,請瀏覽並將 RDoc 註解新增至開發人員將使用的所有方法。通常也會將 # :nodoc:
註解新增至未包含在公開 API 中的程式碼部分。
一旦你的註解準備好,請導覽至你的外掛程式目錄並執行
$ bundle exec rake rdoc