Я прочитал этот вопрос , но я не смог создать полный пример:
class Some def method_a puts "a" end def method_b puts "b" end def method_c puts "c" end end some = Some.new a = true b = true c = true l = [] l << :method_a if a l << :method_b if b l << :method_c if c l.inject(some) { |obj, method| obj.send(method) }
[demas @ arch.local.net] [~ / dev / study / ruby / oop]% ruby inject_ex.rb а inject_ex.rb: 26: в block in <main>': undefined method method_b 'для nil: NilClass (NoMethodError) из inject_ex.rb: 26: в `каждом ' из inject_ex.rb: 26: в `inject ' из inject_ex.rb: 26: в `'
[demas @ arch.local.net] [~ / dev / study / ruby / oop]% ruby inject_ex.rb а
inject_ex.rb: 26: в block in <main>': undefined method method_b 'для nil: NilClass
block in <main>': undefined method
(NoMethodError)
из inject_ex.rb: 26: в `каждом '
из inject_ex.rb: 26: в `inject '
из inject_ex.rb: 26: в `'
Inject передает возвращаемое значение блока на следующую итерацию. Теперь ваш obj имеет возвращаемое значение obj.send(:method_a) после первой итерации. Исправьте инъекцию так:
obj
obj.send(:method_a)
l.inject(some) { |obj, method| obj.send(method) obj }
Вы также можете использовать tap:
tap
l.inject(some) do |obj,method| obj.tap{|o| o.send(method)} end
Или вы можете использовать кран, чтобы избавиться от этого l:
l
some.tap{|s|s.method_a if a}.tap{|s|s.method_b if b}.tap{|s|s.method_c if c}
tap - метод add в ruby 1.9. Но мы можем использовать метод возврата в Rails в ruby 1.8. Код консоли Rails:
>> class Some >> def method_a >> puts "a" >> end >> ?> def method_b >> puts "b" >> end >> ?> def method_c >> puts "c" >> end >> end => nil >> ?> some = Some.new => #<Some:0x2a98c4f938> >> ?> a = true => true >> b = true => true >> c = true => true >> ?> l = [] => [] >> l << :method_a if a => [:method_a] >> l << :method_b if b => [:method_a, :method_b] >> l << :method_c if c => [:method_a, :method_b, :method_c] >> l.inject(some){|obj, method| returning(obj){|r| r.send method}} a b c => #<Some:0x2a98c4f938> >>