Calling a block method on an iterator: each.magic.collect {...}

I have a class with a custom method:

class CurseArray < Array def each_safe each do |element| unless element =~ /bad/ yield element end end end end 

And you want to call various block methods, such as β€œassemble” or β€œinsert” on these iterated elements. For instance:

 curse_array.each_safe.magic.collect {|element| "#{element} is a nice sentence."} 

I know that there is a certain function (which I called "magic" here) to do this, but I forgot. Please help !:-)

+4
source share
3 answers

If the method gives you, you will need to pass a block to it. There is no way to identify a block that automatically transfers itself.

Closest I can go to your specification:

 def magic(meth) to_enum(meth) end def test yield 1 yield 2 end magic(:test).to_a # returns: [1,2] 

The easiest way to implement your request:

 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"] 
+6
source

As you wrote your each_safe method, the simplest would be

 curse_array.each_safe { |element| do_something_with(element) } 

Edit: Oh, your every_safe method is incorrect. It should be "each of them" and not "each.do"

Edit 2: If you really want to do something like " each_safe.map ", and at the same time can also do " each_safe { ... } ", you can write your method for example:

 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
source

The chosen solution uses the common idiom to_enum :method_name unless block_given? which it supports, but there are alternatives:

  • Leave your "unfriendly" yielder method untouched, use enum_for when calling it.

  • Use the lazy Enumerator .

  • Use lazy arrays (requires Ruby 2.0 or gem enumerable-lazy ).

Here is a demo code:

 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 
0
source

Source: https://habr.com/ru/post/1306211/


All Articles