Class: Datadog::Shim

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
MethodWrapping, Patcher
Defined in:
lib/ddtrace/augmentation/shim.rb

Overview

A “stand-in” that intercepts calls to another object. i.e. man-in-the-middle. This shim forwards all methods to object, except those overriden. Useful if you want to intercept inbound behavior to an object without modifying the object in question, especially useful if the overridding behavior shouldn’t be global.

Constant Summary collapse

METHODS =
Set[
  :override_method!,
  :shim,
  :shim?,
  :shim_target,
  :wrap_method!,
  :wrapped_methods
].freeze
EXCLUDED_METHODS =
Set[
  # For all objects
  :__binding__,
  :__id__,
  :__send__,
  :extend,
  :itself,
  :object_id,
  :respond_to?,
  :tap
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MethodWrapping

#wrapped_methods

Methods included from Patcher

included

Methods included from Patcher::CommonMethods

#do_once, #done?, #without_warnings

Constructor Details

#initialize(shim_target) {|_self| ... } ⇒ Shim

Pass this a block to override methods

Yields:

  • (_self)

Yield Parameters:

  • _self (Datadog::Shim)

    the object that the method was called on



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ddtrace/augmentation/shim.rb', line 46

def initialize(shim_target)
  @shim = self
  @shim_target = shim_target

  # Save a reference to the original :define_singleton_method
  # so methods can be defined on the shim after forwarding is applied.
  @definition_method = method(:define_singleton_method)

  # Wrap any methods
  yield(self) if block_given?

  # Forward methods
  forwarded_methods = (
    shim_target.public_methods.to_set \
    - METHODS \
    - EXCLUDED_METHODS \
    - wrapped_methods
  )
  forward_methods!(*forwarded_methods)
end

Instance Attribute Details

#shimObject (readonly)

Returns the value of attribute shim.



36
37
38
# File 'lib/ddtrace/augmentation/shim.rb', line 36

def shim
  @shim
end

#shim_targetObject (readonly)

Returns the value of attribute shim_target.



36
37
38
# File 'lib/ddtrace/augmentation/shim.rb', line 36

def shim_target
  @shim_target
end

Class Method Details

.shim?(object) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
41
42
43
# File 'lib/ddtrace/augmentation/shim.rb', line 38

def self.shim?(object)
  # Check whether it responds to #shim? because otherwise the
  # Shim forwards all method calls, including type checks to
  # the wrapped object, to mimimize its intrusion.
  object.respond_to?(:shim?)
end

Instance Method Details

#override_method!(method_name, &block) ⇒ Object



67
68
69
70
71
72
73
74
75
# File 'lib/ddtrace/augmentation/shim.rb', line 67

def override_method!(method_name, &block)
  return unless block_given?

  without_warnings do
    @definition_method.call(method_name, &block).tap do
      wrapped_methods.add(method_name)
    end
  end
end

#respond_to?(method_name) ⇒ Boolean

Returns:

  • (Boolean)


85
86
87
88
# File 'lib/ddtrace/augmentation/shim.rb', line 85

def respond_to?(method_name)
  return true if METHODS.include?(method_name)
  shim_target.respond_to?(method_name)
end

#shim?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/ddtrace/augmentation/shim.rb', line 81

def shim?
  true
end

#wrap_method!(method_name, &block) ⇒ Object



77
78
79
# File 'lib/ddtrace/augmentation/shim.rb', line 77

def wrap_method!(method_name, &block)
  super(shim_target.method(method_name), &block)
end