rr 0.10.11 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|