akasha 0.0.1 → 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: 01eaf484143fe6572ed3efe8338c2b2fb1251bf2
4
- data.tar.gz: 99b1cfb52b4cb781dd83b2c711d22cbb1ff27ace
3
+ metadata.gz: 1294447dab3ae4202502a232dcc069d06dcdbf5d
4
+ data.tar.gz: 296cfc35578c3f15a90d55f0f0ed1db018458541
5
5
  SHA512:
6
- metadata.gz: f67f3ffbe4d1e75c4c514cff8770f8d8aa95948bafc8241bd1161d27e660765d2de0036d6578e7be60a3cc05f8bd1899400ad24b4461cc85d2b5fd36095ec3a0
7
- data.tar.gz: 447548998189e251c818d4ab8dfb88b71b85e31aa5e70934d22fa6498b8703ba269ca331d71dde6c0f2936330b231c23dbfaf341b0533a78dabec0b98970e898
6
+ metadata.gz: 0b177423fce21ab067cee6c37f0d50e1d132056611791af3af17c56b2b8a2ba6ea20d76a11462e99459814b1ce24259ea86d01bc794818110da1ea49283fcbbc
7
+ data.tar.gz: 3cbe93b9aeafeca8b3541d01feaacfb6bdd0395bf3ed92d9be73a5ee7df3dfdb593deb8ad55e9d9647748f51a069ae881c9fd970aa473fc73f5087f63d012c3e
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1,49 @@
1
+ # Enables Travis to use their new container-based infrastructure
2
+ sudo: false
3
+
4
+ # Build for Ruby
5
+ language: ruby
6
+
7
+ # Enables caching for bundler
8
+ cache: bundler
9
+
10
+ # Passes arguments to bundle install (http://gembundler.com/man/bundle-install.1.html)
11
+ # bundler_args:
12
+
13
+ before_install:
14
+ - gem update --system
15
+ - gem update bundler
16
+
17
+ # Specify which ruby versions you wish to run your tests on, each version will be used
18
+ rvm:
19
+ - 2.2.9
20
+ - 2.3.6
21
+ - 2.4.3
22
+ - 2.5.0
23
+
24
+ # Define how to run your tests (defaults to `bundle exec rake` or `rake` depending on whether you have a `Gemfile`)
25
+ script: "bundle exec rake"
26
+
27
+ # Define tasks to be completed before and after tests run . Will allow folding of content on frontend
28
+ #before_script:
29
+ # - command_1
30
+ # - command_2
31
+ #
32
+ #after_script:
33
+ # - command_1
34
+ # - command_2
35
+
36
+ # Specify the recipients for email notification
37
+ #notifications:
38
+ # recipients:
39
+ # - email-address-1
40
+ # - email-address-2
41
+
42
+ # Disable email notifications
43
+ #notifications:
44
+ # disabled: true
45
+
46
+ # notifications:
47
+ # webhooks:
48
+ # urls:
49
+ # - https://webhooks.gitter.im/e/c6dbb9323007dfcf81df
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+
4
+ ## Version 0.1.0
5
+
6
+ * Cleaner syntax for adding events to changesets: `changeset.append(:it_happened, foo: 'bar')`.
7
+ * Support for command routing (`Akasha::CommandRouter`).
8
+
9
+
10
+ ## Version 0.0.1
11
+
12
+ Initial release, basic functionality.
@@ -1,12 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- akasha (0.0.1)
4
+ akasha (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ byebug (10.0.2)
10
+ coderay (1.1.2)
9
11
  diff-lcs (1.3)
12
+ method_source (0.9.0)
13
+ pry (0.11.3)
14
+ coderay (~> 1.1.0)
15
+ method_source (~> 0.9.0)
16
+ pry-byebug (3.6.0)
17
+ byebug (~> 10.0)
18
+ pry (~> 0.10)
10
19
  rake (10.5.0)
11
20
  rspec (3.7.0)
12
21
  rspec-core (~> 3.7.0)
@@ -29,6 +38,7 @@ PLATFORMS
29
38
  DEPENDENCIES
30
39
  akasha!
31
40
  bundler (~> 1.16)
41
+ pry-byebug
32
42
  rake (~> 10.0)
33
43
  rspec (~> 3.7)
34
44
  timecop
data/README.md CHANGED
@@ -20,31 +20,51 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ The code below uses Sinatra to demonstrate how to use the library in a web application.
24
+ This library makes no assumptions about any web framework, you can use it in any way you see fit.
25
+
23
26
  ```ruby
24
27
  require 'akasha'
25
-
28
+ require 'sinatra'
26
29
 
27
30
  class User < Akasha::Aggregate
28
- def sign_up(email, password)
29
- changeset << Akasha::Event.new(:user_signed_up, email: email, password: password)
31
+ def sign_up(email:, password:, admin: false, **)
32
+ changeset << Akasha::Event.new(:user_signed_up, email: email, password: password, admin: admin)
30
33
  end
31
34
 
32
- def on_user_signed_up(email:, password:, **_)
35
+ def on_user_signed_up(email:, password:, admin:, **)
33
36
  @email = email
34
37
  @password = password
38
+ @admin = admin
35
39
  end
36
40
  end
37
41
 
38
- def initialize
39
- repository = Akasha::Repository.new(Akasha::Storage::MemoryEventStore.new)
40
- Akasha::Aggregate.connect!(repository)
42
+
43
+ before do
44
+ @router = Akasha::CommandRouter.new
45
+
46
+ # Aggregates will load from and save to in-memory storage.
47
+ repository = Akasha::Repository.new(Akasha::Storage::MemoryEventStore.new)
48
+ Akasha::Aggregate.connect!(repository)
49
+
50
+ # This is how you link commands to aggregates.
51
+ @router.register_default_route(:sign_up, User)
52
+
53
+ # Nearly identital to the default handling above but we're setting the admin
54
+ # flag to demo custom command handling.
55
+ @router.register_route(:sign_up_admin) do |aggregate_id, **data|
56
+ user = User.find_or_create(aggregate_id)
57
+ user.sign_up(email: data[:email], password: data[:password], admin: true)
58
+ user.save!
59
+ end
41
60
  end
42
61
 
43
- def handle_sign_up_command(params)
44
- user = User.find_or_create(params[:id])
45
- user.email = params[:email]
46
- user.password = params[:password]
47
- user.save!
62
+ post '/users/:user_id' do # With CQRS client pass unique aggregate ids.
63
+ @router.route!(:sign_up,
64
+ params[:user_id],
65
+ email: params[:email],
66
+ password: params[:password])
67
+ 'OK'
48
68
  end
49
69
  ```
50
70
 
@@ -52,7 +72,7 @@ end
52
72
 
53
73
  ## Next steps
54
74
 
55
- - [ ] Command routing (default and user-defined)
75
+ - [x] Command routing (default and user-defined)
56
76
  - [ ] EventHandler (relying only on Eventstore)
57
77
  - [ ] HTTP Eventstore storage backend
58
78
  - [ ] Namespacing for events and aggregates
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency 'rake', '~> 10.0'
28
28
  spec.add_development_dependency 'rspec', '~> 3.7'
29
29
  spec.add_development_dependency 'timecop'
30
+ spec.add_development_dependency 'pry-byebug'
30
31
  end
@@ -1,4 +1,5 @@
1
1
  require 'akasha/event'
2
2
  require 'akasha/aggregate'
3
+ require 'akasha/command_router'
3
4
  require 'akasha/repository'
4
5
  require 'akasha/storage/memory_event_store'
@@ -8,7 +8,7 @@ module Akasha
8
8
  #
9
9
  # class User < Akasha::Aggregate
10
10
  # def sign_up(email, password)
11
- # changeset << Akasha::Event.new(:user_signed_up, email: email, password: password)
11
+ # changeset.append(:user_signed_up, email: email, password: password)
12
12
  # end
13
13
  #
14
14
  # def on_user_signed_up(email:, password:, **_)
@@ -38,7 +38,9 @@ module Akasha
38
38
  module InstanceMethods
39
39
  # Saves the aggregate.
40
40
  def save!
41
+ return if changeset.empty?
41
42
  self.class.repository.save_aggregate(self)
43
+ changeset.clear!
42
44
  end
43
45
  end
44
46
  end
@@ -10,8 +10,18 @@ module Akasha
10
10
  end
11
11
 
12
12
  # Adds an event to the changeset.
13
- def <<(event)
14
- @events << event
13
+ def append(event_name, **data)
14
+ @events << Akasha::Event.new(event_name, **data)
15
+ end
16
+
17
+ # Returns true if no changes recorded.
18
+ def empty?
19
+ @events.empty?
20
+ end
21
+
22
+ # Clears the changeset.
23
+ def clear!
24
+ @events = []
15
25
  end
16
26
  end
17
27
  end
@@ -0,0 +1,36 @@
1
+ require_relative 'command_router/default_handler'
2
+
3
+ module Akasha
4
+ # Routes commands to their handlers.
5
+ class CommandRouter
6
+ # Raised when no corresponding target can be found for a command.
7
+ NotFoundError = Class.new(RuntimeError)
8
+
9
+ def initialize
10
+ @routes = {}
11
+ end
12
+
13
+ # Registers a custom route, specifying either a lambda or a block.
14
+ # If both lambda and block are specified, lambda takes precedence.
15
+ def register_route(command, lambda = nil, &block)
16
+ callable = lambda || block
17
+ @routes[command] = callable
18
+ end
19
+
20
+ # Registers a default route, mapping a command to an aggregate class.
21
+ # As a result, when `#route!` is called for that command, the aggregate
22
+ # will be loaded from repository, the command will be sent to the object
23
+ # to invoke the object's method, and finally the aggregate will be saved.
24
+ def register_default_route(command, aggregate_class)
25
+ register_route(command, DefaultHandler.new(aggregate_class))
26
+ end
27
+
28
+ # Routes a command to the registered target.
29
+ # Raises NotFoundError if no corresponding target can be found.
30
+ def route!(command, aggregate_id, **data)
31
+ handler = @routes[command]
32
+ return handler.call(command, aggregate_id, **data) if handler
33
+ raise NotFoundError, "Target for command #{command.inspect} not found"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module Akasha
2
+ class CommandRouter
3
+ # Default command handler.
4
+ # Works by loading aggregate from the repo by id,
5
+ # invoking its method `command`, passing all data,
6
+ # and saving changes to the aggregate in the end.
7
+ class DefaultHandler
8
+ def initialize(klass)
9
+ @klass = klass
10
+ end
11
+
12
+ def call(command, aggregate_id, **data)
13
+ aggregate = @klass.find_or_create(aggregate_id)
14
+ aggregate.public_send(command, **data)
15
+ aggregate.save!
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Akasha
2
- VERSION='0.0.1'
2
+ VERSION='0.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: akasha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcin Bilski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-03 00:00:00.000000000 Z
11
+ date: 2018-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  description: A simple CQRS library for Ruby.
70
84
  email:
71
85
  - marcin@tooploox.com
@@ -74,8 +88,11 @@ extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
90
  - ".gitignore"
91
+ - ".rspec"
77
92
  - ".rubocop.yml"
78
93
  - ".ruby-version"
94
+ - ".travis.yml"
95
+ - CHANGELOG.md
79
96
  - Gemfile
80
97
  - Gemfile.lock
81
98
  - LICENSE.txt
@@ -88,6 +105,8 @@ files:
88
105
  - lib/akasha/aggregate.rb
89
106
  - lib/akasha/aggregate/syntax_helpers.rb
90
107
  - lib/akasha/changeset.rb
108
+ - lib/akasha/command_router.rb
109
+ - lib/akasha/command_router/default_handler.rb
91
110
  - lib/akasha/event.rb
92
111
  - lib/akasha/repository.rb
93
112
  - lib/akasha/storage/memory_event_store.rb