0

i am trying to write a method_missing method, so that when i run a method it must hit the hash and look at the keys, if it finds a match to return the value. and continue. the hash is populated from a sql query that i wrote so the values are never constant.

an example would be like

 @month_id.number_of_white_envelopes_made

in the hash

 @data_hash[number_of_white_envelopes_made] => 1

so @month_id will return 1. i have never worked with it before, not much material out there using hashes as the fall back with method missing

EDIT: sorry i forgot to say if it doesnt find the method in the hash then it can continue down to no method error

EDIT: alright so i was hacking away and this is what i have come up with

 def method_missing(method)
   if @data_hash.has_key? method.to_sym
     return @data_hash[method]
   else
     super
   end
 end

is there a better way?

legendary_rob
  • 12,792
  • 11
  • 56
  • 102
  • 2
    How about using [OpenStruct](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/ostruct/rdoc/OpenStruct.html) instead? You can initialize an instance of `OpenStruct` from a hash and reference its attributes using `struct.attribute` syntax. If the value is missing it will simply return `nil`, but otherwise looks like it might work for you. – KL-7 Apr 25 '12 at 11:18
  • 1
    @KL-7 +1 OpenStruct happens to use `method_missing` underneath. – steenslag Apr 25 '12 at 11:23
  • the problem is that there are close too 150 keys?? so creating a struct will be making a lot more work. i am placing it in a presenter so the methods are scattered through out the program sometimes some methods would be used and other times other methods would be used and if i use a hash once the missing method is called the method would be defined and the next time it is called it will be saved in memory – legendary_rob Apr 25 '12 at 11:25
  • @steenslag sure it does, but it saves you from doing it yourself. – KL-7 Apr 25 '12 at 11:28
  • @TheLegend, when you say 'a lot more work' do you mean more work for you or for Ruby? Ruby doesn't define new method and doesn't save anything in memory on its own when you handle smth via `method_missing`. – KL-7 Apr 25 '12 at 11:29
  • never though about OpenStructs using method missing. makes sense being able to access atributes on the fly :D – legendary_rob Apr 25 '12 at 11:31
  • @KL-7 more work for me :D LOL – legendary_rob Apr 25 '12 at 11:32
  • there are many ways that i could have done it i could have cracked open the hash and written methods for each KV pair, and that would have been the most efficient way fro ruby. just trying to be creative – legendary_rob Apr 25 '12 at 11:34
  • 1
    @TheLegend using OpenStruct is less work for you as you just pass hash into its constructor. Btw, looks like OpenStruct uses `method_missing` only when you reference attribute for the 1st time. For later access it [defines](https://github.com/ruby/ruby/blob/trunk/lib/ostruct.rb#L168-177) full-fledged getter and setter. – KL-7 Apr 25 '12 at 11:36
  • @kl-7 sweet thanks for the idea, ill go try a mock up of it now :D – legendary_rob Apr 25 '12 at 11:43

2 Answers2

6

What about something like:

def method_missing(method_sym, *arguments, &block)
  if @data_hash.include? method_sym
    @data_hash[method_sym]
  else
    super
  end
end

And always remember to add the corresponding respond_to? to your object:

def respond_to?(method_sym, include_private = false)
  if @data_hash.include? method_sym
    true
  else
    super
  end
end
Alberto Santini
  • 6,425
  • 1
  • 26
  • 37
2

The shortest is

class Hash
  def method_missing(sym,*)
    fetch(sym){fetch(sym.to_s){super}}
  end
end

which first tries hash[:key] and then hash["key"]

akuhn
  • 27,477
  • 2
  • 76
  • 91