Forum: Ruby OpenStruct,, know what keys are set

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Aaron S. (Guest)
on 2007-03-10 10:29
I need to use an OpenStruct to mimic what an object acts like in another
language. is it possible somehow to find what keys are set on an
OpenStruct at any given time?

thanks
Sharon P. (Guest)
on 2007-03-10 11:37
(Received via mailing list)
On 10/03/2007, at 7:29 PM, Aaron S. wrote:

> I need to use an OpenStruct to mimic what an object acts like in
> another
> language. is it possible somehow to find what keys are set on an
> OpenStruct at any given time?

Disclaimer: I'm fairly new to this, so there's a reasonable chance
I'm wrong to some degree.

Internally, OpenStruct stores the keys as symbols in a hash in an
array @table which can be accessed via marshal_dump.

Alternatively, you may like to add a method like keys_added:

require 'ostruct'

class OpenStruct
  def keys_added
    @table.keys.map{|k| k.to_s}
  end
end

person= OpenStruct.new
person.name= "Fred"
person.age= 100

person.keys_added
=> ["age", "name"]
Robert K. (Guest)
on 2007-03-10 12:45
(Received via mailing list)
On 10.03.2007 10:36, Sharon P. wrote:
> @table which can be accessed via marshal_dump.
>
> person= OpenStruct.new
> person.name= "Fred"
> person.age= 100
>
> person.keys_added
> => ["age", "name"]

Yeah, there doesn't seem to be a public method for this.  An alternative
approach (btw, I'd stick with symbols as they are more efficient):

irb(main):010:0> o=OpenStruct.new
=> #<OpenStruct>
irb(main):011:0> o.foo=1
=> 1
irb(main):012:0> o.bar=2
=> 2
irb(main):013:0> o.instance_variable_get("@table").keys
=> [:bar, :foo]

OTOH, if you frequently need to get the list of defined members a Hash
is probably a better choice.

Kind regards

  robert
Nobuyoshi N. (Guest)
on 2007-03-10 15:41
(Received via mailing list)
Hi,

At Sat, 10 Mar 2007 17:29:18 +0900,
Aaron S. wrote in [ruby-talk:242836]:
> I need to use an OpenStruct to mimic what an object acts like in another
> language. is it possible somehow to find what keys are set on an
> OpenStruct at any given time?

o = OpenStruct.new
o.foo = 1
o.bar = 2
p o.methods(false).grep(/[^=]$/) #=> ["bar", "foo"]
Aaron S. (Guest)
on 2007-03-10 17:53
Thanks for all the input.

Heres some testing:

require 'ostruct'
require 'benchmark'

lady = OpenStruct.new
0.upto(100) do |i|
  eval("lady.cat#{i} = i")
  #puts eval("lady.cat#{i}")
end

Benchmark.bm do |x|
  x.report("Find all keys 1"){lady.methods(false).grep(/[^=]$/)}
  x.report("Find all keys 2"){lady.instance_variable_get("@table").keys}
  x.report("Find all keys 3"){lady.keys_added}
end

#puts "\n" + lady.methods(false).grep(/[^=]$/).to_s
#puts "\n" + lady.instance_variable_get("@table").keys.to_s
#puts "\n" + lady.keys_added #this is always nil.


OUTPUT:
                 user     system      total        real
Find all keys 1  1.130000   0.050000   1.180000 (  1.185657)
Find all keys 2  0.020000   0.000000   0.020000 (  0.019773)
Find all keys 3  0.000000   0.000000   0.000000 (  0.000020)

Results speak for themselves.
Robert K. (Guest)
on 2007-03-10 18:36
(Received via mailing list)
On 10.03.2007 16:53, Aaron S. wrote:
>   #puts eval("lady.cat#{i}")
> #puts "\n" + lady.keys_added #this is always nil.
>
>
> OUTPUT:
>                  user     system      total        real
> Find all keys 1  1.130000   0.050000   1.180000 (  1.185657)
> Find all keys 2  0.020000   0.000000   0.020000 (  0.019773)
> Find all keys 3  0.000000   0.000000   0.000000 (  0.000020)
>
> Results speak for themselves.

Um, for what implementation of "keys_added"?  The comment points out
that it always returns nil - I suspect you just measured performance of
an OpenStruct ad hoc getter:

irb(main):005:0> OpenStruct.new.keys_added
=> nil
irb(main):006:0> OpenStruct.new.foo_bar
=> nil

Kind regards

  robert
Aaron S. (Guest)
on 2007-03-10 18:54
> Um, for what implementation of "keys_added"?  The comment points out
> that it always returns nil - I suspect you just measured performance of
> an OpenStruct ad hoc getter:
>
> irb(main):005:0> OpenStruct.new.keys_added
> => nil
> irb(main):006:0> OpenStruct.new.foo_bar
> => nil
>
> Kind regards
>
>   robert

Ah yes, you caught me. I completely overlooked this code in the above
exmaple:
class OpenStruct
  def keys_added
    @table.keys.map{|k| k.to_s}
  end
end


--
New Tests:

require 'ostruct'
require 'benchmark'

class OpenStruct
  def keys_added
    @table.keys.map{|k| k.to_s}
  end
end

lady = OpenStruct.new
0.upto(10) do |i|
  eval("lady.cat#{i} = i")
  #puts eval("lady.cat#{i}")
end

Benchmark.bm do |x|
  x.report("Find all keys 1"){lady.methods(false).grep(/[^=]$/)}
  x.report("Find all keys 2"){lady.instance_variable_get("@table").keys}
  x.report("Find all keys 3"){lady.keys_added}
  x.report("Find all keys
4"){lady.instance_variable_get("@table").keys.map{|k| k.to_s }}
end


#puts "\n" + lady.methods(false).grep(/[^=]$/).to_s
#puts "\n" + lady.instance_variable_get("@table").keys.to_s
#puts "\n" + lady.keys_added.to_s
#puts "\n" + lady.instance_variable_get("@table").keys.map{|k| k.to_s
}.to_s


OUTPUT:
                 user     system      total        real
Find all keys 1  0.000000   0.000000   0.000000 (  0.000077)
Find all keys 2  0.000000   0.000000   0.000000 (  0.000014)
Find all keys 3  0.000000   0.000000   0.000000 (  0.000017)
Find all keys 4  0.000000   0.000000   0.000000 (  0.000016)
Robert K. (Guest)
on 2007-03-11 00:46
(Received via mailing list)
On 10.03.2007 17:54, Aaron S. wrote:
>>
>
> end
>   x.report("Find all keys 3"){lady.keys_added}
>
>
> OUTPUT:
>                  user     system      total        real
> Find all keys 1  0.000000   0.000000   0.000000 (  0.000077)
> Find all keys 2  0.000000   0.000000   0.000000 (  0.000014)
> Find all keys 3  0.000000   0.000000   0.000000 (  0.000017)
> Find all keys 4  0.000000   0.000000   0.000000 (  0.000016)
>

You should add iterations to the blocks - otherwise the figures are
pretty uninformative. :-)  Using bmbm (with rehearsal) might also be a
good idea.

Kind regards

  robert
Aaron S. (Guest)
on 2007-03-11 01:08
Robert K. wrote:
> On 10.03.2007 17:54, Aaron S. wrote:
>>>
>>
>> end
>>   x.report("Find all keys 3"){lady.keys_added}
>>
>>
>> OUTPUT:
>>                  user     system      total        real
>> Find all keys 1  0.000000   0.000000   0.000000 (  0.000077)
>> Find all keys 2  0.000000   0.000000   0.000000 (  0.000014)
>> Find all keys 3  0.000000   0.000000   0.000000 (  0.000017)
>> Find all keys 4  0.000000   0.000000   0.000000 (  0.000016)
>>
>
> You should add iterations to the blocks - otherwise the figures are
> pretty uninformative. :-)  Using bmbm (with rehearsal) might also be a
> good idea.
>
> Kind regards
>
>   robert

Or if you change the amount of cats the lady has, from 10 to 100000.
then you'll see something more:

lady = OpenStruct.new
0.upto(100000) do |i|
  eval("lady.cat#{i} = i")
  #puts eval("lady.cat#{i}")
end

i'll add iterations to the blocks as well.
Jan F. (Guest)
on 2007-03-12 14:44
o = OpenStruct.new
o.foo = 2
o.bar = 4
o.marshal_dump # => {:foo=>2, :bar=>4}
o.marshal_dump.keys # => [:foo, :bar]

regards,
Jan
Aaron S. (Guest)
on 2007-03-12 21:59
Jan F. wrote:
> o = OpenStruct.new
> o.foo = 2
> o.bar = 4
> o.marshal_dump # => {:foo=>2, :bar=>4}
> o.marshal_dump.keys # => [:foo, :bar]
>
> regards,
> Jan

nice one, that's faster..

require 'ostruct'
require 'benchmark'

class OpenStruct
  def keys_added
    @table.keys.map{|k| k.to_s}
  end
end

lady = OpenStruct.new
0.upto(10) do |i|
  eval("lady.cat#{i} = i")
  #puts eval("lady.cat#{i}")
end

Benchmark.bm do |x|
  x.report("Find all keys 1"){
    0.upto(100000) do
      lady.methods(false).grep(/[^=]$/)
    end
  }

  x.report("Find all keys 2"){
    0.upto(100000) do
      lady.instance_variable_get("@table").keys
    end
  }

  x.report("Find all keys 3"){
    0.upto(100000) do
      lady.keys_added
    end
  }


  x.report("Find all keys 4"){
    0.upto(100000) do
      lady.instance_variable_get("@table").keys.map{|k| k.to_s }
    end
  }

  x.report("Find all keys 5"){
    0.upto(100000) do
      lady.marshal_dump.keys
    end
  }
end

user     system      total        real
Find all keys 1  4.110000   0.010000   4.120000 (  4.151098)
Find all keys 2  0.160000   0.000000   0.160000 (  0.153028)
Find all keys 3  0.870000   0.010000   0.880000 (  0.884275)
Find all keys 4  0.900000   0.000000   0.900000 (  0.897666)
Find all keys 5  0.130000   0.000000   0.130000 (  0.137231)
Sharon P. (Guest)
on 2007-03-13 00:47
(Received via mailing list)
On 13/03/2007, at 6:59 AM, Aaron S. wrote:

> nice one, that's faster..
marshal_dump returns @table, so marshal_dump.keys == @table.keys
except that @table is not accessable from outside OpenStruct.
http://www.ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/
OpenStruct.html
Click on the [Source] link to see the code behind these methods.

Note that some of your examples here return symbols (2 and 5) whilst
3 and 4 take an extra step of transforming these into strings.

Looks like you're having fun :)
Dave
Aaron S. (Guest)
on 2007-03-13 02:36
Sharon P. wrote:
> On 13/03/2007, at 6:59 AM, Aaron S. wrote:
>
>> nice one, that's faster..
> marshal_dump returns @table, so marshal_dump.keys == @table.keys
> except that @table is not accessable from outside OpenStruct.
> http://www.ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/
> OpenStruct.html
> Click on the [Source] link to see the code behind these methods.
>
> Note that some of your examples here return symbols (2 and 5) whilst
> 3 and 4 take an extra step of transforming these into strings.
>
> Looks like you're having fun :)
> Dave

Hey Dave, thanks,
yes I love ruby. I've never had so much fun with a programming language.

It didn't even occur to me I have k.to_s in example 4. I appreciate
you're input.

-a
Trans (Guest)
on 2007-03-13 02:56
(Received via mailing list)
On Mar 10, 4:29 am, Aaron S. <removed_email_address@domain.invalid> wrote:
> I need to use an OpenStruct to mimic what an object acts like in another
> language. is it possible somehow to find what keys are set on an
> OpenStruct at any given time?
>
> thanks

a little late to the party but in any case...

  require 'facets/core/ostruct/instance_delegate'

  OpenStruct.new(:a=>1,:b=>2).instance_delegate.keys  #=> [ :a, :b ]

T.
This topic is locked and can not be replied to.