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