Sure, monkey patching is great and all. That period of disbelief, followed by increasing exasperation as the victim maintenance programmer discovers that an object is behaving differently than it’s source code says it should, is satisfying. But sooner or later he or she wises up and greps through the codebase, discovers where you re-opened the class in question, and the game is up.

The fact of the matter is that monkeys simply aren’t very stealthy. They are easy to find when you know what you are looking for. When you really want to catch a coder by surprise, a monkey doesn’t cut it. What you need is a Ninja:.

And so, today I’m unleashing the technique of Ninja-Patching, along with a reference implementation. Ninja-Patching is silent, untraceable, precise, unpredictable, and always deadly. And unlike monkey patching, which usually happens at startup, Ninja-Patching happens when you least expect it. Here’s an example use:

  require 'ninja'
  Ninja.hire(Enumerable) do def self.to_s "PWNED by Ninjas!!!" end

That’s all you have to do. A silent assassin has been hired, and will ruthlessly hunt down its target. In this case, the target is the first object found in ObjectSpace which is a kind of Enumerable. Which one? Hard to say. Ninjas are, like I said, unpredictable. Once the target is acquired, the Ninja will wait some random amount of time in order to throw off the trail and instill a false sense of security. Then, without warning, the Ninja will attack! The block given to Ninja.hire will be executed in the context of the target object. And then it’s all over but the crying.

Here’s the implementation:

CODE = <<'END_CODE'
class Ninja
  def self.hire(target_description, &instructions)
    self.new(target_description, instructions)
  end

  private

  # target_description can be either an object which responds to +#===+, or a
  # Proc which returns true or false.
  def initialize(target_description, instructions)
    @target_description = if target_description.kind_of?(Proc) then
                            target_description
                          else
                            lambda {|obj| target_description === obj}
                          end
    @instructions       = instructions
    @target             = acquire_target(@target_description)
    if @target.equal?(self)
      $stderr.puts "Never double-cross a Ninja!"
      exit
    elsif @target
      stalk(@target)
    else
      raise "No such object found!"
    end
  end

  def acquire_target(target_description)
    ObjectSpace.each_object do |object|
      if target_description.call(object)
        return object
      end
    end
    nil
  end

  def stalk(target)
    Thread.new do
      sleep(rand(60))
      attack!(target)
    end
  end

  def attack!(target)
    target.instance_eval(&@instructions)
  end
end
END_CODE

# Using eval conceals the Ninja in the stack trace
eval CODE

This code is released under the Ninja Public License (NPL), which releases me from all liability should ninja.rb turn on you and assasinate you in your Kernel#sleep(). Warning: ninja.rb has a known vulnerability to chosen_one.rb.

Published by Avdi Grimm

23 Comments

  1. I suppose this was meant as a joke, but I intend to use “Ninja-Patching” from now on instead of that other phrase, the one actually invented by Python programmers.”

    Reply
  2. “I suppose this was meant as a joke”

    LOOK AT THE DATE MAN!!!!!!!!!!

    Reply
  3. But i must agree somewhat 🙂

    I think whenever someone mentions monkey patching from now on, I will refer to ninja patching. Sounds a lot better.

    Reply
  4. I suppose this was meant as a joke, but I intend to use “Ninja-Patching” from now on instead of that other phrase, the one actually invented by Python programmers.”

    Reply
  5. “I suppose this was meant as a joke”

    LOOK AT THE DATE MAN!!!!!!!!!!

    Reply
  6. But i must agree somewhat 🙂

    I think whenever someone mentions monkey patching from now on, I will refer to ninja patching. Sounds a lot better.

    Reply
  7. […] April Fool’s joke with one that’s funny, clever, practical and silent but deadly: Ninja Patching. Well done Avdi, I […]

    Reply
  8. Being a Python developer, I have no strong feelings either way on this post, but I like your writing style!

    Reply
  9. “I intend to use “Ninja-Patching” from now on instead of that other phrase”

    I personally favor “slapmethoding”, which is entry #3 in _why’s Complete List Of Substitute Names For The Maneuver We Now Know To Be Monkeypatching.

    http://hackety.org/2007/08/10/myCompleteListOfSubstitutePhrasesForTheActWeNowKnowToBeMonkeypatching.html

    Reply
  10. Being a Python developer, I have no strong feelings either way on this post, but I like your writing style!

    Reply
  11. class ChosenOne
    Thread.new do
    while(Module.constants.grep(/Ninja/).empty?)
    sleep(1)
    end
    Ninja.class_eval do
    private
    def attack!
    # Ahah! The ninja is helpless!
    end
    end
    end
    end

    My apologies, I’m still new to Ruby so I’m sure this could be nicer. I couldn’t figure out a decent way to determine if a class is defined (it must be staring me right in the face), and the thread was the only way I could get it to work regardless of the require ordering.

    Needless to say I enjoyed this post!

    One other thing: I lost my comment the first time I submitted because I was prompted about OpenID. I am not a fan of that behaviour :/

    Reply
  12. That is really cool!

    I had to laugh out loud while trying it out and understanding it!

    “Objects, silence! Beware of the Ninja!”

    Reply
  13. Paul: sorry about the lost comment. I’m increasingly not a fan of WordPress, period.

    Reply
  14. That is really cool!

    I had to laugh out loud while trying it out and understanding it!

    “Objects, silence! Beware of the Ninja!”

    Reply
  15. […] Preprocessor). Avdi Grimm even found the final solution to the whole Monkey-patching diatribe: Ninja-Patching, “When you really want to catch a coder by surprise, a monkey doesn’t cut it. What you need […]

    Reply
  16. […] Virtuous Code › Announcing Ninja-Patching! This is hilariously evil! Thanks, Reg. (tags: ruby ninja programming humor hacks) […]

    Reply
  17. Nice write up and blog , Thanks for sharing all those good info

    My Best regards
    Moris
    http://xtonlinegame.com

    Reply
  18. […] Ninja Patching Monkey patching is for weenies and pirates. Ninja Patching is the new hotness: http://avdi.org/devblog/2008/04/01/a…inja-patching/ Their code will never see it coming. — […]

    Reply
  19. A python, a monkey, and a ninja walk into a bar.. LOL

    Reply
  20. nice job, thanks for this useful article

    Reply
  21. Find the files you are looking for at http://your-download.org the most comprehensive source for free-to-try files downloads on the Web

    Reply
  22.  Ninjas everywhere 🙂 Thanks for this man

    Reply

Leave a Reply to gambling Cancel reply

Your email address will not be published. Required fields are marked *