Defining a method to select values from a hash.

Discussion in 'Ruby' started by Danny Tatom, May 29, 2009.

  1. Danny Tatom

    Danny Tatom Guest

    I'm terribly confused with this, and can't seem to figure it out (or
    explain it).

    Using HTTParty, I have a method that grabs some XML and returns it as a
    hash:

    def check(data)
    @results = self.class.post('/checkDocument', :query => {:key =>
    @key,
    :data => data})
    end

    def errors
    errors = @results['results']['error']
    end

    An example of the hash it returns:
    >> atd.check("I'm realy hating this wether")

    => [{"suggestions"=>{"option"=>["really", "ready", "real", "relay",
    "realty"]}, "precontext"=>"I'm", "type"=>"spelling", "string"=>"realy",
    "description"=>"Spelling"}, {"suggestions"=>{"option"=>["weather",
    "whether"]},
    "url"=>"http://service.afterthedeadline.com/info.slp?text=wether",
    "precontext"=>"this", "type"=>"spelling", "string"=>"wether",
    "description"=>"Did you mean..."}]

    Now calling the .errors method, I can get the string from each one like
    this:
    >> atd.errors.each { |error| p error['string'] }

    "realy"
    "wether"

    What I'd like to do is write a method for string, so that
    atd.errors.each { |error| p.error.string } would result in the same
    thing. For the life of me, I can't figure out how to do that. :/

    The other problem I'm having with the way I'm doing it now is that
    calling .errors.each when there's only one error sent back gives me a
    "can't convert String into Integer" error.

    So, if anyone could point me in the right direction, I'd appreciate it.
    :)
    --
    Posted via http://www.ruby-forum.com/.
    Danny Tatom, May 29, 2009
    #1
    1. Advertising

  2. You want foo['bar'] and foo.bar to be the same thing, like in
    Javascript? In that case you need to modify Hash, not String. Below is
    some code which does that.

    ---- 8< ----
    # Extend a Hash with this module to get semantics of a Javascript
    object:
    # me.foo is the same as me['foo']
    module JSObjectMixin
    def method_missing(meth,*rest,&blk)
    key = meth.to_s
    if key[-1] == ?=
    self[key[0..-2]] = rest.first
    else
    self[key]
    end
    end
    end

    def extend_jsobject(tree)
    case tree
    when Hash
    tree.extend JSObjectMixin
    tree.each do |k,v|
    extend_jsobject(v)
    end
    when Array
    tree.each do |v|
    extend_jsobject(v)
    end
    end
    end

    errors = [{"suggestions"=>{"option"=>["really", "ready", "real",
    "relay",
    "realty"]}, "precontext"=>"I'm", "type"=>"spelling",
    "string"=>"realy",
    "description"=>"Spelling"}, {"suggestions"=>{"option"=>["weather",
    "whether"]},
    "url"=>"http://service.afterthedeadline.com/info.slp?text=wether",
    "precontext"=>"this", "type"=>"spelling", "string"=>"wether",
    "description"=>"Did you mean..."}]
    extend_jsobject(errors)

    errors.each { |error| p error['string'] }
    errors.each { |error| p error.string }
    ---- 8< ----

    Another option would be to walk your results structure and replace each
    Hash with an OpenStruct (see ostruct.rb in the standard library).
    However, that would _only_ allow error.string, not error['string']

    > The other problem I'm having with the way I'm doing it now is that
    > calling .errors.each when there's only one error sent back gives me a
    > "can't convert String into Integer" error.


    Simple solution:

    Array(atd.errors).each { ... }

    If atd.errors is already an Array this does nothing; if it isn't, then
    it is wrapped in a one-element array.

    Better solution: If this is using XML::Simple internally, there's an
    option you can give it to return arrays always, even when there's only a
    single instance (or I believe you can tell it to do this for specific
    tags). I can't remember offhand what that option is, but you should be
    able to find it. Then see if the library you're using allows that option
    to be passed through.

    HTH,

    Brian.
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, May 29, 2009
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. johny smith
    Replies:
    8
    Views:
    416
    Peter Koch Larsen
    Jul 2, 2004
  2. Sam
    Replies:
    3
    Views:
    243
    Gerard Flanagan
    Mar 10, 2008
  3. rp
    Replies:
    1
    Views:
    517
    red floyd
    Nov 10, 2011
  4. Erik Veenstra

    Hash#select and Hash#reject

    Erik Veenstra, Sep 21, 2005, in forum: Ruby
    Replies:
    0
    Views:
    117
    Erik Veenstra
    Sep 21, 2005
  5. Srijayanth Sridhar
    Replies:
    19
    Views:
    615
    David A. Black
    Jul 2, 2008
Loading...

Share This Page