mixin question

A

Ara.T.Howard

i have this

jib:~ > cat a.rb
module M
def bar
@bar = 42
super
end
end
class Foo
attr :bar
def initialize
@bar = 'bar'
end
end

foo = Foo.new
p foo.bar

class Foo
include M # of course this acts as super - it does not override
end

p foo.bar


jib:~ > ruby a.rb
"bar"
"bar"

and i want it to print "bar", "42". i'm looking for a way to overide all of a
classes methods via a module (or some other trick) without needing to extend
individual objects and without simply opening up the class and redefining
everything. in otherwords a simple way to override a bunch of bundled methods
at once. it seems like this must be possible but my brain isn't firing on all
fours today...


-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
P

Pit Capitain

Ara.T.Howard said:
(code snipped)

i'm looking for a way to overide all of a classes methods via a module
(or some other trick) without needing to extend individual objects and
without simply opening up the class and redefining everything. in
otherwords a simple way to override a bunch of bundled methods
at once.

Hi Ara,

you could try this:

require 'set'

class Module
def override *methods
methods.map! { |method| method.to_s }
methods = Set.new( methods ) & instance_methods( false )
unless methods.empty?
mod = Module.new
methods.each do |method|
mod.send :define_method, method, instance_method( method )
remove_method method
end
include mod
end
end
end

This code creates a new module, moves some methods from the original module into
the new one, removes the original methods, an then includes the new module. You
would call "override" like this:

module M
def bar
@bar = 42
super
end
def self.append_features mod
mod.override :bar
super
end
end

class Foo
attr :bar
def initialize
@bar = 'bar'
end
end

foo = Foo.new
p foo.bar # ==> "bar"

class Foo
include M
end

p foo.bar # ==> 42

The result is the following:

p Foo.ancestors # ==> [Foo, M, #<Module:0x2a68cf0>, Object, Kernel]

with the original "bar" being defined in the anonymous module.

!!! Note that this overriding doesn't work if the overridden method calls
"super" itself (see ruby-talk:75286) !!!

HTH,
Pit
 
R

Robert Klemme

Ara.T.Howard said:
i have this

jib:~ > cat a.rb
module M
def bar
@bar = 42
super
end
end
class Foo
attr :bar
def initialize
@bar = 'bar'
end
end

foo = Foo.new
p foo.bar

class Foo
include M # of course this acts as super - it does not override
end

p foo.bar


jib:~ > ruby a.rb
"bar"
"bar"

and i want it to print "bar", "42". i'm looking for a way to overide all of a
classes methods via a module (or some other trick) without needing to extend
individual objects and without simply opening up the class and redefining
everything. in otherwords a simple way to override a bunch of bundled methods
at once. it seems like this must be possible but my brain isn't firing on all
fours today...

Does this help?

module M
def self.included(cl)
cl.instance_eval do
instance_methods.each do |meth|
define_method(meth) do |*args|
p args
end
end
end
end

def bar
@bar = 42
super
end
end

class Foo
attr :bar
def initialize
@bar = 'bar'
end
end

foo = Foo.new
p foo.bar

class Foo
include M # of course this acts as super - it does not override
end

p foo.bar


Of course the method definition has to be made a bit smarter.

Regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top