module JSchema::MethodCallLogger

Public Class Methods

enable(log_class) click to toggle source
# File lib/jschema/method_call_logger.rb, line 7
def enable(log_class)
  sub_classes = [log_class]
  sub_classes.each do |klass|
    # We want to observe only the given class and all its subclasses
    observe_class klass

    klass.constants.each do |class_sym|
      sub_class = klass.const_get(class_sym)

      # FIXME: misleading condintion
      if sub_class.is_a?(Module) &&
          sub_class.name.start_with?(log_class.name)

        sub_classes << sub_class
      end
    end
  end
end
log_method_call(klass, method, args) click to toggle source
# File lib/jschema/method_call_logger.rb, line 26
def log_method_call(klass, method, args)
  logger.info "#{klass.name}##{method}(#{args.join(', ')})"
end

Private Class Methods

logger() click to toggle source
# File lib/jschema/method_call_logger.rb, line 32
def logger
  @logger ||= Logger.new(STDOUT)
end
observe_class(observable) click to toggle source
# File lib/jschema/method_call_logger.rb, line 36
def observe_class(observable)
  # Override public instance methods
  observable.public_instance_methods(false).each do |method|
    observable.class_eval do

      # Redefine each public method so that each method call is logged
      # first and then it is forwarded to the origin method

      original_method = public_instance_method(method)

      define_method(method) do |*args, &block|
        MethodCallLogger.log_method_call self.class, method, args
        original_method.bind(self).call(*args, &block)
      end
    end
  end

  # Override public "class" methods
  observable.methods(false).each do |method|
    original_method = observable.method(method).unbind
    observable.define_singleton_method(method) do |*args, &block|

      # FIXME: The following line causes ruby (2.1.2 p95) to crash
      # MethodCallLogger.log_method_call observable, method, args
      # But it works when the method is inserted "inline"
      logger = Logger.new(STDOUT)
      logger.info "#{observable.name}.#{method}(#{args.join(', ')})"

      original_method.bind(self).call(*args, &block)
    end
  end
end