Reputation: 1380
I have a hash with a regex
for the key and a block
for the value. Something like the following:
{ 'test (.+?)' => { puts $1 } }
Not exactly like that, obviously, since the block is being stored as a Proc, but that's the idea.
I then have a regex match later on that looks a lot like this
hash.each do |pattern, action|
if /#{pattern}/i.match(string)
action.call
end
end
The idea was to store the block away in the hash to make it a bit easier for me to expand upon in the future, but now the regex
capture doesn't get passed to the block. Is there a way to do this cleanly that would support any number of captures I put in the regex
(as in, some regex
patterns may have 1 capture, others may have 3)?
Upvotes: 1
Views: 319
Reputation: 14222
What if you pass the match data into your procs?
hash.each do |pattern, action|
if pattern.match(string)
action.call($~)
end
end
Your hash would become:
{ /test (.+?)/i => lambda { |matchdata| puts matchdata[1] } }
Upvotes: 3
Reputation: 160551
I would use Hash.find
which walks the hash elements, passing them into a block, one at a time. The one that returns true
wins:
Something like this:
hash = {/foo/ => lambda { 'foo' }, /bar/ => lambda { 'bar' } }
str = 'foo'
puts hash.find{ |n,v| str =~ n }.to_a.last.call
Obviously I'm using lambda
but it's close enough. And, if there was no match you need to handle nil values. For the example I chained to_a.last.call
but in real life you'd want to react to a nil otherwise Ruby will get mad.
If you are searching through a lot of patterns, or processing a lot of text, your search will be slowed down by having to recompile the regex each time. I'd recommend storing the keys as regex objects to avoid that.
Upvotes: 1