Extending OpenStruct to be lazy and recursive

  • Thread starter Benjamin Kudria
  • Start date
B

Benjamin Kudria

I'm trying to extend OpenStruct for an application I'm building, where
I'd like to access nested hashes as models. OpenStruct (in core) sounds
perfect for this, but I ran into two problems:

- Recursion
My hashes have nested hashes, and I want to convert *those* to
objects, too. I was able to solve this problem pretty easily, see the
to_self method in the linked code [1].

However, this made me run into the second problem - speed. I was loading
rather large documents, and it was taking quite a bit of time to go
through them, instantiating classes for everything. I though I'd make
the code lazy-load, using the lazy.rb [0]

However, I overrode some more core methods for OpenStruct, to create
promises, and demand them, but now the code simply produces incorrect
results.

In IRB, I do:
LazyStruct.new({:a=>1, :b => 2}).a

But my result is 2, not 1. The code is here:
http://gist.github.com/467459

What could be going wrong? Any inishgt would be appreciatted. I'm using
Ruby 1.9.2-preview3

(Apologies for the Railsisms, this is part of a Rails project. The
classify method turns things into a string resembling a class, and
constantize turns that string into a constant - hopefully a class. This
code is bypassed in my simple example.)

0: http://github.com/mental/lazy

Thanks!
Benjamin Kudria
(e-mail address removed)
 
I

Intransition

I'm trying to extend OpenStruct for an application I'm building, where
I'd like to access nested hashes as models. OpenStruct (in core) sounds
perfect for this, but I ran into two problems:

=A0- Recursion
=A0 =A0 My hashes have nested hashes, and I want to convert *those* to
objects, too. I was able to solve this problem pretty easily, see the
to_self method in the linked code [1].

However, this made me run into the second problem - speed. I was loading
rather large documents, and it was taking quite a bit of time to go
through them, instantiating classes for everything. I though I'd make
the code lazy-load, using the lazy.rb [0]

However, I overrode some more core methods for OpenStruct, to create
promises, and demand them, but now the code simply produces incorrect
results.

In IRB, I do:
LazyStruct.new({:a=3D>1, :b =3D> 2}).a

But my result is 2, not 1. The code is here:http://gist.github.com/467459

What could be going wrong? Any inishgt would be appreciatted. I'm using
Ruby 1.9.2-preview3

Not 100%, but maybe have a look at Hashery's OpenCascade for some
ideas (http://rubyworks.github.com/hashery). I think you can do the
lazy lookup without using a Promise.
 
M

Michael Jackson

I've done something similar that's pretty lightweight. My version
actually extends Hash, so it should be pretty fast and you get all the
niceties of Hash for free.

http://mjijackson.com/symboltable
http://github.com/mjijackson/symboltable

--
Michael Jackson
http://mjijackson.com
@mjijackson



I'm trying to extend OpenStruct for an application I'm building, where
I'd like to access nested hashes as models. OpenStruct (in core) sounds
perfect for this, but I ran into two problems:

=A0- Recursion
=A0 =A0My hashes have nested hashes, and I want to convert *those* to
objects, too. I was able to solve this problem pretty easily, see the
to_self method in the linked code [1].

However, this made me run into the second problem - speed. I was loading
rather large documents, and it was taking quite a bit of time to go
through them, instantiating classes for everything. I though I'd make
the code lazy-load, using the lazy.rb [0]

However, I overrode some more core methods for OpenStruct, to create
promises, and demand them, but now the code simply produces incorrect
results.

In IRB, I do:
LazyStruct.new({:a=3D>1, :b =3D> 2}).a

But my result is 2, not 1. The code is here:
http://gist.github.com/467459

What could be going wrong? Any inishgt would be appreciatted. I'm using
Ruby 1.9.2-preview3

(Apologies for the Railsisms, this is part of a Rails project. The
classify method turns things into a string resembling a class, and
constantize turns that string into a constant - hopefully a class. This
code is bypassed in my simple example.)

0: http://github.com/mental/lazy

Thanks!
Benjamin Kudria
(e-mail address removed)
 
B

Benjamin Kudria

Michael said:
I've done something similar that's pretty lightweight. My version
actually extends Hash, so it should be pretty fast and you get all the
niceties of Hash for free.

Michael, thanks for the pointer, but I don't really see how it helps.
Your code doesn't support recursive conversion, or lazy property
retrieval. I'm content with using OpenStruct for all the functionality
your code provides.

Thomas said:
Not 100%, but maybe have a look at Hashery's OpenCascade for some
ideas (http://rubyworks.github.com/hashery). I think you can do the
lazy lookup without using a Promise.

Indeed, my initial version didn't use mental's library, but I had to
reach way deeper into OpenStruct to make the appropriate changes.

OpenCascade is awesome! But,I left out a small detail of my
implementation that is actually rather important - my to_self method
actually tries to find a class corresponding to the name of the key (the
classify.constantize call) and use that if available. So, {:authors =>
[{:name => 'Poe'}, {:name => 'Lovecraft'}]} would actually end up
converting to two Author objects, if the class were available, passing
the hash to the initialize method. This functionality is important to
me, it allows me to hang business logic on sub-documents in my overall
document. OpenCascade, it seems, converts only to OpenCascade.

(I may take a detour and subclass OpenCascade instead, modify it to
support my auto-classifying,, and compare the two approaches.)

Fortunately, mental clued me into the problem with my code [1] shortly
after I posted this. For future reference, I was creating the promise
(with its associated block) and closing over the same k and v variables,
instead of creating a new scope every time. I separated the call out to
a method, and everything worked.

Benjamin Kudria
(e-mail address removed)

1: http://twitter.com/mentalguy/status/17993170022 and
http://twitter.com/mentalguy/status/17993202421
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top