Thomas S. wrote:
Perhaps what is being sought here is a form of search and replace.
class Array
def deep_replace(replacement, &match)
map do |e|
if e.respond_to?(:deep_replace)
e.deep_replace(replacement, &match)
else
match[e] ? replacement : e
end
end
end
require ‘facets/hash/mash’ #[1]
class Hash
def deep_replace(replacement, &match)
mash do |k,v|
nk = if k.respond_to?(:deep_replace)
k.deep_replace(replacement, &match)
else
match[k] ? replacement : k
end
nv = if v.respond_to?(:deep_replace)
v.deep_replace(replacement, &match)
else
match[v] ? replacement : v
end
[nk, nv]
end
end
Not tested but you get the idea.
I’m not 100% sure about handling the key for Hash either, but perhaps
an option could toggle that usage on or off.
[1]http://blog.thepete.net/2010/02/ruby-facets-mash-method.html
That way you can say for example:
Here's a deeply nested object; replace any "content" n which is a
Fixnum with the number 123
But you cannot say:
Here's a deeply nested object; replace any "content" n which is a
Fixnum with the number n + 1
#deep_replace would be a lot more flexible if replacement could be a
lambda.
The drawback is that client code would look ugly:
o.deep_replace(lambda {|x| x+1}) {|y| ...}
Is there an elegant way o pass two blocks of code?
Maybe a more consistent API would look like:
o.deep_replace(
lambda {|x| ... }, # matching conditions
lambda {|x| ... } # replacement code
)
or like:
o.deep_replace(
lambda {|k, v| ... }, # matching conditions
lambda {|k, v| ... [new_k, new_v] } # replacement code
)
But more simply the “matching” may be done by the client code:
o.deep_replace do |k, v|
if matching_conditions(k, v)
# do the replecement
…
[new_k, new_v]
else
[k, v] # leave the same
end
end
so, again, we have to pass one block of code, but for the replacement,
not the match.
G.