How to make a given klass to include a module

Hi, simple code:

···

----------------------------
  module M
    def hello
      "HELLO"
    end
  end

  class A
  end

  klass = A
----------------------------

Now I want to make an instance of klass (so an instance of A) but also
need that klass includes module M.
Note however that I cannot change class A definition since klass is
given in runtime by the user.

NOTE: It must be efficient, I don't want to use eval and so.

Thanks a lot.

--
Iñaki Baz Castillo
<ibc@aliax.net>

# ruby -v: ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
irb(main):001:0> module M
irb(main):002:1> def hello
irb(main):003:2> "HELLO"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> class A
irb(main):007:1> end
=> nil
irb(main):008:0> klass = A
=> A
irb(main):009:0> klass.send(:include, M)
=> A
irb(main):010:0> a = klass.new
=> #<A:0x0000000202cfe0>
irb(main):011:0> a.hello
=> "HELLO"

Alternatively, if you don’t want to pollute the given class, use #extend
on the instances (which is also more clean as it doesn’t require #send).

Vale,
Marvin

···

Am 09.05.2012 13:36, schrieb Iñaki Baz Castillo:

Hi, simple code:

----------------------------
  module M
    def hello
      "HELLO"
    end
  end

  class A
  end

  klass = A
----------------------------

Now I want to make an instance of klass (so an instance of A) but also
need that klass includes module M.
Note however that I cannot change class A definition since klass is
given in runtime by the user.

NOTE: It must be efficient, I don't want to use eval and so.

Thanks a lot.

Any time you modify a class/eigenclass (via include/extend), you lose
efficiency in MRI/YARV. The runtime needs to invalidate its internal
caches for method lookup whenever classes are modified.

···

Iñaki Baz Castillo <ibc@aliax.net> wrote:

NOTE: It must be efficient, I don't want to use eval and so.

Since we don't want to change A, use a subclass. It will have all the
behaviour of A, but you can include modules and so forth while leaving M in
pristine condition.

klass = Class.new(A) { include M }
klass.new.hello # => "HELLO"
A.new.respond_to? :hello # => false

Alternatively, extend your instances:

klass = A
instance = klass.new
instance.extend M
instance.hello # => "HELLO"
A.new.respond_to? :hello # => false

Extending works by opening up the singleton class and including within it.
This means the instance behaves as if A had M included, even though it
doesn't.

···

On Wed, May 9, 2012 at 6:36 AM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

Hi, simple code:

----------------------------
module M
   def hello
     "HELLO"
   end
end

class A
end

klass = A
----------------------------

Now I want to make an instance of klass (so an instance of A) but also
need that klass includes module M.
Note however that I cannot change class A definition since klass is
given in runtime by the user.

NOTE: It must be efficient, I don't want to use eval and so.

Thanks a lot.

Great!

I've tested that first option is much faster (more than 10 times
faster) than extending each instance, so I'll go with first solution.

Thanks a lot.

Thanks a lot.

···

2012/5/9 Quintus <quintus@quintilianus.eu>:

=> A
irb(main):009:0> klass.send(:include, M)
=> A
irb(main):010:0> a = klass.new
=> #<A:0x0000000202cfe0>
irb(main):011:0> a.hello
=> "HELLO"

Alternatively, if you don’t want to pollute the given class, use #extend
on the instances (which is also more clean as it doesn’t require #send).

--
Iñaki Baz Castillo
<ibc@aliax.net>

Good to know. But if the "include" is added during the class
definition there is no efficiency loss, am I right?:

class A
  include M
end

···

2012/5/9 Eric Wong <normalperson@yhbt.net>:

Iñaki Baz Castillo <ibc@aliax.net> wrote:

NOTE: It must be efficient, I don't want to use eval and so.

Any time you modify a class/eigenclass (via include/extend), you lose
efficiency in MRI/YARV. The runtime needs to invalidate its internal
caches for method lookup whenever classes are modified.

--
Iñaki Baz Castillo
<ibc@aliax.net>

Maybe also add an additional test:

irb(main):001:0> class A;end
=> nil
irb(main):002:0> module M; def hello; "hello" end end
=> nil
irb(main):003:0> M===A || A.send(:include, M)
=> A
irb(main):004:0> A.new.hello
=> "hello"

Cheers

robert

···

On Wed, May 9, 2012 at 1:52 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

2012/5/9 Quintus <quintus@quintilianus.eu>:

=> A
irb(main):009:0> klass.send(:include, M)
=> A
irb(main):010:0> a = klass.new
=> #<A:0x0000000202cfe0>
irb(main):011:0> a.hello
=> "HELLO"

Alternatively, if you don’t want to pollute the given class, use #extend
on the instances (which is also more clean as it doesn’t require #send).

Great!

I've tested that first option is much faster (more than 10 times
faster) than extending each instance, so I'll go with first solution.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Hi, I don't get the point of that. M===A always returns false
regardless A includes M:

module MMM ; end

class AAA
  include MMM
end

MMM===AAA
=> false

···

2012/5/9 Robert Klemme <shortcutter@googlemail.com>:

Maybe also add an additional test:

irb(main):001:0> class A;end
=> nil
irb(main):002:0> module M; def hello; "hello" end end
=> nil
irb(main):003:0> M===A || A.send(:include, M)
=> A
irb(main):004:0> A.new.hello
=> "hello"

--
Iñaki Baz Castillo
<ibc@aliax.net>

Stupid me, should've tested better. I confused that with the instance
check. Sorry for the confusion.

I meant "A < M":

irb(main):008:0> class A; end
=> nil
irb(main):009:0>
irb(main):010:0* module M; end
=> nil
irb(main):011:0> A < M
=> nil
irb(main):012:0> A.send :include, M
=> A
irb(main):013:0> A < M
=> true

So it's

A < M || A.send(:include, M)

Kind regards

robert

···

On Wed, May 9, 2012 at 4:32 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

2012/5/9 Robert Klemme <shortcutter@googlemail.com>:

Maybe also add an additional test:

irb(main):001:0> class A;end
=> nil
irb(main):002:0> module M; def hello; "hello" end end
=> nil
irb(main):003:0> M===A || A.send(:include, M)
=> A
irb(main):004:0> A.new.hello
=> "hello"

Hi, I don't get the point of that. M===A always returns false
regardless A includes M:

module MMM ; end

class AAA
include MMM
end

MMM===AAA
=> false

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/