Monkey Patching 2 Methods, Overrides One Method, Not The Other

M

MaggotChild

I'm monkey patching 2 methods of an existing module: some_method() and
another_method()

Calling some_method() on an instance of class that includes the
original module works fine (calls the monkey patched version), but
when I call another_method() the original (not the monkey patched)
method is called.

There is a lot of code, and I've tried to recreate the series of
includes with the below example, yet the example works!

Given this, I hope that someone could still provide me with some
insight as to why this would happen

#original_module.rb

module ToBePatched
module A
def some_method
p 'original some'
end

def another_method
p 'original anotehr'
end
end
end

#original_class.rb

module ToBePatched
class Foo
include ToBePatched::A
end
end

#my_override.rb

module MyModule
module MyNestedModule
def bar
p 'Bar'
end
end
end

module ToBePatched
module A
alias_method :eek:ld_some_method, :some_method
def some_method
p 'override some'
old_some_method
end

alias_method :eek:ld_another_method, :another_method
def another_method
p 'override another'
old_another_method
end
#override other methods
end
end

#my_main.rb

module MyModule
module Main
def self.included(base)
base.extend ClassMethods
end

module ClassMethods
def i_want_that_great_feature
class_eval do
include MyModule::MyNestedModule
end
end
end
end
end


#test program

ToBePatched::Foo.class_eval do
include MyModule::Main
end

class Bs < ToBePatched::Foo
i_want_that_great_feature
end

bs = Bs.new
bs.bar
bs.some_method
bs.another_method
 
7

7stud --

MaggotChild said:
#test program

ToBePatched::Foo.class_eval do
include MyModule::Main
end

class Bs < ToBePatched::Foo
i_want_that_great_feature
end

bs = Bs.new
bs.bar
bs.some_method
bs.another_method

$ ruby r1test.rb
r1test.rb:1: uninitialized constant ToBePatched (NameError)
 
M

MaggotChild

$ ruby r1test.rb
r1test.rb:1: uninitialized constant ToBePatched (NameError)

Not sure what's in r1test.rb, my above code does indeed run.
Regardless, that example is just a simplified version of the monkey
patching paradigm that's causing problems.

What I'm interested in is why would one overridden method in a module
run while another would fall back to the original as if it were never
overridden?
 
D

David A. Black

Hi --

I'm monkey patching 2 methods of an existing module: some_method() and
another_method()

Calling some_method() on an instance of class that includes the
original module works fine (calls the monkey patched version), but
when I call another_method() the original (not the monkey patched)
method is called.

There is a lot of code, and I've tried to recreate the series of
includes with the below example, yet the example works!

Given this, I hope that someone could still provide me with some
insight as to why this would happen

I'm never quite sure what people mean by "monkey patching" -- it
always sounds like deliberately doing something badly, so that having
it not work shouldn't be a surprise :) -- but I think I'd have to see
code that exhibits the problem you're describing in order to analyze
it. Can you look at the difference between your real code and your
example, and try to spot what's not working?


David
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]

I'd seriously reconsider that design... looks very obfuscated to me.
Maybe restructuring your code and untangling that series of
includes will solve your problem or at least expose it.

I've made the experience that most of the time there is a nicer way
than class-evaling stuff and including modules that automatically
include other modules (although probably not always).

It always helps me to sketch my current code out on a board or
a large sheet of paper and then untangle it.
Most of the time there is a really rather good OO solution that
doesn't need any "big magic" behind the scenes.

As David says, it's really rather difficult to give you any other advice
unless
you give us some of your real code.

Greetz!
 
M

MaggotChild

Hi --






I'm never quite sure what people mean by "monkey patching"
-- it always sounds like deliberately doing something badly, so that having
it not work shouldn't be a surprise :)

It sure sounds like you understand what I mean, and I agree, yet the
problematic modules (mine and the one I'm attempting to override) are
filled with this sort of behavior and a full rewrite is not feasible
at this time.

It's unfortunate that the Ruby community has adopted such an abhorrent
practice to the extent it has.
Furthermore, what sort of examples are we setting for the children who
take up Ruby as their first language.

I hope that the The Well-Grounded Rubyist isn't advocating this sort
of OO flummory :^)
Can you look at the difference between your real code and your
example, and try to spot what's not working?

I'd like to think that it has something to do with the way the modules
are required. In the real code there are far more `requires` and even
a `load`.

I go back to my generalization of this problem: How can one module
revert back to its original implementation on one method and not the
other, when both the original and overridden methods are contained in
1 file respectively?

Thanks
 
M

MaggotChild

[Note:  parts of this message were removed to make it a legal post.]

I'd seriously reconsider that design... looks very obfuscated to me.
Maybe restructuring your code and untangling that series of
includes will solve your problem or at least expose it.

I've made the experience that most of the time there is a nicer way
than class-evaling stuff and including modules that automatically
include other modules (although probably not always).

Yes I agree, it's horrible. Unfortunately it's part of a much larger
code base that I can't rewrite overnight.
 
M

Marc Heiler

I'm never quite sure what people mean by "monkey patching" -- it
always sounds like deliberately doing something badly, so that
having it not work shouldn't be a surprise :)

I am glad Dave is hitting on that so I don't have to!
I got so downvoted on reddit when I tried to replace the term
"monkey patching" with "god patching" - guess I couldn't quite
convince people that "god patching" would be a more appropriate
name ... ;)

But hey - I am just glad that I don't seem to be the only one with
a slight dislike for the term "monkey patching". Poor monkeys, too!
 
F

Fabian Streitel

why is there two threads on this topic?
If you look in the other thread, there's a bunch of
code missing. If you add that, it works.

Greetz!
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]

maybe you could try rdebug and see in what order the important
methods are called. Just insert a breakpoint into all of them.
Maybe the order of calls got confused somewhere?

Greetz!

But hey - I am just glad that I don't seem to be the only one with
a slight dislike for the term "monkey patching". Poor monkeys, too!

Same goes for duck typing... those ducks didn't hurt anyone! *qwack*
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

I am glad Dave is hitting on that so I don't have to!
I got so downvoted on reddit when I tried to replace the term
"monkey patching" with "god patching" - guess I couldn't quite
convince people that "god patching" would be a more appropriate
name ... ;)

But hey - I am just glad that I don't seem to be the only one with
a slight dislike for the term "monkey patching". Poor monkeys, too!
Monkey patching is supposed to be a euphemism for guerrilla patching, now
the euphemism needs a euphemism, lol.
 
D

David A. Black

Hi --

Monkey patching is supposed to be a euphemism for guerrilla patching, now
the euphemism needs a euphemism, lol.

I'm boring, so I like saying "overriding methods", "reopening
classes", "programming", and things like that :)


David
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]
"programming", and things like that :)

That word is way over-used. I think we should call it puppy-coding
or maybe llama-cracking...
 
M

MaggotChild

I think I'd have to see
code that exhibits the problem you're describing in order to analyze

This is suited for the Rails group, but the problem can be seen in its
simplest form here:

#config/initializers/ar_attributes.rb

module ActiveRecord
module AttributeMethods

alias_method :ar_read_attribute, :read_attribute
def read_attribute(attr_name)
p "read_override"
ar_read_attribute(attr_name)
end

alias_method :ar_write_attribute, :write_attribute
def write_attribute(attr_name, value)
raise 'You made it!'
end
end
end

In the Rails console:
"read_override"
=> "Joe""read_override"
=> "Bilal"
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top