在Ruby中的类级别添加Enumerable mixin

ide*_*lum 7 ruby ruby-on-rails

我在我的Rails应用程序中使用postgres模式,因此没有明确的方法来查询所有公司(对于我们自己的分析).我想实现迭代所有公司的每个方法,并适当地切换postgres模式.

我想打电话给:

Company.each do |company|
  # do something in the context of each company
end
Run Code Online (Sandbox Code Playgroud)

但是我也希望获得一些其他的Enumerable方法collect,例如在所有公司中获取所有经理的示例:

Company.collect do |company|
  Users.managers
end
Run Code Online (Sandbox Code Playgroud)

目前我有这个效果很好

class Company < ActiveRecord::Base
  # ...

  def self.each(&block)
    Company.all.each do |company|
      if Schemas.include? company.subdomain
        # this changes to that company's schema so all queries are scoped
        Apartment::Database.switch company.subdomain

        yield company if block_given?
      end
    end
  end
Run Code Online (Sandbox Code Playgroud)

但是如何在类级而不是实例级别获取Enumerable mixin.

也就是说,当include Enumerable在类中时,Enumerable方法被调用为

company = Company.new
# which might iterate over the contents (users?) in a company
company.collect {|u| u} 
Run Code Online (Sandbox Code Playgroud)

但我想打电话

# iterate over all companies and collect the managers
Company.collect {|c| User.managers} 
Run Code Online (Sandbox Code Playgroud)

并使用它

 Company.each
Run Code Online (Sandbox Code Playgroud)

我觉得答案很明显,但今天早上我的元编程foo很弱.

Ste*_*fan 4

您可以include从内部使用class << self

\n\n
class Foo\n\n  class << self\n    include Enumerable\n  end\n\n  def self.each\n    yield 1\n    yield 2\n    yield 3\n  end\nend\n\nFoo.map { |x| x * 2 } # => [2, 4, 6]\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种模式用在 Ruby 的Prime中。编写include包含模块对我来说看起来更干净,但您也可以使用extend(请参阅Uri Agassi\'s 答案)。

\n\n

如果包含的模块依赖于回调includedEnumerable不依赖),

\n\n
module M\n  def self.included(other)\n    puts "included in #{other}"\n  end\nend\n\nclass Foo\n  class << self\n    include M\n  end\nend\n#=> "included in #<Class:Foo>"\n\nclass Bar\n  extend M\nend\n#=> nothing\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如\xd0\x97\xd0\xb5\xd0\xbb\xd1\x91\xd0\xbd\xd1\x8b\xd0\xb9 所指出的,您可以each在块内定义:(并且不使用self

\n\n
class Foo\n  class << self\n    include Enumerable\n\n    def each\n      # ...\n    end\n  end\nend\n
Run Code Online (Sandbox Code Playgroud)\n