我有一个带有自定义每个方法的类:
class CurseArray < Array
def each_safe
each do |element|
unless element =~ /bad/
yield element
end
end
end
end
并希望调用不同的块方法,例如“收集”或“注入”这些迭代元素。例如:
curse_array.each_safe.magic.collect {|element| "#{element} is a nice sentence."}
我知道有一个特定的功能(我在这里称之为“魔法”)来做到这一点,但我已经忘记了。请帮忙! : - )
答案 0 :(得分:6)
如果方法产生,则需要将块传递给它。无法定义自动传递的块。
最贴近我可以达到你的规格:
def magic(meth)
to_enum(meth)
end
def test
yield 1
yield 2
end
magic(:test).to_a
# returns: [1,2]
实施请求的最简洁方法可能是:
class MyArray < Array
def each_safe
return to_enum :each_safe unless block_given?
each{|item| yield item unless item =~ /bad/}
end
end
a = MyArray.new
a << "good"; a << "bad"
a.each_safe.to_a
# returns ["good"]
答案 1 :(得分:2)
您编写each_safe
方法的方式最简单的方法是
curse_array.each_safe { |element| do_something_with(element) }
编辑:哦,你的each_safe方法也不正确。它必须是“每个人”,而不是“each.do”
编辑2:如果您真的希望能够执行“each_safe.map
”之类的操作,同时还可以执行“each_safe { ... }
”您可以写这样的方法:
require 'enumerator'
class CurseArray < Array
BLACKLIST = /bad/
def each_safe
arr = []
each do |element|
unless element =~ BLACKLIST
if block_given?
yield element
else
arr << element
end
end
end
unless block_given?
return Enumerator.new(arr)
end
end
end
答案 2 :(得分:0)
选定的解决方案使用了常见的习惯用语to_enum :method_name unless block_given?
,但也有其他选择:
保持“不友好”的yielder方法不变,请在调用时使用enum_for
。
使用惰性Enumerator
。
使用延迟数组(需要Ruby 2.0或gem enumerable-lazy)。
这是一个演示代码:
class CurseArray < Array
def each_safe
each do |element|
unless element =~ /bad/
yield element
end
end
end
def each_safe2
Enumerator.new do |enum|
each do |element|
unless element =~ /bad/
enum.yield element
end
end
end
end
def each_safe3
lazy.map do |element|
unless element =~ /bad/
element
end
end.reject(&:nil?)
end
end
xs = CurseArray.new(["good1", "bad1", "good2"])
xs.enum_for(:each_safe).select { |x| x.length > 1 }
xs.each_safe2.select { |x| x.length > 1 }
xs.each_safe3.select { |x| x.length > 1 }.to_a