module B
def initialize
puts "From B"
end
def self.included(obj)
obj.class_eval {
def initialize
super # call this module's initialize
end
}
end
end
module A
include B
end
class C
include A
end
c = C.new
__END__
From B
Execpt now you've just changed A which could break anything else using
it.
Actually I think J's use of initialize, rather then some other method
was in a err. Yes? You can skip over ancestors using something like
facet/kernel/as but initialize is a touchy matter --it's not something
one generally defines in a module in the first place.
Even so, if that's really wha is wanted....
require 'facet/kernel/as'
class C
include A
def initialize
as(B).initialize
end
end
What does #as do? It get the UnboundMethod in B and binds it to C, and
offers it up in a nice little Functor. You can bypass the Functor if
you want with #send_as(B,:initialize).
I see this idea mentioned often (avoid initialize in modules). Some modules
need initialization, some don't. I don't think it is helpful
to generalize beyond that. I often see:
module A
def foo @foo ||= {}
end
end
which is basically a lazy initialization of @foo by the module instead of:
module A
def initialize @foo = {}
end
end
class B
def initialize
super
# init for B here
end
end
You can use Module#included to handle class/module level initialization but
I sometimes wish there was a well-defined instance initialization hook for
included modules instead of relying on the appropriate use of super() within
initialize(). I'm not sure what it would look like though, maybe:
module M
def self.instantiated(x)
x.initialize_M
end
def initialize_M #initialization for M goes here
end
end
Presumably Class#new would trigger Module.instantiated for all included modules
in some well defined order (appearence in ancestors list?).
These seems kind of inelegant though. There must be a better solution. Or maybe
it is a solution looking for a problem.
Gary Wright
···
On Jul 11, 2006, at 10:21 AM, transfire@gmail.com wrote:
You can skip over ancestors using something like
facet/kernel/as but initialize is a touchy matter --it's not something
one generally defines in a module in the first place.
(nesting[-2] || Object).module_eval do
remove_const mod_name
const_set mod_name, new_mod
end
end
# From the Facets package
def nesting
n = []
name.split(/::/).inject(self){ |mod, name| c = mod.const_get(name)
; n << c ; c }
return n
end
# From the Facets package
def basename
if name and not name.empty?
name.gsub(/^.*::/, '')
else
nil #inspect.gsub('#<','').gsub('>','').sub(':', '_')
end
end
end
I know that I can have unwanted effects but in my case it is ok
because the loading order is pretty strict.
module A
def initialize; puts "From A"; end
end
module B
def initialize; puts "From B"; super; end
end
(nesting[-2] || Object).module_eval do
remove_const mod_name
const_set mod_name, new_mod
end
end
# From the Facets package
def nesting
n =
name.split(/::/).inject(self){ |mod, name| c = mod.const_get(name)
; n << c ; c }
return n
end
# From the Facets package
def basename
if name and not name.empty?
name.gsub(/^.*::/, '')
else
nil #inspect.gsub('#<','').gsub('>','').sub(':', '_')
end
end
end
I know that I can have unwanted effects but in my case it is ok
because the loading order is pretty strict.
module A
def initialize; puts "From A"; end
end
module B
def initialize; puts "From B"; super; end
end
A.insert(B)
class C
include A
end
C.new
#=> From B
#=> From A
This code essentially (or at least partially succeeds at) reversing the
inclusion order of two modules. Ie.
module B; end
module A; include B; end
becomes
module B; include A; end
Are you sure you want to do that? That can have crazy effects! In fact
it's a very bad idea unless you have full control coding over these
modules, and if that's the case you wouldn't need to do it anyway. So
as I say, I'm highly suspect. Looking at exacly what this does it
appears that:
This code essentially (or at least partially succeeds at) reversing the
inclusion order of two modules. Ie.
module B; end
module A; include B; end
becomes
module B; include A; end
exactly
Are you sure you want to do that? That can have crazy effects! In fact
it's a very bad idea unless you have full control coding over these
modules, and if that's the case you wouldn't need to do it anyway. So
as I say, I'm highly suspect. Looking at exacly what this does it
appears that:
A.insert(B)
translates into
Bp = B.dup
module Bp
include A
end
remove_const A
A = Bp
Why do you need this?
Yeah I know it is stange but this is because of Camping !
I can't change the Camping code so I need to find ways to sneak myself in
···
On 11/07/06, transfire@gmail.com <transfire@gmail.com> wrote: