| 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) |
| BoundObjects | = | {} |
| doubles | [R] | |
| method_name | [R] | |
| subject_class | [R] |
# 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
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 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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 83
83: def instances
84: @instances ||= HashWithObjectIdKey.new do |hash, subject_class|
85: hash.set_with_object_id(subject_class, {})
86: end
87: end
# 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.
# File lib/rr/injections/double_injection.rb, line 104
104: def register_double(double)
105: @doubles << double
106: end
# 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.
# 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.
# 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
# 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
# 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.
# 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.
# 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
# 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