2009-09-09 117 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