Redefining methods


#1

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

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

cheers.

a @ http://drawohara.com/


#2

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

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 ?

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


#3

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

we can deny everything, except that we have the possibility of being


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/


#4

2007/7/31, ara.t.howard removed_email_address@domain.invalid:

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


#5

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

  • 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/


#6

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

  • Syntax: like Étienne, I, too, don’t like that it is necessary to
    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/


#7

On 7/31/07, ara.t.howard removed_email_address@domain.invalid 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 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:


#8

On 7/31/07, ara.t.howard removed_email_address@domain.invalid wrote:

alias_method_chain, I can’t comment on which is better, so just a few

  • Implementation: currently, the method chains are only used as a flag


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


#9

2007/7/31, ara.t.howard removed_email_address@domain.invalid:

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


#10

2007/8/1, ara.t.howard removed_email_address@domain.invalid:

(…)
nice work pit!

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

Regards,
Pit


#11

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

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

class C

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/


#12

Pit C. 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,