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 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 136 136: def bind_method 137: subject_class_object_id = subject_class.object_id 138: 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) 139: self 140: end
# File lib/rr/injections/double_injection.rb, line 122 122: def bind_method_that_self_destructs_and_delegates_to_method_missing 123: subject_class_object_id = subject_class.object_id 124: 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) 125: self 126: 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 172 172: def dispatch_method(subject, args, block) 173: if @dispatch_method_delegates_to_dispatch_original_method 174: dispatch_original_method(subject, args, block) 175: else 176: dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block) 177: dispatch.call 178: end 179: end
# File lib/rr/injections/double_injection.rb, line 194 194: def dispatch_method_delegates_to_dispatch_original_method 195: @dispatch_method_delegates_to_dispatch_original_method = true 196: yield 197: ensure 198: @dispatch_method_delegates_to_dispatch_original_method = nil 199: end
# File lib/rr/injections/double_injection.rb, line 181 181: def dispatch_original_method(subject, args, block) 182: dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block) 183: dispatch.call_original_method 184: 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 190 190: def original_method_alias_name 191: "__rr__original_#{@method_name}" 192: 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 160 160: def reset 161: if subject_has_original_method? 162: subject_class.__send__(:remove_method, method_name) 163: subject_class.__send__(:alias_method, method_name, original_method_alias_name) 164: subject_class.__send__(:remove_method, original_method_alias_name) 165: else 166: if subject_has_method_defined?(method_name) 167: subject_class.__send__(:remove_method, method_name) 168: end 169: end 170: 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 186 186: def subject_has_original_method_missing? 187: class_instance_method_defined(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name) 188: 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 150 150: def verify 151: @doubles.each do |double| 152: double.verify 153: end 154: 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 209 209: def bind_method_with_alias 210: subject_class.__send__(:alias_method, original_method_alias_name, method_name) 211: bind_method 212: end