1

I have the following OpenStruct data structure, I'm trying to get key/value pair

> #<OpenStruct conditions=[#<OpenStruct field="Out_of_country", operator="us", values=["true"]>, #<OpenStruct field="Status__c",
> operator="jp", values=["'Approved'"]>, #<OpenStruct field="Status__c",
> operator="gb", values=["'Rejected'"]>], conjunction="and">

Ruby code:

dataResult = nil
dataResult = data['condition'].include?('out_of_country']

is that how you extract key/value pair from OpenStruct?

UPDATE:

you're right I was using the to_s and I remove and here is what I'm trying to access the key/value

myresult = data['mainCondtion']
p myresult --> I got this result:

  > #<OpenStruct conditions=[#<OpenStruct field="Out_of_country", operator="us", values=["true"]>, #<OpenStruct field="Status__c",
    > operator="jp", values=["'Approved'"]>, #<OpenStruct field="Status__c",
    > operator="gb", values=["'Rejected'"]>], conjunction="and">

then I try to access field and values

myresult.each_pair{ |key, value| puts "#{key}: #{value}" }

I get this error:

undefined method "each_pair" for #

Nick Kahn
  • 19,652
  • 91
  • 275
  • 406
  • That's pretty far from a minimal reproducible example. We have absolutely no clue what `data` is. – max May 07 '20 at 18:53
  • `data` has a bigger chuck and its a OpenStruct and I'm filtering out to get only the `mainCondition` which is subset of `data` – Nick Kahn May 07 '20 at 20:05
  • Yeah, but if you want debugging help you have to provide us with an example that reproduces the problem at hand and an actual error message. We have no idea what is going into this and what is happening in between `myresult = data['mainCondtion']` and `myresult.each_pair`. If we can't actually copy your code and run it this just leads to an endless chain of follow up questions. – max May 08 '20 at 10:48

2 Answers2

1

If you are just looking to get a single attribute of an OpenStruct you just call the getter method on it:

country = OpenStruct(name: 'Japan', alpha_2: "jp", alpha_3: "jpn")
puts country.name # japan
puts country.alpha_3 # jpn

This is kind of the whole point of an OpenStruct. You get an object that behaves like an instance of a class without actually having a class or having to define the attributes in advance like on a normal Struct.

You can use OpenStruct#each_pair to loop though its attributes like you would with a hash:

os = OpenStruct.new a: 1, b: 2, c: 3
os.each_pair{ |key, value| puts "#{key}: #{value}" }
# Outputs:
# a: 1
# b: 2
# c: 3
max
  • 96,212
  • 14
  • 104
  • 165
  • I try to do the same with example you showed with the `OpenStruct` I posted above and I get the error complaining `undefined method conditions for # – Nick Kahn May 07 '20 at 17:31
  • Well, for starters whatever you have is a string and not an OpenStruct. My guess is that you did something like `x = somevalue.inspect` or `x = somevalue.to_s`. I can't really tell you anything from the details you have provided though. – max May 07 '20 at 17:36
  • Max, I updated my question with the latest, please have a look – Nick Kahn May 07 '20 at 17:52
0

You are trying to loop over an array of hashes.

See this example answer on SO - How do I iterate over an array of hashes and return the values in a single string?

@max didn't like that I didn't post a long-form explanation, so I'm going to expand on my above answer.

irb(main):029:0> o = OpenStruct.new(foo: "bar", bar: "foo")
=> #<OpenStruct foo="bar", bar="foo">
irb(main):032:0> h = Hash.new
=> {}
irb(main):033:0> h[:foo] = "bar"
=> "bar"
irb(main):034:0> h[:bar] = "foo"
=> "foo"
irb(main):035:0> o
=> #<OpenStruct foo="bar", bar="foo">
irb(main):036:0> h
=> {:foo=>"bar", :bar=>"foo"}
irb(main):037:0> o.respond_to?(:each_pair)
=> true
irb(main):038:0> h.respond_to?(:each_pair)
=> true

Both OpenStructs and Hashes respond to the method that @max recommends - making them no different functionally in the case that you are describing.

irb(main):040:0> one = OpenStruct.new(field: "Out_of_country", operator: "us", values: ["true"])
=> #<OpenStruct field="Out_of_country", operator="us", values=["true"]>
irb(main):041:0> two = OpenStruct.new(field: "Out_of_country", operator: "jp", values: ["true"])
=> #<OpenStruct field="Out_of_country", operator="jp", values=["true"]>
irb(main):042:0> OpenStruct.new(conditions: [one, two])
=> #<OpenStruct conditions=[#<OpenStruct field="Out_of_country", operator="us", values=["true"]>, #<OpenStruct field="Out_of_country", operator="jp", values=["true"]>]>
irb(main):043:0> c = _
=> #<OpenStruct conditions=[#<OpenStruct field="Out_of_country", operator="us", values=["true"]>, #<OpenStruct field="Out_of_country", operator="jp", values=["true"]>]>
irb(main):044:0> hash_one = {field: "Out_of_country", operator: "us", values: ["true"]}
=> {:field=>"Out_of_country", :operator=>"us", :values=>["true"]}
irb(main):045:0> hash_two = {field: "Out_of_country", operator: "jp", values: ["true"]}
=> {:field=>"Out_of_country", :operator=>"jp", :values=>["true"]}
irb(main):046:0> hash_conditions = [hash_one, hash_two]
=> [{:field=>"Out_of_country", :operator=>"us", :values=>["true"]}, {:field=>"Out_of_country", :operator=>"jp", :values=>["true"]}]

irb(main):052:0> hash_conditions.each { |e| puts e[:operator] }
us
jp
=> [{:field=>"Out_of_country", :operator=>"us", :values=>["true"]}, {:field=>"Out_of_country", :operator=>"jp", :values=>["true"]}]
irb(main):053:0> c.conditions.each { |e| puts e[:operator] }
us
jp
=> [#<OpenStruct field="Out_of_country", operator="us", values=["true"]>, #<OpenStruct field="Out_of_country", operator="jp", values=["true"]>]

There is no functional difference.

tgmerritt
  • 714
  • 1
  • 7
  • 16
  • An [OpenStruct](https://ruby-doc.org/stdlib-2.5.1/libdoc/ostruct/rdoc/OpenStruct.html#method-i-each_pair) is not a Hash. – max May 07 '20 at 17:15
  • @max yes, but do you see any difference between Openstruct and hash? – Rajagopalan May 07 '20 at 18:32
  • @Rajagopalan what are you getting at? – max May 07 '20 at 18:51
  • @max functionally, to do what he wants to do, he can treat it as looping over an array of hashes. It's pedantic to say that OS != Hash when the operation he's trying to achieve would be achieved in the same way. You can access an OS key-value pair exactly the same way you can access a Hash key-value pair. I could have been more clear in my explanation, but functionally, for the question posted, there is no difference. – tgmerritt May 07 '20 at 20:24
  • @max, I see no difference in the way both have been used so I asked you – Rajagopalan May 07 '20 at 23:36
  • 1
    Functionally equivalent is an overstatement. You don't have to look farther then `OpenStruct#each` to find one example where they differ greatly. An OpenStruct is somewhat hashlike in that it defines `[]` and `[]=` but that's really where it ends. – max May 08 '20 at 10:38
  • Is it somewhat like a an array of hashes - yes. But that does not make the statement "You are trying to loop over an array of hashes." any less factually wrong. – max May 08 '20 at 10:46
  • @max You are right. Factually it's an inaccurate statement. But we approached this question differently. The question at the top of this page is "How to loop OpenStruct key/value pair" and the answer is not any different than looping over an Array of Hashes. So I've addressed the functional outcome of the original question. Now my answer didn't help the poster learn the in-depth composition of an OpenStruct, but that wasn't what was asked. – tgmerritt May 08 '20 at 20:30