What does 'Monkey Patching' exactly Mean in Ruby?

后端 未结 8 1968
半阙折子戏
半阙折子戏 2020-11-27 03:29

According to Wikipedia, a monkey patch is:

a way to extend or modify the runtime code of dynamic languages [...] without altering the original sou

相关标签:
8条回答
  • 2020-11-27 03:32

    The short answer is that there is no "exact" meaning, because it's a novel term, and different folks use it differently. That much at least can be discerned from the Wikipedia article. There are some who insist that it only applies to "runtime" code (built-in classes, I suppose) while some would use it to refer to the run-time modification of any class.

    Personally, I prefer the more inclusive definition. After all, if we were to use the term for modification of built-in classes only, how would we refer to the run-time modification of all the other classes? The important thing to me is that there's a difference between the source code and the actual running class.

    In Ruby, the term monkey patch was misunderstood to mean any dynamic modification to a class and is often used as a synonym for dynamically modifying any class at runtime.

    The above statement asserts that the Ruby usage is incorrect - but terms evolve, and that's not always a bad thing.

    0 讨论(0)
  • 2020-11-27 03:33

    This is monkey patching:

    class Float
      def self.times(&block)
        self.to_i.times { |i| yield(i) }
        remainder = self - self.to_i
        yield(remainder) if remainder > 0.0
      end
    end
    

    Now I imagine this might be useful sometimes, but imagine if you saw routine.

    def my_method(my_special_number)
      sum = 0
      my_special_number.times { |num| sum << some_val ** num }
      sum
    end
    

    And it breaks only occasionally when it gets called. To those paying attention you already know why, but imagine that you didn't know about the float type having a .times class-method and you automatically assumed that my_special_number is an integer. Every time the parameter is a whole number, integer or float, it would work fine (whole ints are passed back except when there is a floating-point remainder). But pass a number with anything in the decimal area in and it'll break for sure!

    Just imagine how often this might happen with your gems, Rails plugins, and even by your own co-workers in your projects. If there's one or two little methods in there like this and it could take some time to find and correct.


    If you wonder why it breaks, note that sum is an integer and a floating-point remainder could be passed back; in addition, the exponential sign only works when types are the same. So you might think it's fixed, because you converted bother numbers to floats ... only to find that the sum can't take the floating-point result.

    0 讨论(0)
  • 2020-11-27 03:37

    Usually it is meant about ad-hoc changes, using Ruby open classes, frequently with low quality code.

    Good follow-up on the subject:

    http://www.infoq.com/articles/ruby-open-classes-monkeypatching

    0 讨论(0)
  • 2020-11-27 03:45

    The best explanation I heard for Monkey patching/Duck-punching is by Patrick Ewing in RailsConf 2007

    ...if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.

    0 讨论(0)
  • 2020-11-27 03:47

    In Python monkeypatching is referred to a lot as a sign of embarrassment: "I had to monkeypatch this class because..." (I encountered it first when dealing with Zope, which the article mentions). It's used to say that it was necessary to take hold of an upstream class and fix it at runtime instead of lobbying to have the unwanted behaviors fixed in the actual class or fixing them in a subclass. In my experience Ruby people don't talk about monkeypatching that much, because it's not considered especially bad or even noteworthy (hence "duck punching"). Obviously you have to be careful about changing the return values of a method that will be used in other dependencies, but adding methods to a class the way that active_support and facets do is perfectly safe.

    Update 10 years later: I would amend the last sentence to say "is relatively safe". Extending a core library class with new methods can lead to problems if somebody else gets the same idea and adds the same method with a different implementation or method signature, or if people confuse extended methods for core language functionality. Both cases often happen in Ruby (especially regarding active_support methods).

    0 讨论(0)
  • 2020-11-27 03:48

    Monkey patching is when you replace methods of a class at runtime (not adding new methods as others have described).

    In addition to being a very un-obvious and difficult to debug way to change code, it doesn't scale; as more and more modules start monkey patching methods, the likelihood of the changes stomping each other grow.

    0 讨论(0)
提交回复
热议问题