Ruby on rails学习:module的 include/extend 常见操作
通过包含一个模块向类中添加类方法和实例方法
原文
嗨,伙计们。我很高兴地宣布,关于规范模式的文章被选为
RubyWeekly#341
。另外,关于Reddit的文章DecouplingfromRails
[第1部分]开始了令人敬畏的讨论。这意味着我们正朝着正确的方向前进。我将很快完成关于与Rails
解耦的系列文章,但今天我想谈谈模块。如何通过在类中包含一个模块来添加类方法和实例方法。作为Ruby开发人员,我们知道使用模块有两个主要原因:名称空间和混合。
当我们想使用模块作为
mixin
时,我们可以使用include
或extend
。还有一种方法可以预先设置模块。我在这篇文章中谈到了这一点。让我们找出
include
和extend
之间的区别。
如果我们使用 include-all
模块方法将成为类的实例方法。请参见此示例:
module Persistence
def save
'saving'
end
end
class User
include Persistence
end
u = User.new
u.save # => 'saving'
让我们检查一下 extend
是如何工作的:
module Persistence
def find(id)
"looking for entity with id=#{id}"
end
end
class User
extend Persistence
end
User.find(10) # => looking for entity with id=10
如果您考虑类似 ActiveRecord 模型的东西,它允许我们同时拥有实例方法和类方法。对于模型,我们可以使用类方法来查找对象:User。全部,用户。首先,用户。其中(名字:“John”)等。同时,我们拥有更新或保存每个特定用户的实例方法:
u = User.last
# instance methods
u.save
u.update(first_name: "Sergii")
让我们从最简单的部分开始,从实例方法开始。为了实现这一目标,我们可以使用包括,正如我们以前看到的:
module Persistence
def save
'saving'
end
def update
'updating entity'
end
end
class User
include Persistence
end
u = User.new
u.save #=> saving
u.update #=> updating entity
我们不能使用扩展持久性,因为在这种情况下,save
和 update
方法将是 class User
的class
方法。
为了解决这个问题,我们将使用模块回调。让我向您展示回调是如何工作的:
module Persistence
def self.included(klass)
"Persistence module was included into #{klass}"
end
end
class User
include Persistence
end
它将打印“持久化模块已包含到用户中”。每当任何类包含模块时,Ruby都会触发 self
。该模块上包含的方法。它还将作为参数传递类。在本例中,用户类将位于 klass
参数中。还有几个回调可用:包括、扩展、为模块添加前缀和为类继承。
现在我们知道我们可以访问包含模块的类。我们可以利用这一点,从同一个模块中逐个扩展该类方法。我将展示最终实现,然后我们将逐行了解其工作原理:
它将打印“持久化模块已包含到用户中”。每当任何类包含模块时,Ruby
都会触发 self
。该模块上包含的方法。它还将作为参数传递类。在本例中,用户类将位于 klass
参数中。还有几个回调可用:包括、扩展、为模块添加前缀和为类继承。
现在我们知道我们可以访问包含模块的类。我们可以利用这一点,从同一个模块中逐个扩展该类方法。我将展示最终实现,然后我们将逐行了解其工作原理:
module Persistence
def self.included(klass)
klass.extend(ClassMethods)
end
module ClassMethods
def all
puts 'all'
end
def find(id)
puts "looking for entity with id=#{id}"
end
end
def save
puts 'saving'
end
def update
puts 'updating entity'
end
end
class User
include Persistence
end
u = User.new
# instance methods
u.save #=> saving
u.update #=> updating entity
# class methods
User.all #=> all
User.find(1) #=> looking for entity with id=1