2014-07-09 37 views
7

我在我的Rails應用程序中使用postgres模式,因此沒有明確的方法可以跨所有公司查詢(針對我們自己的分析)。我想實現遍歷所有公司的每種方法並適當地切換postgres模式。在Ruby中的類級別添加可枚舉mixin

我希望能夠調用:

Company.each do |company| 
    # do something in the context of each company 
end 

,但我也想獲得一些其他可枚舉的方法,如在collect所有公司得到所有經理的這個例子:

Company.collect do |company| 
    Users.managers 
end 

目前我有這個效果很好

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 

但怎麼辦我在類級別獲得Enumerable mixin,而不是實例級別。

即當include Enumerable是班上,可枚舉的方法被調用像

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

,但我想打電話給

# iterate over all companies and collect the managers 
Company.collect {|c| User.managers} 

,並把它用

Company.each 

我覺得就像答案是顯而易見的,但我的元編程foo今天早上很弱。

+0

這個問題有很多學習東西給我.. –

+0

供參考:我最初試圖用ActiveRecord類來做到這一點。不要這樣做!當你調用Company.count時,你會得到非常奇怪的失敗,並且它不再調用ActiveRecord計數方法來統計數據庫行。記得Enumerable模塊真的很大 – ideasasylum

回答

4

您可以使用includeclass << self內:

class Foo 

    class << self 
    include Enumerable 
    end 

    def self.each 
    yield 1 
    yield 2 
    yield 3 
    end 
end 

Foo.map { |x| x * 2 } # => [2, 4, 6] 

這種模式在Ruby的Prime class使用。編寫include包含一個模塊看起來比較乾淨,但您也可以使用extend(請參閱Uri Agassi's answer)。

會有區別,如果依靠included回調包括模塊(Enumerable沒有):

module M 
    def self.included(other) 
    puts "included in #{other}" 
    end 
end 

class Foo 
    class << self 
    include M 
    end 
end 
#=> "included in #<Class:Foo>" 

class Bar 
    extend M 
end 
#=> nothing 

由於noted by Зелёный你可以定義塊中右each:(和不使用self

class Foo 
    class << self 
    include Enumerable 

    def each 
     # ... 
    end 
    end 
end 
+1

你現在贏得了我的Ruby .. +1 –

+1

爲什麼不全部包裝('include'和'def')呢? –

+0

@Зелёный謝謝你的建議,我已經更新了我的答案 – Stefan

3

要 「包括可枚舉」 到類使用extend

class Company 
    extend Enumerable 

    def self.each 
    yield 'a' 
    yield 'b' 
    yield 'c' 
    end 
end 

Company.inject(&:+) 
# => "abc" 
+0

你贏了我的Ruby .. :-) –

+0

簡單!謝謝 – ideasasylum