`

script/plugin

阅读更多
well, 由於我跟 Rails 不熟,所以很多地方只能憑空臆測,如果有誤也望請指點。很多跟 Rails 有直接關係的細節我也難以深究,所以大概只能從 Ruby 的角度看下去。總而言之呢,Rails 的 plugin 比起 rubygems 還更要簡單得多,根本沒有任何需要設定的部份,只要把目錄開好就可以輕易使用了。目錄結構大約是:

init.rb
install.rb
lib/*.rb
test/*.rb

init.rb 是 Rails 在 load up 時會執行的部份,所以 plugin 要把 init up 的程式碼放到這邊,例如最常見的恐怕是:
ActiveRecord::Base.send(:include, OOO)
這邊使用 send 而不是直接用 . 的緣故是 include 本身是 private method, 用 . 的會有 NoMethodError. 不過我建議可能可以考慮使用 __send__ 而非 send, 因為有些 class 的 send 有被 override, 一不小心可能會有未預期的錯誤。(雖然應該一看就知道會是出什麼問題就是了)

install.rb 則是在安裝時才會執行的程式,例如使用 script/plugin install OOO 就會先執行此 install.rb, 而日後不管何時使用此 plugin 時,install.rb 都不會再被執行。這部份可能會放的程式碼也許是會動到目錄結構的程式,例如在 app/models 下寫入 OOO_plugin.rb, 像這種只需要在安裝時執行一次即可。這樣做有什麼好處呢?我想感覺就有點像 script/generate OOO_plugin 的感覺吧。

至於 lib/ 則會自動加入 load path, 這部份跟 rubygems 裡 gemspec 裡的 s.require_path = 'lib' 是相同的概念。test/ 的部份也和 rubygems 相同。

接下來還有什麼好講的嗎?有的,參考〈acts_as_taggable Plugin 使用方式〉一文,可以發現 acts_as_taggable.rb 寫得相當複雜,這當然是有原因的。我參考了官方網站裡跟 plugin 有關的系列文章,發現 ActsAsOOO 是個相當常見的 plugin 模式,其中似乎有某種 pattern 在其中…。就是 ClassMethods, SingletonMethods, 與 InstanceMethods.

這樣做的原因很簡單,就只是加強模組化與避免名稱污染,所以多繞了幾個圈。在這種模式的做法下,ActiveRecord::Base 所多出來的 method 只有 acts_as_taggable. 而當你在寫 class MyModel < ActiveRecord::Base; acts_as_taggable; end 時,只有 MyModel 多出 class method => find_tagged_with, instance methods => tag_with, tag_list. 而不是整個 ActiveRecord::Base 都多出這些 methods.

其實這做法也有點像 meta-programming, 只不過是用 mixin 的形式。在前一陣子裡,由於我搞不太清楚 include 與 extend 的差異,所以調查了一下,並做了些筆記:(我知道多半連不上,所以 copy 一份到這)

=begin
2007.02.13

include 將 module 內的所有 method 原封不動拿過來,extend 則是在原本的 method 前面多加個 self. 即 class C 內,寫 include M 則追加 instance method. 如果寫 extend M 則追加 class method.

module 內也可以使用 include 與 extend, 結果同 class. include 為 instance level, extend 為 class level. 基本上這兩樣東西是很接近的。至於 module level 的 method, 則不受 include 也不受 extend 影響。其實跟 meta-programming 很像。

module M
def m; end # 只能由 include 或 extend 取用
def self.m; end # 只能用 M.m 來呼叫
end

class C
include C # 獲得 instance method m
extend C # 獲得 class method m
end
=end

除此之外,module 還有個特別的東西叫 module_function, 這東西我還沒仔細研究,但初步認識的結果是,他會造成指定的 method 同時定義 def m; end 與 def self.m; end 詳細的內容可以當成讀者練習,呵。(雖然其實可能就只是這樣而已)

回到 acts_as_taggable, 在 module Taggable 中唯一的 method 是:
def self.included(base)
base.extend(ClassMethods)
end
這個相信大家都很熟了,就是指當此 module 被 include 時會執行的 method, 有點 hook 的概念。這裡的 base 就是 includer, who include this module. 在 Taggable 中,當然就是 ActiveRecord::Base 了。extend 上面看到了,會促使該 class 擁有此 module 中所有的 method 成為 class method, 所以 ActiveRecord::Base 多了個 acts_as_taggable 為 class method. 如此一來,就能寫:
class MyModel < ActiveRecord::Base
acts_as_taggable
end

其實我覺得這樣實作有點過於複雜,我會比較喜歡這種形式:
class ActiveRecord::Base
def self.acts_as_taggable
# ...
end
end
這樣就一目了然了。缺點當然就是會比較難將此 method 丟給其他人用,例如假設哪天有了一個 class 是 PassiveRecord, 也想將 act_as_taggable 丟給他使用,可能就必須 copy & paste, 或是一些非常詭譎的方式,這邊不多提。

而在 acts_as_taggable 的最下方,呼叫了:
include ActiveRecord::Acts::Taggable::InstanceMethods
extend ActiveRecord::Acts::Taggable::SingletonMethods
的意思就非常明顯了,將 module InstanceMethods 的 method 變成 MyModel 的 instance method, 將 module SingletonMethods 的 method 變成 MyModel 的 class method.(不太明白為何要取做 SinglethonMethods, 也許只是因為 ClassMethods 用過了吧?)

原因是 :include 與 :extend 的 message receiver 是 MyModel 而不是 ActiveRecord::Base, 所以被擴充的是 MyModel; ActiveRecord::Base 不受影響。

大抵上就是這樣了。

abstract:
init.rb 在 Rails load up 後會執行
install.rb 在 plugin install 後會執行
lib/ 自動加入 load path

下次再研究 rake 要怎麼用,相信以之拿來做 test 會很方便。

2007.05.05 godfat 真常

延伸閱讀
分享到:
评论

相关推荐

    rails_plugins_presentation.pdf

    之后,你可以通过`./script/plugin install plugin_name`或`./script/plugin install svn://svn.seesaw.it/tabnav`这样的命令来安装特定的插件。安装过程会将插件放置在Rails应用根目录下的`vendor/plugins`子文件夹...

    Wordpress EU Cookie Script / Plugin:易于安装的wordpress插件,符合欧盟Cookie法规-开源

    ===设备和浏览器兼容性===在http://www.browserstack.com上的Internet Explorer 6之外的所有主要设备和浏览器上均可正确显示================= =======================说明=== Rankguard在wordpress页脚中提供了一...

    Ruby on Rails插件

    除了标准的`script/plugin`工具,还有其他插件管理工具,例如RaPT(Rapid Plugin Tool)。RaPT是一个替代方案,可以通过gem安装,提供了从命令行搜索插件的功能,并且因为其缓存机制,运行速度较快。开发者可以使用`...

    model_cache:用于缓存模型代码的 Rails 插件

    模型缓存ModelCache 是一个简单...安装作为宝石: gem install model-cache 作为插件: script/plugin install git://github.com/moskyt/model_cache.git 或者 script/plugin install http://github.com/moskyt/model_c

    moonshine_denyhosts:Moonshine的denyhosts插件

    script/plugin install git://github.com/railsmachine/moonshine_denyhosts.git --force # Rails 3 script/rails plugin install git://github.com/railsmachine/moonshine_denyhosts.git --force 根据需要在...

    替代Rails中的Prototype为jQueryjRails.zip

    jRails是一个替代 Rails 中的Prototype/script.aculo.us 为 jQuery 的项目。使用 jRails,你能获得所有..../script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails 标签:jRails

    XChatOSD perl script / c plugin-开源

    【XChatOSD perl script / c plugin-开源】是一个针对XChat聊天客户端的增强插件,它使用了XOSD库来实现一个更直观、更动态的消息显示方式。这个项目的核心在于提供一种新的视觉体验,使得用户在进行聊天时能够以...

    event_calendar:显示日历日和日历行中的多个重叠事件。 Rails插件

    script/plugin install git://github.com/elevation/event_calendar.git 生成必要的静态文件和以下示例: script/generate event_calendar Rails 作为宝石: gem install event - calendar 将此添加到您的...

    Rails GUI Development with Ext JS 10-Jan-08 RUG-B.pdf

    - 使用命令 `script/plugin install http://rug-b.rubyforge.org/svn/ext_scaffold` 安装 `ext_scaffold` 插件。 4. **生成资源**: - 通过命令 `script/generate ext_scaffold Post title:string body:text ...

    jintastic:Formtastic生成的基于jQuery的就地编辑器

    script/plugin install git://github.com/rubymood/jintastic.git 安装Jintastic宝石或插件后,生成Jintastic资产 script/generate jintastic 用法 下载jQuery(&gt; = 1.3.2)在您的模板中包含jintastic:

    zebra_printer:生成要在 Zebra 标签打印机上打印的标签

    script/plugin install git://github.com/BaobabHealthTrust/zebra_printer.git 用法 生成“你好标签!” 标签 require 'zebra_printer' label = ZebraPrinter :: StandardLabel . new label . draw_multi_text ( ...

    nativescript-plugin-firebase:Firebase的NativeScript插件

    为了与NativeScript 7兼容,请运行tns plugin add @nativescript/firebase 。 为了与NativeScript 6.1+兼容,请安装polugin版本10: tns plugin add nativescript-plugin-firebase@10 。 对于NativeScript 6.0及...

    vue-plugin-load-script:一个Vue插件,用于注入远程脚本

    import LoadScript from 'vue-plugin-load-script' ; Vue . use ( LoadScript ) ; // As a global method Vue . loadScript ( "https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY" ) . then ( ( ) =&gt; ...

    com.googlecode 的 maven-db-plugin.jar 包

    `maven-db-plugin` 插件有两个版本,即 `1.3` 和 `1.4`,这两个版本的 JAR 文件在压缩包中分别以 `maven-db-plugin-1.4.jar` 和 `maven-db-plugin-1.3.jar` 的形式存在。这些 JAR 文件包含了插件所需的全部类和资源...

    execute-script-plugin

    FIT2CLOUD Execute-Script-Plugin for JenkinsJenkins是当前最常用的CI服务器,FIT2CLOUD Execute-Script-Plugin for Jenkins的功能是:代码在Jenkins服务器构建通过之后,可以在FIT2CLOUD中在指定范围的虚机上执行...

    easyui插件

    easyui.js插件, &lt;script type="text/javascript" src="/js/easyui.js"&gt;&lt;/script&gt; &lt;script type="text/javascript" src="/js/easyui-lang-zh_CN.js"&gt;&lt;/script&gt;

    网页弹框I6版本太低提示下载

    &lt;script&gt;var cssUrl = './source/plugin/amu_kie6/images/style.zh.css'; var cssTS = '本站提示您正在使用基于 Internet Explorer 6 内核的浏览器浏览网页,如果您升级到 Internet Explorer 8&lt;/strong&gt; 或...

    inline_attachment:官方不支持

    官方不支持 从 ActionMailer 3.0 及更高版本开始,内联附件变得非常简单,并内置于 Rails 中。 它们不像使用inline_attachments那样简单,但了解如何... $ script/plugin install git://github.com/smathy/inline_att

    redmine_ssl_auth:使用 SSL 客户端证书在 Redmine 中启用身份验证

    管理平台SSL身份验证插件 这个 redmine 插件使用 SSL 客户端证书启用身份验证用法 这很简单安装插件:ruby script/plugin install git://github.com/koke/redmine_ssl_auth.git 为 SSL 身份验证配置 apache(请参阅...

    moonshine_scout:安装和配置Scout代理

    快速入门说明script/plugin install git://github.com/railsmachine/moonshine_scout.git 在config/moonshine.yml配置代理密钥 :scout: :agent_key: YOUR-PRIVATE-SCOUT-KEY在月光清单中包含插件和配方 recipe :...

Global site tag (gtag.js) - Google Analytics