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
···
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
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/\.