我现在有一个对象:
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
我希望这是有道理的,可能我会忽略一些可以让我的生活在两行中变得更加轻松的宏伟计划。
答案 0 :(得分:6)
在我发布一个如何重做的例子之前,有一些观察。
解决问题的一种方法是专门为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
答案 1 :(得分:2)
你知道Ruby关键词 yield 吗?
我不太确定你到底想做什么。我对你的意图有两种解释,所以我给出了一个例子,它使两个完全不同的东西,其中一个希望回答你的问题:
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 或 a.each 或完全不同的内容?
答案 2 :(得分: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
对于他的示例数据,您将获得以下输出:
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
由于我不知道有什么方法可以检查方法名是来自属性还是来自其他方法(除了你在类Module中重新定义attr_accessor,attr等)我添加了一些健全性检查:我测试是否存在相应的方法和该名称的实例变量。由于类ItemsCollection不强制只添加类Item的对象,因此我只选择满足两个检查的元素。您还可以删除选择并将测试放入地图中,如果检查失败,则返回nil。
答案 3 :(得分:-1)
关键是返回值。如果没有给出'return'语句,则返回最后一个语句的结果。你最后一个语句返回一个哈希。
添加'return self'作为初始化的最后一行,你就是黄金。
Class Item
def initialize(options = {})
## Do all kinds of stuff.
return self
end
end