ruby_dci 0.2.0 → 0.3.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 +5 -5
- data/CHANGELOG.md +13 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +19 -1
- data/README.md +12 -11
- data/lib/dci/accessor.rb +4 -0
- data/lib/dci/configuration.rb +10 -8
- data/lib/dci/context.rb +13 -5
- data/lib/dci/event_router.rb +4 -5
- data/lib/dci/null_transaction.rb +2 -0
- data/lib/dci/version.rb +3 -1
- data/lib/dci.rb +5 -1
- data/ruby_dci.gemspec +0 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a61a836ec90dab9c17d7f88cfd866ac24fd7e4ca
|
4
|
+
data.tar.gz: 892f6b68acb2b87b6ef653c6c19860b3eac95c37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f81879bf07b9d8d4c335f9e7c53783edaf19d0cc3e1f0b6abf5f26d11edd3f696bfacd017925778f9d7b7fb93abc3258af419e27481f7cb5d0689e8c7430277
|
7
|
+
data.tar.gz: 888c5768b1f5c9d35454173eb91103ce3ad40914cb39f99e22b4898190e3b084fd033f3703d16b5eb725f39cc79ad03fc9c3be6ae2b40cafb06b663d2b74c89b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## 0.3.0 (2018-05-24)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Renamed `DCI::Configuration` accessors. `event_routes` is now `routes`, `route_methods` is now `router`, `raise_in_event_router` is now `raise_in_router`.
|
6
|
+
- `events` is not an instance variable defined in the context anymore, but has the same access style like the `context` itself. In the role don't push events to `context.events`, but to `context_events`.
|
7
|
+
|
8
|
+
Bugfixes:
|
9
|
+
|
10
|
+
- Added specs
|
11
|
+
- Added `README.md`
|
12
|
+
- Added `CHANGELOG.md`
|
13
|
+
|
1
14
|
## 0.2.0 (2018-05-19)
|
2
15
|
|
3
16
|
Features:
|
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{ repo_name }" }
|
4
|
+
|
5
|
+
gem "coveralls", require: false
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in ruby_dci.gemspec
|
6
8
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ruby_dci (0.
|
4
|
+
ruby_dci (0.3.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
coderay (1.1.2)
|
10
|
+
coveralls (0.8.21)
|
11
|
+
json (>= 1.8, < 3)
|
12
|
+
simplecov (~> 0.14.1)
|
13
|
+
term-ansicolor (~> 1.3)
|
14
|
+
thor (~> 0.19.4)
|
15
|
+
tins (~> 1.6)
|
10
16
|
diff-lcs (1.3)
|
17
|
+
docile (1.1.5)
|
18
|
+
json (2.1.0)
|
11
19
|
method_source (0.9.0)
|
12
20
|
pry (0.11.3)
|
13
21
|
coderay (~> 1.1.0)
|
@@ -26,12 +34,22 @@ GEM
|
|
26
34
|
diff-lcs (>= 1.2.0, < 2.0)
|
27
35
|
rspec-support (~> 3.7.0)
|
28
36
|
rspec-support (3.7.1)
|
37
|
+
simplecov (0.14.1)
|
38
|
+
docile (~> 1.1.0)
|
39
|
+
json (>= 1.8, < 3)
|
40
|
+
simplecov-html (~> 0.10.0)
|
41
|
+
simplecov-html (0.10.2)
|
42
|
+
term-ansicolor (1.6.0)
|
43
|
+
tins (~> 1.0)
|
44
|
+
thor (0.19.4)
|
45
|
+
tins (1.16.3)
|
29
46
|
|
30
47
|
PLATFORMS
|
31
48
|
ruby
|
32
49
|
|
33
50
|
DEPENDENCIES
|
34
51
|
bundler (~> 1.16)
|
52
|
+
coveralls
|
35
53
|
pry (~> 0.11.3)
|
36
54
|
rake (~> 10.0)
|
37
55
|
rspec (~> 3.0)
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
[](https://travis-ci.org/egze/ruby_dci)
|
2
|
+
[](https://coveralls.io/github/egze/ruby_dci?branch=master)
|
2
3
|
|
3
4
|
# RubyDci
|
4
5
|
|
@@ -9,7 +10,7 @@ A classic DCI implementation for ruby with some extra sugar. I've been using DCI
|
|
9
10
|
Add this line to your application's Gemfile:
|
10
11
|
|
11
12
|
```ruby
|
12
|
-
gem 'ruby_dci'
|
13
|
+
gem 'ruby_dci', require: 'dci'
|
13
14
|
```
|
14
15
|
|
15
16
|
And then execute:
|
@@ -43,8 +44,8 @@ I configure the gem in `config/initializers/dci_configuration.rb`.
|
|
43
44
|
|
44
45
|
```ruby
|
45
46
|
DCI.configure do |config|
|
46
|
-
config.
|
47
|
-
config.
|
47
|
+
config.routes = Hash.new([])
|
48
|
+
config.router = EventRouter.new
|
48
49
|
config.transaction_class = ApplicationRecord
|
49
50
|
config.raise_in_event_router = !Rails.env.production?
|
50
51
|
config.on_exception_in_router = -> (exception) {}
|
@@ -55,7 +56,7 @@ end
|
|
55
56
|
|
56
57
|
Usually you want your code to run in a transaction. Either everything runs fine, or nothing is saved. This is done by wrapping the executed code in a transaction block. I use ActiveRecord, but you can use whatever you want. Your class just needs to implement a `transaction` method that takes a block. If you don't want any transactions, you can either skip `config.transaction_class` completely, or set it to `DCI::NullTransaction`.
|
57
58
|
|
58
|
-
### config.
|
59
|
+
### config.routes
|
59
60
|
|
60
61
|
This is your mapping of events that may happen in the context. Key is a class name, and the value is an array of method names. Example:
|
61
62
|
|
@@ -65,7 +66,7 @@ This is your mapping of events that may happen in the context. Key is a class na
|
|
65
66
|
}
|
66
67
|
```
|
67
68
|
|
68
|
-
The system will know that it needs to execute `send_product_added_notification` from `config.route_methods` for every event of class `DomainEvents::ProductAddedToCart`. If you don't have any actions that you need to perform after a transaction,
|
69
|
+
The system will know that it needs to execute `send_product_added_notification` from `config.route_methods` for every event of class `DomainEvents::ProductAddedToCart`. If you don't have any actions that you need to perform after a transaction, then just skip `config.event_routes` completely or set it to `Hash.new([])`.
|
69
70
|
|
70
71
|
I implement events as plain ruby Structs. Example:
|
71
72
|
|
@@ -79,12 +80,12 @@ end
|
|
79
80
|
|
80
81
|
Why do I do it like this? It makes it easier to add other callbacks later. I can do it in one place instead of searching through hundreds of files. Also makes testing easier.
|
81
82
|
|
82
|
-
### config.
|
83
|
+
### config.router
|
83
84
|
|
84
|
-
This is a class that implements the methods for the `config.
|
85
|
+
This is a class that implements the methods for the `config.routes` mapping. Example:
|
85
86
|
|
86
87
|
```ruby
|
87
|
-
class
|
88
|
+
class EventRouter
|
88
89
|
|
89
90
|
def send_product_added_notification(event)
|
90
91
|
AddedToCartNotificationJob.perform_later(id: event.product.id)
|
@@ -106,7 +107,7 @@ config.raise_in_event_router = !Rails.env.production?
|
|
106
107
|
In case there is an exception in the event router, you can provide a handler for the exception. It should be a lambda that receives an exception as a parameter. You can use it to log the exception. If you don't need any logging, just skip `config.on_exception_in_router` completely, or assign an empty lambda.
|
107
108
|
|
108
109
|
```ruby
|
109
|
-
config.
|
110
|
+
config.on_exception_in_router = -> (exception) { Rails.logger.error(exception) }
|
110
111
|
```
|
111
112
|
|
112
113
|
|
@@ -142,7 +143,7 @@ Couple of thigs to keep in mind:
|
|
142
143
|
|
143
144
|
### Role
|
144
145
|
|
145
|
-
In a Rails app I put my roles in `app/roles`. Roles are plain ruby modules. You define a role by including `DCI::Role`.
|
146
|
+
In a Rails app I put my roles in `app/roles`. Roles are plain ruby modules. You define a role by including `DCI::Role`. A role has access to the `context` and to the `context_events` methods. You can push events to `context_events` to process them after the transaction.
|
146
147
|
|
147
148
|
```ruby
|
148
149
|
module Customer
|
@@ -153,7 +154,7 @@ module Customer
|
|
153
154
|
# do your thing
|
154
155
|
|
155
156
|
# add event to the context
|
156
|
-
|
157
|
+
context_events << DomainEvents::ProductAddedToCart.new(product)
|
157
158
|
end
|
158
159
|
|
159
160
|
end
|
data/lib/dci/accessor.rb
CHANGED
data/lib/dci/configuration.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
module DCI
|
2
2
|
class Configuration
|
3
|
+
|
3
4
|
attr_accessor :transaction_class,
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
5
|
+
:routes,
|
6
|
+
:router,
|
7
|
+
:on_exception_in_router,
|
8
|
+
:raise_in_router
|
8
9
|
|
9
10
|
def initialize
|
10
11
|
@transaction_class = NullTransaction
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@on_exception_in_router = -> (exception) {
|
12
|
+
@routes = Hash.new([])
|
13
|
+
@router = nil
|
14
|
+
@raise_in_router = false
|
15
|
+
@on_exception_in_router = -> (exception) {}
|
15
16
|
end
|
17
|
+
|
16
18
|
end
|
17
19
|
end
|
data/lib/dci/context.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module DCI
|
2
|
-
|
3
2
|
module Context
|
4
3
|
|
5
4
|
include EventRouter
|
@@ -16,8 +15,10 @@ module DCI
|
|
16
15
|
|
17
16
|
def perform_in_transaction
|
18
17
|
old_context = context
|
19
|
-
|
18
|
+
old_context_events = context_events
|
19
|
+
|
20
20
|
self.context = self
|
21
|
+
self.context_events = []
|
21
22
|
|
22
23
|
res = nil
|
23
24
|
|
@@ -25,33 +26,40 @@ module DCI
|
|
25
26
|
res = call
|
26
27
|
end
|
27
28
|
|
28
|
-
route_events!(
|
29
|
+
route_events!(context_events)
|
29
30
|
res
|
30
31
|
ensure
|
31
32
|
self.context = old_context
|
32
|
-
self.
|
33
|
+
self.context_events = old_context_events
|
33
34
|
end
|
34
35
|
|
35
36
|
def context=(ctx)
|
36
37
|
Thread.current[:context] = ctx
|
37
38
|
end
|
38
39
|
|
40
|
+
def context_events=(ctx_events = [])
|
41
|
+
Thread.current[:context_events] = Array(ctx_events).compact.flatten
|
42
|
+
end
|
43
|
+
|
39
44
|
def call
|
40
45
|
raise NotImplementedError.new("implement me")
|
41
46
|
end
|
42
47
|
|
43
48
|
private
|
49
|
+
|
44
50
|
def init_context_events
|
45
51
|
[]
|
46
52
|
end
|
53
|
+
|
47
54
|
end
|
48
55
|
|
49
56
|
module ClassMethods
|
57
|
+
|
50
58
|
def call(*args)
|
51
59
|
new(*args).perform_in_transaction
|
52
60
|
end
|
61
|
+
|
53
62
|
end
|
54
63
|
|
55
64
|
end
|
56
|
-
|
57
65
|
end
|
data/lib/dci/event_router.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module DCI
|
2
|
-
|
3
2
|
module EventRouter
|
4
3
|
|
5
4
|
def route_events!(events)
|
@@ -7,10 +6,11 @@ module DCI
|
|
7
6
|
end
|
8
7
|
|
9
8
|
private
|
9
|
+
|
10
10
|
def route_event!(event)
|
11
|
-
DCI.configuration.
|
11
|
+
DCI.configuration.routes[event.class].each do |callback|
|
12
12
|
dispatch_catching_standard_errors do
|
13
|
-
DCI.configuration.
|
13
|
+
DCI.configuration.router.send(callback, event)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -21,10 +21,9 @@ module DCI
|
|
21
21
|
rescue StandardError => exception
|
22
22
|
DCI.configuration.on_exception_in_router.call(exception) rescue nil
|
23
23
|
|
24
|
-
raise exception if DCI.configuration.
|
24
|
+
raise exception if DCI.configuration.raise_in_router
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
29
|
-
|
30
29
|
end
|
data/lib/dci/null_transaction.rb
CHANGED
data/lib/dci/version.rb
CHANGED
data/lib/dci.rb
CHANGED
@@ -7,8 +7,11 @@ require "dci/context"
|
|
7
7
|
require "dci/role"
|
8
8
|
|
9
9
|
module DCI
|
10
|
+
|
10
11
|
class << self
|
11
|
-
|
12
|
+
|
13
|
+
#attr_accessor :configuration
|
14
|
+
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.configuration
|
@@ -22,4 +25,5 @@ module DCI
|
|
22
25
|
def self.configure
|
23
26
|
yield(configuration)
|
24
27
|
end
|
28
|
+
|
25
29
|
end
|
data/ruby_dci.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_dci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksandr Lossenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
117
|
rubyforge_project:
|
118
|
-
rubygems_version: 2.
|
118
|
+
rubygems_version: 2.6.13
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: Opinionated DCI implementation for ruby.
|