lib/core/facets/hash/recursively.rb in facets-2.8.4 vs lib/core/facets/hash/recursively.rb in facets-2.9.0.pre.1
- old
+ new
@@ -1,29 +1,61 @@
+require 'facets/functor'
+require 'facets/enumerable/recursively'
+
class Hash
- # Apply a block to hash, and recursively apply that block
- # to each subhash.
+ # Apply a block to a hash, and recursively apply that block
+ # to each sub-hash:
#
- # h = {:a=>1, :b=>{:b1=>1, :b2=>2}}
- # h.recursively{|h| h.rekey(&:to_s) }
- # => {"a"=>1, "b"=>{"b1"=>1, "b2"=>2}}
+ # h = {:a=>1, :b=>{:x=>1, :y=>2}}
+ # h.recursively.map{ |k,v| [k.to_s, v] }
+ # #=> [["a", 1], ["b", [["y", 2], ["x", 1]]]]
#
- def recursively(&block)
- warn "Use #recusive instead of #recursively for future versions"
- h = inject({}) do |hash, (key, value)|
- if value.is_a?(Hash)
- hash[key] = value.recursively(&block)
- else
- hash[key] = value
+ # The recursive iteration can be treated separately from the non-recursive
+ # iteration by passing a block to the #recursive method:
+ #
+ # h = {:a=>1, :b=>{:x=>1, :y=>2}}
+ # h.recursively{ |k,v| [k.to_s, v] }.map{ |k,v| [k.to_s, v.to_s] }
+ # #=> [["a", "1"], ["b", [["y", "2"], ["x", "1"]]]]
+ #
+ def recursively(*types, &block)
+ Recursor.new(self, *types, &block)
+ end
+
+ class Recursor < Enumerable::Recursor #:nodoc:
+ def method_missing(op, &yld)
+ yld = yld || lambda{ |k,v| [k,v] } # ? to_enum
+ rec = @block || yld #lambda{ |k,v| [k,v] }
+ @enum.__send__(op) do |k,v|
+ case v
+ when String # b/c of 1.8
+ yld.call(k,v)
+ when *@types
+ res = v.recursively(*@types, &@block).__send__(op,&yld)
+ rec.call(k, res)
+ else
+ yld.call(k,v)
+ end
end
- hash
end
- yield h
end
- # In place form of #recursively.
-
- def recursively!(&block)
- replace(recursively(&block))
+## TODO: When no longer need 1.8.6 support.
+=begin
+ def recursively(*types, &block)
+ types = types.empty? ? [self.class] : types
+ Functor.new do |op, &yld|
+ rec = block || yld
+ __send__(op) do |k,v|
+ case v
+ when *types
+ rec.call(k, v.recursively(*types, &block).__send__(op,&yld))
+ else
+ yld.call(k,v)
+ end
+ end
+ end
end
+=end
end
+