Trans,
Can you show us more "useful" example? Your usecase does not feel "right" for me, no more than consistency. In general, I buy YAGNI over consistency.
- matz.
Sure, I can give some other use cases, though I think this has been the most useful for me. FYI IAUI (I Am Using It) just as I give in my example. Makes it a snap to accept either a hash, any other object that responds to #to_h or an assignment block as an argument.
While I'm looking, here's a related use for populating a class. This is nice to use in #initialize for the similar reasons (Notice the embedded comment, I think that's mildly relevant).
require 'facets/core/hash/to_h'
require 'facets/core/proc/to_h'
module Kernel
# Similar to #set_with, but ignores missing setters.
def populate( data=nil, &yld )
if data = (data || yld).to_h
data.each do |k,v|
send( "#{k}=", v ) rescue nil
end
end
# If the context of the error could be known
# Maybe this could be used instead of converting
# the block to a hash.
#begin
# yield self
#rescue NoMethodError => e
# if e.context == self and e.name.to_s =~ /=$/
# resume
# else
# raise e
# end
#end
self
end
end
Trans,
You need to give us more information. I am confusing how adding to_h to Proc can be useful. I don't even understand what your populate method does.
Sorry.
- matz.
That's okay. #populate takes a hash and iterates through each pair calling writer methods by the key's name, ie. send("#{key}=", value), but it won't bomb is there is no writer by the key's name (hence the 'rescue nil'). It also can take a block, which basically is called via yield(self) BUT we don't want it to bomb if the writer method doesn't exist, so we convert it to a hash ans used it that way. The upshot is code like this:
class Foo
attr_accessor :x, :y
def initialize(d=nil,&b)
populate(d,&b)
end
def show
@x + ' ' + @y
end
end
f1 = Foo.new(:x => "Hello", :y=>"World")
f1.show #=> "Hello World"
f2 = Foo.new { |foo|
foo.x = "Good"
foo.y = "Bye"
}
f2.show #-> "Good Bye"
It's a versitle way to fill out a new object's attributes with either a hash or a block.
Ok, now I understand what populate does. It is a very interesting trick.
But still, your example introduces unnecessary relationship between Proc and Hash. Proc is not automatically convertible to Hash in general. Is there any other object suitable to have to_s method?
-matz.
Just thought of another case: nil. NilClass has #to_s, #to_i and #to_a, but not #to_h. Yet #to_h can be just as useful for similar reasons. Passing nil to a method that normally accepts "hashy" objects and verifies it via #to_h is just as reasonable, and would be expected to take a nil value just as a method would for any of the core types.
def expect_stringy_thing(x)
x.to_s
end
def expect_integery_thing(x)
x.to_i
end
def expect_arrayee_thing(x)
x.to_a
end
All accept nil without issue. Why is Hash exceptional?
Logan Capaldo presents another potential use in ruby-
talk:222573.
class Array
def to_h
Hash[*self]
end
end
%w{ a x b y }.to_h #=> {'a'=>'1', 'b'=>'y'}
Although one could also argue that it should turn an associative array into a hash instead, thus allowing round tripping. Eg.
a == a.to_h.to_a
I think #to_hash is better in that case, since associative arrays and hashes are essentially similar.
In anycase, the above implementation is another potential usecase for #to_h.
T.
Can you show us more "useful" example? Your usecase does not feel "right" for me, no more than consistency. In general, I buy YAGNI over consistency.
- matz.
Sure, I can give some other use cases, though I think this has been the most useful for me. FYI IAUI (I Am Using It) just as I give in my example. Makes it a snap to accept either a hash, any other object that responds to #to_h or an assignment block as an argument.
While I'm looking, here's a related use for populating a class. This is nice to use in #initialize for the similar reasons (Notice the embedded comment, I think that's mildly relevant).
require 'facets/core/hash/to_h' require 'facets/core/proc/to_h' module Kernel # Similar to #set_with, but ignores missing setters. def populate( data=nil, &yld ) if data = (data || yld).to_h data.each do |k,v| send( "#{k}=", v ) rescue nil end end # If the context of the error could be known # Maybe this could be used instead of converting # the block to a hash. #begin # yield self #rescue NoMethodError => e # if e.context == self and e.name.to_s =~ /=$/ # resume # else # raise e # end #end self end endTrans,
You need to give us more information. I am confusing how adding to_h to Proc can be useful. I don't even understand what your populate method does.
Sorry.
- matz.
That's okay. #populate takes a hash and iterates through each pair calling writer methods by the key's name, ie. send("#{key}=", value), but it won't bomb is there is no writer by the key's name (hence the 'rescue nil'). It also can take a block, which basically is called via yield(self) BUT we don't want it to bomb if the writer method doesn't exist, so we convert it to a hash ans used it that way. The upshot is code like this:
class Foo attr_accessor :x, :y def initialize(d=nil,&b) populate(d,&b) end def show @x + ' ' + @y end end f1 = Foo.new(:x => "Hello", :y=>"World") f1.show #=> "Hello World" f2 = Foo.new { |foo| foo.x = "Good" foo.y = "Bye" } f2.show #-> "Good Bye"It's a versitle way to fill out a new object's attributes with either a hash or a block.
Ok, now I understand what populate does. It is a very interesting trick.
But still, your example introduces unnecessary relationship between Proc and Hash. Proc is not automatically convertible to Hash in general. Is there any other object suitable to have to_s method?
-matz.
Just thought of another case: nil. NilClass has #to_s, #to_i and #to_a, but not #to_h. Yet #to_h can be just as useful for similar reasons. Passing nil to a method that normally accepts "hashy" objects and verifies it via #to_h is just as reasonable, and would be expected to take a nil value just as a method would for any of the core types.
def expect_stringy_thing(x) x.to_s end def expect_integery_thing(x) x.to_i end def expect_arrayee_thing(x) x.to_a endAll accept nil without issue. Why is Hash exceptional?
Logan Capaldo presents another potential use in ruby-talk:222573.
class Array def to_h Hash[*self] end end %w{ a x b y }.to_h #=> {'a'=>'1', 'b'=>'y'}Although one could also argue that it should turn an associative array into a hash instead, thus allowing round tripping. Eg.
I think #to_hash is better in that case, since associative arrays and hashes are essentially similar.
In anycase, the above implementation is another potential usecase for #to_h.
T.