[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

problem with Module#append_features

Ferenc Engard

9/8/2003 4:26:00 PM

Hi all,

I need to write a constructor-like method for a module. From the help I
have found the Module#append_features method, which look like is the one
I want. The problem is that apparently this method does not exist! At
least, it do not work for me (i.e. is not called automatically), and
there is no such method in the Object#private_instance_methods list.

What is wrong?

Thanks:
Circum
22 Answers

ts

9/8/2003 4:42:00 PM

0

>>>>> "F" == Ferenc Engard <ferenc@engard.hu> writes:

F> I need to write a constructor-like method for a module. From the help I
F> have found the Module#append_features method, which look like is the one
F> I want. The problem is that apparently this method does not exist! At

svg% ruby -e ''p Module.private_instance_methods(false).grep(/app/)''
["append_features"]
svg%

F> least, it do not work for me (i.e. is not called automatically), and

Well, it depend what you want to do

svg% cat b.rb
#!/usr/bin/ruby
module M
def self.append_features(kl)
puts "append_features #{kl}"
super
end
end

class A
include M
end
svg%

svg% b.rb
append_features A
svg%


Guy Decoux

Ferenc Engard

9/8/2003 5:52:00 PM

0

> svg% ruby -e ''p Module.private_instance_methods(false).grep(/app/)''
> ["append_features"]
> svg%

I was totally confused. I tried Object.private_instance_methods, and of
course, there was no such method there. :-/

> module M
> def self.append_features(kl)
> puts "append_features #{kl}"
> super
> end
> end

[...]

That is what I wanted to. Thank you, now it works. Well, I had no idea
that I need to write "self.append_features" instead of just
"append_features". Anyway, after you showed me, it looks
straightforward. :-)

"self.anything" is the same as "M.anything"?

Circum

Ferenc Engard

9/8/2003 6:02:00 PM

0

Hello,

Sorry, I pushed "send" too early. That is not exactly what I want. I
want a method which will be called when an object is instantiated, if
the object''s Class includes this Module. I.e., I do not want to write a
''init_x_module'' call into each classes'' constructor, which includes this
module, but want the system call that method. Something like multiple
inheritance in C++.

Circum

> > module M
> > def self.append_features(kl)
> > puts "append_features #{kl}"
> > super
> > end
> > end
>
> [...]
>
> That is what I wanted to. Thank you, now it works. Well, I had no idea

Dan Doel

9/8/2003 7:55:00 PM

0

Here''s some black magic to do something like you want to do. If there''s
an easier way, I''m sure
someone will post it as a follow-up to my message. :)

class Foo
def initialize
puts "Foo!"
end
end

module Bar
def self.append_features(cls)

class << cls # Trap the
initialize
proc { |x| @init = x } # method in an
unbound
end.call(cls.instance_method(:initialize)) # method object

cls.class_eval do remove_method :initialize end # Remove the old
# initialize

super # Make sure to call super
end

def initialize
unbound = class << self.class; @init; end # Retrieve the old method

init = unbound.bind self # Bind it to the current
# object
init.call
puts "Bar!" # new stuff goes here
end
end

class Foo
include Bar
end

Foo.new

Ferenc Engard wrote:

>Hello,
>
>Sorry, I pushed "send" too early. That is not exactly what I want. I
>want a method which will be called when an object is instantiated, if
>the object''s Class includes this Module. I.e., I do not want to write a
>''init_x_module'' call into each classes'' constructor, which includes this
>module, but want the system call that method. Something like multiple
>inheritance in C++.
>
>


ts

9/9/2003 9:23:00 AM

0

>>>>> "F" == Ferenc Engard <ferenc@engard.hu> writes:

F> Sorry, I pushed "send" too early. That is not exactly what I want. I
F> want a method which will be called when an object is instantiated, if
F> the object''s Class includes this Module. I.e., I do not want to write a
F> ''init_x_module'' call into each classes'' constructor, which includes this
F> module, but want the system call that method. Something like multiple
F> inheritance in C++.

This ?

svg% cat b.rb
#!./ruby

module M
def initialize#before
puts "M#initialize#before"
end
end

class A
include M
end

A.new
svg%

svg% ./ruby b.rb
M#initialize#before
svg%



p.s. : don''t try it, this is a modified version of ruby which exist only at
moulon :-))


Guy Decoux

Tobias Peters

9/9/2003 11:20:00 AM

0

Ferenc Engard wrote:
> Hello,
>
> I
> want a method which will be called when an object is instantiated, if
> the object''s Class includes this Module. I.e., I do not want to write a
> ''init_x_module'' call into each classes'' constructor, which includes this
> module, but want the system call that method. Something like multiple
> inheritance in C++.

In standard ruby:

class Module
def before(*method_names)
@before = method_names
end
alias pre_beforehack_append_features append_features
def append_features(klass)
@before ||= []
@before.each{|method_name|
klass.module_eval <<-END_OF_ADVICE
alias pre_include_#{self}_#{method_name} #{method_name}
def #{method_name}(*args,&block)
#{method_name}_#{self}(*args,&block)
pre_include_#{self}_#{method_name}(*args,&block)
end
END_OF_ADVICE
}
pre_beforehack_append_features(klass)
end
end
module M
before :initialize
def initialize_M(*args)
puts "#{self}: initializing M part"
end
end
class A
def initialize
puts "#{self}: initializing A part"
end
include M
end

A.new

=> #<A:0x25cb5d8>: initializing M part
#<A:0x25cb5d8>: initializing A part

The reader may now:
- implement Module#after
- do something intelligent to preserve method arity
- investigate if all of this is not already implemented in AspectR

--
Tobias
(email-address is anti-spammed, remove invalid parts)

Mauricio Fernández

9/9/2003 12:23:00 PM

0

On Tue, Sep 09, 2003 at 06:22:37PM +0900, ts wrote:
> This ?
>
> svg% cat b.rb
> #!./ruby
>
> module M
> def initialize#before
> puts "M#initialize#before"
> end
> end
>
> class A
> include M
> end
>
> A.new
> svg%
>
> svg% ./ruby b.rb
> M#initialize#before
> svg%
>
>
>
> p.s. : don''t try it, this is a modified version of ruby which exist only at
> moulon :-))

You like teasing people, don''t you ;-)

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| ''_ \ / _` | __/ __| ''_ ` _ \ / _` | ''_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Make it idiot-proof, and someone will breed a better idiot.
-- Oliver Elphick

ts

9/9/2003 2:16:00 PM

0

>>>>> "T" == Tobias Peters <tpeters@invalid.uni-oldenburg.de> writes:

T> The reader may now:
T> - implement Module#after
T> - do something intelligent to preserve method arity
T> - investigate if all of this is not already implemented in AspectR

Well, it''s not as simple as you think. To give you an example, when
plruby run with a timeout, it don''t give the possibility to the user code
to create threads. It''s really easy to do it in C (it just need to undef
Thread.new, ...), try to write it in ruby but don''t forget :
* you must be able to create Thread when $SAFE <= 3
* it must not exist a possibility to do the same when $SAFE >= 4

With hook, you just need to write

class Thread
class << self
def new:before(*args)
raise if $SAFE >= 4
end
# etc, for start ...
end
end


Guy Decoux







Ferenc Engard

9/10/2003 10:18:00 PM

0

Hello,

> module Bar
> def self.append_features(cls)
>
> class << cls # Trap the
> initialize
> proc { |x| @init = x } # method in an
> unbound
> end.call(cls.instance_method(:initialize)) # method object
>
> cls.class_eval do remove_method :initialize end # Remove the old
> # initialize
>
> super # Make sure to call super
> end
>
> def initialize
> unbound = class << self.class; @init; end # Retrieve the old method
>
> init = unbound.bind self # Bind it to the current
> # object
> init.call
> puts "Bar!" # new stuff goes here
> end
> end

Somehow I have understand your solution. Anyway, I have some questions
which I cannot figure out with my knowledge from Pragmatic Programmer''s
guide.

I do not understand the relation between the body of a class definition,
and the singleton class body.

Let''s take this snippet:

class A
@x=1
def A.fn1
puts @x
end
def fn2
puts @x
end
end

class << A
@x=2
end

a=A.new
a.instance_eval "@x=3"
class << a
@x=4
end

A.fn1 # 1
class << A
puts @x # 2
end
a.fn2 # 3
class << a
puts @x # 4
end

This prints out 1,2,3,4. For values for 4 @x''es (two for the object and
two for the class). And I didn''t used class variables (@@x). If I get
just one object (e.g. the "A" object of type Class), where do these two
instance variables belong? Also, what other techniques are available to
get/set these variables? Maybe there are more @x''es? :)

Thank you:

Circum, who are getting confused in these classes and metaclasses and
meta-metaclasses... :)

Dan Doel

9/11/2003 1:36:00 AM

0

Let''s see:

class A; end
a = A.new

Defines two objects. A is an object whose proper class is Class, and a is
an object whose proper class is A. You can access these objects with:

A.class
a.class

a.class is A for all instances of the A class. A.class is Class, and that''s
the same for all classes.

However, every object in Ruby also has a singleton class. In a sense, this
class is a subclass of the object''s proper class, so any changes you make
to it are reflected in the object, but not other objects with the same
proper
class. So the hierarchy looks something like:

Class
|
A-Singleton -> A
|
a-singleton -> a

If vertical means inheritence, and horizontal means "instance of".

Of course, it''s more complicated than that, because a-singleton is an
instance of Class, so it has Class as its proper class, and
a-singleton-singleton as its singleton class. And Likewise
a-singleton-singleton is an instance of Class and has a proper class
and a singleton class.

So, about your examples:

for @x = 1, that''s a class instance variable of the A class. It''s
accessible using A.class_eval { @x } or a.class.class_eval { @x }
You can make attribute writers/readers by doing:

class << A
attr_reader :x
end

for @x = 2, it''s also a class instance variable, but it uses the
singleton class of A instead of A itself. Since the singleton class
is exclusively related to A, it''s no better than a class instance
variable of A, but in reality it''s a class instance variable of the
singleton class of A. To write an accessor, you do:

def A.x
class << self
@x
end
end

@x = 3 is a normal instance variable

@x = 4 is an instance variable of the singleton class of a, so it''s
technically a class instance variable. However, since the singleton
class of a is only related to a, it''s no better than an instance
variable of a in a different namespace.

Of course, you can go on as far as you want and make instance variables
like so:

def a.xN(N)
return @x if N < 1

cls = self

N.times do
cls = class << cls; self; end
end

cls.class_eval { @x }
end

So a.xN(1) would read the @x variable in a''s singleton class, while
a.xN(2) would read the @x variable in the singleton class of a''s
singleton class (I haven''t tested this. It assumes that singleton
classes go up infinitely as necessary).

Of course, this would be pretty crazy, and I wouldn''t recommend it.

Anyway, this has gone on very long, so I should stop. If you have
any more questions, I''ll do my best to answer them, especially if
they''re about the code I wrote.

Hope this has helped some.

- Dan