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

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

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

[Source]

     # 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

[Source]

     # 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

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

[Source]

     # 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

[Source]

     # 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

[Source]

     # 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

[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 80
80:         def instances
81:           @instances ||= HashWithObjectIdKey.new do |hash, subject_class|
82:             hash.set_with_object_id(subject_class, {})
83:           end
84:         end

[Source]

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

[Source]

     # File lib/rr/injections/double_injection.rb, line 100
100:       def register_double(double)
101:         @doubles << double
102:       end

[Source]

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

[Source]

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

[Source]

    # 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

[Source]

     # 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

[Source]

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

[Source]

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

[Source]

    # 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

Protected Instance methods

[Source]

     # 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

[Source]

     # File lib/rr/injections/double_injection.rb, line 198
198:       def deferred_bind_method
199:         unless subject_has_method_defined?(original_method_alias_name)
200:           bind_method_with_alias
201:         end
202:         @performed_deferred_bind = true
203:       end

[Validate]