-
-
Save Veejay/2047303 to your computer and use it in GitHub Desktop.
Array.class_eval do | |
def extract! | |
if block_given? | |
[].tap do |rejects| | |
delete_if do |element| | |
yield(element) and rejects << element | |
end | |
end | |
else | |
self | |
end | |
end | |
end |
Since the extract! method uses Object#tap, it returns the object it was called on, minus some processing done inside the body of the block passed as a parameter.
Is it thus possible to do something like:
1.9.3p0 :218 > a = ["aaa", Proc.new{}, 123, true, true, 12, 23]
=> ["aaa", #<Proc:0x007fc00e434718@(irb):218>, 123, true, true, 12, 23]
1.9.3p0 :261 > a.extract!{ |e| e.is_a?(Integer) }.extract!{ |e| e > 100 }
=> [123]
How useful is this method? Probably not very useful, it was mainly coded as an exercise. A use case scenario for such a method might be input sanitizing.
For example, you get an array as input and you want to make sure that all unwanted elements have been removed from the array before using it.
Using extract!, it's as simple as defining a series of filters (defined by blocks) and having array go through all of them successively. The "safe" array should come out in the end. The process of filtering in this case basically takes the form of a call to extract! using the blocks generated from criteria you defined (be it in the blocks themselves, in a personal format or using JSON/YAML/XML/YOU_NAME_IT).
At each step, it is of course possible to do something with the rejected elements (logging comes to mind for example).
Documentation for Object#tap: http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap
This method is available for Ruby 1.9 and on and allows for powerful chaining.