Class RR::Injections::DoubleInjection
In: lib/rr/injections/double_injection.rb
Parent: Injection

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.

Methods

Included Modules

ClassInstanceMethodDefined

Constants

MethodArguments = Struct.new(:arguments, :block)
BoundObjects = {}

Attributes

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

Public Class methods

[Source]

     # File lib/rr/injections/double_injection.rb, line 95
 95:       def initialize(subject_class, method_name)
 96:         @subject_class = subject_class
 97:         @method_name = method_name.to_sym
 98:         @doubles = []
 99:         @dispatch_method_delegates_to_dispatch_original_method = nil
100:       end

Public Instance methods

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

[Source]

     # File lib/rr/injections/double_injection.rb, line 111
111:       def bind
112:         if subject_has_method_defined?(method_name)
113:           bind_method_with_alias
114:         else
115:           Injections::MethodMissingInjection.find_or_create(subject_class)
116:           Injections::SingletonMethodAddedInjection.find_or_create(subject_class)
117:           bind_method_that_self_destructs_and_delegates_to_method_missing
118:         end
119:         self
120:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 140
140:       def bind_method
141:         id = BoundObjects.size
142:         BoundObjects[id] = subject_class
143: 
144:         subject_class.class_eval("def \#{method_name}(*args, &block)\narguments = MethodArguments.new(args, block)\nobj = ::RR::Injections::DoubleInjection::BoundObjects[\#{id}]\nRR::Injections::DoubleInjection.dispatch_method(self, obj, :\#{method_name}, arguments.arguments, arguments.block)\nend\n", __FILE__, __LINE__ + 1)
145:         self
146:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 124
124:       def bind_method_that_self_destructs_and_delegates_to_method_missing
125:         id = BoundObjects.size
126:         BoundObjects[id] = subject_class
127: 
128:         subject_class.class_eval("def \#{method_name}(*args, &block)\n::RR::Injections::DoubleInjection::BoundObjects[\#{id}].class_eval do\nremove_method(:\#{method_name})\nend\nmethod_missing(:\#{method_name}, *args, &block)\nend\n", __FILE__, __LINE__ + 1)
129:         self
130:       end

[Source]

    # File lib/rr/injections/double_injection.rb, line 34
34:         def dispatch_method(subject, subject_class, method_name, arguments, block)
35:           subject_eigenclass = (class << subject; self; end)
36:           if (
37:             exists?(subject_class, method_name) &&
38:             (subject_class == subject_eigenclass) || !subject.is_a?(Class)
39:           )
40:             find(subject_class, method_name.to_sym).dispatch_method(subject, arguments, block)
41:           else
42:             new(subject_class, method_name.to_sym).dispatch_original_method(subject, arguments, block)
43:           end
44:         end

[Source]

     # File lib/rr/injections/double_injection.rb, line 179
179:       def dispatch_method(subject, args, block)
180:         if @dispatch_method_delegates_to_dispatch_original_method
181:           dispatch_original_method(subject, args, block)
182:         else
183:           dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
184:           dispatch.call
185:         end
186:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 201
201:       def dispatch_method_delegates_to_dispatch_original_method
202:         @dispatch_method_delegates_to_dispatch_original_method = true
203:         yield
204:       ensure
205:         @dispatch_method_delegates_to_dispatch_original_method = nil
206:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 188
188:       def dispatch_original_method(subject, args, block)
189:         dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
190:         dispatch.call_original_method
191:       end

[Source]

    # File lib/rr/injections/double_injection.rb, line 26
26:         def exists?(subject_class, method_name)
27:           !!find(subject_class, method_name)
28:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 30
30:         def exists_by_subject?(subject, method_name)
31:           exists?((class << subject; self; end), method_name)
32:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 18
18:         def find(subject_class, method_name)
19:           instances[subject_class] && instances[subject_class][method_name.to_sym]
20:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 22
22:         def find_by_subject(subject, method_name)
23:           find(class << subject; self; end, method_name)
24:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 8
 8:         def find_or_create(subject_class, method_name)
 9:           instances[subject_class][method_name.to_sym] ||= begin
10:             new(subject_class, method_name.to_sym).bind
11:           end
12:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 14
14:         def find_or_create_by_subject(subject, method_name)
15:           find_or_create(class << subject; self; end, method_name)
16:         end

[Source]

    # File lib/rr/injections/double_injection.rb, line 83
83:         def instances
84:           @instances ||= HashWithObjectIdKey.new do |hash, subject_class|
85:             hash.set_with_object_id(subject_class, {})
86:           end
87:         end

[Source]

     # File lib/rr/injections/double_injection.rb, line 197
197:       def original_method_alias_name
198:         "__rr__original_#{@method_name}"
199:       end

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

[Source]

     # File lib/rr/injections/double_injection.rb, line 104
104:       def register_double(double)
105:         @doubles << double
106:       end

[Source]

    # File lib/rr/injections/double_injection.rb, line 46
46:         def reset
47:           instances.each do |subject_class, method_double_map|
48:             SingletonMethodAddedInjection.find(subject_class) && SingletonMethodAddedInjection.find(subject_class).reset
49:             method_double_map.keys.each do |method_name|
50:               reset_double(subject_class, method_name)
51:             end
52:             Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances.has_key?(subject_class)
53:           end
54:         end

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

[Source]

     # File lib/rr/injections/double_injection.rb, line 167
167:       def reset
168:         if subject_has_original_method?
169:           subject_class.__send__(:remove_method, method_name)
170:           subject_class.__send__(:alias_method, method_name, original_method_alias_name)
171:           subject_class.__send__(:remove_method, original_method_alias_name)
172:         else
173:           if subject_has_method_defined?(method_name)
174:             subject_class.__send__(:remove_method, method_name)
175:           end
176:         end
177:       end

Resets the DoubleInjection for the passed in subject and method_name.

[Source]

    # File lib/rr/injections/double_injection.rb, line 77
77:         def reset_double(subject_class, method_name)
78:           double_injection = Injections::DoubleInjection.instances[subject_class].delete(method_name)
79:           double_injection.reset
80:           Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances[subject_class].empty?
81:         end

[Source]

     # File lib/rr/injections/double_injection.rb, line 193
193:       def subject_has_original_method_missing?
194:         class_instance_method_defined(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
195:       end

[Source]

    # File lib/rr/injections/double_injection.rb, line 56
56:         def verify(*subjects)
57:           subject_classes = subjects.empty? ?
58:             Injections::DoubleInjection.instances.keys :
59:             subjects.map {|subject| class << subject; self; end}
60:           subject_classes.each do |subject_class|
61:             instances.include?(subject_class) &&
62:               instances[subject_class].keys.each do |method_name|
63:                 verify_double(subject_class, method_name)
64:               end &&
65:               instances.delete(subject_class)
66:           end
67:         end

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

[Source]

     # File lib/rr/injections/double_injection.rb, line 157
157:       def verify
158:         @doubles.each do |double|
159:           double.verify
160:         end
161:       end

Verifies the DoubleInjection for the passed in subject and method_name.

[Source]

    # File lib/rr/injections/double_injection.rb, line 70
70:         def verify_double(subject_class, method_name)
71:           Injections::DoubleInjection.find(subject_class, method_name).verify
72:         ensure
73:           reset_double subject_class, method_name
74:         end

Protected Instance methods

[Source]

     # File lib/rr/injections/double_injection.rb, line 216
216:       def bind_method_with_alias
217:         subject_class.__send__(:alias_method, original_method_alias_name, method_name)
218:         bind_method
219:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 209
209:       def deferred_bind_method
210:         unless subject_has_method_defined?(original_method_alias_name)
211:           bind_method_with_alias
212:         end
213:         @performed_deferred_bind = true
214:       end

[Validate]