Metaprogramming help

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-forum.com/.

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

···

On Nov 26, 2007 10:20 AM, Chris Richards <evilgeenius@gmail.com> wrote:

--

http://ruby-smalltalk.blogspot.com/

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

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://codeforpeople.com/

···

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-forum.com/\.

--
share your knowledge. it's a way to achieve immortality.
h.h. the 14th dalai lama

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.

···

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

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

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

Sorry
R.

> 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-forum.com/\.
>

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.

···

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:

regards
a @ http://codeforpeople.com/
--
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.blogspot.com/

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-forum.com/\.

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

a @ http://codeforpeople.com/

···

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...

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

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.

···

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