Skip to content

Instantly share code, notes, and snippets.

@lmarburger
Forked from rkh/hack.rb
Created May 17, 2012 16:49
Show Gist options
  • Save lmarburger/2720127 to your computer and use it in GitHub Desktop.
Save lmarburger/2720127 to your computer and use it in GitHub Desktop.
Possible for a module included somewhere to override a class's instance method?
class Base
def call
'call'
end
end
p Base.new.call #=> "call"
# Monkeypatching "works" but doesn't provide access to #super
class Base
def call
'monkeypatched'
end
end
module Prepending
def append_features(base)
return super unless base.is_a? Class
prepend = self
base.extend Module.new { define_method(:new) { |*args| super(*args).extend(prepend) }}
end
end
p Base.new.call #=> "monkeypatched"
# This is the spirit of what I'd like, but methods defined on the class will be
# preferred over those in ancestors.
module Override
extend Prepending
def call
[ 'overridden', super ]
end
end
class Base
include Override
end
p Base.new.call #=> ["overridden", "monkeypatched"]
# This works but I don't have access to the class instances to apply this method.
instance = Base.new
class << instance
def call
[ 'overridden', super ]
end
end
p instance.call #=> ["overridden", ["overridden", "monkeypatched"]]
@lmarburger
Copy link
Author

$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.3.0]

$ ruby hack.rb 
"X: x"
"call"
"X: y"
"monkeypatched"
hack.rb:24:in `block (2 levels) in append_features': implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly. (RuntimeError)
    from hack.rb:43:in `<main>'

Passings args explicitly with super(*args) seems to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment