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)

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 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

[Source]

     # 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

[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 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

[Source]

     # 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

[Source]

     # 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

[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 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.

[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 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.

[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 186
186:       def subject_has_original_method_missing?
187:         class_instance_method_defined(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
188:       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 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.

[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 209
209:       def bind_method_with_alias
210:         subject_class.__send__(:alias_method, original_method_alias_name, method_name)
211:         bind_method
212:       end

[Source]

     # File lib/rr/injections/double_injection.rb, line 202
202:       def deferred_bind_method
203:         unless subject_has_method_defined?(original_method_alias_name)
204:           bind_method_with_alias
205:         end
206:         @performed_deferred_bind = true
207:       end

[Validate]