要把 model 中的代码拿出来, common pattern 是这样的:
module MyModule
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
class MyClass
include MyModule
endmodule MyModule
def self.included(base)
p 'hook'
end
end
class MyClass
include MyModule # 打印 'hook'
end- included 是一个钩子方法, 当该 module 被 include 进某个类时, 会自动执行;
- included 接收参数(base), 值为 include 该 module 的类.
为什么要在 module 中用 def self.foo 的方式定义方法.
这样做之后, 这个方法可以被当做模块方法 调用, MyModule.foo, 不加 self 是不行的. module 是 class 的超类, self 的这种行为两者保持一致.
这个 module 被 mix-in 时, 该方法不会成为类的实例方法. 如果一个类 include 一个 module, 这个类会继承这个 module(实际上是这个 module 的代理类), 因此module 中定义的方法会成为类的实例方法. 而 module 中定义的 self.test 方法会成为什么样的方法呢? 会成为模块的方法, 但是不会成为代理类的方法, 所以这个类也无法获取的这个方法(这点存疑) 这里的关键问题在于, module 有单件类么, self.test 到底存在于哪里
在 module 里面写 extend self 会起到相同的作用.
http://stackoverflow.com/questions/11550213/ruby-module-function-vs-including-module
有个问题没搞清楚呢: 在 module 定义中里面 self 表示什么; 在其他地方, self 都表示当前对象; module 本身就是对象啊, 所以是给当前 module 增加了方法, 跟上文的解释是一致的. 如果是类的话, self 定义的方法, 其实是给类的单件类添加了实例方法; module 有没有单件类呢? 还是说只有代理类?
module MyModule
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
...
end
end
class MyClass
include MyModule
end在钩子方法内部, 调用了base.extend ClassMethods, ClassMethods 中定义的方法就成为了 Myclass 的类方法.这样等同于
module MyModule
...
module ClassMethods
...
end
end
class MyClass
include MyModule
extend MyModule::ClassMethods
end但是很明显使用钩子方法好一些,这样在类中 include 该 module 时, 自动 extend 了定义类方法的 module.
module MyModule
def self.included(base)
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
end
class MyClass
include MyModule
end这样实现的效果是
class MyClass
scope :disabled, -> { where(disabled: true) }
end但是为什么呢?
第一步理解 class_eval class_eval 是在目标类的上下文中执行一个 block, 在 block 中定义的方法会成为目标类的实例方法, 很好理解.
MyClass.class_eval do
def hi
p 'hi'
end
end
MyClass.new.hi => 打印 hi第二部理解 scope scope 是一种类宏(class macro).
类宏是可以在类定义中使用的普通方法, 看起来很像是关键字, 本质是在类的单例类中定义的实例方法.
所以说在调用类宏时, 应该在类的上下文中调用. problem solved, right?