Simple Monkey Patching

Discussion in 'RGSS3 Scripts (RMVX Ace)' started by BakaCoder, Nov 18, 2013.

  1. BakaCoder

    BakaCoder Warper Member

    Messages:
    4
    Likes Received:
    3
    First Language:
    Chinese
    Simple Monkey Patching - v0.5​
    I am tired of aliasing​
     ​
     ​
    The Default Way of Monkey Patching:
    class Scene_Base alias monkeypatch_demo_sb_init initialize def initialize monkeypatch_demo_sb_init puts "A Scene Has Been Initiliazed!" endendWhy do we need all these aliases?

    The Simple Way:
    class Scene_Base monkeypatch :initialize do puts "A Scene Has Been Initialized!" endendThis is much better  B)

    Normal Usages:
    Code:
    class WhateverClass  monkeypatch :method_name do    #whatever you want to do ._.  endend
    Code:
    class Scene_Base  monkeypatch :initialize, :before do    puts "This is called before the original scripts"  endend
    Installation
    get the script here: http://pastebin.com/zgQe4HWH
    insert this before all scripts that uses this type of monkey-patching.​
     ​
    Possible Updates
    I really don't like the naming of the aliases._.. Maybe I will improve it later.​
    You still cannot call the original return value._., maybe you can later.​
     ​
    Known Bugs
    Currently None, but there is a high possibility that there are some  >_>
     ​
    Terms of Use
    You can repost this anywhere else without my permission.​
    You can modify the script as long as you keep my name on it.​
    Credit Me.  ​
     
    #1
    DerTraveler, IceDragon and estriole like this.
  2. IceDragon

    IceDragon Elder Cookie Dragon Veteran

    Messages:
    73
    Likes Received:
    60
    Location:
    Jamaica
    First Language:
    English
    Primarily Uses:
    N/A
    Nice idea, I like,

    However a few problems:

    1. Don't use global variables to store context sensitive functions.

    2. there is a chance (1 out 9998) that you will alias an already aliased functions (resulting in that rather scary SystemStackError) if you end up calling it

    3. You can shorten this code quite a bit

    4. My take:

    #===============================================================================# Monkeypatch v 0.5 by BakaCoder aka XXX#===============================================================================# monkeypatch <method_name (sym)> (&block)#===============================================================================proc do# Example class Scene_Base patch :initialize do puts "A Scene has been initialized!" end end# Endend module MonkeyPatch def monkeypatch(sym, pos=:after, &block) meth = instance_method(sym) # original method define_method(sym, &block) meth2 = instance_method(sym) # alias method if pos == :after define_method(sym) do |*a, &b| meth.bind(self).call(*a, & meth2.bind(self).call(*a, & end else define_method(sym) do |*a, &b| meth2.bind(self).call(*a, & meth.bind(self).call(*a, & end end end alias :patch :monkeypatch end class Module include MonkeyPatchendBy using UnboundMethodBy the way, I've added this edit to my kode-xchange, :) if you don't mind.
     
    Last edited by a moderator: Nov 19, 2013
    #2
  3. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,061
    Location:
    Toronto
    First Language:
    English
    How would I do something like this using your monkey patch method

    Code:
    alias :old_method :methoddef method  # do something here  res = old_method  # do something with the resend
    It definitely saves me from having to come up with an aliased method name though, especially since it can become arbitrarily lengthy.
     
    Last edited by a moderator: Nov 19, 2013
    #3
  4. IceDragon

    IceDragon Elder Cookie Dragon Veteran

    Messages:
    73
    Likes Received:
    60
    Location:
    Jamaica
    First Language:
    English
    Primarily Uses:
    N/A
    Could be done by adding a third option for patch-ing (aka chaining)

    Right, just make it the second arg.

    patch :method_name, :chain do |result_from_original_method| do_stuffendUpdate:
    Code:
    #===============================================================================#  Monkeypatch v 0.5 by BakaCoder aka XXX#  rewritten by IceDragon#===============================================================================# monkeypatch <method_name (sym)> (&block)#===============================================================================proc do# Example  class Scene_Base    patch :initialize do      puts "A Scene has been initialized!"    end    patch :initialize, :before do      puts "Scene #{self.class.name} initializing"    end  end  class Something    def sum      1 + 1    end    patch :sum, :chain do |oldsum|      oldsum + 1    end  end# Endendmodule MonkeyPatch  def monkeypatch(sym, pos=:after, &block)    meth = instance_method(sym) # original method    define_method(sym, &block)    meth2 = instance_method(sym) # alias method    case pos    when :after      define_method(sym) do |*a, &b|        meth.bind(self).call(*a, &        meth2.bind(self).call(*a, &      end    when :before      define_method(sym) do |*a, &b|        meth2.bind(self).call(*a, &        meth.bind(self).call(*a, &      end    when :chain      define_method(sym) do |*a, &b|        meth2.bind(self).call(meth.bind(self).call(*a, &, *a, &      end    end  end  alias :patch :monkeypatchendclass Module  include MonkeyPatchend
    I feel I've hijacked this thread... :x
     
    Last edited by a moderator: Nov 19, 2013
    #4
  5. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,061
    Location:
    Toronto
    First Language:
    English
    That makes it easier, especially being able to control when the old method should be called.

    Very often I do things like this as well

    Code:
    def test  @value += 20endalias :old_test :testdef test  @value = new_value  # :before  old_test  @value *= 2         # :after  return @valueend
    So I can use a :before and an :after to accomplish this.
     
    Last edited by a moderator: Nov 19, 2013
    #5
  6. BakaCoder

    BakaCoder Warper Member

    Messages:
    4
    Likes Received:
    3
    First Language:
    Chinese
    I feel I've hijacked this thread... :x
    Actually this is much more better. Having someone that is better than me in ruby is so much better :) . I really like this way to call the original return value. Anyway, thank you very much.
     
    #6

Share This Page