简体   繁体   中英

Can I create methods from a ruby REST API call?

I am creating a client for a REST API that returns JSON like so:

2.1.5 :006 > system = api.system
=> {"DatabaseVersion"=>5, "Name"=>"Orthanc", "Version"=>"0.8.6"} 

I'm wondering if there is a way to convert those JSON keys into methods so I could call something like

version = api.system.version

And would get the value of that JSON key:

=> "0.8.6" 

Obviously I could hardcode each JSON item key as a method in the client, retrieving the value of a specific key with something like:

api.system["Version"]

But I'm wondering if this can be done programatically for each key/value that is received, without previous knowledge of the keys/values to be returned

OpenStruct comes to the rescue:

▶ os = OpenStruct.new({
▷   "DatabaseVersion"=>5,
▷   "Name"=>"Orthanc",
▷   "Version"=>"0.8.6"
▷ })
▶ os.DatabaseVersion
#⇒ 5

edit :

As @mudasobwa pointed out, there is already a standard implementation, with a class that uses method_missing and an inner Hash object...

Apparently this behavior is loved by many and found it's way to the standard library.

see the documentation on OpenStruct .

remember to require the implementation using: require 'ostruct'

original post :

I think you might be looking for a solution based on method_missing .

It's possible to monkey patch the Hash class for a behavior that will mimic what you want.

Here's a quick dirty patch:

class Hash

  def method_missing(name, *args, &block)
    # getter for symbole
    return self[name] if self.has_key? name 
    # getter for String
    return self[name.to_s] if self.has_key? name.to_s 
    # setter for adding or editing hash keys,
    # using the shortcut hash.key = value.
    if name.to_s[-1] == '=' && name.to_s.length > 1
      self.[]=(name.to_s[0..-2], *args)
      self.[]=(name.to_s[0..-2].to_sym, *args)
      return *args
    end
    # nothing happened? move it up the chain for default behavior.
    # (assumes Hash doesn't handle missing methods).
    super
  end

end

This will behave like an 'on the fly' getter and setter. Notice the getter will work only for existing properties and that numbers are not supported (only Strings and symbols).

Also notice that symbols and strings will be unified - if will not be possible to use a symbol and a string for different values using these getter/setters. Also, symbols will have priority.

Personally, I would probably forgo such a solution of convenience or opt to sub-classing the Hash class. I'm not too comfortable with monkey patches.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM