在下面的代码中,问题是在对象类型为LogsCollection的方法上调用方法.find_name后,返回的对象将成为本机数组,并且不会保留为LogsCollection类型。我相信正确的方法可能是创建一个接受数组并返回正确类型的全新对象的构造函数/初始值设定项。但我不确定没有更好的方法来实现这个目标吗?
Ruby-pro可以关注这段代码并建议(在代码级别)从.find_name返回对象的最佳方法仍然是类型LogsCollection(不是数组)吗?
class Log
attr_accessor :name, :expense_id, :is_excluded, :amount, :paid_to
def initialize(name, expense_id, is_excluded, amount, paid_to)
@name = name
@expense_id = expense_id
@is_excluded = is_excluded
@amount = amount
@paid_to = paid_to
end
end
class LogsCollection < Array
def names
collect do |i|
i.name
end
end
def find_name(name)
@name = name
self.select { |l| l.name == @name }
end
end
logs = LogsCollection.new
logs.push(Log.new('Smith', 1, false, 323.95, nil))
logs.push(Log.new('Jones', 1, false, 1000, nil))
logs = logs.find_name('Smith')
puts logs.count
unless logs.empty?
puts logs.first.name # works since this is a standard function in native array
puts logs.names # TODO: figure out why this fails (we lost custom class methods--LogsCollection def find_name returns _native_ array, not type LogsCollection)
end
任何人搜索的最终代码后回复(注意删除基类&lt;数组):
class Log
attr_accessor :name, :expense_id, :is_excluded, :amount, :paid_to
def initialize(name, expense_id, is_excluded, amount, paid_to)
@name = name
@expense_id = expense_id
@is_excluded = is_excluded
@amount = amount
@paid_to = paid_to
end
end
class LogsCollection
attr_reader :logs
def initialize(logs)
@logs = logs
end
def add(log)
@logs.push(log)
end
def names
@logs.collect { |l| l.name }
end
def find_name(name)
LogsCollection.new(@logs.select { |l| l.name == name })
end
end
logs = LogsCollection.new([])
logs.add(Log.new('Smith', 1, false, 323.95, nil))
logs.add(Log.new('Jones', 1, false, 1000, nil))
puts logs.names
puts '--- post .find_name ---'
puts logs.find_name('Smith').names
答案 0 :(得分:2)
正如您在the docs Enumerable#select
中看到的那样,一个块总是会返回一个数组。 E.g。
{:a => 1, :b => 2, :c => 3}.select { |k,v | v > 1 }
=> [[:b, 2], [:c, 3]]
你可以做的是LogsCollection
的某种构造函数,它将普通数组包装为LogsCollection
个对象,并在find_name
中调用它。
根据要求,这是一个示例课程(我在工作并在等待某些事情完成时写这个,它完全未经测试):
class LogsCollection
attr_reader :logs
def initialize(logs)
@logs = logs
end
def names
@logs.collect { |i| i.name }
end
def find_name(n)
name = n
LogsCollection.new(@logs.select { |l| l.name == n })
end
# if we don't know a method, forward it to the @logs array
def method_missing(m, *args, &block)
@logs.send(m, args, block)
end
end
使用
lc = LogsCollection.new
logs = lc.logs.find_name('Smith')