require 'vedeu/configuration/configuration' require 'vedeu/output/esc' require 'vedeu/support/log' module Vedeu # :nocov: # This class currently provides the means to trace each method call which # occurs inside Vedeu. This is very useful (to me!) for debugging. Running # this will make your application less responsive, and the tests # excruciatingly slow to run. # class Trace # @todo # Replace this class with this: # # def self.trace # trace = TracePoint.new(:call) do |tp| # if tp.defined_class.to_s.match(/Troo/) # Vedeu.log(type: :debug, # message: [tp.defined_class.to_s, # tp.method_id.to_s].join(' ')) # end # end # trace.enable # end # @param options [Hash] # @option option event [Symbol] # @option option trace [Boolean] # @return [void] def self.call(options = {}) new(options).trace end # Returns a new instance of Vedeu::Trace # # @param options [Hash] # @return [Trace] def initialize(options = {}) @options = options end # Performs the trace operation. Building strings which include: # - (class_count) a count of classes registered with Vedeu, # - (classname) the class name being traced, # - (id) the method name being traced, # - (vars) any local variables belonging to the method. # # @todo Deprecate, and use TracePoint instead. # # @return [NilClass|String] def trace set_trace_func proc { |event, _file, _line, id, binding, name| if event == watched && id != :log && classes.include?(name.to_s) vars = variables(binding) if vars.empty? log_this(format('%s %-25s #%-20s', count, name, id)) else log_this(format("%s %-25s #%-20s\n%s\n", count, name, id, vars)) end end } if trace? end private # Writes the message to the log file. # # @param message [String] # @return [String] def log_this(message) Vedeu::Log.logger.debug(message) message end # Provides inspection of the local variables set within the method being # traced. Makes the log file extremely noisy, but very useful for hunting # down bugs. # # @param binding [Class] # @return [String] def variables(binding) binding.eval('local_variables').each do |var| variable = Vedeu::Esc.green { var.to_s } value = binding.local_variable_get(var) klass = Vedeu::Esc.magenta { value.class.to_s } output = (value.is_a?(Proc)) ? '# :yellow, 'Fixnum' => :cyan, 'Hash' => :blue, 'NilClass' => :red, 'String' => :green, 'Symbol' => :magenta, }.fetch(klass, :white) { |colour| Vedeu::Esc.send(colour) { output } } end # Returns the number of Vedeu classes/modules. (Useful for debugging.) # # @return [String] def count @count ||= "(#{classes.size}/#{vedeu_classes.size})" end # Returns the classes to be traced, without exceptions or ignored classes. # # @return [Set] def classes @classes ||= vedeu_classes - vedeu_exceptions - ignored_classes end # Returns all the classes defined within Vedeu. # # @return [Set] def vedeu_classes @vedeu_classes ||= Vedeu.constants.collect do |c| Vedeu.const_get(c).to_s end.to_set end # Returns all the exceptions defined within Vedeu. # # @todo Vedeu should produce this set. # # @return [Set] def vedeu_exceptions Vedeu::Exceptions.to_set end # Returns a set of classes to ignore during tracing. # # @todo Make this configurable at runtime. # # @return [Set] def ignored_classes Set.new [ 'Vedeu::Coercions', 'Vedeu::Colour', 'Vedeu::Common', 'Vedeu::Configuration', 'Vedeu::Esc', 'Vedeu::Event', 'Vedeu::Geometry', 'Vedeu::Log', 'Vedeu::Position', 'Vedeu::Presentation', 'Vedeu::Repository', 'Vedeu::Stream', 'Vedeu::Style', 'Vedeu::Terminal', 'Vedeu::Trace', 'Vedeu::Translator', ] end end # Trace # :nocov: end # Vedeu