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

On Jul 12, 2006, at 12:07 AM, David C. wrote:

end
def new(*args, &block)

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 Wed, 12 Jul 2006, Logan C. 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.

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

On Jul 12, 2006, at 1:01 AM, [email protected] wrote:

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 12:15 AM, Logan C. wrote:

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

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

David C. wrote:

On Jul 12, 2006, at 12:15 AM, Logan C. 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.