Is there any way to have a module change a class instance
variables upon inclusion OR extend-functionality?
I think the easiest way for you would be to define an initialize method on Foo in which you change the values as you want, and then call super at the end of Bar#initialize. That way Foo#initialize will be called sooner or later, provided you included Foo in Bar. If you don't include it, Foo#initialize will never be called and you're fine.
If you want some finer control I think you will have to do some magic around the Module#included hook and a hash of standard values.
I think the easiest way for you would be to define an initialize
method on Foo in which you change the values as you want, and
then call super at the end of Bar#initialize.
Hmm. But how does this work?
Foo is a module, can it have an initialize method?
Yes, it can. The reason modules are able to have an initialize method
is that it is a regular method which just happens to be called
after object creation.
That way you can include it in arbitrary class hierarchies and still
keep #initialize call chain intact - even if super class #initialize
have different argument lists.
Yes, it is strange... I actually looked it up, and the latest
Pickaxe book also mentions that. I kind of did not read the new
pickaxe book too closely, most of it I seem to know already,
but this part I did not know.
The pickaxe also mentions the initialize method, but I never
saw this method in a module before.
But this brings me to another question, actually ...
Why do we really use subclasses in Ruby when there are almost
completely legit alternative uses to do the same with modules?
That is almost as if there are two different ways to do (almost)
the same and I am unsure whether this is really what matz always
intended? But perhaps I am wrong ... it just feels as if there
are two ways to do quite the same...
Yes, it can. The reason modules are able to have an initialize method is that it is a regular method which just happens to be called after object creation. And since you are able to propagate a method call up the chain of ancestors with super, this will work in #initialize as well.
···
On 17.09.2013 02:42, Marc Heiler wrote:
I think the easiest way for you would be to define an initialize
method on Foo in which you change the values as you want, and
then call super at the end of Bar#initialize.
Hmm. But how does this work?
Foo is a module, can it have an initialize method?
Yes, it can. The reason modules are able to have an initialize method
is that it is a regular method which just happens to be called
after object creation.
Interesting, I never heard that before!
If a module needs an initialize method I would typically do this
module Foo
def initialize(*a, &b)
super
# init for module
end
end
That way you can include it in arbitrary class hierarchies and still
keep #initialize call chain intact - even if super class #initialize
have different argument lists.
Thanks to you two by the way!
You're welcome!
Kind regards
Hobbes
···
On Tue, Sep 17, 2013 at 12:28 PM, Marc Heiler <lists@ruby-forum.com> wrote:
The approach does have a bit of a downside: usually you invoke super
class initialization _before_ you do initialization in the current
class. For this approach to work you need to invoke super _after_
initialization in this class or make it lazy.
$ cat -n x.rb
1 module Foo
2 def initialize
3 @test = 'test 2'
4 end
5 end
6
7 class Bar
8 attr_reader :test
9
10 include Foo
11
12 def initialize
13 super
14 @test = 'test 1'
15 end
16 end
17
18 p Bar.new.test
19
20 class Bar
21 def initialize
22 @test = 'test 1'
23 super
24 end
25 end
26
27 p Bar.new.test
28
29 class Bar
30 def initialize
31 super
32 @test ||= 'test 1'
33 end
34 end
35
36 p Bar.new.test
$ ruby x.rb
"test 1"
"test 2"
"test 2"
Cheers
robert
···
On Tue, Sep 17, 2013 at 3:00 AM, Calvin Bornhofen <calvin.bornhofen@web.de> wrote:
On 17.09.2013 02:42, Marc Heiler wrote:
I think the easiest way for you would be to define an initialize
method on Foo in which you change the values as you want, and
then call super at the end of Bar#initialize.
Hmm. But how does this work?
Foo is a module, can it have an initialize method?
Yes, it can. The reason modules are able to have an initialize method is
that it is a regular method which just happens to be called after object
creation. And since you are able to propagate a method call up the chain of
ancestors with super, this will work in #initialize as well.