On Sep 5, 7:54=A0am, "Robert Klemme" <shortcut... / googlemail.com> wrote:
> Hi,
>
> I just had a use case where I wanted to have several counters and not
> store them in a Hash because of the nicer syntax of OpenStruct.
> Currently, the code has to do
>
> counters =3D OpenStruct.new
> ...
> counters.foo ||=3D 0
> counters.foo +=3D 1
>
> For obvious reasons I'd like to get rid of the initialization.
>
> The suggestion would be to do this: if the argument to
> OpenStruct#initialize is not a Hash use it as default value which is
> returned for undefined properties. As far as I can see this won't
> break existing code since the default is nil. =A0With the change one
> could do
>
> counters =3D OpenStruct.new 0
> ...
> counters.foo +=3D 1
>
> We could go even further and copy the Hash approach by also allowing a
> block which is invoked when a property is accessed for the first time.
> =A0Block argument would be the symbol of the property and the return
> value would be used to initialize the property. =A0Then you could do
>
> data =3D OpenStruct.new {[]}
> ...
> data.animals << "cat" << "dog"
>
> or even
>
> data =3D OpenStruct.new do |sym|
> =A0 case sym
> =A0 when :animals : []
> =A0 when :dictionary : {}
> =A0 end
> end
>
> In other words: declarative lazy initialization.
>
> Again, existing code would not be affected.
>
> What do others think?

I recently submitted a patch that allowed OpenStruct to take a self
yielding block, e.g you could do:

 data =3D OpenStruct.new do |o|
   o.animals =3D []
   o.dictionary =3D {}
 end

I don't really see that much use for complex lazy initialization as
you suggest. Though, I can see the Hash block form being useful. Maybe
that would be a better use of the block. Actually, both could be
supported if we differentiate on the arity of the block. With two
args:

  OpenStruct.new{ |o, k| o[k] =3D [] }

Note, my patch also add #[] and #[]=3D, which are more important
changes.

Robert would you like to update my patch to support the Hash block
notation and resubmit it?

T.