作者godfat (godfat 真常)
看板Ruby
标题Re: [连结] ActiveRecord act_as_xxx的原理跟template
时间Sat Nov 3 02:05:28 2007
※ 引述《ddman (ddman)》之铭言:
: 觉得act_as_xxx很神奇,去找了一下,有两篇文章讲原理跟一个简单的template
: 原理: http://tinyurl.com/275usq
: template: http://textsnippets.com/posts/show/384
: 基本上是利用mixing来做。我得承认以我的程度,不是很了解...Orz
: 有高手可以帮忙解释一下?
是不是想得太复杂了?我承认我没仔细看,(只翻了一下 code, 文章没看)
也跟 rails 不熟 XDDD 不过看起来大致上就是很单纯的 mixing.
(只是绕了非常多圈,所以也许 ruby 不够熟可能会觉得混乱)
ActiveRecord::Base.send(:include, MyMod::Acts::Roled)
叫 ActiveRecord::Base 去 include MyMod::Acts::Roled
这个动作,会触发:
def self.included(base)
# Add acts_as_roled availability by extending the module
# that owns the function.
base.extend AddActsAsMethod
end
这是 ruby 本身的机制,当 module 被 included 时会呼叫的 hook,
base 就是那个 mixer, 这里就会是:ActiveRecord::Base,
因为是他去 include Roled
於是就等同於呼叫
ActiveRecord::Base.extend AddActsAsMethod
所以 ActiveRecord::Base 就获得了:acts_as_random 这个 method,
接下来就可以这样:
class MyModel < ActiveRecord::Base
act_as_random
end
因为 MyModel 继承 Base, 所以当然能用 Base 的 method acts_as_random
於是 MyModel 就会执行这段:
class_eval <<-END
include MyMod::Acts::Roled::InstanceMethods
END
这简单地说就是很正常的 include, 所以 InstanceMethods 这个 module
就会被 include 到 MyModel 中,於是理所当然 MyModel 就能使用
这些 instance methods. 同时这段也会被执行到:
def self.included(aClass)
aClass.extend ClassMethods
end
aClass 就会是 MyModel, 因为是他去 include InstanceMethods,
然後他又被 extend ClassMethods,
所以 MyModel 也会获得这些 class methods.
以上只是随意的解释,也没细看该网站上的文章,所以如果有误望请指正 :)
不过我想应该没什麽错,因为我之前有稍微翻过 rails plugin 的作法,
有参考过一些 plugin 的大致作法,跟上面那样做还满像的。
不过老实讲,我个人觉得这样做还蛮多此一举的,绕了太多圈了,很麻烦。
除非需要做到很大的 plugin 吧?否则我觉得就一个 module 就好了。
顶多这样吧?
module ClassMethods
def class_method; 'class_method'; end
end
module InstanceMethods
def instance_method; 'instance_method'; end;
end
class MyModel < ActiveRecord::Base
include InstanceMethods
extend ClassMethods
end
嫌要 include 又要 extend 很麻烦的话:
module MyPlugin
def self.included base
base.__send__ :include, InstanceMethods
base.__send__ :extend, ClassMethods # 因为这些是 private methods
end
end
然後
class MyModel < ActiveRecord::Base
include MyPlugin
end
这样就好了,省得绕那麽多圈看得晕头转向的。
如果还是喜欢 act_as_... 的名字:
def ActiveRecord::Base.act_as_me
include MyPlugin
end
就可以:
class MyModel < ActiveRecord::Base
act_as_me
end
试试吧,我刚刚试了一下没什麽问题。
在 rails 中的话要考虑各 .rb 的执行顺序即可。
--
In Lisp, you don't just write your program down toward the language,
you also build the language up toward your program.
《Programming Bottom-Up》- Paul Graham 1993
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.28.18
1F:推 ddman:我没深入研究ruby mixing,module跟继承,得花时间看看 11/03 21:57
2F:推 godfat:看 Programming Ruby 24 章:Classes and Objects 即可 11/04 09:23