2009-09-09 118 views
2

我現在的對象:紅寶石對象數組...或哈希

class Items 
    attr_accessor :item_id, :name, :description, :rating 

    def initialize(options = {}) 
     options.each { 
     |k,v| 
     self.send("#{k.to_s}=".intern, v) 
     } 
    end 

end 

我有它被指定爲單個對象到一個數組...

@result = [] 

some loop>> 
    @result << Items.new(options[:name] => 'name', options[:description] => 'blah') 
end loop>> 

但是,相反的我分配單數對象到一個數組...我怎麼能讓對象本身成爲一個集合?

基本上要有對象以這樣的方式,這樣我可以定義方法,如

def self.names 
    @items.each do |item| 
     item.name 
    end 
end 

我希望是有道理的,可能是我俯瞰一些大計劃,這將使我的生活無限更容易2行。

回答

6

在我發佈一個如何返工的例子之前的幾個觀察。

  • 給人一種類聲明新的對象時,在這種情況下,你會打電話Items.new一個複數名稱可能會導致大量的語義問題,這意味着你要創建幾個項目的時候,其實真正做一個。爲單個實體使用單數形式。
  • 調用任意方法時要小心,因爲在任何錯過時都會拋出異常。要麼檢查你可以先打電話給他們,或者在適用的情況下從不可避免的災難中拯救。

解決您的問題的一種方法是專門爲Item對象創建自定義集合類,它可以爲您提供名稱等所需的信息。例如:

class Item 
    attr_accessor :item_id, :name, :description, :rating 

    def initialize(options = { }) 
    options.each do |k,v| 
     method = :"#{k}=" 

     # Check that the method call is valid before making it 
     if (respond_to?(method)) 
     self.send(method, v) 
     else 
     # If not, produce a meaningful error 
     raise "Unknown attribute #{k}" 
     end 
    end 
    end 
end 

class ItemsCollection < Array 
    # This collection does everything an Array does, plus 
    # you can add utility methods like names. 

    def names 
    collect do |i| 
     i.name 
    end 
    end 
end 

# Example 

# Create a custom collection 
items = ItemsCollection.new 

# Build a few basic examples 
[ 
    { 
    :item_id => 1, 
    :name => 'Fastball', 
    :description => 'Faster than a slowball', 
    :rating => 2 
    }, 
    { 
    :item_id => 2, 
    :name => 'Jack of Nines', 
    :description => 'Hypothetical playing card', 
    :rating => 3 
    }, 
    { 
    :item_id => 3, 
    :name => 'Ruby Book', 
    :description => 'A book made entirely of precious gems', 
    :rating => 1 
    } 
].each do |example| 
    items << Item.new(example) 
end 

puts items.names.join(', ') 
# => Fastball, Jack of Nines, Ruby Book 
+0

是否有一種方法可以使項目的所有屬性都自動錶現得像'名稱'方法? IE瀏覽器。調用.descriptions返回與.names相同的內容...? – holden 2009-09-09 21:31:35

+0

如果您想獲得冒險精神,可以動態構建這些方法,也可以使用method_missing來捕獲調用。 – tadman 2009-09-10 14:43:56

+0

我可以使用Ruby mixins將這種功能添加到包含ActiveRecord對象的所有數組嗎?一些指針會很有用。 – Sanjay 2009-09-11 11:18:17

-1

關鍵是返回值。如果沒有給出'return'語句,則返回最後一條語句的結果。你最後的語句返回一個哈希。

添加'返回自我'作爲初始化的最後一行,你是黃金。

Class Item 
    def initialize(options = {}) 
    ## Do all kinds of stuff. 

    return self 
    end 
end 
+0

那麼,那部分實際上工作正常,它只是我餵我的對象到一個數組,當我想要一個可以執行功能的巨型對象(集合) – holden 2009-09-09 14:44:56

+0

Item.new總是返回新創建的對象,無論initialize()的返回值如何。添加回報自我沒有任何意義。 – molf 2009-09-09 14:48:29

+1

與其他語言不同,Ruby初始值設定項的返回值將被忽略,並且始終返回創建的對象。這可以通過重寫類新方法來改變,但這可能是一個壞主意。 – tadman 2009-09-09 15:01:41

2

你知道紅寶石關鍵詞產生

我不太確定你想要做什麼。我有你的意圖的兩種解釋,所以我給這使得兩種完全不同的東西,其中一個希望回答你的問題的例子:

class Items 
    @items = [] 
    class << self 
    attr_accessor :items 
    end 
    attr_accessor :name, :description 
    def self.each(&args) 
    @items.each(&args) 
    end 
    def initialize(name, description) 
    @name, @description = name, description 
    Items.items << self 
    end 
    def each(&block) 
    yield name 
    yield description 
    end 
end 

a = Items.new('mug', 'a big cup') 
b = Items.new('cup', 'a small mug') 
Items.each {|x| puts x.name} 
puts 
a.each {|x| puts x} 

此輸出

mug 
cup 

mug 
a big cup 

你問過這樣的事情Items.each or a.each或者完全不同的東西?

+0

在使用兩個參數的情況下,當使用兩個參數時可能會更有用,這似乎很奇怪。 – tadman 2009-09-09 15:15:58

+0

取決於人們想做什麼。方法「each」通常會爲插入當前元素的每個元素調用給定的塊一次。當然,如果我的例子是正確的(這沒有太大意義,我只是想顯示用法)。產生兩個參數只會在插入兩個元素後調用該塊。 – Whoever 2009-09-09 16:13:20

1

回答剛纔您在您的評論要求tadman的解決方案的另一個問題:如果您在tadman的代碼由

def method_missing(symbol_s, *arguments) 
    symbol, s = symbol_s.to_s[0..-2], symbol_s.to_s[-1..-1] 
    if s == 's' and arguments.empty? 
    select do |i| 
     i.respond_to?(symbol) && i.instance_variables.include?("@#{symbol}") 
    end.map {|i| i.send(symbol)} 
    else 
    super 
    end 
end 

替代方法的定義在類ItemsCollection 對於他的示例數據,您將得到以下輸出:

puts items.names.join(', ') 
# => Fastball, Jack of Nines, Ruby Book 
puts items.descriptions.join(', ') 
# => Faster than a slowball, Hypothetical playing card, A book made entirely of precious gems 

因爲我不知道任何方法來檢查方法名稱來自一個屬性或來自另一個方法(除非你重新定義類模塊中的attr_accessor,attr等)我添加了一些理智檢查:我測試是否存在相應的方法和該名稱的實例變量。由於類ItemsCollection並未強制只添加類Item的對象,所以我只選擇滿足兩個檢查的元素。您也可以刪除選擇並將測試放入地圖,如果檢查失敗,則返回零。

+0

我剛剛在上面添加我的評論後,在此處看到了此處。如果您使用Rails,則可以使用單數化方法爲您執行depluralization,而不是採用's'-stripping。 – tadman 2009-09-10 14:45:44