rr 0.10.11 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +5 -0
- data/Gemfile +6 -0
- data/README.rdoc +28 -2
- data/VERSION.yml +3 -3
- data/lib/rr.rb +23 -17
- data/lib/rr/adapters/rr_methods.rb +43 -17
- data/lib/rr/blank_slate.rb +2 -2
- data/lib/rr/class_instance_method_defined.rb +9 -0
- data/lib/rr/double.rb +2 -2
- data/lib/rr/double_definitions/double_definition.rb +29 -16
- data/lib/rr/double_definitions/double_definition_create.rb +52 -86
- data/lib/rr/double_definitions/double_injections/any_instance_of.rb +28 -0
- data/lib/rr/double_definitions/double_injections/instance.rb +16 -0
- data/lib/rr/double_definitions/double_injections/new_instance_of.rb +53 -0
- data/lib/rr/double_definitions/strategies/double_injection/any_instance_of.rb +31 -0
- data/lib/rr/double_definitions/strategies/double_injection/double_injection_strategy.rb +10 -0
- data/lib/rr/double_definitions/strategies/double_injection/instance.rb +17 -0
- data/lib/rr/double_definitions/strategies/double_injection/new_instance_of.rb +37 -0
- data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +0 -5
- data/lib/rr/double_definitions/strategies/implementation/proxy.rb +0 -2
- data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +0 -2
- data/lib/rr/double_definitions/strategies/strategy.rb +0 -27
- data/lib/rr/double_definitions/strategies/strategy_methods.rb +53 -0
- data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +0 -2
- data/lib/rr/double_definitions/strategies/verification/mock.rb +0 -2
- data/lib/rr/double_definitions/strategies/verification/stub.rb +0 -2
- data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +0 -5
- data/lib/rr/hash_with_object_id_key.rb +4 -0
- data/lib/rr/injections/double_injection.rb +94 -71
- data/lib/rr/injections/injection.rb +8 -10
- data/lib/rr/injections/method_missing_injection.rb +13 -20
- data/lib/rr/injections/singleton_method_added_injection.rb +19 -17
- data/lib/rr/method_dispatches/base_method_dispatch.rb +1 -1
- data/lib/rr/method_dispatches/method_dispatch.rb +4 -4
- data/lib/rr/method_dispatches/method_missing_dispatch.rb +17 -14
- data/lib/rr/recorded_calls.rb +1 -1
- data/lib/rr/space.rb +6 -6
- data/lib/rr/times_called_matchers/times_called_matcher.rb +2 -2
- data/scratch.rb +118 -0
- data/spec/api/any_instance_of/all_instances_of_spec.rb +14 -0
- data/spec/api/any_instance_of/any_instance_of_spec.rb +47 -0
- data/spec/api/mock/mock_spec.rb +2 -2
- data/spec/api/new_instance_of/instance_of_spec.rb +15 -0
- data/spec/api/new_instance_of/new_instance_of_spec.rb +61 -0
- data/spec/environment_fixture_setup.rb +3 -2
- data/spec/rr/adapters/rr_methods_space_spec.rb +8 -10
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +1 -1
- data/spec/rr/double_definitions/double_definition_create_blank_slate_spec.rb +6 -2
- data/spec/rr/double_definitions/double_definition_create_spec.rb +1 -52
- data/spec/rr/double_injection/double_injection_verify_spec.rb +1 -1
- data/spec/rr/rspec/rspec_adapter_spec.rb +5 -5
- data/spec/rr/space/space_spec.rb +58 -67
- data/spec/spec_helper.rb +2 -2
- metadata +33 -9
- data/lib/rr/double_definitions/strategies/scope/instance.rb +0 -15
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +0 -50
- data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +0 -15
@@ -0,0 +1,28 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module DoubleInjections
|
4
|
+
class AnyInstanceOf
|
5
|
+
extend(Module.new do
|
6
|
+
include RR::Adapters::RRMethods
|
7
|
+
|
8
|
+
def call(subject_class, stubbed_methods=nil, &block)
|
9
|
+
::RR::DoubleDefinitions::DoubleDefinitionCreate.set_default_double_injection_strategy(lambda do |double_definition_create|
|
10
|
+
::RR::DoubleDefinitions::Strategies::DoubleInjection::AnyInstanceOf.new(double_definition_create)
|
11
|
+
end) do
|
12
|
+
if stubbed_methods
|
13
|
+
subject_class.class_eval do
|
14
|
+
stubbed_methods.each do |name, value|
|
15
|
+
value_proc = value.is_a?(Proc) ? value : lambda {value}
|
16
|
+
RR.stub(subject_class, name).returns(&value_proc)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
block.call(subject_class)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module DoubleInjections
|
4
|
+
class Instance
|
5
|
+
extend(Module.new do
|
6
|
+
include ::RR::Adapters::RRMethods
|
7
|
+
|
8
|
+
def call(double_method_name, *args, &definition_eval_block)
|
9
|
+
double_definition_create = DoubleDefinitions::DoubleDefinitionCreate.new
|
10
|
+
double_definition_create.send(double_method_name, *args, &definition_eval_block)
|
11
|
+
end
|
12
|
+
end)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module DoubleInjections
|
4
|
+
class NewInstanceOf
|
5
|
+
extend(Module.new do
|
6
|
+
include RR::Adapters::RRMethods
|
7
|
+
def call(subject, stubbed_methods={})
|
8
|
+
double_definition_create = DoubleDefinitionCreate.new.stub
|
9
|
+
stub.proxy(subject).allocate do |instance|
|
10
|
+
add_stubbed_methods(instance, stubbed_methods)
|
11
|
+
add_method_chain_definition(instance, double_definition_create)
|
12
|
+
yield(instance) if block_given?
|
13
|
+
instance
|
14
|
+
end
|
15
|
+
stub(subject).new do |*args|
|
16
|
+
instance = subject.allocate
|
17
|
+
initialize_subject_instance(instance, args)
|
18
|
+
end
|
19
|
+
DoubleDefinitionCreateBlankSlate.new(double_definition_create)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def add_stubbed_methods(subject_instance, stubbed_methods)
|
24
|
+
stubbed_methods.each do |name, value|
|
25
|
+
value_proc = value.is_a?(Proc) ? value : lambda {value}
|
26
|
+
stub(subject_instance, name).returns(&value_proc)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_method_chain_definition(subject_instance, double_definition_create)
|
31
|
+
implementation_strategy = double_definition_create.implementation_strategy
|
32
|
+
if implementation_strategy.method_name
|
33
|
+
stub(subject_instance).method_missing(
|
34
|
+
implementation_strategy.method_name,
|
35
|
+
*implementation_strategy.args,
|
36
|
+
&implementation_strategy.handler
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_subject_instance(subject_instance, args)
|
42
|
+
if args.last.is_a?(ProcFromBlock)
|
43
|
+
subject_instance.__send__(:initialize, *args[0..(args.length-2)], &args.last)
|
44
|
+
else
|
45
|
+
subject_instance.__send__(:initialize, *args)
|
46
|
+
end
|
47
|
+
subject_instance
|
48
|
+
end
|
49
|
+
end)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module Strategies
|
4
|
+
module DoubleInjection
|
5
|
+
# This class is Deprecated.
|
6
|
+
# Calling instance_of will cause all instances of the passed in Class
|
7
|
+
# to have the Double defined.
|
8
|
+
#
|
9
|
+
# The following example mocks all User's valid? method and return false.
|
10
|
+
# mock.instance_of(User).valid? {false}
|
11
|
+
#
|
12
|
+
# The following example mocks and proxies User#projects and returns the
|
13
|
+
# first 3 projects.
|
14
|
+
# mock.instance_of(User).projects do |projects|
|
15
|
+
# projects[0..2]
|
16
|
+
# end
|
17
|
+
class AnyInstanceOf < DoubleInjectionStrategy
|
18
|
+
protected
|
19
|
+
def do_call
|
20
|
+
if !double_definition_create.no_subject? && !double_definition_create.subject.is_a?(Class)
|
21
|
+
raise ArgumentError, "instance_of only accepts class objects"
|
22
|
+
end
|
23
|
+
# subject, method_name
|
24
|
+
double_injection = Injections::DoubleInjection.find_or_create(subject, method_name)
|
25
|
+
Double.new(double_injection, definition)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module Strategies
|
4
|
+
module DoubleInjection
|
5
|
+
class Instance < DoubleInjectionStrategy
|
6
|
+
protected
|
7
|
+
def do_call
|
8
|
+
double_injection = Injections::DoubleInjection.find_or_create(
|
9
|
+
(class << subject; self; end), method_name
|
10
|
+
)
|
11
|
+
Double.new(double_injection, definition)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module Strategies
|
4
|
+
module DoubleInjection
|
5
|
+
# This class is Deprecated.
|
6
|
+
# Calling instance_of will cause all instances of the passed in Class
|
7
|
+
# to have the Double defined.
|
8
|
+
#
|
9
|
+
# The following example mocks all User's valid? method and return false.
|
10
|
+
# mock.instance_of(User).valid? {false}
|
11
|
+
#
|
12
|
+
# The following example mocks and proxies User#projects and returns the
|
13
|
+
# first 3 projects.
|
14
|
+
# mock.instance_of(User).projects do |projects|
|
15
|
+
# projects[0..2]
|
16
|
+
# end
|
17
|
+
class NewInstanceOf < DoubleInjectionStrategy
|
18
|
+
protected
|
19
|
+
def do_call
|
20
|
+
if !double_definition_create.no_subject? && !double_definition_create.subject.is_a?(Class)
|
21
|
+
raise ArgumentError, "instance_of only accepts class objects"
|
22
|
+
end
|
23
|
+
DoubleDefinitions::DoubleInjections::NewInstanceOf.call(subject) do |subject|
|
24
|
+
add_double_to_instance(subject)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_double_to_instance(instance)
|
29
|
+
double_injection = Injections::DoubleInjection.find_or_create((class << instance; self; end), method_name)
|
30
|
+
Double.new(double_injection, definition)
|
31
|
+
instance
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,11 +3,6 @@ module RR
|
|
3
3
|
module Strategies
|
4
4
|
module Implementation
|
5
5
|
class ImplementationStrategy < Strategy
|
6
|
-
class << self
|
7
|
-
def register_self_at_double_definition_create(strategy_method_name)
|
8
|
-
DoubleDefinitionCreate.register_implementation_strategy_class(self, strategy_method_name)
|
9
|
-
end
|
10
|
-
end
|
11
6
|
end
|
12
7
|
end
|
13
8
|
end
|
@@ -2,29 +2,6 @@ module RR
|
|
2
2
|
module DoubleDefinitions
|
3
3
|
module Strategies
|
4
4
|
class Strategy
|
5
|
-
class << self
|
6
|
-
attr_reader :strategy_method_name
|
7
|
-
def register(strategy_method_name, *alias_method_names)
|
8
|
-
@strategy_method_name = strategy_method_name
|
9
|
-
register_self_at_double_definition_create(strategy_method_name)
|
10
|
-
DoubleDefinitionCreate.class_eval do
|
11
|
-
alias_method_names.each do |alias_method_name|
|
12
|
-
alias_method alias_method_name, strategy_method_name
|
13
|
-
end
|
14
|
-
end
|
15
|
-
RR::Adapters::RRMethods.register_strategy_class(self, strategy_method_name)
|
16
|
-
DoubleDefinition.register_strategy_class(self, strategy_method_name)
|
17
|
-
RR::Adapters::RRMethods.class_eval do
|
18
|
-
alias_method_names.each do |alias_method_name|
|
19
|
-
alias_method alias_method_name, strategy_method_name
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def register_self_at_double_definition_create(strategy_method_name)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
5
|
attr_reader :double_definition_create, :definition, :method_name, :args, :handler
|
29
6
|
include Space::Reader
|
30
7
|
|
@@ -37,10 +14,6 @@ module RR
|
|
37
14
|
do_call
|
38
15
|
end
|
39
16
|
|
40
|
-
def name
|
41
|
-
self.class.strategy_method_name
|
42
|
-
end
|
43
|
-
|
44
17
|
def verify_subject(subject)
|
45
18
|
end
|
46
19
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module RR
|
2
|
+
module DoubleDefinitions
|
3
|
+
module Strategies
|
4
|
+
module StrategyMethods
|
5
|
+
extend(Module.new do
|
6
|
+
def lately_bound_alias_method(target_method_name, source_method_name)
|
7
|
+
module_eval((<<-METHOD), __FILE__, __LINE__+1)
|
8
|
+
def #{target_method_name}(*args, &block)
|
9
|
+
#{source_method_name}(*args, &block)
|
10
|
+
end
|
11
|
+
METHOD
|
12
|
+
end
|
13
|
+
end)
|
14
|
+
|
15
|
+
def mock!(method_name=nil, &definition_eval_block)
|
16
|
+
mock(Object.new, method_name, &definition_eval_block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def stub!(method_name=nil, &definition_eval_block)
|
20
|
+
stub(Object.new, method_name, &definition_eval_block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def dont_allow!(method_name=nil, &definition_eval_block)
|
24
|
+
dont_allow(Object.new, method_name, &definition_eval_block)
|
25
|
+
end
|
26
|
+
lately_bound_alias_method :do_not_allow, :dont_allow
|
27
|
+
lately_bound_alias_method :do_not_allow!, :dont_allow!
|
28
|
+
|
29
|
+
def proxy!(method_name=nil, &definition_eval_block)
|
30
|
+
proxy(Object.new, method_name, &definition_eval_block)
|
31
|
+
end
|
32
|
+
lately_bound_alias_method :probe, :proxy
|
33
|
+
lately_bound_alias_method :probe!, :proxy!
|
34
|
+
|
35
|
+
def strong!(method_name=nil, &definition_eval_block)
|
36
|
+
strong(Object.new, method_name, &definition_eval_block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def any_instance_of!(method_name=nil, &definition_eval_block)
|
40
|
+
any_instance_of(Object.new, method_name, &definition_eval_block)
|
41
|
+
end
|
42
|
+
lately_bound_alias_method :all_instances_of, :any_instance_of
|
43
|
+
lately_bound_alias_method :all_instances_of!, :any_instance_of!
|
44
|
+
|
45
|
+
def instance_of!(method_name=nil, &definition_eval_block)
|
46
|
+
instance_of(Object.new, method_name, &definition_eval_block)
|
47
|
+
end
|
48
|
+
lately_bound_alias_method :new_instance_of, :instance_of
|
49
|
+
lately_bound_alias_method :new_instance_of!, :instance_of!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -3,11 +3,6 @@ module RR
|
|
3
3
|
module Strategies
|
4
4
|
module Verification
|
5
5
|
class VerificationStrategy < Strategy
|
6
|
-
class << self
|
7
|
-
def register_self_at_double_definition_create(strategy_method_name)
|
8
|
-
DoubleDefinitionCreate.register_verification_strategy_class(self, strategy_method_name)
|
9
|
-
end
|
10
|
-
end
|
11
6
|
end
|
12
7
|
end
|
13
8
|
end
|
@@ -4,67 +4,95 @@ module RR
|
|
4
4
|
# A double_injection has 0 to many Double objects. Each Double
|
5
5
|
# has Argument Expectations and Times called Expectations.
|
6
6
|
class DoubleInjection < Injection
|
7
|
-
|
8
|
-
def
|
9
|
-
instances[
|
10
|
-
new(
|
7
|
+
extend(Module.new do
|
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
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
14
|
+
def find_or_create_by_subject(subject, method_name)
|
15
|
+
find_or_create(class << subject; self; end, method_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(subject_class, method_name)
|
19
|
+
instances[subject_class] && instances[subject_class][method_name.to_sym]
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_by_subject(subject, method_name)
|
23
|
+
find(class << subject; self; end, method_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def exists?(subject_class, method_name)
|
27
|
+
!!find(subject_class, method_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def exists_by_subject?(subject, method_name)
|
31
|
+
exists?((class << subject; self; end), method_name)
|
32
|
+
end
|
33
|
+
|
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
|
16
41
|
end
|
17
42
|
|
18
43
|
def reset
|
19
|
-
instances.each do |
|
44
|
+
instances.each do |subject_class, method_double_map|
|
45
|
+
SingletonMethodAddedInjection.find(subject_class) && SingletonMethodAddedInjection.find(subject_class).reset
|
20
46
|
method_double_map.keys.each do |method_name|
|
21
|
-
reset_double(
|
47
|
+
reset_double(subject_class, method_name)
|
22
48
|
end
|
49
|
+
Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances.has_key?(subject_class)
|
23
50
|
end
|
24
51
|
end
|
25
52
|
|
26
53
|
def verify(*subjects)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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)
|
32
61
|
end &&
|
33
|
-
instances.delete(
|
62
|
+
instances.delete(subject_class)
|
34
63
|
end
|
35
64
|
end
|
36
65
|
|
37
66
|
# Verifies the DoubleInjection for the passed in subject and method_name.
|
38
|
-
def verify_double(
|
39
|
-
Injections::DoubleInjection.
|
67
|
+
def verify_double(subject_class, method_name)
|
68
|
+
Injections::DoubleInjection.find(subject_class, method_name).verify
|
40
69
|
ensure
|
41
|
-
reset_double
|
70
|
+
reset_double subject_class, method_name
|
42
71
|
end
|
43
72
|
|
44
73
|
# Resets the DoubleInjection for the passed in subject and method_name.
|
45
|
-
def reset_double(
|
46
|
-
double_injection = Injections::DoubleInjection.instances[
|
47
|
-
Injections::DoubleInjection.instances.delete(subject) if Injections::DoubleInjection.instances[subject].empty?
|
74
|
+
def reset_double(subject_class, method_name)
|
75
|
+
double_injection = Injections::DoubleInjection.instances[subject_class].delete(method_name)
|
48
76
|
double_injection.reset
|
77
|
+
Injections::DoubleInjection.instances.delete(subject_class) if Injections::DoubleInjection.instances[subject_class].empty?
|
49
78
|
end
|
50
79
|
|
51
80
|
def instances
|
52
|
-
@instances ||= HashWithObjectIdKey.new do |hash,
|
53
|
-
hash.set_with_object_id(
|
81
|
+
@instances ||= HashWithObjectIdKey.new do |hash, subject_class|
|
82
|
+
hash.set_with_object_id(subject_class, {})
|
54
83
|
end
|
55
84
|
end
|
56
|
-
end
|
85
|
+
end)
|
57
86
|
|
58
87
|
attr_reader :subject_class, :method_name, :doubles
|
59
88
|
|
60
89
|
MethodArguments = Struct.new(:arguments, :block)
|
61
90
|
|
62
|
-
def initialize(
|
63
|
-
@subject = subject
|
91
|
+
def initialize(subject_class, method_name)
|
64
92
|
@subject_class = subject_class
|
65
93
|
@method_name = method_name.to_sym
|
66
94
|
@doubles = []
|
67
|
-
@
|
95
|
+
@dispatch_method_delegates_to_dispatch_original_method = nil
|
68
96
|
end
|
69
97
|
|
70
98
|
# RR::DoubleInjection#register_double adds the passed in Double
|
@@ -77,20 +105,37 @@ module RR
|
|
77
105
|
# that dispatches to the matching Double when the method
|
78
106
|
# is called.
|
79
107
|
def bind
|
80
|
-
if
|
81
|
-
|
82
|
-
if subject_is_proxy_for_method?(method_name)
|
83
|
-
bind_method
|
84
|
-
else
|
85
|
-
bind_method_with_alias
|
86
|
-
end
|
87
|
-
else
|
88
|
-
Injections::MethodMissingInjection.create(subject)
|
89
|
-
Injections::SingletonMethodAddedInjection.create(subject)
|
90
|
-
end
|
108
|
+
if subject_has_method_defined?(method_name)
|
109
|
+
bind_method_with_alias
|
91
110
|
else
|
92
|
-
|
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
|
117
|
+
|
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(<<-METHOD, __FILE__, __LINE__ + 1)
|
121
|
+
def #{method_name}(*args, &block)
|
122
|
+
ObjectSpace._id2ref(#{subject_class_object_id}).class_eval do
|
123
|
+
remove_method(:#{method_name})
|
124
|
+
end
|
125
|
+
method_missing(:#{method_name}, *args, &block)
|
93
126
|
end
|
127
|
+
METHOD
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def bind_method
|
132
|
+
subject_class_object_id = subject_class.object_id
|
133
|
+
subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
|
134
|
+
def #{method_name}(*args, &block)
|
135
|
+
arguments = MethodArguments.new(args, block)
|
136
|
+
RR::Injections::DoubleInjection.dispatch_method(self, ObjectSpace._id2ref(#{subject_class_object_id}), :#{method_name}, arguments.arguments, arguments.block)
|
137
|
+
end
|
138
|
+
METHOD
|
94
139
|
self
|
95
140
|
end
|
96
141
|
|
@@ -118,48 +163,36 @@ module RR
|
|
118
163
|
end
|
119
164
|
end
|
120
165
|
|
121
|
-
def dispatch_method(args, block)
|
122
|
-
|
123
|
-
|
124
|
-
dispatch.call_original_method
|
166
|
+
def dispatch_method(subject, args, block)
|
167
|
+
if @dispatch_method_delegates_to_dispatch_original_method
|
168
|
+
dispatch_original_method(subject, args, block)
|
125
169
|
else
|
170
|
+
dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
|
126
171
|
dispatch.call
|
127
172
|
end
|
128
173
|
end
|
129
174
|
|
130
|
-
def
|
131
|
-
MethodDispatches::
|
175
|
+
def dispatch_original_method(subject, args, block)
|
176
|
+
dispatch = MethodDispatches::MethodDispatch.new(self, subject, args, block)
|
177
|
+
dispatch.call_original_method
|
132
178
|
end
|
133
179
|
|
134
180
|
def subject_has_original_method_missing?
|
135
|
-
|
181
|
+
ClassInstanceMethodDefined.call(subject_class, MethodDispatches::MethodMissingDispatch.original_method_missing_alias_name)
|
136
182
|
end
|
137
183
|
|
138
184
|
def original_method_alias_name
|
139
185
|
"__rr__original_#{@method_name}"
|
140
186
|
end
|
141
187
|
|
142
|
-
def
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
def bypass_bound_method
|
147
|
-
@bypass_bound_method = true
|
188
|
+
def dispatch_method_delegates_to_dispatch_original_method
|
189
|
+
@dispatch_method_delegates_to_dispatch_original_method = true
|
148
190
|
yield
|
149
191
|
ensure
|
150
|
-
@
|
192
|
+
@dispatch_method_delegates_to_dispatch_original_method = nil
|
151
193
|
end
|
152
194
|
|
153
195
|
protected
|
154
|
-
def subject_is_proxy_for_method?(method_name_in_question)
|
155
|
-
!(
|
156
|
-
class << @subject;
|
157
|
-
self;
|
158
|
-
end).
|
159
|
-
instance_methods.
|
160
|
-
detect {|method_name| method_name.to_sym == method_name_in_question.to_sym}
|
161
|
-
end
|
162
|
-
|
163
196
|
def deferred_bind_method
|
164
197
|
unless subject_has_method_defined?(original_method_alias_name)
|
165
198
|
bind_method_with_alias
|
@@ -171,16 +204,6 @@ module RR
|
|
171
204
|
subject_class.__send__(:alias_method, original_method_alias_name, method_name)
|
172
205
|
bind_method
|
173
206
|
end
|
174
|
-
|
175
|
-
def bind_method
|
176
|
-
subject = @subject.is_a?(Class) && !@subject.name.to_s.empty? ? @subject.name : "self"
|
177
|
-
subject_class.class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
|
178
|
-
def #{@method_name}(*args, &block)
|
179
|
-
arguments = MethodArguments.new(args, block)
|
180
|
-
RR::Injections::DoubleInjection.create(#{subject}, :#{@method_name}).dispatch_method(arguments.arguments, arguments.block)
|
181
|
-
end
|
182
|
-
METHOD
|
183
|
-
end
|
184
207
|
end
|
185
208
|
end
|
186
209
|
end
|