1 2 3 4 5 6 7 8 9 10 11 12 13 14
class MyFancyClass def initialize(hash) ... end end @json = '{ "type": "world", "message": "hello" }' @json.gsub!("type", "mtype") post = JSON.parse(@json) test = MyFancyClass.new(post) do_something(test.mtype)
Refactorings
No refactoring yet !
Dragan Cvetinovic
June 17, 2010, June 17, 2010 09:00, permalink
One way to solve this is by using "BlankSlate" technique :
"BlankSlate provides an abstract base class with no predefined
methods (except for __send__ and __id__(*)).
BlankSlate is useful as a base class when writing classes that
depend upon method_missing (e.g. dynamic proxies)."
(for more details see for instance BlankSlate implementation in hpricot gem by Jim Weirich)
(*) or whatever method is excepted by your implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
class BlankSlate class << self def hide(name) undef_method name if instance_methods.include?(name) and name !~ /^(__|instance_eval)/ end end instance_methods.each { |m| hide(m) } end class MyFancyClass < BlankSlate def initialize(hash) ... end end @json = '{ "type": "world", "message": "hello" }' post = JSON.parse(@json) test = MyFancyClass.new(post) test.type # => world
Dragan Cvetinovic
June 21, 2010, June 21, 2010 14:51, permalink
For instance :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
require 'json' class BlankSlate class << self def hide(name) undef_method name if instance_methods.include?(name) and name !~ /^(__|instance_eval|object_id)/ end end instance_methods.each { |m| hide(m) } end class MyFancyClass < BlankSlate def initialize(hash) @attributes = hash end def method_missing(name, *args) attribute = name.to_s super unless @attributes[attribute] @attributes[attribute] end end @json = '{ "type": "world", "message": "hello" }' #@json.gsub!("type", "mtype") post = JSON.parse(@json) test = MyFancyClass.new(post) puts test.type #=> world
When you work with APIs that return JSON response, its common to have field named "type".
The problem is that "type" is a reserved word in ruby. As soon as you transform your hash into an object with that type method collision happen, type will return the class name.
(this method is depreciated for class instead, but the problem is still the same even if its less common to see "class" field in APIs)
I'm using a simple gsub to fix the problem and access the field, but as you can see, its neither robust or elegant.