Redefining methods

i was playing with this last night, thought some here might be interested:

   http://drawohara.tumblr.com/post/7241442

cheers.

a @ http://drawohara.com/

···

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Just for the syntax, I don't like :

···

Le mardi 31 juillet 2007 à 23:48 +0900, ara.t.howard a écrit :

i was playing with this last night, thought some here might be
interested:

   http://drawohara.tumblr.com/post/7241442

cheers.

a @ http://drawohara.com/
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama

---
redefining :foo do
  def foo(*a, &b) super.reverse end
end
---
I prefer :
---
redefining :foo do |*a, &b|
  super.reverse
end
---
Greater, it isn't ?
---

However, there is an other way :
---
redefining :foo do |&old| # &old or old, see after
  def foo(*a, &b) old.call.reverse end
end
---
and maybe...
---
redefining :foo do |*olds| # list, ordered (asc or desc ?)
  def foo(*a, &b) (olds.shift.call + olds.shift.call).reverse end
  # maybe add a shortcut for shift.call...
end
---

Regards

--
Etienne Vallette d'Osia

Hi Ara, since I don't know the implementation of Rails'
alias_method_chain, I can't comment on which is better, so just a few
remarks concerning your code:

* Syntax: like Étienne, I, too, don't like that it is necessary to
repeat the method name in both the #redefining call and the method
definition. Couldn't you just call #redefining without an argument and
look in the new module which methods have been defined there?

* Implementation: I haven't checked in detail, but I think you could
get problems with the class variable when there's a class hierarchy.

* Implementation: currently, the method chains are only used as a flag
whether to create the "initial" module or not. Do you plan to use it
for other things? Otherwise you don't need an array with all the
intermediate modules.

Btw. nice use of the BEGIN block!

Regards,
Pit

···

2007/7/31, ara.t.howard <ara.t.howard@gmail.com>:

i was playing with this last night, thought some here might be
interested:

   http://drawohara.tumblr.com/post/7241442

As Etienne and Pit pointed it out (guys are you using 1.9 and pointing
fingers at us ;)?) the &blk sntax in block is really missing.
This is a big issue here

  if method_chain.empty?
          m = Module.new do
            class_variable_set "@@#{ method }", this.module_eval{
instance_method method }
            module_eval "def #{ method }(*a, &b) @@#{ method
}.bind(self).call(*a, &b) end"
          end
          remove_method method
          include m
        end
As it is soo easy to have a class with @@#{method} in your class :frowning:
I do not see any solution, if only we could use closures with a
define_method m do |*args,&blk|

I know I am not DROP here :frowning:

BTW
I would write

def method_chains
        @method_chains ||= Hash.new
  end

Cheers
Robert

P.S.
Nice work :slight_smile:

···

On 7/31/07, ara.t.howard <ara.t.howard@gmail.com> wrote:

i was playing with this last night, thought some here might be
interested:

   http://drawohara.tumblr.com/post/7241442

cheers.

a @ http://drawohara.com/

--
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

i was playing with this last night, thought some here might be
interested:

   http://drawohara.tumblr.com/post/7241442

cheers.

a @ http://drawohara.com/
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama

Just for the syntax, I don't like :
---
redefining :foo do
  def foo(*a, &b) super.reverse end
end
---
I prefer :
---
redefining :foo do |*a, &b|
  super.reverse
end
---
Greater, it isn't ?

absolutely. and when define_method takes a block that would indeed by the way to do it.

---

However, there is an other way :
---
redefining :foo do |&old| # &old or old, see after
  def foo(*a, &b) old.call.reverse end
end
---

this can't work though - old is not in scope inside foo - only with define_method would that be possible, but there you lose the ability to define methods which themselves take blocks...

and maybe...
---
redefining :foo do |*olds| # list, ordered (asc or desc ?)
  def foo(*a, &b) (olds.shift.call + olds.shift.call).reverse end
  # maybe add a shortcut for shift.call...
end
---

again - same issue with scoping. although i agree and more closure based solution would be nice. for now though - i don't think it's possible. i'd be very happy to be proven wrong though! :wink:

kind regards.

a @ http://drawohara.com/

···

On Jul 31, 2007, at 11:27 AM, dohzya wrote:

Le mardi 31 juillet 2007 à 23:48 +0900, ara.t.howard a écrit :

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Pit Capitain wrote:

Btw. nice use of the BEGIN block!

Yes.

That was a question that came up at the Advanced Ruby Studio
in Reston a couple weeks ago: of what practical use are those
BEGIN/END things anyway? :wink:

Regards,

···

--
Bil Kleb
http://nasarb.rubyforge.org

* Syntax: like Étienne, I, too, don't like that it is necessary to
repeat the method name in both the #redefining call and the method
definition. Couldn't you just call #redefining without an argument and
look in the new module which methods have been defined there?

indeed you could/would. just playing now. patches welcome! :wink:

* Implementation: I haven't checked in detail, but I think you could
get problems with the class variable when there's a class hierarchy.

yeah - a class instance var would be the way to go - i was just saving on typing for demo..

* Implementation: currently, the method chains are only used as a flag
whether to create the "initial" module or not. Do you plan to use it
for other things? Otherwise you don't need an array with all the
intermediate modules.

hmmm - you mean use only the two: the initial and subsequent? i think that would work... i was indeed thinking of being able to call a 'specific super' though...

Btw. nice use of the BEGIN block!

i like the idiom, but the error reporting and require semantics stink - it's nice for examples though :wink:

cheers.

a @ http://drawohara.com/

···

On Jul 31, 2007, at 12:09 PM, Pit Capitain wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

updated:

   http://drawohara.tumblr.com/post/7241442

i played some cannot seem to come up with a way to avoid having the stack of modules and also maintain super semantics across multiple invocations - anyone else have a go?

a @ http://drawohara.com/

···

On Jul 31, 2007, at 12:09 PM, Pit Capitain wrote:

2007/7/31, ara.t.howard <ara.t.howard@gmail.com>:

i was playing with this last night, thought some here might be
interested:

   http://drawohara.tumblr.com/post/7241442

Hi Ara, since I don't know the implementation of Rails'
alias_method_chain, I can't comment on which is better, so just a few
remarks concerning your code:

* Syntax: like Étienne, I, too, don't like that it is necessary to
repeat the method name in both the #redefining call and the method
definition. Couldn't you just call #redefining without an argument and
look in the new module which methods have been defined there?

* Implementation: I haven't checked in detail, but I think you could
get problems with the class variable when there's a class hierarchy.

* Implementation: currently, the method chains are only used as a flag
whether to create the "initial" module or not. Do you plan to use it
for other things? Otherwise you don't need an array with all the
intermediate modules.

Btw. nice use of the BEGIN block!

Regards,
Pit

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Wow can you read my mind :), you fixed it already!! Very impressive
technique, but what a pain...

Robert

···

On 7/31/07, ara.t.howard <ara.t.howard@gmail.com> wrote:

On Jul 31, 2007, at 12:09 PM, Pit Capitain wrote:

> 2007/7/31, ara.t.howard <ara.t.howard@gmail.com>:
>> i was playing with this last night, thought some here might be
>> interested:
>>
>> http://drawohara.tumblr.com/post/7241442
>
> Hi Ara, since I don't know the implementation of Rails'
> alias_method_chain, I can't comment on which is better, so just a few
> remarks concerning your code:
>
> * Syntax: like Étienne, I, too, don't like that it is necessary to
> repeat the method name in both the #redefining call and the method
> definition. Couldn't you just call #redefining without an argument and
> look in the new module which methods have been defined there?
>
> * Implementation: I haven't checked in detail, but I think you could
> get problems with the class variable when there's a class hierarchy.
>
> * Implementation: currently, the method chains are only used as a flag
> whether to create the "initial" module or not. Do you plan to use it
> for other things? Otherwise you don't need an array with all the
> intermediate modules.
>
> Btw. nice use of the BEGIN block!
>
> Regards,
> Pit
>

updated:

   http://drawohara.tumblr.com/post/7241442

i played some cannot seem to come up with a way to avoid having the
stack of modules and also maintain super semantics across multiple
invocations - anyone else have a go?

a @ http://drawohara.com/
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama

--
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

i played some cannot seem to come up with a way to avoid having the
stack of modules and also maintain super semantics across multiple
invocations - anyone else have a go?

Ara, I didn't mean you don't need a stack of modules, but you don't
need to store the modules in an array (yet).

just playing now. patches welcome! :wink:

Not a patch, but a slightly different implementation based on your idea:

class C
    def foo() 'f' end
    def bar() 'b' end
    def foobar() foo + bar end
  end
  c = C.new
  p c.foobar # => "fb"

  class C
    redefining do
      def foo() super + 'oo' end
    end
  end
  p c.foobar # => "foob"

  class C
    redefining do
      def bar() super + 'ar' end
    end
  end
  p c.foobar # => "foobar"

  class C
    redefining do
      def foo() super.reverse end
      def bar() super.reverse end
    end
  end
  p c.foobar # => "oofrab"

  ### the implementation

  BEGIN {
    class Class
      def redefining &block
        unless defined? @_org
          org_mod = Module.new
          @_org = { :mod => org_mod }
          include org_mod
        end

        m = Module.new(&block)

        (m.instance_methods(false) & instance_methods(false)).each do |method|
          @_org[method] = instance_method method
          @_org[:mod].module_eval <<-EOC
            def #{method}(*a, &b)
              org = self.class.instance_variable_get("@_org")
              org["#{method}"].bind(self).call(*a, &b)
            end
          EOC
          remove_method method
        end

        include m
      end
    end
  }

I used the old way of getting at the original method (storing it
somewhere), because I'm not sure whether the garbage collector could
remove it if you only remember it's object_id.

Regards,
Pit

···

2007/7/31, ara.t.howard <ara.t.howard@gmail.com>:

i played some cannot seem to come up with a way to avoid having the
stack of modules and also maintain super semantics across multiple
invocations - anyone else have a go?

Ara, I didn't mean you don't need a stack of modules, but you don't
need to store the modules in an array (yet).

just playing now. patches welcome! :wink:

Not a patch, but a slightly different implementation based on your idea:

class C

<snip>

I used the old way of getting at the original method (storing it
somewhere), because I'm not sure whether the garbage collector could
remove it if you only remember it's object_id.

Regards,
Pit

updated (and new commenting finally :wink: )

   http://drawohara.tumblr.com/post/7241442

nice work pit!

a @ http://drawohara.com/

···

On Jul 31, 2007, at 3:51 PM, Pit Capitain wrote:

2007/7/31, ara.t.howard <ara.t.howard@gmail.com>:

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Thanks, Ara, but it's still your original idea and design. I only
changed a part of the implementation.

Regards,
Pit

···

2007/8/1, ara.t.howard <ara.t.howard@gmail.com>:

(...)
nice work pit!