#==============================================================================| # ** Script Info | #------------------------------------------------------------------------------| # * Script Name | # DoubleX RMVXA Object Trace | #------------------------------------------------------------------------------| # * Functions | # Traces all objects meeting some conditions linked to the queried object | # Designed as a bug diagnosis tool used by scripters with debug experience | #------------------------------------------------------------------------------| # * Example | # obj.inspect | # - [url]http://pastebin.com/kb1q1Dru[/url] | # obj.trace_obj(Proc); obj.obj_trace[Proc].inspect | # - [url]http://pastebin.com/PZ4KNbHv[/url] | #------------------------------------------------------------------------------| # * Terms Of Use | # You shall keep this script's Script Info part's contents intact | # You shalln't claim that this script is written by anyone other than | # DoubleX or his aliases | # None of the above applies to DoubleX or his aliases | #------------------------------------------------------------------------------| # * Prerequisites | # Abilities: | # 1. Basic knowledge of inspecting objects in Ruby | # 2. Some RGSS3 scripting proficiency to fully utilize this script | #------------------------------------------------------------------------------| # * Instructions | # 1. Open the script editor and put this script into an open slot between | # Materials and Main, save to take effect. | #------------------------------------------------------------------------------| # * Links | # Script Usage 101: | # 1. forums.rpgmakerweb.com/index.php?/topic/32752-rmvxa-script-usage-101/ | # 2. rpgmakervxace.net/topic/27475-rmvxa-script-usage-101/ | # This script: | # 1. [url]http://pastebin.com/pySjrKvh[/url] | # Mentioned Patreon Supporters: | # [url]https://www.patreon.com/posts/71738797[/url] | #------------------------------------------------------------------------------| # * Author | # DoubleX | #------------------------------------------------------------------------------| # * Changelog | # v1.02a(GMT 0100 27-10-2015): | # 1. Lets uers set the conditions and labels for tracing objects | # v1.01b(GMT 1300 13-7-2015): | # 1. Fixed not tracing klass linked to klass linked to queried object bug | # 2. Fixed some Script Call Info and Implementation documentation typos | # 3. Added more info in Prerequisites and Script Call Info | # 4. Increased this script's compactness | # v1.01a(GMT 1300 6-7-2015): | # 1. Instance methods can be traced as well | # v1.00b(GMT 0800 1-7-2015): | # 1. Fixed object having Range and/or Structs not tracing klass properly bug| # v1.00a(GMT 1200 27-6-2015): | # 1. 1st version of this script finished | #==============================================================================| #==============================================================================| # ** Script Call Info | # A path in the object trace will stop if it'd be cyclic | #------------------------------------------------------------------------------| # * Object manipulations | # 1. trace_obj(cond, label) | # - Traces all objects meeting cond method linked to this object | # - Labels all traced objects using label method | # - cond and label are method symbols in Object Trace Condition Method | # and Object Trace Label Method respectively | # 2. obj_trace[cond] | # - Returns all traced objects meeting cond method linked to this object | # - cond is a method symbol in Object Trace Condition Method | # 3. (v1.01a+)trace_idef | # - Traces all instance methods linked to this object | # 4. (v1.01a+)idef_trace | # - Returns the trace of all instance methods linked to this object | #==============================================================================| ($doublex_rmvxa ||= {})[:Obj_Trace] = "v1.02a" module DoubleX_RMVXA # v1.02a+ module Obj_Trace #--------------------------------------------------------------------------| # Object Trace Condition Method | # - Setups cond used by trace_obj(cond, label) | #--------------------------------------------------------------------------| # cond must be the symbol of a method taking the currently traced object as # the only arguement # The below examples are added to help you setup your own cond methods # Checks if the currently traced object belongs to klass def self.cond_klass(obj) obj.is_a?(klass) end # cond_klass # Add your own cond methods here #--------------------------------------------------------------------------| # Object Trace Label Method | # - Setups label used by trace_obj(cond, label) | #--------------------------------------------------------------------------| # label must be the symbol of a method taking the currently traced object as # the only arguement # The below examples are added to help you setup your own label methods # Labels all traced objects using their class symbol def self.label_klass(obj) :"#{obj.class}" end # label_klass # Add your own label methods here end # Obj_Trace end # DoubleX_RMVXA #==============================================================================| # ** Script Implementations | # You need not edit this part as it's about how this script works | #------------------------------------------------------------------------------| # * Script Support Info: | # 1. Prerequisites | # - Solid understanding of inspecting objects in Ruby | # - Decent RGSS3 scripting proficiency to fully comprehend this script | # 2. Method documentation | # - The 1st part describes why this method's rewritten/aliased for | # rewritten/aliased methods or what the method does for new methods | # - The 2nd part describes what the arguments of the method are | # - The 3rd part informs which version rewritten, aliased or created this| # method | # - The 4th part informs whether the method's rewritten or new | # - The 5th part informs whether the method's a real or potential hotspot| # - The 6th part describes how this method works for new methods only, | # and describes the parts added, removed or rewritten for rewritten or | # aliased methods only | # Example: | # #--------------------------------------------------------------------------| | # # Why rewrite/alias/What this method does | | # #--------------------------------------------------------------------------| | # # *argv: What these variables are | # # &argb: What this block is | # def def_name(*argv, &argb) # Version X+; Rewrite/New; Hotspot | # # Added/Removed/Rewritten to do something/How this method works | # def_name_code | # # | # end # def_name | #------------------------------------------------------------------------------| class Object # Edit #----------------------------------------------------------------------------| # New public instance variables | #----------------------------------------------------------------------------| attr_reader :idef_trace # (v1.01a+)The trace of all linked instance methods attr_reader :obj_trace # The traces of all objects linked to this object # (v1.01a+)The list of symbols of all instance variables added by this script OBJ_TRACE_IVAR = [:"@idef_trace", :"@obj_trace"] def trace_idef # v1.01a+; New # Stop tracing the object if the object trace path would be cyclic @idef_trace ? return : @idef_trace = {} # trace_instance_idef return trace_array_idef if is_a?(Array) return trace_hash_idef if is_a?(Hash) return trace_range_idef if is_a?(Range) trace_struct_idef if is_a?(Struct) end # trace_idef def trace_instance_idef # v1.01a+; New (instance_variables - OBJ_TRACE_IVAR).each { |ivar| traverse_idef_tree(ivar, instance_variable_get(ivar)) } end # trace_instance_idef def trace_array_idef # v1.01a+; New each_with_index { |val, index| traverse_idef_tree(index, val) } end # trace_array_idef def trace_hash_idef # v1.01a+; New each { |key, val| traverse_idef_tree(key, val) } end # trace_hash_idef def trace_range_idef # v1.01a+; New index = -1 each { |val| traverse_idef_tree(index += 1, val) } end # trace_range_idef def trace_struct_idef # v1.01a+; New each_pair { |key, val| traverse_idef_tree(key, val) } end # trace_struct_idef #----------------------------------------------------------------------------| # Label and use all nonempty subtrees to form the original object trace tree| #----------------------------------------------------------------------------| # iks: The index/key/symbol of the object trace # val: The object to be traced def traverse_idef_tree(iks, val) # v1.01a+; New # Recursively traverse the object trace tree using Depth First Search unless (idefs = val.instance_methods).empty? @idef_trace[iks] = [idefs] end val.trace_idef return if (trace = val.idef_trace).empty? (@obj_trace[iks] ||= []) << trace # end # traverse_idef_tree # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_obj(cond, label) # New # Stop tracing the object if the object trace path would be cyclic (@obj_trace ||= {})[cond] ? return : @obj_trace[cond] = {} # trace_instance_obj(cond, label) return trace_array_obj(cond, label) if is_a?(Array) return trace_hash_obj(cond, label) if is_a?(Hash) return trace_range_obj(cond, label) if is_a?(Range) trace_struct_obj(cond, label) if is_a?(Struct) end # trace_obj # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_instance_obj(cond, label) # New (instance_variables - OBJ_TRACE_IVAR).each { |ivar| trace_all_obj(cond, label, ivar, instance_variable_get(ivar)) } end # trace_instance_obj # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_array_obj(cond, label) # New each_with_index { |val, index| trace_all_obj(cond, label, index, val) } end # trace_array_obj # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_hash_obj(cond, label) # New each { |key, val| trace_all_obj(cond, label, key, val) } end # trace_hash_obj # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_range_obj(cond, label) # v1.00b+; New # Embeds the klass traces of all ranges linking to this object index = -1 each { |val| trace_all_obj(cond, label, index += 1, val) } # end # trace_range_obj # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument def trace_struct_obj(cond, label) # v1.00b+; New each_pair { |key, val| trace_all_obj(cond, label, key, val) } end # trace_struct_obj #----------------------------------------------------------------------------| # Label and use all nonempty subtrees to form the original object trace tree| #----------------------------------------------------------------------------| # cond: The object trace condition method symbol taking the object as argument # label: The object trace label method symbol taking the object as argument # iks: The index/key/symbol of the object trace # val: The object to be traced def trace_all_obj(cond, label, iks, val) # v1.01a+; New # Recursively traverse the object trace tree using Depth First Search ot = DoubleX_RMVXA::Obj_Trace @obj_trace[cond][iks] = [ot.send(label, val)] if ot.send(cond, val) val.trace_obj(cond, label) return if (trace = val.obj_trace[cond]).empty? (@obj_trace[cond][iks] ||= []) << trace # end # trace_all_obj end # Object #------------------------------------------------------------------------------| #==============================================================================|