Injecting methods from one class into another

Hello everyone,

I am wondering if the following is possible in Ruby:

class Source
def my_method
puts 'IT WORKS'
end
end

class Dest
# no method
end

inject_method(Source, :my_method, Dest)

d = Dest.new
d.my_method # => IT WORKS

Is it possible to write 'inject_method' in Ruby ?
Thanks in advance,
George

inject_method(Source, :my_method, Dest)

What do you expect with this ?

   inject_method(Array, :, Hash)

Guy Decoux

George Moschovitis wrote:

Is it possible to write 'inject_method' in Ruby ?

Apart from the ways that were already mentioned you can also do this:

obj = Class.new { def bar() puts "foo" }.new

class Foo
   define_method(:bar, &obj.method(:bar))
end

But note that this is the same as doing this:

class Foo
   define_method(:bar) { obj.method(:bar).call }
end

I've posted in this thread already that EvilRuby is less restrictive with Method#force_bind, but I don't think that this is needed in your case. (It could however be useful to implement AOP-like stuff.)

What do you expect with this ?
inject_method(Array, :, Hash)

this is an artificial example. I expect Hash's to be replaced
with Array's version thus creating a bug.

however, I would like to use it carefully. My question was: is this
possible?

-g.

Florian,

THANK you for this intelligent reply, this is what I was looking for.
Perhaps another poster was correct, 'you can do everything in Ruby' :slight_smile:
best regards,
George.

however, I would like to use it carefully. My question was: is this
possible?

Well, you can use #instance_method and #bind but ruby will make the test

uln% ruby -e 'Array.instance_method(:).bind(Hash.new)'
-e:1:in `bind': bind argument must be an instance of Array (TypeError)
        from -e:1
uln%

Guy Decoux

Why you don't want to use module?

module CustomFunctionality
   def my_method
     puts 'IT WORKS'
   end
end

class Source
   include CustomFunctionality
end

class Dest
   include CustomFunctionality

   def another_method
     puts 'HELLO'
   end
end

d = Dest.new

d.my_method # => IT WORKS

···

--
Szymon Drejewicz
Yet Another Pragmatic Rubist :slight_smile:

Well, I know about modules, this is not what I want.

I want to inject only ONE method from a class containing multiple
methods into another.

-g.

Well, you can use #instance_method and #bind but ruby will make the

test

uln% ruby -e 'Array.instance_method(:).bind(Hash.new)'
-e:1:in `bind': bind argument must be an instance of Array

(TypeError)

from -e:1

this test really kills 'duck typing', and renders the
instance_method/bind trick almost useless :frowning:
Many thanks for the tip though.

-g.

Well, you can use #instance_method and #bind but ruby will make the

test

wow, this is magic!
-g.

ts wrote:

"G" == George Moschovitis <george.moschovitis@gmail.com> writes:

> however, I would like to use it carefully. My question was: is this
> possible?

Well, you can use #instance_method and #bind but ruby will make the test

uln% ruby -e 'Array.instance_method(:).bind(Hash.new)'
-e:1:in `bind': bind argument must be an instance of Array (TypeError)

Note that EvilRuby has a less strict version of UnboundMethod#bind (#force_bind) which will work in this case:

class Foo
   def x() end
end

class Bar
end

Foo.instance_method(:x).bind(Bar.new) # raises TypeError
Foo.instance_method(:x).force_bind(Bar.new) # works
Hash.instance_method(:).force_bind(Array.new) # still doesn't work

George Moschovitis wrote:

Well, I know about modules, this is not what I want.

I want to inject only ONE method from a class containing multiple
methods into another.

-g.

Object methods do not work in vacuum, they usually use instance variables to reffer to the object's state, possibly changing it (remember encapsulation ;-)?). How would you expect your inject_method() deal with it?

Gennady.

Note that EvilRuby has a less strict version of UnboundMethod#bind

wtf is EvilRuby ?!?! :slight_smile:

-g.

Object methods do not work in vacuum, they usually use instance
variables to reffer to the object's state, possibly changing it
(remember encapsulation ;-)?). How would you expect your
inject_method() deal with it?

I thought Ruby promotes 'duck typing'.

I would like to inject specific methods between specific classes. The
destination class has all the instance variables needed to succesfully
execute the method.

George Moschovitis wrote:

wtf is EvilRuby ?!?! :slight_smile:

See http://evil.rubyforge.org -- code is available from CVS.

George Moschovitis wrote:

Object methods do not work in vacuum, they usually use instance
variables to reffer to the object's state, possibly changing it
(remember encapsulation ;-)?). How would you expect your
inject_method() deal with it?

I thought Ruby promotes 'duck typing'.

I would like to inject specific methods between specific classes. The
destination class has all the instance variables needed to succesfully
execute the method.

I do not think what you want has anything to do with 'duck typing'. 'duck typing' only means that you can send a message to any object and if the object has a corresponding method it gets executed regardless of object type. It does not urge you to abandon the "normal" way of method definition for a class.

In general, I am very cautious to dynamically adding methods down the road, as it greatly increases the risk of your system becoming incomprehensible.

As somebody has indicated, Ruby has other ways to "inject" methods in some controlled manner, like mixins or inheritance. I would consider them first before resorting to any sort of "tricks", even if they were possible (everything is possible in Ruby, you know ;-), one way or another).

Gennady.

"George Moschovitis" <george.moschovitis@gmail.com> schrieb im Newsbeitrag
news:1106667522.708436.185960@z14g2000cwz.googlegroups.com...

> Object methods do not work in vacuum, they usually use instance
> variables to reffer to the object's state, possibly changing it
> (remember encapsulation ;-)?). How would you expect your
> inject_method() deal with it?

I thought Ruby promotes 'duck typing'.

I would like to inject specific methods between specific classes. The
destination class has all the instance variables needed to succesfully
execute the method.

And what about other methods that are used by a method? I think it's not
generally possible to move methods around.

But maybe this trick helps:

class Object
  def cast(target_class)
    copy = case target_class
      when Class; target_class.allocate
      when Module; dup
      else target_class.class.allocate
    end

    instance_variables.each do |var|
      copy.instance_variable_set(var, instance_variable_get(var))
    end

    copy
  end
end

Then you can create a tmp copy of an instance with all instance variables
copied but a different class. So you can do
foo.cast(Bar).bar_method_to_be_called().

Cheers

    robert

That's not duck typing, it's duck cloning, Dr. Frankenstein!

···

On Wed, 26 Jan 2005 00:40:49 +0900, George Moschovitis <george.moschovitis@gmail.com> wrote:

> Object methods do not work in vacuum, they usually use instance
> variables to reffer to the object's state, possibly changing it
> (remember encapsulation ;-)?). How would you expect your
> inject_method() deal with it?

I thought Ruby promotes 'duck typing'.

I would like to inject specific methods between specific classes. The
destination class has all the instance variables needed to succesfully
execute the method.

--
Nicholas Van Weerdenburg

"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag
news:35nafhF4of2saU1@individual.net...

"George Moschovitis" <george.moschovitis@gmail.com> schrieb im

Newsbeitrag

news:1106667522.708436.185960@z14g2000cwz.googlegroups.com...
> > Object methods do not work in vacuum, they usually use instance
> > variables to reffer to the object's state, possibly changing it
> > (remember encapsulation ;-)?). How would you expect your
> > inject_method() deal with it?
>
> I thought Ruby promotes 'duck typing'.
>
> I would like to inject specific methods between specific classes. The
> destination class has all the instance variables needed to succesfully
> execute the method.

And what about other methods that are used by a method? I think it's

not

generally possible to move methods around.

But maybe this trick helps:

Should've read

class Object
  def cast(target_class)
    copy = case target_class
      when Class; target_class.allocate
      when Module; dup.extend(target_class)
      else target_class.class.allocate
    end

    instance_variables.each do |var|
      copy.instance_variable_set(var, instance_variable_get(var))
    end

    copy
  end
end

Then you can create a tmp copy of an instance with all instance

variables

···

copied but a different class. So you can do
foo.cast(Bar).bar_method_to_be_called().

Cheers

    robert

I do not think what you want has anything to do with 'duck typing'.

Of course it has. Have a look at the following example:

class C1
attr_accessor :a

def a1
puts @a
end

def a2
puts 'hello'
end
end

class C2
attr_accessor :a
end

So for method C1#a1 the class C2 'quacks like a duck' (ie, it has the
attribute @a)

So in 'duck typing' spirit, it should be possible to do:

c = C2.new

m = C1.instance_method(:a1)
m.bind(c)

c.a1

however Ruby raises a TypeError :frowning:

Can anyone give me an example, where this #bind method is usefull? I
mean, you can only bind a Method back to an object of the original
method's Class or a Subclass. But such an object allready has this
method, so whats the point?
Am I missing something here?

regards,
George