class RR::Injections::DoubleInjection

RR::DoubleInjection is the binding of an subject and a method. A double_injection has 0 to many Double objects. Each Double has Argument Expectations and Times called Expectations.

Constants

BoundObjects
MethodArguments

Attributes

doubles[R]
method_name[R]
subject_class[R]

Public Class Methods

new(subject_class, method_name) click to toggle source
# File lib/rr/injections/double_injection.rb, line 103
def initialize(subject_class, method_name)
  @subject_class = subject_class
  @method_name = method_name.to_sym
  @doubles = []
  @dispatch_method_delegates_to_dispatch_original_method = nil
end

Public Instance Methods

bind() click to toggle source

RR::DoubleInjection#bind injects a method that acts as a dispatcher that dispatches to the matching Double when the method is called.

# File lib/rr/injections/double_injection.rb, line 119
def bind
  if subject_has_method_defined?(method_name)
    if subject_has_original_method?
      bind_method
    else
      bind_method_with_alias
    end
  else
    Injections::MethodMissingInjection.find_or_create(subject_class)
    Injections::SingletonMethodAddedInjection.find_or_create(subject_class)
    bind_method_that_self_destructs_and_delegates_to_method_missing
  end
  self
end
bind_method() click to toggle source
# File lib/rr/injections/double_injection.rb, line 152
      def bind_method
        id = BoundObjects.size
        BoundObjects[id] = subject_class

        if KeywordArguments.fully_supported?
          subject_class.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
            def #{method_name}(*args, **kwargs, &block)
              arguments = MethodArguments.new(args, kwargs, block)
              obj = ::RR::Injections::DoubleInjection::BoundObjects[#{id}]
              ::RR::Injections::DoubleInjection.dispatch_method(
                self,
                obj,
                :#{method_name},
                arguments.arguments,
                arguments.keyword_arguments,
                arguments.block
              )
            end
          RUBY
        else
          subject_class.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
            def #{method_name}(*args, &block)
              arguments = MethodArguments.new(args, {}, block)
              obj = ::RR::Injections::DoubleInjection::BoundObjects[#{id}]
              ::RR::Injections::DoubleInjection.dispatch_method(
                self,
                obj,
                :#{method_name},
                arguments.arguments,
                arguments.keyword_arguments,
                arguments.block
              )
            end
            ruby2_keywords(:#{method_name}) if respond_to?(:ruby2_keywords, true)
          RUBY
        end
        self
      end
bind_method_that_self_destructs_and_delegates_to_method_missing() click to toggle source
# File lib/rr/injections/double_injection.rb, line 136
      def bind_method_that_self_destructs_and_delegates_to_method_missing
        id = BoundObjects.size
        BoundObjects[id] = subject_class

        subject_class.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
          def #{method_name}(*args, &block)
            ::RR::Injections::DoubleInjection::BoundObjects[#{id}].class_eval do
              remove_method(:#{method_name})
            end
            method_missing(:#{method_name}, *args, &block)
          end
          ruby2_keywords(:#{method_name}) if respond_to?(:ruby2_keywords, true)
        RUBY
        self
      end
dispatch_method(subject, args, kwargs, block) click to toggle source
# File lib/rr/injections/double_injection.rb, line 215
def dispatch_method(subject, args, kwargs, block)
  if @dispatch_method_delegates_to_dispatch_original_method
    dispatch_original_method(subject, args, kwargs, block)
  else
    dispatch = MethodDispatches::MethodDispatch.new(
      self,
      subject,
      args,
      kwargs,
      block
    )
    dispatch.call
  end
end
dispatch_method_delegates_to_dispatch_original_method() { || ... } click to toggle source
# File lib/rr/injections/double_injection.rb, line 249
def dispatch_method_delegates_to_dispatch_original_method
  @dispatch_method_delegates_to_dispatch_original_method = true
  yield
ensure
  @dispatch_method_delegates_to_dispatch_original_method = nil
end
dispatch_original_method(subject, args, kwargs, block) click to toggle source
# File lib/rr/injections/double_injection.rb, line 230
def dispatch_original_method(subject, args, kwargs, block)
  dispatch = MethodDispatches::MethodDispatch.new(
    self,
    subject,
    args,
    kwargs,
    block
  )
  dispatch.call_original_method
end
original_method_alias_name() click to toggle source
# File lib/rr/injections/double_injection.rb, line 245
def original_method_alias_name
  "__rr__original_#{@method_name}"
end
register_double(double) click to toggle source

RR::DoubleInjection#register_double adds the passed in Double into this DoubleInjection's list of Double objects.

# File lib/rr/injections/double_injection.rb, line 112
def register_double(double)
  @doubles << double
end
reset() click to toggle source

It binds the original method implementation on the subject if one exists.

# File lib/rr/injections/double_injection.rb, line 203
def reset
  if subject_has_original_method?
    subject_class.__send__(:remove_method, method_name)
    subject_class.__send__(:alias_method, method_name, original_method_alias_name)
    subject_class.__send__(:remove_method, original_method_alias_name)
  else
    if subject_has_method_defined?(method_name)
      subject_class.__send__(:remove_method, method_name)
    end
  end
end
subject_has_original_method_missing?() click to toggle source
# File lib/rr/injections/double_injection.rb, line 241
def subject_has_original_method_missing?
  class_instance_method_defined(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
end
verify() click to toggle source

RR::DoubleInjection#verify verifies each Double TimesCalledExpectation are met.

# File lib/rr/injections/double_injection.rb, line 193
def verify
  @doubles.each do |double|
    double.verify
  end
end

Protected Instance Methods

bind_method_with_alias() click to toggle source
# File lib/rr/injections/double_injection.rb, line 265
def bind_method_with_alias
  subject_class.__send__(:alias_method, original_method_alias_name, method_name)
  bind_method
end
deferred_bind_method() click to toggle source
# File lib/rr/injections/double_injection.rb, line 257
def deferred_bind_method
  if respond_to?(method_name) and
      not subject_has_method_defined?(original_method_alias_name)
    bind_method_with_alias
  end
  @performed_deferred_bind = true
end