Ruby on rails学习:module的 include/extend 常见操作

通过包含一个模块向类中添加类方法和实例方法
更新于: 2021-12-21 15:11:36

原文

嗨,伙计们。我很高兴地宣布,关于规范模式的文章被选为 RubyWeekly#341。另外,关于Reddit的文章 DecouplingfromRails [第1部分]开始了令人敬畏的讨论。这意味着我们正朝着正确的方向前进。我将很快完成关于与 Rails 解耦的系列文章,但今天我想谈谈模块。如何通过在类中包含一个模块来添加类方法和实例方法。

作为Ruby开发人员,我们知道使用模块有两个主要原因:名称空间和混合。

当我们想使用模块作为 mixin 时,我们可以使用 includeextend。还有一种方法可以预先设置模块。我在这篇文章中谈到了这一点。

让我们找出 includeextend 之间的区别。

 

如果我们使用 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

我们不能使用扩展持久性,因为在这种情况下,saveupdate 方法将是 class Userclass方法。
为了解决这个问题,我们将使用模块回调。让我向您展示回调是如何工作的:

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

参考