Can monkey patching be discovered when you require a library?

Is it possible to know whether a method, class, or instance was overridden
by another when you require 'said_gem' in (i.e. monkeypatched)? I'm
thinking something that would let gem users know if a gem is going to
override core methods or attrs?

I was thinking that alot of the time, we try out a gem hoping it will suit
our needs, and ideally, you would probably want to look at the source code
of the gem before using it in production. However, if you were able to
run some test or metric on a gem to find out what (if any) methods, classes,
instances, attributes, etc., were being overwritten, and where they were
being overwritten at, it might give you a better idea of potential problems
down the road.

-Nick Klauer

Not really.

One quick and dirty way to do this is to freeze all your classes before including a gem. Obviously you would never deploy code that does this, but you most certainly can try things out in a local IRB session.

In fact, I tinkered around with this a while ago and came up with the never released "monkey_proof" library.

  require 'monkey_proof'

  monkey_proof Object
  monkey_proof Array
  monkey_proof Hash
  monkey_proof Fixnum

  require 'active_support/all'

  #=> RuntimeError: can't modify frozen class

Very heavy handed, but it will tell you if someone is monkeying about with your classes.

Blessings,
TwP

···

On Sep 12, 2011, at 8:52 PM, Nick Klauer wrote:

Is it possible to know whether a method, class, or instance was overridden
by another when you require 'said_gem' in (i.e. monkeypatched)? I'm
thinking something that would let gem users know if a gem is going to
override core methods or attrs?

I was thinking that alot of the time, we try out a gem hoping it will suit
our needs, and ideally, you would probably want to look at the source code
of the gem before using it in production. However, if you were able to
run some test or metric on a gem to find out what (if any) methods, classes,
instances, attributes, etc., were being overwritten, and where they were
being overwritten at, it might give you a better idea of potential problems
down the road.

Turn on warnings.

  $ cat t.rb
  class String
    def to_s; end
  end

  $ ruby -w t.rb
  t.rb:2: warning: method redefined; discarding old to_s

···

On Sep 12, 10:52 pm, Nick Klauer <kla...@gmail.com> wrote:

Is it possible to know whether a method, class, or instance was overridden
by another when you require 'said_gem' in (i.e. monkeypatched)? I'm
thinking something that would let gem users know if a gem is going to
override core methods or attrs?

The question is: _how_ would you find out if such were the case?

Can you look at the eigenclass where the method definition is located
and, from there, determine whether it's on the original class or if it's
on some other class's definition?

For example, I define a class named Foo:

class Foo
  def bar; do_something; end
end

and then I do some monkey patching to it elsewhere:

def Foo.bar; do_something_else; end

How would you determine that the new definition of bar is different from
the original? Or, _can_ you determine that it's fundamentally different
now?

···

On Tue, Sep 13, 2011 at 11:52:50AM +0900, Nick Klauer wrote:

Is it possible to know whether a method, class, or instance was overridden
by another when you require 'said_gem' in (i.e. monkeypatched)? I'm
thinking something that would let gem users know if a gem is going to
override core methods or attrs?

--
Darryl L. Pierce <mcpierce@gmail.com>
http://mcpierce.multiply.com/
"What do you care what people think, Mr. Feynman?"

That doesn't work.

class String
  alias old_to_s to_s
  def to_s; end
end

···

On Sep 16, 2011, at 11:39 , Intransition wrote:

On Sep 12, 10:52 pm, Nick Klauer <kla...@gmail.com> wrote:

Is it possible to know whether a method, class, or instance was overridden
by another when you require 'said_gem' in (i.e. monkeypatched)? I'm
thinking something that would let gem users know if a gem is going to
override core methods or attrs?

Turn on warnings.

$ cat t.rb
class String
   def to_s; end
end