module Stenotype::Emitter

An extension for a plain Ruby class in order to track invocation of instance methods.

Constants

ClassMethodsExtension

Class methods for target to be extended by

InstanceMethodsExtension

Instance methods to be included into target class ancestors chain

Public Class Methods

build_class_methods(class_mod) click to toggle source

Adds class method [#emit_klass_event_before] to every class

inherited from [Object]
# File lib/stenotype/emitter.rb, line 114
    def self.build_class_methods(class_mod)
      class_mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
        def emit_event_before(*methods)
          proxy = const_get(:InstanceProxy)

          methods.each do |method|
            proxy.module_eval do
              define_method(method) do |*args, **rest_args, &block|
                Stenotype::Event.emit!(
                  # @todo How do we name such events?
                  "instance_method",
                  {
                    type: "instance_method",
                    class: self.class.name,
                    method: __method__,
                  },
                  eval_context: { klass: self },
                )
                super(*args, **rest_args, &block)
              end
            end
          end

          send(:prepend, proxy)
        end

        def emit_klass_event_before(*class_methods)
          proxy = const_get(:ClassProxy)

          class_methods.each do |method|
            proxy.module_eval do
              define_method(method) do |*args, **rest_args, &block|
                Stenotype::Event.emit!(
                  # @todo How do we name such events?
                  "class_method",
                  {
                    type: "class_method",
                    class: self.name,
                    method: __method__,
                  },
                  eval_context: { klass: self },
                )
                super(*args, **rest_args, &block)
              end
            end

            singleton_class.send(:prepend, proxy)
          end
        end
      RUBY
    end
build_instance_methods(instance_mod) click to toggle source

Adds an instance method: [#emit_event] to a target class

where {Stenotype::Emitter} in included in
# File lib/stenotype/emitter.rb, line 93
    def self.build_instance_methods(instance_mod)
      instance_mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
        def emit_event(event_name, attributes = {}, method: caller_locations.first.label, eval_context: nil)
          Stenotype::Event.emit!(
            event_name,
            {
              type: "instance_method",
              class: self.class.name,
              method: method.to_sym,
              **attributes,
            },
            eval_context: (eval_context || { klass: self })
          )
        end
      RUBY
    end
included(klass) click to toggle source

@!visibility private

Calls superclass method
# File lib/stenotype/emitter.rb, line 19
def self.included(klass)
  instance_mod = InstanceMethodsExtension.new
  class_mod = ClassMethodsExtension.new

  build_instance_methods(instance_mod)
  build_class_methods(class_mod)

  klass.const_set(:InstanceProxy, Module.new)
  klass.const_set(:ClassProxy, Module.new)

  klass.public_send(:include, instance_mod)
  klass.extend(class_mod)

  super
end