On Aug 23, 11:37=A0am, Robert Klemme <shortcut... / googlemail.com> wrote:

> I could not get that to work on 1.9.1:
>
> 17:33:49 ~$ irb19
> Ruby version 1.9.1
> irb(main):001:0> =A0def memo(&block)
> =A0 =A0key =3D eval('__method__', block)
> =A0 =A0val =3D block.call
> =A0 =A0singleton_class =3D (class << self; self; end)
> =A0 =A0singleton_class.__send__(:define_method, key){ vairb(main):002:1> =
l }
> =A0 =A0key =3D eval('__method__', block)
> irb(main):003:1> =A0 =A0val =3D block.call
> irb(main):004:1> =A0 =A0singleton_class =3D (class << self; self; end)
> irb(main):005:1> =A0 =A0singleton_class.__send__(:define_method, key){ va=
l }
> irb(main):006:1> =A0 =A0val
> irb(main):007:1> =A0end
> =3D> nil
> irb(main):008:0> class ME
> irb(main):009:1> attr_accessor :a
> irb(main):010:1> def m;memo { @a }; end
> irb(main):011:1> end
> =3D> nil
> irb(main):012:0> ex=3DME.new
> =3D> #<ME:0x10049a74>
> irb(main):013:0> ex.a=3D10
> =3D> 10
> irb(main):014:0> ex.m
> TypeError: wrong argument type Proc (expected Binding)
> =A0 =A0 =A0 =A0 from (irb):2:in `eval'
> =A0 =A0 =A0 =A0 from (irb):2:in `memo'
> =A0 =A0 =A0 =A0 from (irb):10:in `m'
> =A0 =A0 =A0 =A0 from (irb):14
> =A0 =A0 =A0 =A0 from /opt/bin/irb19:12:in `<main>'
> irb(main):015:0>

Looks like you can't pass a Proc to eval in 1.9+. Wonder why that was
gotten rid of? Ironically I only leaned one could even do that at all
a few month ago! I love having to unlearn.

Looks like it can be fixed with:

  key =3D eval('__method__', block.binding)

> Also I believe the results would not be like your comments suggest
> since you redefine the method all the time. =A0Am I missing something?

After the first time, the original method would no longer be
accessible (at least not via normal method calling).

> > Downside / upsides to the approach? Any suggestions for improvement?
> > Or is this just an altogether bad idea?
>
> I do not see the advantage over plain definition of
>
> def ex.m; 10; end
>
> since you are storing a single value anyway. =A0It seems your approach
> is only advantageous if you need to access instance variables because
> then it spares some ugly syntax. =A0But since you have to call #memo
> explicitly you can even pass the value to bind to the method as well,
> e.g.
>
> =A0def memo(name, val)
> =A0 =A0(class << self; self; end).define_method(name){ val }
> =A0end
>
> =A0ex.memo :a, 10
>
> As long as you have to invoke the method setting the value explicitly
> you do not gain anything, do you? =A0Somehow I must be missing something
> but I can't see it right now.

Yes, part of the reason for this design is to avoid restating the
method name. That's the only reason a block is used in fact, to gain
access to the callers binding so as to get the method name.

The use case for #memo is an alternative to:

  def m
    @m ||=3D ....
  end

But differs in that it avoids the need for an instance variable. I
tend to use the "@m ||=3D" idiom a lot, though I wonder about it's
threading implications, and whether something like #memo would be more
robust.