Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this example? Should the add_stuff method check whether the variable has been initialized every time, or should this be done by implementing a callback like append_features or included? (That's how I'd want to do it, but it's not clear which or how...)
Thanks,
Jeff
module Foo
def add_stuff(key, stuff)
(@foo_the_stuff ||= {})[key] = stuff
end
end
If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.
Ryan
···
On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)
Thanks,
Jeff
Well, it took a while but I found the answer. This is done in ActiveRecord to wrap a possible setup method in the unit tests for auto-instrumentation of fixtures. Once I knew what to look for, however, I found an old post by Florian Gross that lays out the exact answer nicely:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834
For educational purposes though, I'll explain a few things I found...
1) The append_features method is deprecated, and the included method is now the preferred callback. This method is called when a module is included, and it is passed the module that has done the including.
2) There is another callback, method_added, which is a meta-class method that is called every time a new method is defined for its class, and the symbol for the method name is passed.
So, the trick is to add a custom method_added method to the meta-class of the class that does the including by extending it in the included callback. The custom method_added needs to redefine initialize after it is added so that it does the custom setup, then calls the original.
Phew... Too bad we can't just have another callback that lets us do this easily. Maybe that feels too much like multiple inheritance or something?
module Foo
def module_initialize
@myvar = Hash.new {|k,v| k[v] = }
end
def bar(key)
@mybar[key]
end
end
Isn't this a common thing to want?
-Jeff
Jeff Rose wrote:
···
Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this example? Should the add_stuff method check whether the variable has been initialized every time, or should this be done by implementing a callback like append_features or included? (That's how I'd want to do it, but it's not clear which or how...)
Thanks,
Jeff
This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:
http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance
Kind regards
robert
···
2006/5/22, Jeff Rose <rosejn@gmail.com>:
Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)
--
Have a look: Robert K. | Flickr
That's what I was afraid of. In this example case it's no big deal, but in a module where you are accessing a more complex variable many times it's a real pain, let alone inefficient. We are working on an event system, so the hash is a hash of arrays or possibly a hash of hashes. Any of 4 methods could be called, which would require an initialized value. Having this in every method is sorta lame...
handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
Of course we can pull it out to a method:
def handlers(key)
@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end
but just initializing on inclusion seems to be the most reasonable way, doesn't it?
-Jeff
Ryan Leavengood wrote:
···
module Foo
def add_stuff(key, stuff)
(@foo_the_stuff ||= {})[key] = stuff
end
end
If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.
Ryan
On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)
Thanks,
Jeff
and precisely one of the reasons i wrote traits - with traits you can simply
ignore the issue altogether:
harp:~ > gem install traits
harp:~ > cat a.rb
require 'rubygems'
require 'traits'
module Foo
trait 'myvar' => Hash.new{|k,v| k[v] = }
def bar(key) myvar[key] end
end
class Bar
include Foo
end
b = Bar.new
p b.bar(:k)
p b.myvar
harp:~ > ruby a.rb
{:k=>}
-a
···
On Tue, 23 May 2006, Jeff Rose wrote:
Well, it took a while but I found the answer. This is done in ActiveRecord to wrap a possible setup method in the unit tests for auto-instrumentation of fixtures. Once I knew what to look for, however, I found an old post by Florian Gross that lays out the exact answer nicely:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834
For educational purposes though, I'll explain a few things I found...
1) The append_features method is deprecated, and the included method is now the preferred callback. This method is called when a module is included, and it is passed the module that has done the including.
2) There is another callback, method_added, which is a meta-class method that is called every time a new method is defined for its class, and the symbol for the method name is passed.
So, the trick is to add a custom method_added method to the meta-class of the class that does the including by extending it in the included callback. The custom method_added needs to redefine initialize after it is added so that it does the custom setup, then calls the original.
Phew... Too bad we can't just have another callback that lets us do this easily. Maybe that feels too much like multiple inheritance or something?
module Foo
def module_initialize
@myvar = Hash.new {|k,v| k[v] = }
end
def bar(key)
@mybar[key]
end
end
Isn't this a common thing to want?
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama
hi matz-
(rcr ahead)
the other day i realized that one could detect class creation using
class Class
def inherited
...
end
end
but that no such hook existed for class Module. could one be added such as
class Module
def instantiated
...
end
end
to hook into rb_define_module/rb_define_module_under?
regards.
-a
···
On Tue, 23 May 2006, Yukihiro Matsumoto wrote:
Hi,
In message "Re: initializing instance variables in a module" > on Tue, 23 May 2006 00:51:35 +0900, Jeff Rose <rosejn@gmail.com> writes:
>Is there a standard or correct way to initialize @foo_the_stuff in this
>example?
This is not the answer, but I have been aware of this issue. I'm
planning to add method combination a la CLOS in the future to support
this issue. It is another option that adding a new hook like
'module_initialize' which is called at instantiation time for all
modules.
matz.
--
be kind whenever possible... it is always possible.
- h.h. the 14th dali lama
Yukihiro Matsumoto wrote:
Hi,
>Is there a standard or correct way to initialize @foo_the_stuff in this >example?
This is not the answer, but I have been aware of this issue. I'm
planning to add method combination a la CLOS in the future to support
this issue. It is another option that adding a new hook like
'module_initialize' which is called at instantiation time for all
modules.
matz.
That would do the trick, and it would probably make the AOP people very happy. But that is a bit different than an explicit module initialization method. Is there a reason you don't want module_initialize or something like that?
CLOS does something like (defmethod rock :before ...), right? Any ideas on how the method combination would work in ruby?
# Maybe using methods...
module Rocker
def pre_rock
puts 'pre rock'
end
before :rock, :pre_rock
end
# Or with syntax...
module Rocker
def before:rock
puts 'pre rock'
end
end
class Foo
include Rocker
def rock
puts 'We are rocking'
end
end
Foo.new.rock # => "pre rock\nWe are rocking\n"
-Jeff
···
In message "Re: initializing instance variables in a module" > on Tue, 23 May 2006 00:51:35 +0900, Jeff Rose <rosejn@gmail.com> writes:
Robert Klemme wrote:
This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:
http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance
Nice writeup. I especially like that you captured the need to
tranparently pass arguments thru the module initializer. That's easy to
miss at first glance.
···
--
-- Jim Weirich
--
Posted via http://www.ruby-forum.com/\.
This thread seems to have gone astray a bit but I didn't see this
solution which I regard the standard way to handle this. The important
part is to use initialize(*a,&b) in the module. I've put this on the
wiki for easier reference:
http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance
Kind regards
robert
This doesn't really solve the problem. The idea is that you don't want the including class to have to do anything related to initialization of the module(s) being included. In your example any including class would have to call super in order to make it work. If Derived implements an initialize method and doesn't call super then the module isn't initialized. But why should it call super, it isn't deriving from anything, it is mixing it in.
The two options Matz mentioned are the way to go. Either a callback (module_initialize), which will act as an initialization method for the module, or the ability for the module to insert its own method(s) before, after, or around the class that includes it. (CLOS method combinations... AOP)
-Jeff
Jeff Rose wrote:
but just initializing on inclusion seems to be the most reasonable
way, doesn't it?
Put the initialization code in the module's initialize method and have
every class that includes the module call super from its initialize
method:
module Foo
def initialize(*args, &block)
# whatever...
end
end
class Bar
include Foo
def initialize(*args, &block)
super # calls Foo's initialize
# more stuff
end
end
···
--
Posted via http://www.ruby-forum.com/\.
Jeff, I tried a few combinations of class_eval and module_eval and I
couldn't figure it out. What seems to be desired is for the mixed-in
module code to create an instance variable in the class which is doing
the mixin. I'll bet there's a way to do it.
···
On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
That's what I was afraid of. In this example case it's no big deal, but
in a module where you are accessing a more complex variable many times
it's a real pain, let alone inefficient. We are working on an event
system, so the hash is a hash of arrays or possibly a hash of hashes.
Any of 4 methods could be called, which would require an initialized
value. Having this in every method is sorta lame...
handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
Of course we can pull it out to a method:
def handlers(key)
@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end
but just initializing on inclusion seems to be the most reasonable
way, doesn't it?
-Jeff
Ryan Leavengood wrote:
> module Foo
> def add_stuff(key, stuff)
> (@foo_the_stuff ||= {})[key] = stuff
> end
> end
>
> If @foo_the_stuff is null, it will be initialized to an empty hash,
> otherwise the existing value will be used. I consider this use of ||=
> to be a Ruby idiom.
>
> Ryan
>
> On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
>> Have a module:
>>
>> Module Foo
>> def add_stuff(key, stuff)
>> @foo_the_stuff[key] = stuff
>> end
>> end
>>
>> class Bar
>> include Foo
>> end
>>
>> Is there a standard or correct way to initialize @foo_the_stuff in this
>> example? Should the add_stuff method check whether the variable has
>> been initialized every time, or should this be done by implementing a
>> callback like append_features or included? (That's how I'd want to do
>> it, but it's not clear which or how...)
>>
>> Thanks,
>> Jeff
>
Hi --
Ryan Leavengood wrote:
Have a module:
Module Foo
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
end
Is there a standard or correct way to initialize @foo_the_stuff in this
example? Should the add_stuff method check whether the variable has
been initialized every time, or should this be done by implementing a
callback like append_features or included? (That's how I'd want to do
it, but it's not clear which or how...)
Thanks,
Jeff
module Foo
def add_stuff(key, stuff)
(@foo_the_stuff ||= {})[key] = stuff
end
end
If @foo_the_stuff is null, it will be initialized to an empty hash,
otherwise the existing value will be used. I consider this use of ||=
to be a Ruby idiom.
Ryan
That's what I was afraid of. In this example case it's no big deal, but in a module where you are accessing a more complex variable many times it's a real pain, let alone inefficient. We are working on an event system, so the hash is a hash of arrays or possibly a hash of hashes. Any of 4 methods could be called, which would require an initialized value. Having this in every method is sorta lame...
handlers = (@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
Of course we can pull it out to a method:
def handlers(key)
@event_handlers ||= Hash.new {|k,v| k[v] = })[key]
end
but just initializing on inclusion seems to be the most reasonable way, doesn't it?
Not if it leads to code you strongly dislike It seems OK to wrap
it in a method, perhaps like this:
def event_handlers
@event_handlers ||= Hash.new {|k,v| k[v] = }
end
def whatever ...
handlers = event_handlers[key]
end
David
···
On Tue, 23 May 2006, Jeff Rose wrote:
On 5/22/06, Jeff Rose <rosejn@gmail.com> wrote:
--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
> Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
> Ruby for Rails
You still have to call it every time you use the variable.
···
On 5/22/06, dblack@wobblini.net <dblack@wobblini.net> wrote:
Hi --
On Tue, 23 May 2006, Jeff Rose wrote:
> Well, it took a while but I found the answer. This is done in ActiveRecord
> to wrap a possible setup method in the unit tests for auto-instrumentation of
> fixtures. Once I knew what to look for, however, I found an old post by
> Florian Gross that lays out the exact answer nicely:
>
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129834
>
> For educational purposes though, I'll explain a few things I found...
>
> 1) The append_features method is deprecated, and the included method is now
> the preferred callback. This method is called when a module is included, and
> it is passed the module that has done the including.
>
> 2) There is another callback, method_added, which is a meta-class method that
> is called every time a new method is defined for its class, and the symbol
> for the method name is passed.
>
> So, the trick is to add a custom method_added method to the meta-class of the
> class that does the including by extending it in the included callback. The
> custom method_added needs to redefine initialize after it is added so that it
> does the custom setup, then calls the original.
>
> Phew... Too bad we can't just have another callback that lets us do this
> easily. Maybe that feels too much like multiple inheritance or something?
>
> module Foo
> def module_initialize
> @myvar = Hash.new {|k,v| k[v] = }
> end
>
> def bar(key)
> @mybar[key]
> end
> end
>
> Isn't this a common thing to want?
I'm probably being thick but what's wrong with just writing a method
that wraps @myvar and initializes it if necessary, and then returns
it?
David
--
David A. Black (dblack@wobblini.net)
* Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
> Ruby and Rails consultancy and training
* Author of "Ruby for Rails" from Manning Publications!
> Ruby for Rails
Hi,
In message "Re: [OT] Re: initializing instance variables in a module"
the other day i realized that one could detect class creation using
class Class
def inherited
...
end
end
but that no such hook existed for class Module. could one be added such as
class Module
def instantiated
...
end
end
to hook into rb_define_module/rb_define_module_under?
I am not sure what situation that kind of method is useful. But in
any case I don't feel the word "instantiated" is the right word for
the method. Note that I am not opposing the method itself.
matz.
> This thread seems to have gone astray a bit but I didn't see this
> solution which I regard the standard way to handle this. The important
> part is to use initialize(*a,&b) in the module. I've put this on the
> wiki for easier reference:
>
> http://wiki.rubygarden.org/Ruby/page/show/InitializingWithInheritance
>
> Kind regards
>
> robert
This doesn't really solve the problem. The idea is that you don't want
the including class to have to do anything related to initialization of
the module(s) being included.
It doesn't have to.
In your example any including class would
have to call super in order to make it work.
But this is true for classes inheriting anyway. You could even make it
yourself a habit to even call super if you do not inherit specifically
(i.e. inherit Obect).
If Derived implements an
initialize method and doesn't call super then the module isn't
initialized. But why should it call super, it isn't deriving from
anything, it is mixing it in.
I don't fully agree: Derived actually inherits from Base so it's
standard procedure to invoke the super class initialize. If you then
write your module initialize with signature (*a,&b) you can insert it
into *any* inheritance chain that obeys the basic behavior without
doing any harm or losing initialization code.
The two options Matz mentioned are the way to go. Either a callback
(module_initialize), which will act as an initialization method for the
module, or the ability for the module to insert its own method(s)
before, after, or around the class that includes it. (CLOS method
combinations... AOP)
Well, yes, if a change to the language / lib can be considered these
are probably better.
Kind regards
robert
···
2006/5/23, Jeff Rose <rosejn@gmail.com>:
--
Have a look: http://www.flickr.com/photos/fussel-foto/
Francis Cianfrocca schrieb:
You still have to call it every time you use the variable.
Do you realy need to use the variable directly?
My scripts tend to have very little use of '@'.
module Foo
def bar(key)
@myvar ||= Hash.new {|k,v| k[v] = }
@myvar[key]
end
end
class Test
include Foo
end
t = Test.new
t.bar('baz') << 'eeek'
p t.bar('baz')
I didn't followed the whole thread so please ignore me
if this was suggested before.
cheers
Simon
Hi,
Jeff Rose wrote:
but just initializing on inclusion seems to be the most reasonable
way, doesn't it?
Put the initialization code in the module's initialize method and have
every class that includes the module call super from its initialize
method:
module Foo
def initialize(*args, &block)
# whatever...
end
end
class Bar
include Foo
def initialize(*args, &block)
super # calls Foo's initialize
# more stuff
end
end
What is wrong with what Tim suggests? I must be missing something. Here is a specific example:
module Foo
def initialize
super
@foo_the_stuff = {}
end
def add_stuff(key, stuff)
@foo_the_stuff[key] = stuff
end
end
class Bar
include Foo
def show_stuff
puts "stuff: #{@foo_the_stuff.inspect}"
end
end
b1 = Bar.new
b2 = Bar.new
b1.add_stuff("one", 1)
b2.add_stuff("two", 2)
b1.add_stuff("three", 3)
b2.add_stuff("four", 4)
b1.show_stuff
b2.show_stuff
Cheers,
Bob
···
On May 22, 2006, at 12:20 PM, Tim Hunter wrote:
----
Bob Hutchison -- blogs at <http://www.recursive.ca/hutch/>
Recursive Design Inc. -- <http://www.recursive.ca/>
Raconteur -- <http://www.raconteur.info/>
xampl for Ruby -- <http://rubyforge.org/projects/xampl/>