aop 0.0.2 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af9f44c8cac54ec4197e54a135d3c6829b8badd6
4
- data.tar.gz: f9ffd78f10555e9ef4f09c2d14231d7248f4c82f
3
+ metadata.gz: 265bbfbbde5fedca853374f381977f960186c174
4
+ data.tar.gz: 5ba07e066d01dfb9647f8294f29b1508604fe2ea
5
5
  SHA512:
6
- metadata.gz: f24dd40907b9bd09ac43e491651cfb64cedaa4044363d99fba028e3b23c85afe2a5d1a12baa6d2c440a6e7dec0aec8f65413048753584183cb63efb8a8451b2a
7
- data.tar.gz: af8f883d3f73072302b052afd3e69cca24d4d5d0517bb404cb30c68bc9f9be906e987aa3e1a596c9d3e625a96e028a28c5f7166708f405e66aa184b23282ca71
6
+ metadata.gz: 4e762bcad98bbbf72d5f867d22bb20e1add43d02a66e0f63f1da21c1804b335b539bee2eea2c2956c0a7900153931285052a4ee21413bc78e620575c0caefb79
7
+ data.tar.gz: aa177e07c23669b04a02ac5de5e4ca9bedb2dacc7e92dd8124419b63fd5d5924fa0d236fee9dc01471ec32c8a3454e20cb19f59eb1c9e3b8c77cf1cb969092df
data/README.md CHANGED
@@ -50,8 +50,6 @@ end
50
50
 
51
51
  ### Around advice
52
52
 
53
- *Not implemented*
54
-
55
53
  ```ruby
56
54
  module Transactional
57
55
  Aop["BankAccount#transfer:around"].advice do |joint_point, account, *args, &blk|
@@ -62,9 +60,31 @@ module Transactional
62
60
  end
63
61
  ```
64
62
 
65
- ## TODO (to specify)
63
+ ### Class methods
64
+
65
+ Use `.method` notation:
66
+
67
+ ```ruby
68
+ module Transactional
69
+ Aop["BankAccount.transfer:around"].advice do |joint_point, klass, *args, &blk|
70
+ start_transaction
71
+ joint_point.call
72
+ finish_transaction
73
+ end
74
+ end
75
+ ```
76
+
77
+ ### Multiple classes, methods and advices
66
78
 
67
- - multiple classes, methods and types of advices at once
79
+ Use `,` to use multiple classes, methods and advices:
80
+
81
+ ```ruby
82
+ module Analytics
83
+ Aop["User,Admin#sign_in,.sign_up,#sign_out:before,:after"].advice do |target, *args, &blk|
84
+ report("auth_action", user.id)
85
+ end
86
+ end
87
+ ```
68
88
 
69
89
  ## Contributing
70
90
 
data/lib/aop/pointcut.rb CHANGED
@@ -13,16 +13,16 @@ module Aop
13
13
  @class_names = @class_spec.split(",")
14
14
  @classes = @class_names.map { |name| Object.const_get(name) }
15
15
 
16
- @method_spec = spec.scan(/[#\.][^#\.:]+/)
16
+ @method_spec = spec.scan(/[#\.][^,#\.:]+/)
17
17
  @methods = @method_spec.map { |m| MethodReference.from(m) }
18
18
 
19
- @advices = spec.scan(/[^:]:([^:]+)/).flatten
19
+ @advices = spec.scan(/[^:]:([^:,]+)/).flatten
20
20
  end
21
21
 
22
22
  def advice(&advised)
23
- advices = @advices
24
- advices.each do |advice|
25
- _advice(advice, advised)
23
+ return _advice(@advices.first, advised) if @advices.count == 1
24
+ @advices.each do |advice|
25
+ Aop["#{@class_names.join(",")}#{@method_spec.join(",")}:#{advice}"].advice(&advised)
26
26
  end
27
27
  end
28
28
 
@@ -30,6 +30,7 @@ module Aop
30
30
 
31
31
  def _advice(advice, advised)
32
32
  return before_advice(advised) if advice == "before"
33
+ return around_advice(advised) if advice == "around"
33
34
  after_advice(advised)
34
35
  end
35
36
 
@@ -63,6 +64,17 @@ module Aop
63
64
  end
64
65
  end
65
66
 
67
+ def around_advice(advised)
68
+ generic_advice(advised) do |method_ref|
69
+ lambda do |*args, &blk|
70
+ result = nil
71
+ joint_point = lambda { result = method_ref.call(self, *args, &blk) }
72
+ advised.call(joint_point, self, *args, &blk)
73
+ result
74
+ end
75
+ end
76
+ end
77
+
66
78
  class MethodReference
67
79
  def self.from(m)
68
80
  return new(m) if m[0...1] == "#"
@@ -83,7 +95,7 @@ module Aop
83
95
  end
84
96
 
85
97
  def call(target, *args, &blk)
86
- alias_target(target).send(alias_name, *args, &blk)
98
+ target.send(alias_name, *args, &blk)
87
99
  end
88
100
 
89
101
  private
data/lib/aop/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Aop
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,110 @@
1
+ RSpec.describe "Advanced advices" do
2
+ include FixtureLoader
3
+
4
+ let(:spy) { double("Spy") }
5
+
6
+ before do
7
+ load_fixture("BankAccount", "bank_account")
8
+ load_fixture("CashAccount", "cash_account")
9
+ end
10
+
11
+ describe "class methods" do
12
+ before do
13
+ Aop["BankAccount.transfer:around"].advice do |joint_point, klass, *args, &blk|
14
+ spy.before(klass, *args, &blk)
15
+ joint_point.call
16
+ spy.after(klass, *args, &blk)
17
+ end
18
+ end
19
+
20
+ it "fires around #transfer" do
21
+ account = BankAccount.new(spy)
22
+ other = BankAccount.new(spy)
23
+ amount = 55
24
+
25
+ expect(spy).to receive(:before).with(BankAccount, spy, account, other, amount).ordered.once
26
+ expect(spy).to receive(:inside).with(spy, account, other, amount).ordered.once
27
+ expect(spy).to receive(:after).with(BankAccount, spy, account, other, amount).ordered.once
28
+
29
+ expect(BankAccount.transfer(spy, account, other, amount)).to eq(:a_result)
30
+ end
31
+ end
32
+
33
+ describe "multiple classes, methods and advices" do
34
+ before do
35
+ Aop["BankAccount,CashAccount#transfer,#withdraw,.transfer:before,:after"].advice do |*args, &blk|
36
+ spy.report(*args, &blk)
37
+ end
38
+ end
39
+
40
+ it "works for BankAccount#transfer" do
41
+ account = BankAccount.new(spy)
42
+ other = BankAccount.new(spy)
43
+ amount = 55
44
+
45
+ expect(spy).to receive(:report).with(account, other, amount).ordered.once
46
+ expect(spy).to receive(:inside).with(other, amount).ordered.once
47
+ expect(spy).to receive(:report).with(account, other, amount).ordered.once
48
+
49
+ expect(account.transfer(other, amount)).to eq(:a_result)
50
+ end
51
+
52
+ it "works for CashAccount#transfer" do
53
+ account = CashAccount.new(spy)
54
+ other = CashAccount.new(spy)
55
+ amount = 55
56
+
57
+ expect(spy).to receive(:report).with(account, other, amount).ordered.once
58
+ expect(spy).to receive(:inside).with(:cash_account, other, amount).ordered.once
59
+ expect(spy).to receive(:report).with(account, other, amount).ordered.once
60
+
61
+ expect(account.transfer(other, amount)).to eq(:a_result)
62
+ end
63
+
64
+ it "works for BankAccount#withdraw" do
65
+ account = BankAccount.new(spy)
66
+ amount = 55
67
+
68
+ expect(spy).to receive(:report).with(account, amount).ordered.once
69
+ expect(spy).to receive(:withdraw).with(account, amount).ordered.once
70
+ expect(spy).to receive(:report).with(account, amount).ordered.once
71
+
72
+ expect(account.withdraw(amount)).to eq(:a_result)
73
+ end
74
+
75
+ it "works for CashAccount#withdraw" do
76
+ account = CashAccount.new(spy)
77
+ amount = 55
78
+
79
+ expect(spy).to receive(:report).with(account, amount).ordered.once
80
+ expect(spy).to receive(:withdraw).with(:cash_account, account, amount).ordered.once
81
+ expect(spy).to receive(:report).with(account, amount).ordered.once
82
+
83
+ expect(account.withdraw(amount)).to eq(:a_result)
84
+ end
85
+
86
+ it "works for BankAccount.transfer" do
87
+ account = BankAccount.new(spy)
88
+ other = BankAccount.new(spy)
89
+ amount = 55
90
+
91
+ expect(spy).to receive(:report).with(BankAccount, spy, account, other, amount).ordered.once
92
+ expect(spy).to receive(:inside).with(spy, account, other, amount).ordered.once
93
+ expect(spy).to receive(:report).with(BankAccount, spy, account, other, amount).ordered.once
94
+
95
+ expect(BankAccount.transfer(spy, account, other, amount)).to eq(:a_result)
96
+ end
97
+
98
+ it "works for CashAccount.transfer" do
99
+ account = CashAccount.new(spy)
100
+ other = CashAccount.new(spy)
101
+ amount = 55
102
+
103
+ expect(spy).to receive(:report).with(CashAccount, spy, account, other, amount).ordered.once
104
+ expect(spy).to receive(:inside).with(:cash_account, spy, account, other, amount).ordered.once
105
+ expect(spy).to receive(:report).with(CashAccount, spy, account, other, amount).ordered.once
106
+
107
+ expect(CashAccount.transfer(spy, account, other, amount)).to eq(:a_result)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,27 @@
1
+ RSpec.describe "Around advice" do
2
+ include FixtureLoader
3
+
4
+ let(:spy) { double("Spy") }
5
+
6
+ before do
7
+ load_fixture("BankAccount", "bank_account")
8
+
9
+ Aop["BankAccount#transfer:around"].advice do |joint_point, account, *args, &blk|
10
+ spy.before(account, *args, &blk)
11
+ joint_point.call
12
+ spy.after(account, *args, &blk)
13
+ end
14
+ end
15
+
16
+ it "fires around #transfer" do
17
+ account = BankAccount.new(spy)
18
+ other = BankAccount.new(spy)
19
+ amount = 55
20
+
21
+ expect(spy).to receive(:before).with(account, other, amount).ordered.once
22
+ expect(spy).to receive(:inside).with(other, amount).ordered.once
23
+ expect(spy).to receive(:after).with(account, other, amount).ordered.once
24
+
25
+ expect(account.transfer(other, amount)).to eq(:a_result)
26
+ end
27
+ end
@@ -3,4 +3,14 @@ class BankAccount < Struct.new(:spy)
3
3
  spy.inside(to, amount)
4
4
  :a_result
5
5
  end
6
+
7
+ def withdraw(amount)
8
+ spy.withdraw(self, amount)
9
+ :a_result
10
+ end
11
+
12
+ def self.transfer(spy, from, to, amount)
13
+ spy.inside(spy, from, to, amount)
14
+ :a_result
15
+ end
6
16
  end
@@ -0,0 +1,16 @@
1
+ class CashAccount < Struct.new(:spy)
2
+ def transfer(to, amount)
3
+ spy.inside(:cash_account, to, amount)
4
+ :a_result
5
+ end
6
+
7
+ def withdraw(amount)
8
+ spy.withdraw(:cash_account, self, amount)
9
+ :a_result
10
+ end
11
+
12
+ def self.transfer(spy, from, to, amount)
13
+ spy.inside(:cash_account, spy, from, to, amount)
14
+ :a_result
15
+ end
16
+ end
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: 0.0.2
4
+ version: 0.1.0
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-02-07 00:00:00.000000000 Z
11
+ date: 2015-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,9 +56,12 @@ files:
56
56
  - lib/aop.rb
57
57
  - lib/aop/pointcut.rb
58
58
  - lib/aop/version.rb
59
+ - spec/aop/advanced_spec.rb
59
60
  - spec/aop/after_spec.rb
61
+ - spec/aop/around_spec.rb
60
62
  - spec/aop/before_spec.rb
61
63
  - spec/fixtures/bank_account.rb
64
+ - spec/fixtures/cash_account.rb
62
65
  - spec/spec_helper.rb
63
66
  - spec/support/loader.rb
64
67
  homepage: https://github.com/waterlink/aop
@@ -86,8 +89,11 @@ signing_key:
86
89
  specification_version: 4
87
90
  summary: Very thin AOP gem for Ruby
88
91
  test_files:
92
+ - spec/aop/advanced_spec.rb
89
93
  - spec/aop/after_spec.rb
94
+ - spec/aop/around_spec.rb
90
95
  - spec/aop/before_spec.rb
91
96
  - spec/fixtures/bank_account.rb
97
+ - spec/fixtures/cash_account.rb
92
98
  - spec/spec_helper.rb
93
99
  - spec/support/loader.rb