method_decorator 2.0.0 → 2.1.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.
- checksums.yaml +4 -4
- data/README.rdoc +5 -3
- data/lib/method_decorator/decoration.rb +3 -3
- data/lib/method_decorator/repository.rb +12 -9
- data/lib/method_decorator/version.rb +1 -1
- data/lib/method_decorator.rb +38 -12
- data/spec/lib/method_decorator_spec.rb +104 -14
- data/spec/support/dummy_class.rb +69 -0
- metadata +4 -4
- data/spec/support/some_class.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b76ea850afa9489fa5475cb52dce8f6884215b6a
|
4
|
+
data.tar.gz: 9a05e1374523166287151e6790b66e5701ae9c09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c088113e4a0803b007944eba4781cd8655f2d907be4a9fcd3493583faa688868b30521706057e2b4b89b39a17e8adfc55d4ece2bac25f85a2bb6c91bb1650cf
|
7
|
+
data.tar.gz: b46674adf3ff149e6fe00ff5bff6df99415ea6a4b7650f96e7d98d090660b52d6dfd04cce6ebb1a772a699ec065c11c8abaf3ea04eaf8574f2d8714fab28d26f
|
data/README.rdoc
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
= Method Decorator
|
2
2
|
|
3
|
-
Provides a way to dynamically
|
3
|
+
Provides a way to dynamically override methods without losing original behavior.
|
4
4
|
|
5
5
|
== Example
|
6
6
|
|
7
|
+
For a given class:
|
8
|
+
|
7
9
|
class SomeClass
|
8
10
|
|
9
11
|
def some_method(some_arg)
|
@@ -14,7 +16,7 @@ Provides a way to dynamically overwrite methods without losing original behavior
|
|
14
16
|
|
15
17
|
MethodDecorator.decorate SomeClass, :some_method do |*args|
|
16
18
|
puts :decorated_some_method
|
17
|
-
MethodDecorator.
|
19
|
+
MethodDecorator.call_original_method self, :some_method, *args
|
18
20
|
end
|
19
21
|
|
20
22
|
This call:
|
@@ -44,7 +46,7 @@ It works too:
|
|
44
46
|
|
45
47
|
MethodDecorator.decorate SomeClass.singleton_class, :some_method do |*args|
|
46
48
|
puts :decorated_some_method
|
47
|
-
MethodDecorator.
|
49
|
+
MethodDecorator.call_original_method self, :some_method, *args
|
48
50
|
end
|
49
51
|
|
50
52
|
SomeClass.some_method 'some arg'
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module MethodDecorator
|
2
2
|
class Decoration
|
3
3
|
|
4
|
-
attr_accessor :target_class, :
|
4
|
+
attr_accessor :target_class, :target_method_name, :target_method, :decoration
|
5
5
|
|
6
|
-
def initialize(target_class, target_method_name, target_method)
|
6
|
+
def initialize(target_class, target_method_name, target_method, &decoration)
|
7
7
|
self.target_class = target_class
|
8
|
-
self.
|
8
|
+
self.target_method_name = target_method_name
|
9
9
|
self.target_method = target_method
|
10
10
|
self.decoration = block_given? ? Proc.new : nil
|
11
11
|
end
|
@@ -6,22 +6,25 @@ module MethodDecorator
|
|
6
6
|
|
7
7
|
attr_writer :decorations
|
8
8
|
|
9
|
-
def
|
10
|
-
exists =
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
def add(target_class, target_method_name, target_method, &decoration)
|
10
|
+
exists = original_target_method_of target_class, target_method_name
|
11
|
+
|
12
|
+
self.decorations.push(
|
13
|
+
Decoration.new target_class, target_method_name, target_method, &decoration
|
14
|
+
) unless exists
|
15
|
+
|
14
16
|
not exists
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
19
|
+
def original_target_method_of(target_class, target_method_name)
|
20
|
+
decoration = self.decorations.select do
|
21
|
+
|d| d.target_class.eql?(target_class) and d.target_method_name.eql?(target_method_name)
|
22
|
+
end.first
|
23
|
+
|
20
24
|
decoration ? decoration.target_method : nil
|
21
25
|
end
|
22
26
|
|
23
27
|
def decorations; @decorations ||= [] end
|
24
|
-
|
25
28
|
end
|
26
29
|
end
|
27
30
|
end
|
data/lib/method_decorator.rb
CHANGED
@@ -1,29 +1,55 @@
|
|
1
1
|
require 'method_decorator/repository'
|
2
2
|
|
3
3
|
module MethodDecorator
|
4
|
+
|
4
5
|
class << self
|
5
6
|
|
6
|
-
def decorate(target_class,
|
7
|
-
|
8
|
-
|
7
|
+
def decorate(target_class, target_method_name, &decoration)
|
8
|
+
raise 'target_method_name must be a symbol' unless target_method_name.is_a? Symbol
|
9
|
+
added = add_to_repository(decoration, target_class, target_method_name)
|
10
|
+
override_method(decoration, target_class, target_method_name) if added
|
9
11
|
added
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
protected
|
15
|
+
|
16
|
+
def add_to_repository(decoration, target_class, target_method_name)
|
17
|
+
Repository.add(
|
18
|
+
target_class,
|
19
|
+
target_method_name,
|
20
|
+
target_class.instance_method(target_method_name),
|
21
|
+
&decoration
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def override_method(decoration, target_class, target_method_name)
|
26
|
+
is_protected = target_class.protected_instance_methods.include? target_method_name
|
27
|
+
is_private = target_class.private_instance_methods.include? target_method_name
|
28
|
+
target_class.send :define_method, target_method_name, &decoration
|
29
|
+
target_class.instance_eval { protected target_method_name } if is_protected
|
30
|
+
target_class.instance_eval { private target_method_name } if is_private
|
16
31
|
end
|
17
32
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
target_context
|
33
|
+
public
|
34
|
+
|
35
|
+
def call_original_method(target_context, target_method_name, *original_args, &original_block)
|
36
|
+
target_class = target_class_from_context(target_context)
|
37
|
+
target_method = Repository.original_target_method_of(target_class, target_method_name)
|
38
|
+
target_method.bind(target_context).call(*original_args, &original_block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def target_class_from_context(target_context)
|
42
|
+
if target_type_from_context(target_context).eql? :singleton
|
43
|
+
target_context.singleton_class
|
44
|
+
else
|
45
|
+
target_context.class
|
46
|
+
end
|
22
47
|
end
|
23
48
|
|
24
|
-
def
|
49
|
+
def target_type_from_context(target_context)
|
25
50
|
target_context.class.eql?(Class) ? :singleton : :class
|
26
51
|
end
|
27
52
|
|
28
53
|
end
|
54
|
+
|
29
55
|
end
|
@@ -1,26 +1,116 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'support/
|
2
|
+
require 'support/dummy_class'
|
3
3
|
|
4
4
|
describe MethodDecorator do
|
5
5
|
|
6
|
-
let(:
|
6
|
+
let(:dummy_arg) { :dummy_arg }
|
7
7
|
|
8
|
-
|
8
|
+
context 'when common class as target' do
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
let(:target) { DummyClass }
|
11
|
+
let(:target_instance) { target.new }
|
12
|
+
|
13
|
+
context 'when public method' do
|
14
|
+
|
15
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_public_instance_method).ordered }
|
16
|
+
before { expect(target_instance).to receive(:puts).with("a_public_instance_method_arg: #{dummy_arg}").ordered }
|
17
|
+
|
18
|
+
it { target_instance.a_public_instance_method dummy_arg }
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when protected method' do
|
23
|
+
|
24
|
+
context 'when calling protected method deliberately' do
|
25
|
+
|
26
|
+
it { expect{target_instance.a_protected_instance_method dummy_arg}.to raise_error NoMethodError }
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when calling protected method through `send`' do
|
31
|
+
|
32
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_protected_instance_method).ordered }
|
33
|
+
before { expect(target_instance).to receive(:puts).with("a_protected_instance_method_arg: #{dummy_arg}").ordered }
|
34
|
+
|
35
|
+
it { target_instance.send :a_protected_instance_method, dummy_arg }
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when private method' do
|
42
|
+
|
43
|
+
context 'when calling private method deliberately' do
|
44
|
+
|
45
|
+
it { expect{target_instance.a_private_instance_method dummy_arg}.to raise_error NoMethodError }
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when calling private method through `send`' do
|
50
|
+
|
51
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_private_instance_method).ordered }
|
52
|
+
before { expect(target_instance).to receive(:puts).with("a_private_instance_method_arg: #{dummy_arg}").ordered }
|
53
|
+
|
54
|
+
it { target_instance.send :a_private_instance_method, dummy_arg }
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
14
59
|
|
15
|
-
context 'when singleton method context' do
|
16
|
-
let(:target) { SomeClass }
|
17
|
-
it { subject }
|
18
60
|
end
|
19
61
|
|
20
|
-
context 'when
|
21
|
-
|
22
|
-
let(:
|
23
|
-
|
62
|
+
context 'when singleton class as target' do
|
63
|
+
|
64
|
+
let(:target) { DummyClass.singleton_class }
|
65
|
+
let(:target_instance) { DummyClass }
|
66
|
+
|
67
|
+
context 'when public method' do
|
68
|
+
|
69
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_public_singleton_method).ordered }
|
70
|
+
before { expect(target_instance).to receive(:puts).with("a_public_singleton_method_arg: #{dummy_arg}").ordered }
|
71
|
+
|
72
|
+
it { target_instance.a_public_singleton_method dummy_arg }
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when protected method' do
|
77
|
+
|
78
|
+
context 'when calling protected method deliberately' do
|
79
|
+
|
80
|
+
it { expect{target_instance.a_protected_singleton_method dummy_arg}.to raise_error NoMethodError }
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when calling protected method through `send`' do
|
85
|
+
|
86
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_protected_singleton_method).ordered }
|
87
|
+
before { expect(target_instance).to receive(:puts).with("a_protected_singleton_method_arg: #{dummy_arg}").ordered }
|
88
|
+
|
89
|
+
it { target_instance.send :a_protected_singleton_method, dummy_arg }
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when private method' do
|
96
|
+
|
97
|
+
context 'when calling private method deliberately' do
|
98
|
+
|
99
|
+
it { expect{target_instance.a_private_singleton_method dummy_arg}.to raise_error NoMethodError }
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when calling private method through `send`' do
|
104
|
+
|
105
|
+
before { expect(target_instance).to receive(:puts).with(:a_decorated_private_singleton_method).ordered }
|
106
|
+
before { expect(target_instance).to receive(:puts).with("a_private_singleton_method_arg: #{dummy_arg}").ordered }
|
107
|
+
|
108
|
+
it { target_instance.send :a_private_singleton_method, dummy_arg }
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
24
114
|
end
|
25
115
|
|
26
116
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class DummyClass
|
2
|
+
|
3
|
+
def a_public_instance_method(arg)
|
4
|
+
puts "a_public_instance_method_arg: #{arg}"
|
5
|
+
end
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def a_protected_instance_method(arg)
|
10
|
+
puts "a_protected_instance_method_arg: #{arg}"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def a_private_instance_method(arg)
|
16
|
+
puts "a_private_instance_method_arg: #{arg}"
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
def a_public_singleton_method(arg)
|
22
|
+
puts "a_public_singleton_method_arg: #{arg}"
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def a_protected_singleton_method(arg)
|
28
|
+
puts "a_protected_singleton_method_arg: #{arg}"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def a_private_singleton_method(arg)
|
34
|
+
puts "a_private_singleton_method_arg: #{arg}"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
MethodDecorator.decorate DummyClass, :a_public_instance_method do |*args, &block|
|
42
|
+
puts :a_decorated_public_instance_method
|
43
|
+
MethodDecorator.call_original_method self, :a_public_instance_method, *args, &block
|
44
|
+
end
|
45
|
+
|
46
|
+
MethodDecorator.decorate DummyClass, :a_protected_instance_method do |*args, &block|
|
47
|
+
puts :a_decorated_protected_instance_method
|
48
|
+
MethodDecorator.call_original_method self, :a_protected_instance_method, *args, &block
|
49
|
+
end
|
50
|
+
|
51
|
+
MethodDecorator.decorate DummyClass, :a_private_instance_method do |*args, &block|
|
52
|
+
puts :a_decorated_private_instance_method
|
53
|
+
MethodDecorator.call_original_method self, :a_private_instance_method, *args, &block
|
54
|
+
end
|
55
|
+
|
56
|
+
MethodDecorator.decorate DummyClass.singleton_class, :a_public_singleton_method do |*args, &block|
|
57
|
+
puts :a_decorated_public_singleton_method
|
58
|
+
MethodDecorator.call_original_method self, :a_public_singleton_method, *args, &block
|
59
|
+
end
|
60
|
+
|
61
|
+
MethodDecorator.decorate DummyClass.singleton_class, :a_protected_singleton_method do |*args, &block|
|
62
|
+
puts :a_decorated_protected_singleton_method
|
63
|
+
MethodDecorator.call_original_method self, :a_protected_singleton_method, *args, &block
|
64
|
+
end
|
65
|
+
|
66
|
+
MethodDecorator.decorate DummyClass.singleton_class, :a_private_singleton_method do |*args, &block|
|
67
|
+
puts :a_decorated_private_singleton_method
|
68
|
+
MethodDecorator.call_original_method self, :a_private_singleton_method, *args, &block
|
69
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: method_decorator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- r4z3c
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -87,7 +87,7 @@ files:
|
|
87
87
|
- method_decorator.gemspec
|
88
88
|
- spec/lib/method_decorator_spec.rb
|
89
89
|
- spec/spec_helper.rb
|
90
|
-
- spec/support/
|
90
|
+
- spec/support/dummy_class.rb
|
91
91
|
homepage: https://github.com/r4z3c/method_decorator.git
|
92
92
|
licenses:
|
93
93
|
- MIT
|
@@ -115,4 +115,4 @@ summary: Overwrite methods preserving the original behavior
|
|
115
115
|
test_files:
|
116
116
|
- spec/lib/method_decorator_spec.rb
|
117
117
|
- spec/spec_helper.rb
|
118
|
-
- spec/support/
|
118
|
+
- spec/support/dummy_class.rb
|
data/spec/support/some_class.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
class SomeClass
|
2
|
-
|
3
|
-
class << self
|
4
|
-
|
5
|
-
def some_method(some_arg)
|
6
|
-
puts some_arg
|
7
|
-
end
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def some_method(some_arg)
|
12
|
-
puts some_arg
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
[SomeClass, SomeClass.singleton_class].each do |target_class|
|
18
|
-
MethodDecorator.decorate target_class, :some_method do |*args, &block|
|
19
|
-
puts :decorated_some_method
|
20
|
-
MethodDecorator.call_original self, :some_method, *args, &block
|
21
|
-
end
|
22
|
-
end
|