Just thought I'd drop in for a quick script release. Very, very simple this time: I get tired of having to alias stuff, so I set up a faster and easier way to do it. Usage and example are both in the script header.
No demo, no screenshots - because either would be entirely pointless for this specific case. It's a scripter's tool, and by itself will do absolutely nothing to the game.
Adds a Tack module with two methods: hook_after, and hook_before. Both methods require two symbols and a code block. The symbols are the class name, preceded by a ":" (a colon, without the quotes), and a function name, preceded by ":". A code block can be wrapped in between "do" and "end".
Usage example (changed - please review if updating):
Code:
Tack.hook_before :GameTimer, :start do |instance, args|
args[0][0] += 5 #sorry about the double array here. nothing I can do about it that retains mutability.
end
Tack.hook_after :GameTimer, :start do |instance, args|
instance.stop
end
hook_after will execute your code block after the target function is run; hook_before will execute your code block before the target function is triggered.
The new version should work with any of the standard RPG Maker products.
THE SCRIPT 2.1 (aka absolute sorcery edition)
Code:
# avarisc's Tack (a.k.a. quick-alias) | A simple mini-script that provides an
# v2.1 - 3/23/15 - Public Domain | easier and cleaner alternative to alias
################################################################################
# Usage Examples: [hook_before runs your block before, hook_after runs after]
# Tack.hook_before :Game_Timer, :start do |instance, args|
# args[0][0] += 5
# end
# Tack.hook_after :Game_Timer, :start do |instance, args|
# instance.stop
# end
################################################################################
module Tack
begin @@b, @@i = Hash.new, Array.new end
def self.hook_before(c, m, &b) tack(true, c, m, &b) end
def self.hook_after(c, m, &b) tack(false, c, m, &b) end
def self.tack(before, c_symbol, m_symbol, &block)
caller_id = caller[1].gsub(/[^0-9a-z]/i, '').hash
@@i.include?(caller_id) ? return : @@i << caller_id
_class = Object.const_get(c_symbol)
_class.send :define_method, :__tack_y__ do |*args|
instance_eval do block.call(self, args) end
end
k = ((before ? 'b_' : 'a_') + (m_s=m_symbol.to_s)).hash
@@b[k] = Array.new if !@@b.has_key? k
@@b[k] << _class.instance_method(:__tack_y__)
_class.send :remove_method, :__tack_y__
f = ('__tack_stub_' + m_s + '__').to_sym
if _class.method_defined?(f)
_class.send :alias_method, m_symbol, f
end
_class.send :alias_method, f, m_symbol
_class.send :define_method, m_symbol do |*args|
if @@b.has_key?(k=('b_' + m_s).hash)
@@b[k].each {|m|m.bind(self).call args}
end
self.send f, *args
if @@b.has_key?(k=('a_' + m_s).hash)
@@b[k].each {|m|m.bind(self).call args}
end
end
end
end
But how does it work?
It takes the code block you pass, creates a temporary class method in the target class to house the block. It then unbinds the method from the class and stores it in a specially tracked array in the Tack module. The temporary method is then deleted. If this is the first hook for the targeted method, then the Tack module aliases it to add the wrapper code. The wrapper code simply checks the specially tracked array for unbound functions that should run before or after a targeted function, and binds and executes them, along with calling the wrapped method.
TL;DR - you were better off not asking.