| 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.
| MethodArguments | = | Struct.new(:arguments, :block) |
| doubles | [R] | |
| method_name | [R] | |
| subject_class | [R] |
# File lib/rr/injections/double_injection.rb, line 91
91: def initialize(subject_class, method_name)
92: @subject_class = subject_class
93: @method_name = method_name.to_sym
94: @doubles = []
95: @dispatch_method_delegates_to_dispatch_original_method = nil
96: end
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 107
107: def bind
108: if subject_has_method_defined?(method_name)
109: bind_method_with_alias
110: else
111: Injections::MethodMissingInjection.find_or_create(subject_class)
112: Injections::SingletonMethodAddedInjection.find_or_create(subject_class)
113: bind_method_that_self_destructs_and_delegates_to_method_missing
114: end
115: self
116: end
# File lib/rr/injections/double_injection.rb, line 132
132: def bind_method
133: subject_class_object_id = subject_class.object_id
134: subject_class.class_eval("def \#{method_name}(*args, &block)\narguments = MethodArguments.new(args, block)\nRR::Injections::DoubleInjection.dispatch_method(self, ObjectSpace._id2ref(\#{subject_class_object_id}), :\#{method_name}, arguments.arguments, arguments.block)\nend\n", __FILE__, __LINE__ + 1)
135: self
136: end
# File lib/rr/injections/double_injection.rb, line 118
118: def bind_method_that_self_destructs_and_delegates_to_method_missing
119: subject_class_object_id = subject_class.object_id
120: subject_class.class_eval("def \#{method_name}(*args, &block)\nObjectSpace._id2ref(\#{subject_class_object_id}).class_eval do\nremove_method(:\#{method_name})\nend\nmethod_missing(:\#{method_name}, *args, &block)\nend\n", __FILE__, __LINE__ + 1)
121: self
122: end
# 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 exists?(subject_class, method_name) && (subject_class == subject_eigenclass || subject_eigenclass.superclass != (class << Class; self; end))
37: find(subject_class, method_name.to_sym).dispatch_method(subject, arguments, block)
38: else
39: new(subject_class, method_name.to_sym).dispatch_original_method(subject, arguments, block)
40: end
41: end
# File lib/rr/injections/double_injection.rb, line 168
168: def dispatch_method(subject, args, block)
169: if @dispatch_method_delegates_to_dispatch_original_method
170: dispatch_original_method(subject, args, block)
171: else
172: dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
173: dispatch.call
174: end
175: end
# File lib/rr/injections/double_injection.rb, line 190
190: def dispatch_method_delegates_to_dispatch_original_method
191: @dispatch_method_delegates_to_dispatch_original_method = true
192: yield
193: ensure
194: @dispatch_method_delegates_to_dispatch_original_method = nil
195: end
# File lib/rr/injections/double_injection.rb, line 177
177: def dispatch_original_method(subject, args, block)
178: dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
179: dispatch.call_original_method
180: end
# File lib/rr/injections/double_injection.rb, line 26
26: def exists?(subject_class, method_name)
27: !!find(subject_class, method_name)
28: end
# 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
# 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
# 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
# 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
# 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
# File lib/rr/injections/double_injection.rb, line 80
80: def instances
81: @instances ||= HashWithObjectIdKey.new do |hash, subject_class|
82: hash.set_with_object_id(subject_class, {})
83: end
84: end
# File lib/rr/injections/double_injection.rb, line 186
186: def original_method_alias_name
187: "__rr__original_#{@method_name}"
188: end
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 100
100: def register_double(double)
101: @doubles << double
102: end
# File lib/rr/injections/double_injection.rb, line 43
43: def reset
44: instances.each do |subject_class, method_double_map|
45: SingletonMethodAddedInjection.find(subject_class) && SingletonMethodAddedInjection.find(subject_class).reset
46: method_double_map.keys.each do |method_name|
47: reset_double(subject_class, method_name)
48: end
49: Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances.has_key?(subject_class)
50: end
51: end
It binds the original method implementation on the subject if one exists.
# File lib/rr/injections/double_injection.rb, line 156
156: def reset
157: if subject_has_original_method?
158: subject_class.__send__(:remove_method, method_name)
159: subject_class.__send__(:alias_method, method_name, original_method_alias_name)
160: subject_class.__send__(:remove_method, original_method_alias_name)
161: else
162: if subject_has_method_defined?(method_name)
163: subject_class.__send__(:remove_method, method_name)
164: end
165: end
166: end
Resets the DoubleInjection for the passed in subject and method_name.
# File lib/rr/injections/double_injection.rb, line 74
74: def reset_double(subject_class, method_name)
75: double_injection = Injections::DoubleInjection.instances[subject_class].delete(method_name)
76: double_injection.reset
77: Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances[subject_class].empty?
78: end
# File lib/rr/injections/double_injection.rb, line 182
182: def subject_has_original_method_missing?
183: ClassInstanceMethodDefined.call(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
184: end
# File lib/rr/injections/double_injection.rb, line 53
53: def verify(*subjects)
54: subject_classes = subjects.empty? ?
55: Injections::DoubleInjection.instances.keys :
56: subjects.map {|subject| class << subject; self; end}
57: subject_classes.each do |subject_class|
58: instances.include?(subject_class) &&
59: instances[subject_class].keys.each do |method_name|
60: verify_double(subject_class, method_name)
61: end &&
62: instances.delete(subject_class)
63: end
64: end
RR::DoubleInjection#verify verifies each Double TimesCalledExpectation are met.
# File lib/rr/injections/double_injection.rb, line 146
146: def verify
147: @doubles.each do |double|
148: double.verify
149: end
150: end
Verifies the DoubleInjection for the passed in subject and method_name.
# File lib/rr/injections/double_injection.rb, line 67
67: def verify_double(subject_class, method_name)
68: Injections::DoubleInjection.find(subject_class, method_name).verify
69: ensure
70: reset_double subject_class, method_name
71: end
# File lib/rr/injections/double_injection.rb, line 205
205: def bind_method_with_alias
206: subject_class.__send__(:alias_method, original_method_alias_name, method_name)
207: bind_method
208: end