Reputation: 1751
I am trying to use method_missing to convert dollar to different currencies.
class Numeric
@@currency={"euro"=>2, "yen"=>6}
def method_missing(method_id,*args,&block)
method_id.to_s.gsub!(/s$/,'') #get rid of s in order to handle "euros"
@@currency.has_key?(method_id) ? self*@@currency[method_id] : super
end
end
> 3.euro #expect to return 6
NoMethodError: undefined method 'euro' for 3:Fixnum
from (pry):24:in 'method_missing'
> 3.euros #expect to return 6
NoMethodError: undefined method 'euros' for 3:Fixnum
from (pry):24:in 'method_missing'
I guess 3.euro
isn't working because :euro.to_s.gsub!(/s$/,'')
returns nil
. I am not sure why it returns no method error.
Thanks for any help.
Upvotes: 3
Views: 555
Reputation: 118261
When method_missing will be called, then euro
will be assigned to the method_id
as a symbol. But your @@currency
hash holds all keys as a strings, you need to convert them as symbols.
method_id.to_s.gsub!(/s$/,'')
no way will change the actual object method_id
. Because method_id.to_s
will give you a new string object, and #gsub!
will work on this only. No way you are changing the method_id
, it remains as it is. Better to use non-bang one, because it will give you the actual object if no change made, or changed object, if change is made, then you need to assign this return value to a new variable.
With your @@currency
, @@currency.has_key?(method_id)
evaluated as false
and super
class method_missing
has been called. Why? As method_id
didn't convert into strings, which you expected may happened.
But, if you want to respond for both like euro
or euros
, then
class Numeric
@@currency={"euro" => 2, "yen" => 6}
def method_missing(method_id,*args,&block)
#get rid of s in order to handle "euros"
new_method_id = method_id.to_s.gsub(/s$/,'')
@@currency.has_key?(new_method_id) ? self*@@currency[new_method_id] : super
end
end
3.euros # => 6
3.euro # => 6
Upvotes: 4
Reputation: 46183
gsub!
modifies a string in place and returns nil
. That won't work very well with the string you're using, which is a temporary created by to_s
and never stored in a variable. Also, you are not even storing the result anywhere anyway. Why should gsub!
on a string be expected to modify symbols, which are immutable anyway?
Try using gsub
instead, which returns the modified string and leaves the caller alone. You'll also need to store the return value.
real_method_name = method_id.to_s.gsub(/s$/, "")
Also: The reason 3.euro
didn't work is because your hash uses strings as keys but method_id
is passed to the method as a symbol. If you didn't have to do string manipulations (to remove s suffixes, in this case), I would have suggested to just use symbols as your hash keys. As it is, though, you need to do string operations anyway, so my answer uses strings.
Upvotes: 1