[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

module private methods inheritance ?

zimba.tm@gmail.com

7/11/2006 12:31:00 PM

Hi list,

while playing with ruby, I've hit a point I'm not really clear about.

code :

module A
def initialize; puts "From A" end
end

module B
def initialize; puts "From B" end
end

module A
include B
end

class C
include A
end

c = C.new
From A
=> #<C:0x...>

Now, let's say that the only thing I can change in that code it the B
module. How would you do so that I get "From B" instead of "From A" ?

--
Cheers,
zimbatm

http://zimba...

11 Answers

Trans

7/11/2006 1:12:00 PM

0


Jonas Pfenniger wrote:
> Hi list,
>
> while playing with ruby, I've hit a point I'm not really clear about.
>
> code :
>
> module A
> def initialize; puts "From A" end
> end
>
> module B
> def initialize; puts "From B" end
> end
>
> module A
> include B
> end
>
> class C
> include A
> end
>
> c = C.new
> From A
> => #<C:0x...>
>
> Now, let's say that the only thing I can change in that code it the B
> module. How would you do so that I get "From B" instead of "From A" ?

see Facets' Kernel#as

T.


Sean O'Halpin

7/11/2006 1:32:00 PM

0

On 7/11/06, Jonas Pfenniger <zimba.tm@gmail.com> wrote:
> Hi list,
>
> while playing with ruby, I've hit a point I'm not really clear about.
>
> code :
>
> module A
> def initialize; puts "From A" end
> end
>
> module B
> def initialize; puts "From B" end
> end
>
> module A
> include B
> end
>
> class C
> include A
> end
>
> c = C.new
> From A
> => #<C:0x...>
>
> Now, let's say that the only thing I can change in that code it the B
> module. How would you do so that I get "From B" instead of "From A" ?
>
> --
> Cheers,
> zimbatm
>
> http://zimba...
>
>

This might do what you want:

module A
def initialize
puts "From A"
end
end

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


Regards,
Sean

Trans

7/11/2006 2:21:00 PM

0


Sean O'Halpin wrote:

>
> This might do what you want:
>
> module A
> def initialize
> puts "From A"
> end
> end
>
> 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).

T.


Gary Wright

7/11/2006 3:06:00 PM

0


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.

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




zimba.tm@gmail.com

7/11/2006 4:17:00 PM

0

Thanks for your help,

I finally decided to create a new Module#insert method :

class Module
def insert(new_mod)
new_mod = new_mod.dup
old_mod = self
mod_name = self.basename

new_mod.module_eval do
include old_mod
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

:-)

--
Cheers,
zimbatm

http://zimba...

Trans

7/11/2006 5:22:00 PM

0


Jonas Pfenniger wrote:
> Thanks for your help,
>
> I finally decided to create a new Module#insert method :
>
> class Module
> def insert(new_mod)
> new_mod = new_mod.dup
> old_mod = self
> mod_name = self.basename
>
> new_mod.module_eval do
> include old_mod
> 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:

A.insert(B)

translates into

Bp = B.dup

module Bp
include A
end

remove_const A
A = Bp

Why do you need this?

T.


zimba.tm@gmail.com

7/11/2006 5:28:00 PM

0

On 11/07/06, transfire@gmail.com <transfire@gmail.com> wrote:
> 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 :-)

--
Cheers,
zimbatm

http://zimba...

Trans

7/11/2006 5:40:00 PM

0


Jonas Pfenniger wrote:

>
> 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 :-)

Why can't you change Camping code? It should be no different extending
Ruby itself.

T.


Sean O'Halpin

7/11/2006 8:10:00 PM

0

On 7/11/06, transfire@gmail.com <transfire@gmail.com> wrote:
>
> Sean O'Halpin wrote:
>
> >
> > This might do what you want:
>> [snip code]
>
> Execpt now you've just changed A which could break anything else using
> it.
>

Indeed - but isn't that what Jonas wanted?

module A
include B
end

with B overriding A?

However, this could well have unwanted side-effects on other classes
which expect A's behaviour. Caveat preemptor...

Regards,
Sean

Daniel DeLorme

7/11/2006 11:37:00 PM

0

Why go through such convoluted hoops? The problem is simple: the original module
has a bug (it doesn't call super). All you have to do is fix the bug:

module A
alias buggy_initialize initialize
def initialize
super
buggy_initialize
end
end

That's a lot cleaner than undefining and redefining constants.

BTW I suggest that a module's initialize should always pass through parameters
to the upper level:

def initialize(*a,&b)
super
#do your stuff...
end

And if Matz is reading this, I wish that 'call super' would be the *default*
behavior. ^_^

Daniel

Jonas Pfenniger wrote:
> Thanks for your help,
>
> I finally decided to create a new Module#insert method :
>
> class Module
> def insert(new_mod)
> new_mod = new_mod.dup
> old_mod = self
> mod_name = self.basename
>
> new_mod.module_eval do
> include old_mod
> end
>
> (nesting[-2] || Object).module_eval do
> remove_const mod_name
> const_set mod_name, new_mod
> end
> end