Alias new?

I've seen this work before:

module MagicWithMethodMissing
   alias_method :__orig_method_missing, :method_missing
   def method_missing(sym, *args, &block)
     if some_condition
       #do special stuff
     else
       __orig_method_missing(sym, *args, &block)
     end
   end
end

class MyClass
   include MagicWithMethodMissing
end

I want to do the same thing w/ :new on the class

module MagicWithNew
   alias_method :__orig_new, :new
   def new(*args, &block)
     if some_condition
       #do special stuff
     else
       __orig_new(*args, &block)
     end
   end
end

The question I have is how do I get this included in the meta class of MyClass?

Thanks,
David

Couple of things
1) alias_method gets executed at "compile" time. This means that it will try to alias MagicWithNew.

2) This is ok because you dont want to use alias's in this case. Since #new is almost never overriden (it's usually #initialize. Incidentally are you sure you don't want to define #initialize instead?) it's pretty much guaranteed that you class is using the original implementation in Class.
so we can use inheritance and super

module MagicWithNew
   def new(*args, &block)
     if some_condition
        do_special_stuff
     else
        super
     end
   end
end

class MyClass
   extend MagicWithNew # note #extend, not #include
end

···

On Jul 12, 2006, at 12:07 AM, David Chelimsky wrote:

I've seen this work before:

module MagicWithMethodMissing
  alias_method :__orig_method_missing, :method_missing
  def method_missing(sym, *args, &block)
    if some_condition
      #do special stuff
    else
      __orig_method_missing(sym, *args, &block)
    end
  end
end

class MyClass
  include MagicWithMethodMissing
end

I want to do the same thing w/ :new on the class

module MagicWithNew
  alias_method :__orig_new, :new
  def new(*args, &block)
    if some_condition
      #do special stuff
    else
      __orig_new(*args, &block)
    end
  end
end

The question I have is how do I get this included in the meta class of MyClass?

Thanks,
David

Couple of things
1) alias_method gets executed at "compile" time. This means that it will try to alias MagicWithNew.

2) This is ok because you dont want to use alias's in this case. Since #new is almost never overriden (it's usually #initialize. Incidentally are you sure you don't want to define #initialize instead?) it's pretty much guaranteed that you class is using the original implementation in Class.
so we can use inheritance and super

module MagicWithNew
def new(*args, &block)
   if some_condition
      do_special_stuff

   fails to initialize object! you need the old 'new' here. or super.

   else
      super
   end
end
end

class MyClass
extend MagicWithNew # note #extend, not #include
end

here is an example of a fairly robust pattern

   harp:~ > cat a.rb
   module M
     ClassMethods = lambda do
       alias_method '__new__', 'new' # correct alias of new

       def new *a, &b
         obj = __new__(*a, &b)

···

On Wed, 12 Jul 2006, Logan Capaldo wrote:
       #
       # do anything you want with obj here based on any condition. this is just
       # an example.
       #
         class << obj
           def answer() 42 end
         end
         obj
       end
     end

     def self.included other
       meta =
         class << other
           self
         end
       meta.module_eval &ClassMethods
       super
     end
   end

   class C
     include M
   end

   p C.new.answer

   harp:~ > ruby a.rb
   42

regards.

-a
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Couple of things
1) alias_method gets executed at "compile" time. This means that it will try to alias MagicWithNew.

2) This is ok because you dont want to use alias's in this case. Since #new is almost never overriden (it's usually #initialize. Incidentally are you sure you don't want to define #initialize instead?) it's pretty much guaranteed that you class is using the original implementation in Class.
so we can use inheritance and super

module MagicWithNew
def new(*args, &block)
   if some_condition
      do_special_stuff

  fails to initialize object! you need the old 'new' here. or super.

Well he did say "special stuff". He only needs old new or super there if he plans on initializing the object :wink:

···

On Jul 12, 2006, at 1:01 AM, ara.t.howard@noaa.gov wrote:

On Wed, 12 Jul 2006, Logan Capaldo wrote:

   else
      super
   end
end
end

class MyClass
extend MagicWithNew # note #extend, not #include
end

here is an example of a fairly robust pattern

  harp:~ > cat a.rb
  module M
    ClassMethods = lambda do
      alias_method '__new__', 'new' # correct alias of new

      def new *a, &b
        obj = __new__(*a, &b)
      #
      # do anything you want with obj here based on any condition. this is just
      # an example.
      #
        class << obj
          def answer() 42 end
        end
        obj
      end
    end

    def self.included other
      meta =
        class << other
          self
        end
      meta.module_eval &ClassMethods
      super
    end
  end

  class C
    include M
  end

  p C.new.answer

  harp:~ > ruby a.rb
  42

regards.

-a
--
suffering increases your inner strength. also, the wishing for suffering
makes the suffering disappear.
- h.h. the 14th dali lama

Yes. I'm writing an acts_as_mock plugin for rails controller tests. Since activerecord relies on a bunch of class methods, I need to be able to mock them as well so I can write tests like this:

   def test_blah
     expected = Story.new
     Story.should_receive(:new).and_return(expected)
     expected.should_receive(:some_message)

     get :blah
   end

This (in theory) will allow us to run controller (functional) tests in isolation (i.e. no DB necessary), and therefore much faster.

In the example above, the first call to :new gets handled by super. The second line tells the class that the next time :new is called, it should return this particular object (expected). After that, you can set expectations on expected.

Thanks to your help here, this is working like a charm!

I've got a lot more work to do on this to make it even alpha-release worthy, but I'll post a note here when I get there.

Cheers,
David

···

On Jul 12, 2006, at 12:15 AM, Logan Capaldo wrote:

On Jul 12, 2006, at 1:01 AM, ara.t.howard@noaa.gov wrote:

On Wed, 12 Jul 2006, Logan Capaldo wrote:

module MagicWithNew
def new(*args, &block)
   if some_condition
      do_special_stuff

  fails to initialize object! you need the old 'new' here. or super.

Well he did say "special stuff". He only needs old new or super there if he plans on initializing the object :wink:

David Chelimsky wrote:

Yes. I'm writing an acts_as_mock plugin for rails controller tests.
Since activerecord relies on a bunch of class methods, I need to be
able to mock them as well so I can write tests like this:

   def test_blah
     expected = Story.new
     Story.should_receive(:new).and_return(expected)
     expected.should_receive(:some_message)

     get :blah
   end

This (in theory) will allow us to run controller (functional) tests
in isolation (i.e. no DB necessary), and therefore much faster.

Sounds interesting. I've been working on something similar - a mocking
library called Mocha (http://mocha.rubyforge.org). It's not specifically
targetted at Rails controller tests, but I think the Stubba/AutoMocha
parts might allow you to do what you want.

Stubba allows you to mock or stub class methods.

For AutoMocha, I alias the :new method in Mocha:MockClass
(http://mocha.rubyforge.org/classes/Mocha/MockClass.html\) and define a
new version that delegates to method_missing which is at the heart of
the mocking functionality. The inherited method then ensures that any
subclasses get the original :new method back.

James.

···

On Jul 12, 2006, at 12:15 AM, Logan Capaldo wrote:

--
Posted via http://www.ruby-forum.com/\.