Class: Delfos::Patching::MethodOverride

Inherits:
Object
  • Object
show all
Includes:
ModuleDefiningMethods
Defined in:
lib/delfos/patching/method_override.rb

Constant Summary collapse

META_PROGRAMMING_REGEX =
/`define_method'\z|`attr_accessor'\z|`attr_reader'\z|`attr_writer'\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ModuleDefiningMethods

#module_definition

Constructor Details

#initialize(klass, name, private_methods, class_method) ⇒ MethodOverride

Returns a new instance of MethodOverride.



53
54
55
56
57
58
59
# File 'lib/delfos/patching/method_override.rb', line 53

def initialize(klass, name, private_methods, class_method)
  @klass           = klass
  @name            = name
  @private_methods = private_methods
  @class_method    = class_method
  original_method # ensure memoized method is the original not the overridden one
end

Instance Attribute Details

#class_methodObject (readonly)

Returns the value of attribute class_method.



51
52
53
# File 'lib/delfos/patching/method_override.rb', line 51

def class_method
  @class_method
end

#klassObject (readonly)

Returns the value of attribute klass.



51
52
53
# File 'lib/delfos/patching/method_override.rb', line 51

def klass
  @klass
end

#nameObject (readonly)

Returns the value of attribute name.



51
52
53
# File 'lib/delfos/patching/method_override.rb', line 51

def name
  @name
end

#private_methodsObject (readonly)

Returns the value of attribute private_methods.



51
52
53
# File 'lib/delfos/patching/method_override.rb', line 51

def private_methods
  @private_methods
end

Class Method Details

.setup(klass, name, private_methods, class_method:) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
# File 'lib/delfos/patching/method_override.rb', line 17

def setup(klass, name, private_methods, class_method:)
  return if skip_meta_programming_defined_method?

  MUTEX.synchronize do
    return if Thread.current[:__delfos_disable_patching]
  end

  instance = new(klass, name, private_methods, class_method)

  instance.ensure_method_recorded_once!
end

.skip_meta_programming_defined_method?Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/delfos/patching/method_override.rb', line 31

def skip_meta_programming_defined_method?
  stack = caller.dup

  i = stack.index do |l|
    l["delfos/patching/basic_object.rb"]
  end

  return unless i

  result = stack[i + 1][META_PROGRAMMING_REGEX]

  return unless result

  Delfos.logger.debug "Skipping setting up delfos logging of method defined by #{result} #{stack[i+1]}"
  true
end

Instance Method Details

#ensure_method_recorded_once!Object



61
62
63
# File 'lib/delfos/patching/method_override.rb', line 61

def ensure_method_recorded_once!
  record_method! { setup }
end

#original_methodObject



114
115
116
117
118
119
120
# File 'lib/delfos/patching/method_override.rb', line 114

def original_method
  @original_method ||= if class_method
                         klass.method(name)
                       else
                         klass.instance_method(name)
                       end
end

#setupObject

Redefine the method at runtime to enabling logging to Neo4j



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/delfos/patching/method_override.rb', line 67

def setup
  cm = class_method
  with_stack = method(:with_stack)
  method_name = name
  om = original_method

  mod = module_definition(klass, name, class_method) do
    define_method(method_name) do |*args, **kw_args, &block|
      stack = caller.dup
      caller_binding = binding.dup
      parameters = Delfos::MethodLogging::MethodParameters.new(args, kw_args, block)

      call_site = Delfos::MethodLogging::CodeLocation.from_call_site(stack, caller_binding)

      if call_site
        Delfos::MethodLogging.log(call_site, self, om, cm, parameters)
      end

      with_stack.call(call_site) do
        if !kw_args.empty?
          super(*args, **kw_args, &block)
        else
          super(*args, &block)
        end
      end
    end
  end
  return unless mod

  if class_method
    klass.prepend mod
  else
    klass.instance_eval { prepend mod }
  end
end

#with_stack(call_site) ⇒ Object



103
104
105
106
107
108
109
110
111
112
# File 'lib/delfos/patching/method_override.rb', line 103

def with_stack(call_site)
  return yield unless call_site

  begin
    CallStack.push(call_site)
    yield
  ensure
    CallStack.pop
  end
end