開發 Rails plugin 的心得與筆記

為我開發的 jq4r 作個記錄。

開發 Rails plugin 其實很簡單,在 Rails app 裡的 script 就有一個 generate 的指令可以幫忙產生 plugin 的目錄結構,只要直接執行:
[code]
# ruby script/generate plugin foo
[/code]
就會在 $RAILS_ROOT/vendor/plugins 下建一個 foo 目錄($RAILS_ROOT 指的是你 rails app 的目錄),像這樣:
[code]

create vendor/plugins/foo/lib
create vendor/plugins/foo/tasks
create vendor/plugins/foo/test
create vendor/plugins/foo/README
create vendor/plugins/foo/Rakefile
create vendor/plugins/foo/init.rb
create vendor/plugins/foo/install.rb
create vendor/plugins/foo/uninstall.rb
create vendor/plugins/foo/lib/foo.rb
create vendor/plugins/foo/tasks/foo_tasks.rake
create vendor/plugins/foo/test/foo_test.rb
[/code]
如果你沒有要作特別的事,其實只需要編輯 init.rblib/foo.rb 這兩個檔案就可以了,這兩個檔案負責的事情分別是:

  • init.rb - 當你 Rails app 的環境啟動了之後(使用 script/console 或是打開 server),都會去執行 plugin 目錄中的 init.rb 檔,所以你必須在這個檔案裡做「插入」的動作,才能讓插件(plug-in)插進去。(怎麼聽起來怪怪的...XD)
  • lib/foo.rb - 預設是用來放你主要程式碼的地方,當然,只要你放在 lib 目錄下,要起什麼名字都沒關係,但記得要在 init.rbrequire 就對了。

看起來重點就在於 init.rb 的插入動作了,這裡如果你很熟悉 Ruby 這個程式語言的話,你應該很快就猜到一般常見的作法,就是用 Mix-in 的方式塞進去(我之前有寫過介紹 Mix-in 概念的文章),大多數程式語言都沒有 Mix-in 的設計,像在 Java 裡面也許大家就會採用 abstract class 的方式來作,而 Ruby's way 則是--

寫一個 module,然後在「要被插」的 class 裡去 extend/include 這個 module

但是...但是,像我的 jq4r,它今天是要插進 ActionView.Base 裡面,總不會這麼「厚工」去改 actionpack 裡 action_view 的程式碼吧!?當然啦,你要的話也是可以,但這樣一點都沒有 agile 的感覺,這時候就可以請出邪惡的 send method,所以 jq4r 的 init.rb 就會寫成這樣:


require 'jq4r'
ActionView::Base.send(:include, ActionView::Helpers::JQueryHelper)

也就是利用 send 來叫該 class 執行 :include 的動作,至於為什麼說 send 邪惡呢?因為至少在 Ruby 1.8 裡, send 可以直接呼叫 protected/private method,這樣根本就是對 OOP 基本教義派來說是「逆天」呀!

這樣一來就差不多沒什麼事要做了,如果要使用 plugin 的開發者必須先作一些動作的話,你可以寫在 install.rb 裡叫他執行,或是像我一樣寫成一個 rake task 叫他先 rake 一下。

看吧!開發 Rails plugin 根本就非常簡單呀!希望大家多多來寫更多實用的 plugins 吧~

  • sun

    按照你的步骤做了一下,但是在调用的是有提示

    undefined method `getRdlist’ for #