----------------------------
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.
# 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.
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.
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.
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.
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"
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: