[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Metaprogramming help

EvilGeenius

11/26/2007 9:20:00 AM

I have created a module as follows which adds an initialize method to
the class it is included in. The problem is that the initializer method
could be easily overriden by the includer Class. Is there a way to
ensure that the initialize method is run even though it may have been
overriden??

module SomeModule

def self.included(base)
base.class_eval do

attr_accessor :fields, :x_position, :y_position

def initialize(x_position=0, y_position=0)
@fields=self.class.xfields.clone
self.y_position=y_position
self.x_position=x_position
for field in @fields
eval "self."+field[:var] + " = field[:value]"
end
@fields = @fields.sort_by{|f| f[:order]} if @fields.find{|f|
f[:order]}
end
end
end

end

Any help is appreciated.
Thanks, Chris
--
Posted via http://www.ruby-....

8 Answers

Robert Dober

11/26/2007 10:42:00 AM

0

On Nov 26, 2007 10:20 AM, Chris Richards <evilgeenius@gmail.com> wrote:
> I have created a module as follows which adds an initialize method to
> the class it is included in. The problem is that the initializer method
> could be easily overriden by the includer Class. Is there a way to
> ensure that the initialize method is run even though it may have been
> overriden??
No there is none and I am not sure it is a good idea, as it is the
users responsability to call super.
But if it turns out to be a good idea than one could imagine doing
something like below, which kind of hides better what you try to hide.
I believe that hiding your own init method and assure it is called in
new might be a better model of your intent, initialize belongs to the
user after all, right?
>
>
module M
class << self
def included into
my_init = nil
into.module_eval do
### More sophistication can be added here to avoid naming conflicts
### in the includee (into)
define_method :my_init do puts 42 end
my_init = instance_method :my_init
remove_method :my_init
end

class << into; self end.module_eval do
alias_method :_orig_new_, :new
define_method :new do | *args | # more hocus pocus needed for &blk
o = _orig_new_( *args )
my_init.bind( o ).call( *args )
o
end
end
end
end
end


class C
include M
def my_init; puts 222 end
end

c= C.new
c.my_init

Of course a user can still mess with C#new but your code might be save
from most common reusage patterns :).

HTH
Robert

--

http://ruby-smalltalk.blo...

---
All truth passes through three stages. First, it is ridiculed. Second,
it is violently opposed. Third, it is accepted as being self-evident.
Schopenhauer (attr.)

Robert Dober

11/26/2007 11:16:00 AM

0

Sorry for quothing myself but you know Murphy's law :(

of course it is unnecessary to alias new to _orig_new_, just replace
_orig_new_ with a call to super.

Sorry
R.

ara.t.howard

11/26/2007 5:49:00 PM

0


On Nov 26, 2007, at 2:20 AM, Chris Richards wrote:

> I have created a module as follows which adds an initialize method to
> the class it is included in. The problem is that the initializer
> method
> could be easily overriden by the includer Class. Is there a way to
> ensure that the initialize method is run even though it may have been
> overriden??
>
> module SomeModule
>
> def self.included(base)
> base.class_eval do
>
> attr_accessor :fields, :x_position, :y_position
>
> def initialize(x_position=0, y_position=0)
> @fields=self.class.xfields.clone
> self.y_position=y_position
> self.x_position=x_position
> for field in @fields
> eval "self."+field[:var] + " = field[:value]"
> end
> @fields = @fields.sort_by{|f| f[:order]} if @fields.find{|f|
> f[:order]}
> end
> end
> end
>
> end
>
> Any help is appreciated.
> Thanks, Chris
> --
> Posted via http://www.ruby-....
>

i'd be inclined to do something like this:

cfp:~ > cat a.rb
module M
def M.initialize obj
obj.instance_eval{
@a = 42
}
end

module ClassMethods
def new *a, &b
obj = super
ensure
M.initialize obj
end
end

module InstanceMethods
attr :a
end

def self.included other
other.send :extend, ClassMethods
other.send :include, InstanceMethods
end
end

class C
include M
end

p C.new.a


cfp:~ > ruby a.rb
42


allowing you to extend the includee's class, instances, and also keep
your private initialize private rather than dropping it into the
includee

regards
a @ http://codeforp...
--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama



Robert Dober

11/26/2007 8:53:00 PM

0

On Nov 26, 2007 6:49 PM, ara.t.howard <ara.t.howard@gmail.com> wrote:
>
>
> On Nov 26, 2007, at 2:20 AM, Chris Richards wrote:
>
> > I have created a module as follows which adds an initialize method to
> > the class it is included in. The problem is that the initializer
> > method
> > could be easily overriden by the includer Class. Is there a way to
> > ensure that the initialize method is run even though it may have been
> > overriden??
> >
> > module SomeModule
> >
> > def self.included(base)
> > base.class_eval do
> >
> > attr_accessor :fields, :x_position, :y_position
> >
> > def initialize(x_position=0, y_position=0)
> > @fields=self.class.xfields.clone
> > self.y_position=y_position
> > self.x_position=x_position
> > for field in @fields
> > eval "self."+field[:var] + " = field[:value]"
> > end
> > @fields = @fields.sort_by{|f| f[:order]} if @fields.find{|f|
> > f[:order]}
> > end
> > end
> > end
> >
> > end
> >
> > Any help is appreciated.
> > Thanks, Chris
> > --
> > Posted via http://www.ruby-....
> >
>
> i'd be inclined to do something like this:
>
> cfp:~ > cat a.rb
> module M
> def M.initialize obj
> obj.instance_eval{
> @a = 42
> }
> end
>
> module ClassMethods
> def new *a, &b
> obj = super
> ensure
> M.initialize obj
> end
> end
>
> module InstanceMethods
> attr :a
> end
>
> def self.included other
> other.send :extend, ClassMethods
> other.send :include, InstanceMethods
> end
> end
>
> class C
> include M
> end
>
> p C.new.a
>
>
> cfp:~ > ruby a.rb
> 42
>
>
> allowing you to extend the includee's class, instances, and also keep
> your private initialize private rather than dropping it into the
> includee
Well the simplicity and elegance of your code speak for themselves, I
would like to defend myself nevertheless;)
my aim was hiding the implementation even more, but as I put it
myself, that might not make sense very easily.
But I learnt a lot from your approach here...
R.
>
> regards
> a @ http://codeforp...
> --
> share your knowledge. it's a way to achieve immortality.
> h.h. the 14th dalai lama
>
>
>
>



--
what do I think about Ruby?
http://ruby-smalltalk.blo...

ara.t.howard

11/26/2007 11:31:00 PM

0


On Nov 26, 2007, at 1:53 PM, Robert Dober wrote:

> Well the simplicity and elegance of your code speak for themselves, I
> would like to defend myself nevertheless;)
> my aim was hiding the implementation even more, but as I put it
> myself, that might not make sense very easily.
> But I learnt a lot from your approach here...



lol - my own code looks much more like yours. i go back and forth
with methodology. this week i am using modules ;-)

a @ http://codeforp...
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




Trans

11/26/2007 11:52:00 PM

0



On Nov 26, 4:20 am, Chris Richards <evilgeen...@gmail.com> wrote:
> I have created a module as follows which adds an initialize method to
> the class it is included in. The problem is that the initializer method
> could be easily overriden by the includer Class. Is there a way to
> ensure that the initialize method is run even though it may have been
> overriden??
>
> module SomeModule
>
> def self.included(base)
> base.class_eval do
>
> attr_accessor :fields, :x_position, :y_position
>
> def initialize(x_position=0, y_position=0)
> @fields=self.class.xfields.clone
> self.y_position=y_position
> self.x_position=x_position
> for field in @fields
> eval "self."+field[:var] + " = field[:value]"
> end
> @fields = @fields.sort_by{|f| f[:order]} if @fields.find{|f|
> f[:order]}
> end
> end
> end
>
> end

This is more of an aside then an answer to your question. But it is
important to note that you should not do the above. You are
"falsifying" inclusion and actually injecting code. The reason I say
"falsify" is because you end up with a module in the hierarchy that
contains no code. If you want to inject code, then simply define a
class method that does it. Don't use the included callback.

BTW: To ensure a routine always runs on initialization despite
#initialize, one way:

class X
class << self
def new(*a, &b)
o = allocate
o.do_your_thing
o.initialize(*a,&b)
o
end
end
end

The other is AOP which is a much larger can of worms.

T.

EvilGeenius

11/27/2007 10:15:00 AM

0

Wow, thanks for all your replies.

> BTW: To ensure a routine always runs on initialization despite
> #initialize, one way:
>
> class X
> class << self
> def new(*a, &b)
> o = allocate
> o.do_your_thing
> o.initialize(*a,&b)
> o
> end
> end
> end
>
> The other is AOP which is a much larger can of worms.

so whats the simplest way to ensure this method was always run ? :

def initialize(x=0, y=0)
self.x_position=x
self.y_position=y
end

Thanks
Chris

--
Posted via http://www.ruby-....

Trans

11/27/2007 2:24:00 PM

0



On Nov 27, 5:15 am, Chris Richards <evilgeen...@gmail.com> wrote:
> Wow, thanks for all your replies.
>
> > BTW: To ensure a routine always runs on initialization despite
> > #initialize, one way:
>
> > class X
> > class << self
> > def new(*a, &b)
> > o = allocate
> > o.do_your_thing
> > o.initialize(*a,&b)
> > o
> > end
> > end
> > end
>
> > The other is AOP which is a much larger can of worms.
>
> so whats the simplest way to ensure this method was always run ? :
>
> def initialize(x=0, y=0)
> self.x_position=x
> self.y_position=y
> end

Why do you want to thwart super here? You should have very clear
reason for doing so, otherwise leave it.

But to answer your question directly:

class X
class << self
def new(*a, &b)
o = allocate
o.pre_initialize(*a, &b)
o.initialize(*a,&b)
o
end
end

def pre_initialize(x=0, y=0)
self.x_position=x
self.y_position=y
end
end

T.