aop 1.0.0 → 1.0.1
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/.travis.yml +5 -2
- data/Gemfile +4 -3
- data/benchmarks/before.rb +2 -2
- data/integration/contracts.rb +23 -0
- data/lib/aop.rb +11 -2
- data/lib/aop/errors.rb +14 -0
- data/lib/aop/joint_point.rb +14 -0
- data/lib/aop/method_reference.rb +63 -0
- data/lib/aop/pointcut.rb +4 -76
- data/lib/aop/version.rb +1 -1
- data/spec/aop/around_spec.rb +2 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a11ed9fc8c66d7dbf41febbfb8fc4d0205a3c937
|
|
4
|
+
data.tar.gz: 78ecf889219aeb28e044d948a40185901475b7fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 264164d2abb7be0975a398ae799b0ddf59068d86a0194182476725babba90a2d1875c9d2c155ad6d775f3f54130c5aa7a9b6708fc295db77f0be9f61b9931259
|
|
7
|
+
data.tar.gz: 8ab954e1e2afe9dbc5b3b7c4cf7c9b2c9311615483841b2f5c0efd2c787b2c67b5d1c1d7cdf044711abe8745e139d0d05d28950c65d72b579f3390533c789c4b
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
source
|
|
1
|
+
source "https://rubygems.org"
|
|
2
2
|
|
|
3
3
|
# Specify your gem's dependencies in aop.gemspec
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
6
|
group :test do
|
|
7
|
-
gem
|
|
7
|
+
gem "rspec"
|
|
8
|
+
gem "contracts"
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
group :development do
|
|
11
12
|
gem "method_profiler"
|
|
12
13
|
gem "ruby-prof"
|
|
13
|
-
end
|
|
14
|
+
end
|
data/benchmarks/before.rb
CHANGED
|
@@ -42,8 +42,8 @@ def profile
|
|
|
42
42
|
observers << MethodProfiler.observe(Example)
|
|
43
43
|
observers << MethodProfiler.observe(Aop)
|
|
44
44
|
observers << MethodProfiler.observe(Aop::Pointcut)
|
|
45
|
-
observers << MethodProfiler.observe(Aop::
|
|
46
|
-
observers << MethodProfiler.observe(Aop::
|
|
45
|
+
observers << MethodProfiler.observe(Aop::MethodReference)
|
|
46
|
+
observers << MethodProfiler.observe(Aop::MethodReference::Singleton)
|
|
47
47
|
|
|
48
48
|
10000.times do
|
|
49
49
|
example.heavy_add(rand(1000), rand(1000))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "aop"
|
|
2
|
+
require "contracts"
|
|
3
|
+
|
|
4
|
+
class BankAccount < Struct.new(:number, :amount)
|
|
5
|
+
include Contracts
|
|
6
|
+
|
|
7
|
+
Contract BankAccount, Num => Num
|
|
8
|
+
def transfer(other, amount)
|
|
9
|
+
self.amount -= amount
|
|
10
|
+
other.amount += amount
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@actual = nil
|
|
15
|
+
@expected = "Transfered 100 from 12345 to 98765"
|
|
16
|
+
|
|
17
|
+
Aop["BankAccount#transfer:after"].advice do |account, other, amount|
|
|
18
|
+
@actual = "Transfered #{amount} from #{account.number} to #{other.number}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
BankAccount[12345, 955].transfer(BankAccount[98765, 130], 100)
|
|
22
|
+
|
|
23
|
+
fail "\nExpected: #{@expected}\nActual: #{@actual}" unless @expected == @actual
|
data/lib/aop.rb
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
%w[
|
|
2
|
+
version
|
|
3
|
+
|
|
4
|
+
errors
|
|
5
|
+
pointcut
|
|
6
|
+
joint_point
|
|
7
|
+
method_reference
|
|
8
|
+
].each { |name| require "aop/#{name}" }
|
|
3
9
|
|
|
4
10
|
module Aop
|
|
11
|
+
def self.[](pointcut_spec)
|
|
12
|
+
Pointcut.new(pointcut_spec)
|
|
13
|
+
end
|
|
5
14
|
end
|
data/lib/aop/errors.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Aop
|
|
2
|
+
class PointcutNotFound < StandardError
|
|
3
|
+
attr_reader :original_error
|
|
4
|
+
|
|
5
|
+
def initialize(pointcut_spec, original_error)
|
|
6
|
+
super("Unable to find pointcut #{pointcut_spec}")
|
|
7
|
+
@original_error = original_error
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
"#{super}\n\tReason: #{original_error.inspect}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Aop
|
|
2
|
+
class MethodReference
|
|
3
|
+
def self.from(m)
|
|
4
|
+
return new(m) if m[0...1] == "#"
|
|
5
|
+
Singleton.new(m)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def initialize(m)
|
|
9
|
+
@name = m[1..-1]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def decorate(target, &with)
|
|
13
|
+
name = @name
|
|
14
|
+
new_name = alias_name
|
|
15
|
+
alias_target(target).class_eval do
|
|
16
|
+
alias_method(new_name, name)
|
|
17
|
+
define_method(name, &with)
|
|
18
|
+
end
|
|
19
|
+
rescue NameError => err
|
|
20
|
+
raise PointcutNotFound.new(method_spec(target), err)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def call(target, *args, &blk)
|
|
24
|
+
target.send(alias_name, *args, &blk)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def method_name
|
|
28
|
+
"#{method_notation}#{@name}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def method_spec(target)
|
|
34
|
+
"#{target_name(target)}#{method_name}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def method_notation
|
|
38
|
+
"#"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def alias_target(target)
|
|
42
|
+
target
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def target_name(target)
|
|
46
|
+
target.name || target.inspect
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def alias_name
|
|
50
|
+
@_alias_name ||= :"__aop_#{SecureRandom.hex(10)}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class Singleton < self
|
|
54
|
+
def method_notation
|
|
55
|
+
"."
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def alias_target(target)
|
|
59
|
+
class << target; self; end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/aop/pointcut.rb
CHANGED
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
require "securerandom"
|
|
2
2
|
|
|
3
3
|
module Aop
|
|
4
|
-
def self.[](pointcut_spec)
|
|
5
|
-
Pointcut.new(pointcut_spec)
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
class PointcutNotFound < StandardError
|
|
9
|
-
attr_reader :original_error
|
|
10
|
-
|
|
11
|
-
def initialize(pointcut_spec, original_error)
|
|
12
|
-
super("Unable to find pointcut #{pointcut_spec}")
|
|
13
|
-
@original_error = original_error
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def to_s
|
|
17
|
-
"#{super}\n\tReason: #{original_error.inspect}"
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
4
|
class Pointcut
|
|
22
5
|
def initialize(spec)
|
|
23
6
|
@spec = spec
|
|
@@ -87,69 +70,14 @@ module Aop
|
|
|
87
70
|
generic_advice(advised) do |method_ref|
|
|
88
71
|
lambda do |*args, &blk|
|
|
89
72
|
result = nil
|
|
90
|
-
joint_point =
|
|
73
|
+
joint_point = JointPoint.new(
|
|
74
|
+
method_ref.method_name,
|
|
75
|
+
lambda { result = method_ref.call(self, *args, &blk) }
|
|
76
|
+
)
|
|
91
77
|
advised.call(joint_point, self, *args, &blk)
|
|
92
78
|
result
|
|
93
79
|
end
|
|
94
80
|
end
|
|
95
81
|
end
|
|
96
|
-
|
|
97
|
-
class MethodReference
|
|
98
|
-
def self.from(m)
|
|
99
|
-
return new(m) if m[0...1] == "#"
|
|
100
|
-
Singleton.new(m)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def initialize(m)
|
|
104
|
-
@name = m[1..-1]
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def decorate(target, &with)
|
|
108
|
-
name = @name
|
|
109
|
-
new_name = alias_name
|
|
110
|
-
alias_target(target).class_eval do
|
|
111
|
-
alias_method(new_name, name)
|
|
112
|
-
define_method(name, &with)
|
|
113
|
-
end
|
|
114
|
-
rescue NameError => err
|
|
115
|
-
raise PointcutNotFound.new(method_spec(target), err)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def call(target, *args, &blk)
|
|
119
|
-
target.send(alias_name, *args, &blk)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
private
|
|
123
|
-
|
|
124
|
-
def method_spec(target)
|
|
125
|
-
"#{target_name(target)}#{method_notation}#{@name}"
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def method_notation
|
|
129
|
-
"#"
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def alias_target(target)
|
|
133
|
-
target
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def target_name(target)
|
|
137
|
-
target.name || target.inspect
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def alias_name
|
|
141
|
-
@_alias_name ||= :"__aop_#{SecureRandom.hex(10)}"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
class Singleton < self
|
|
145
|
-
def method_notation
|
|
146
|
-
"."
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def alias_target(target)
|
|
150
|
-
class << target; self; end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
82
|
end
|
|
155
83
|
end
|
data/lib/aop/version.rb
CHANGED
data/spec/aop/around_spec.rb
CHANGED
|
@@ -8,6 +8,7 @@ RSpec.describe "Around advice" do
|
|
|
8
8
|
|
|
9
9
|
Aop["BankAccount#transfer:around"].advice do |joint_point, account, *args, &blk|
|
|
10
10
|
spy.before(account, *args, &blk)
|
|
11
|
+
spy.method_is(joint_point.method_name)
|
|
11
12
|
joint_point.call
|
|
12
13
|
spy.after(account, *args, &blk)
|
|
13
14
|
end
|
|
@@ -19,6 +20,7 @@ RSpec.describe "Around advice" do
|
|
|
19
20
|
amount = 55
|
|
20
21
|
|
|
21
22
|
expect(spy).to receive(:before).with(account, other, amount).ordered.once
|
|
23
|
+
expect(spy).to receive(:method_is).with("#transfer").ordered.once
|
|
22
24
|
expect(spy).to receive(:inside).with(other, amount).ordered.once
|
|
23
25
|
expect(spy).to receive(:after).with(account, other, amount).ordered.once
|
|
24
26
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Fedorov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -54,7 +54,11 @@ files:
|
|
|
54
54
|
- Rakefile
|
|
55
55
|
- aop.gemspec
|
|
56
56
|
- benchmarks/before.rb
|
|
57
|
+
- integration/contracts.rb
|
|
57
58
|
- lib/aop.rb
|
|
59
|
+
- lib/aop/errors.rb
|
|
60
|
+
- lib/aop/joint_point.rb
|
|
61
|
+
- lib/aop/method_reference.rb
|
|
58
62
|
- lib/aop/pointcut.rb
|
|
59
63
|
- lib/aop/version.rb
|
|
60
64
|
- spec/aop/advanced_spec.rb
|