Class: RR::Injections::DoubleInjection

Inherits:
Injection
  • Object
show all
Includes:
ClassInstanceMethodDefined
Defined in:
lib/rr/injections/double_injection.rb

Overview

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.

Defined Under Namespace

Classes: MethodArguments

Constant Summary collapse

BoundObjects =
{}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ClassInstanceMethodDefined

#class_instance_method_defined

Methods inherited from Injection

#original_method, #subject_has_method_defined?, #subject_has_original_method?

Methods included from Space::Reader

#space

Constructor Details

#initialize(subject_class, method_name) ⇒ DoubleInjection

Returns a new instance of DoubleInjection.



95
96
97
98
99
100
# File 'lib/rr/injections/double_injection.rb', line 95

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

Instance Attribute Details

#doublesObject (readonly)

Returns the value of attribute doubles.



91
92
93
# File 'lib/rr/injections/double_injection.rb', line 91

def doubles
  @doubles
end

#method_nameObject (readonly)

Returns the value of attribute method_name.



91
92
93
# File 'lib/rr/injections/double_injection.rb', line 91

def method_name
  @method_name
end

#subject_classObject (readonly)

Returns the value of attribute subject_class.



91
92
93
# File 'lib/rr/injections/double_injection.rb', line 91

def subject_class
  @subject_class
end

Instance Method Details

#bindObject

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



111
112
113
114
115
116
117
118
119
120
# File 'lib/rr/injections/double_injection.rb', line 111

def bind
  if subject_has_method_defined?(method_name)
    bind_method_with_alias
  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_methodObject



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/rr/injections/double_injection.rb', line 139

def bind_method
  id = BoundObjects.size
  BoundObjects[id] = subject_class

  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.block)
  end
  RUBY
  self
end

#bind_method_that_self_destructs_and_delegates_to_method_missingObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rr/injections/double_injection.rb', line 124

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
  RUBY
  self
end

#dispatch_method(subject, args, block) ⇒ Object



177
178
179
180
181
182
183
184
# File 'lib/rr/injections/double_injection.rb', line 177

def dispatch_method(subject, args, block)
  if @dispatch_method_delegates_to_dispatch_original_method
    dispatch_original_method(subject, args, block)
  else
    dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
    dispatch.call
  end
end

#dispatch_method_delegates_to_dispatch_original_methodObject



199
200
201
202
203
204
# File 'lib/rr/injections/double_injection.rb', line 199

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, block) ⇒ Object



186
187
188
189
# File 'lib/rr/injections/double_injection.rb', line 186

def dispatch_original_method(subject, args, block)
  dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
  dispatch.call_original_method
end

#original_method_alias_nameObject



195
196
197
# File 'lib/rr/injections/double_injection.rb', line 195

def original_method_alias_name
  "__rr__original_#{@method_name}"
end

#register_double(double) ⇒ Object

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



104
105
106
# File 'lib/rr/injections/double_injection.rb', line 104

def register_double(double)
  @doubles << double
end

#resetObject

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



165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rr/injections/double_injection.rb', line 165

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?Boolean

Returns:

  • (Boolean)


191
192
193
# File 'lib/rr/injections/double_injection.rb', line 191

def subject_has_original_method_missing?
  class_instance_method_defined(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
end

#verifyObject

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



155
156
157
158
159
# File 'lib/rr/injections/double_injection.rb', line 155

def verify
  @doubles.each do |double|
    double.verify
  end
end