Edit: Forgot to include [Ace] in the headline
I'm trying to get a simple module working that will register instances of classes that include the module.
I'm doing this because I hate overwriting DataManager#load_database for every script that does stuff in Marshal loaded classes.
This was (in essence), my first attempt:
module Register @@resources = [] def include(value) @@resources << value endendmodule Registrar def load_because_marshal_skips_initialize msgbox("beep beep") end alias :registration_initialize :initialize def initialize(*args = nil) registration_initialize(args) Register.include(self) endendclass ::RPG::Actor include Registrarendmodule ::DataManager extend Register class << self alias :register_load_database :load_database def load_database register_load_database return unless !(@@resources.nil? || @@resources.empty?) @@resources.each { |x| x.load_because_marshal_skips_initialize } @@resources.clear end endendIt obviously fails because initialize doesn't even get called - so Registrar#initialize doesn't do jack diddly, meaning that the instance is never registered on the DataManager.
So, attempt #2:
I learned about Module#included
module Registrar def included(base) Register.include(base) endendWell isn't that nifty, now I have a single entry...and it is the class, rather than an instance of RPG::Actor. Not what I was hoping for, but it makes complete sense.
So onto attempt #3:
module Registrar def self.included(base) if base.method_defined?:)new) base.define_method:)register_new, self.register_new) alias_method:)new, :register_new) end end def self.register_new(*args) result = new(args) Register.include(result) return result endendI'm not comfortable with extending #new, so I would like to avoid it; However, not even this approach worked
My final attempt is to basically just add an extension to each Marshal loaded class that can be explicitly invoked by the DataManager.
Not a good strategy, but I've exhausted myself for today and was hoping that you fine folk could offer a smarter alternative.
Any suggestions to clean this up and get it working would be seriously appreciated.
Instance registration - Object pools with marshal loaded data?
● ARCHIVED · READ-ONLY
-
-
I ended up achieving the desired result, but with an entirely different solution.
#------------------------------------------------------------------------------# Note: This is optional; strictly for simplicity.#------------------------------------------------------------------------------class Object def try_method(method) condition = self.respond_to?(method) self.send(method) if condition return condition end end # Object#------------------------------------------------------------------------------# This contains the secret sauce.#------------------------------------------------------------------------------module DataManager # This defines the symbol for the method to invoke Load_Method = :load_resources # You can even set it to :initialize class << self alias :registrar_load_data :load_data def load_data(path) # Grab the return result first. result = registrar_load_data(path) # Most results of load_data return an array. if result.is_a?:):Array) # Some items are nil. Remember to compact. result.compact.each { |x| x.try_method(Load_Method) } else # RPG::System doesn't return an array. result.try_method(Load_Method) end return result # Don't forget to return the original result. end end end # DataManager#------------------------------------------------------------------------------# This override is optional, but proves it works.#------------------------------------------------------------------------------class ::RPG::Actor def load_resources msgbox "victory" if @id == 1 end end # ::RPG::ActorPretty much all I'm doing is just executing a name method if it exists on objects that are loaded through DataManager#load_data
Some objects like RPG::Actor don't call initialize when loaded, so you can use #load_data to simply intercept all objects loaded this way.
Hacky, but better than my previous attempts.
Unless someone else is able to answer my previous question, I'm going to be marking this one as the answer. -
So basically this will automatically call any methods that need to be run when an instance is created, regardless whether you marshal load them or you instantiate them, etc.
-
This particular script will only run on the objects that were marshal loaded.
In DataManager, from lines 36 - 69, you can see all of the default global data variables being set - which is accomplished by calling #load_data(path).
In fact, the DataManager#load_database method that is usually overridden, is just a method that determines which paths to provide when invoking #load_data.
So, rather than explicitly looping through each Marshal loaded class instance and attempting to invoke the method, this script will implicitly invoke the target method because #load_data returns all instances of Marshal loaded data.
It would probably be even better to override something in Marshal, but I don't yet know enough about that object.