event_sourcery_generators 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +35 -0
- data/Rakefile +6 -0
- data/bin/eventsourcery +4 -0
- data/event_sourcery_generators.gemspec +27 -0
- data/lib/event_sourcery_generators.rb +5 -0
- data/lib/event_sourcery_generators/cli.rb +20 -0
- data/lib/event_sourcery_generators/generators/command.rb +86 -0
- data/lib/event_sourcery_generators/generators/project.rb +70 -0
- data/lib/event_sourcery_generators/generators/query.rb +51 -0
- data/lib/event_sourcery_generators/generators/reactor.rb +41 -0
- data/lib/event_sourcery_generators/generators/templates/command/aggregate.rb.tt +8 -0
- data/lib/event_sourcery_generators/generators/templates/command/aggregate/apply_event_method.rb.tt +6 -0
- data/lib/event_sourcery_generators/generators/templates/command/aggregate/command_method.rb.tt +11 -0
- data/lib/event_sourcery_generators/generators/templates/command/api_endpoint.rb.tt +6 -0
- data/lib/event_sourcery_generators/generators/templates/command/command.rb.tt +40 -0
- data/lib/event_sourcery_generators/generators/templates/command/event.rb.tt +1 -0
- data/lib/event_sourcery_generators/generators/templates/project/app.json.tt +16 -0
- data/lib/event_sourcery_generators/generators/templates/project/config.ru.tt +6 -0
- data/lib/event_sourcery_generators/generators/templates/project/environment.rb.tt +64 -0
- data/lib/event_sourcery_generators/generators/templates/project/gemfile.tt +19 -0
- data/lib/event_sourcery_generators/generators/templates/project/procfile.tt +2 -0
- data/lib/event_sourcery_generators/generators/templates/project/rakefile.tt +69 -0
- data/lib/event_sourcery_generators/generators/templates/project/readme.md.tt +39 -0
- data/lib/event_sourcery_generators/generators/templates/project/request_helpers.rb.tt +10 -0
- data/lib/event_sourcery_generators/generators/templates/project/script_server.tt +7 -0
- data/lib/event_sourcery_generators/generators/templates/project/script_setup.tt +22 -0
- data/lib/event_sourcery_generators/generators/templates/project/server.rb.tt +59 -0
- data/lib/event_sourcery_generators/generators/templates/project/spec_helper.rb.tt +38 -0
- data/lib/event_sourcery_generators/generators/templates/query/api_endpoint.rb.tt +7 -0
- data/lib/event_sourcery_generators/generators/templates/query/projector.rb.tt +40 -0
- data/lib/event_sourcery_generators/generators/templates/query/projector_process.tt +4 -0
- data/lib/event_sourcery_generators/generators/templates/query/query.rb.tt +11 -0
- data/lib/event_sourcery_generators/generators/templates/reactor/reactor.rb.tt +42 -0
- data/lib/event_sourcery_generators/generators/templates/reactor/reactor_process.tt +4 -0
- data/lib/event_sourcery_generators/version.rb +3 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0bd36fd327e879aab367ddb7735f380114ab5e62
|
4
|
+
data.tar.gz: ec0daa66a01178d180b03f24763c9c769542991a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: af41b94266b367488bc505d558bfff155a0c02b551c85737f5da1515c6eeb0bd6ac629cdb4dfb5b0ce48d1bd9cd6e9ef5369b46a39c8d1da05da2a7170041602
|
7
|
+
data.tar.gz: '094c8926a14ffe7beca942bf1816b7352ad491fbcd14f5259862c71bc2390258c06ed18ccb88ff60fdd36185518a27df26a21ae39e18dd70079093aaaa389f60'
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at odindutton@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Envato
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# EventSourcery Generators
|
2
|
+
|
3
|
+
An opinionated CLI tool for building event sourced systems with EventSourcery.
|
4
|
+
|
5
|
+
## Getting started
|
6
|
+
|
7
|
+
Generate a new event sourcery application:
|
8
|
+
|
9
|
+
```sh
|
10
|
+
$ eventsourcery new recipe_book
|
11
|
+
```
|
12
|
+
|
13
|
+
Generate a new aggregate, command and event:
|
14
|
+
|
15
|
+
```sh
|
16
|
+
$ eventsourcery generate:command recipe add
|
17
|
+
```
|
18
|
+
|
19
|
+
Generate a query and projection that subscribes to events:
|
20
|
+
|
21
|
+
```sh
|
22
|
+
$ eventsourcery generate:query active_recipes recipe_added
|
23
|
+
```
|
24
|
+
|
25
|
+
Generate a reactor that subscribes to events:
|
26
|
+
|
27
|
+
```sh
|
28
|
+
$ eventsourcery generate:reactor recipe_publisher recipe_added recipe_deleted
|
29
|
+
```
|
30
|
+
|
31
|
+
## References
|
32
|
+
|
33
|
+
For more information, check out the `event_sourcery` repository here:
|
34
|
+
<https://github.com/envato/event_sourcery>
|
35
|
+
|
data/Rakefile
ADDED
data/bin/eventsourcery
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'event_sourcery_generators/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'event_sourcery_generators'
|
8
|
+
spec.version = EventSourceryGenerators::VERSION
|
9
|
+
spec.authors = ['Sebastian von Conrad', 'Pablo Lee', 'Chun-wei Kuo', 'Giancarlo Salamanca']
|
10
|
+
spec.email = ['sebastian.von.conrad@envato.com', 'pablo.lee@envato.com', 'chun-wei.kuo@envato.com', 'giancarlo.salamanca@envato.com']
|
11
|
+
|
12
|
+
spec.summary = 'Generators for EventSourcery'
|
13
|
+
spec.description = 'An opinionated CLI tool for building event-sourced Ruby services with EventSourcery'
|
14
|
+
spec.homepage = 'https://github.com/envato/event_sourcery_generators'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'thor', '~> 0.19'
|
22
|
+
spec.add_dependency 'activesupport', '~> 5.1'
|
23
|
+
spec.add_dependency 'verbs', '~> 2.1'
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
25
|
+
spec.add_development_dependency 'rake', '~> 11.2'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.6'
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'verbs'
|
4
|
+
|
5
|
+
require 'event_sourcery_generators/generators/project'
|
6
|
+
require 'event_sourcery_generators/generators/command'
|
7
|
+
require 'event_sourcery_generators/generators/query'
|
8
|
+
require 'event_sourcery_generators/generators/reactor'
|
9
|
+
|
10
|
+
module EventSourceryGenerators
|
11
|
+
class CLI < Thor
|
12
|
+
# Creating projects
|
13
|
+
register(Generators::Project, 'new', 'new [PROJECT NAME]', 'Creates a new EventSourcery project')
|
14
|
+
|
15
|
+
# Creating components inside a project
|
16
|
+
register(Generators::Command, 'generate:command', 'generate:command [AGGREGATE] [COMMAND]', 'Generates a new COMMAND for AGGREGATE')
|
17
|
+
register(Generators::Query, 'generate:query', 'generate:query [NAME] [EVENT1 EVENT2 ...]', 'Generates a new query with the name NAME and an optional list of EVENTs to subscribe to')
|
18
|
+
register(Generators::Reactor, 'generate:reactor', 'generate:reactor NAME [EVENT1 EVENT2 ...]', 'Generates a new Reactor with the name NAME and an optional list of EVENTs to subscribe to')
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module EventSourceryGenerators
|
2
|
+
module Generators
|
3
|
+
class Command < Thor::Group
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
argument :aggregate
|
7
|
+
argument :command
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
File.join(File.dirname(__FILE__), 'templates/command')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_or_inject_into_aggregate_file
|
14
|
+
aggregate_file = "app/aggregates/#{aggregate_name}.rb"
|
15
|
+
|
16
|
+
@command_method = erb_file('aggregate/command_method.rb.tt')
|
17
|
+
@apply_event_method = erb_file('aggregate/apply_event_method.rb.tt')
|
18
|
+
|
19
|
+
if File.exist?(aggregate_file)
|
20
|
+
insert_into_file(aggregate_file, @command_method, after: "include EventSourcery::AggregateRoot\n")
|
21
|
+
insert_into_file(aggregate_file, @apply_event_method, after: "include EventSourcery::AggregateRoot\n")
|
22
|
+
else
|
23
|
+
template('aggregate.rb.tt', aggregate_file)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_command_file
|
28
|
+
template('command.rb.tt', "app/commands/#{aggregate}/#{command}.rb")
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_event
|
32
|
+
event_file = "app/events/#{event_name}.rb"
|
33
|
+
|
34
|
+
unless File.exist?(event_file)
|
35
|
+
template('event.rb.tt', event_file)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def inject_command_to_api
|
40
|
+
insert_into_file('app/web/server.rb', after: "< Sinatra::Base\n") do
|
41
|
+
erb_file('api_endpoint.rb.tt')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def aggregate_name
|
48
|
+
@aggregate_name ||= aggregate.underscore
|
49
|
+
end
|
50
|
+
|
51
|
+
def aggregate_class_name
|
52
|
+
@aggregate_class_name ||= aggregate_name.camelize
|
53
|
+
end
|
54
|
+
|
55
|
+
def command_name
|
56
|
+
@command_name ||= command.underscore
|
57
|
+
end
|
58
|
+
|
59
|
+
def command_class_name
|
60
|
+
@command_class_name ||= command_name.camelize
|
61
|
+
end
|
62
|
+
|
63
|
+
def event_name
|
64
|
+
past_participle = Verbs::Conjugator.send(:past_participle, command.downcase.to_sym).to_s
|
65
|
+
[ aggregate, past_participle ].map(&:underscore).join('_')
|
66
|
+
end
|
67
|
+
|
68
|
+
def event_class_name
|
69
|
+
@event_class_name ||= event_name.underscore.camelize
|
70
|
+
end
|
71
|
+
|
72
|
+
def erb_file(file)
|
73
|
+
path = File.join(self.class.source_root, file)
|
74
|
+
ERB.new(::File.binread(path), nil, "-", "@output_buffer").result(binding)
|
75
|
+
end
|
76
|
+
|
77
|
+
def project_name
|
78
|
+
@project_name ||= File.split(Dir.pwd).last
|
79
|
+
end
|
80
|
+
|
81
|
+
def project_class_name
|
82
|
+
@project_class_name ||= project_name.underscore.camelize
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module EventSourceryGenerators
|
2
|
+
module Generators
|
3
|
+
class Project < Thor::Group
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
argument :project_name
|
7
|
+
|
8
|
+
class_options skip_tests: false, skip_setup: false
|
9
|
+
|
10
|
+
def self.source_root
|
11
|
+
File.join(File.dirname(__FILE__), 'templates', 'project')
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup_ruby_project
|
15
|
+
template('gemfile.tt', "#{project_name}/Gemfile")
|
16
|
+
template('rakefile.tt', "#{project_name}/Rakefile")
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_readme
|
20
|
+
template('readme.md.tt', "#{project_name}/README.md")
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_app
|
24
|
+
template('server.rb.tt', "#{project_name}/app/web/server.rb")
|
25
|
+
|
26
|
+
%w{aggregates commands events projections reactors}.each do |directory|
|
27
|
+
create_file("#{project_name}/app/#{directory}/.gitkeep")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_environment
|
32
|
+
template('environment.rb.tt', "#{project_name}/config/environment.rb")
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_scripts
|
36
|
+
%w{server setup}.each do |script_name|
|
37
|
+
template("script_#{script_name}.tt", "#{project_name}/script/#{script_name}")
|
38
|
+
chmod("#{project_name}/script/#{script_name}", 0755)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_rspec
|
43
|
+
return if options[:skip_tests]
|
44
|
+
|
45
|
+
template('spec_helper.rb.tt', "#{project_name}/spec/spec_helper.rb")
|
46
|
+
template('request_helpers.rb.tt', "#{project_name}/spec/support/request_helpers.rb")
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup_processes_infrastructure
|
50
|
+
template('Procfile.tt', "#{project_name}/Procfile")
|
51
|
+
template('config.ru.tt', "#{project_name}/config.ru")
|
52
|
+
template('app.json.tt', "#{project_name}/app.json")
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_setup_script
|
56
|
+
return if options[:skip_setup]
|
57
|
+
|
58
|
+
inside(project_name) do
|
59
|
+
run('./script/setup')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def project_class_name
|
66
|
+
@project_class_name ||= project_name.underscore.camelize
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module EventSourceryGenerators
|
2
|
+
module Generators
|
3
|
+
class Query < Thor::Group
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
argument :query_name
|
7
|
+
argument :event_names, type: :array, default: []
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
File.join(File.dirname(__FILE__), 'templates/query')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_query
|
14
|
+
template('query.rb.tt', "app/projections/#{query_name}/query.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_projector
|
18
|
+
template('projector.rb.tt', "app/projections/#{query_name}/projector.rb")
|
19
|
+
end
|
20
|
+
|
21
|
+
def inject_query_to_api
|
22
|
+
insert_into_file('app/web/server.rb', after: "< Sinatra::Base\n") do
|
23
|
+
erb_file('api_endpoint.rb.tt')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_projector_to_rakefile
|
28
|
+
insert_into_file('Rakefile', erb_file('projector_process.tt'), after: "processors = [\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def project_name
|
34
|
+
@project_name ||= File.split(Dir.pwd).last
|
35
|
+
end
|
36
|
+
|
37
|
+
def project_class_name
|
38
|
+
@project_class_name ||= project_name.underscore.camelize
|
39
|
+
end
|
40
|
+
|
41
|
+
def query_class_name
|
42
|
+
@query_class_name ||= query_name.underscore.camelize
|
43
|
+
end
|
44
|
+
|
45
|
+
def erb_file(file)
|
46
|
+
path = File.join(self.class.source_root, file)
|
47
|
+
ERB.new(::File.binread(path), nil, "-", "@output_buffer").result(binding)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module EventSourceryGenerators
|
2
|
+
module Generators
|
3
|
+
class Reactor < Thor::Group
|
4
|
+
include Thor::Actions
|
5
|
+
|
6
|
+
argument :reactor_name
|
7
|
+
argument :event_names, type: :array, default: []
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
File.join(File.dirname(__FILE__), 'templates/reactor')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_reactor
|
14
|
+
template('reactor.rb.tt', "app/reactors/#{reactor_name}.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_reactor_to_rakefile
|
18
|
+
insert_into_file('Rakefile', erb_file('reactor_process.tt'), after: "processors = [\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def project_name
|
24
|
+
@project_name ||= File.split(Dir.pwd).last
|
25
|
+
end
|
26
|
+
|
27
|
+
def project_class_name
|
28
|
+
@project_class_name ||= project_name.underscore.camelize
|
29
|
+
end
|
30
|
+
|
31
|
+
def reactor_class_name
|
32
|
+
@reactor_class_name ||= reactor_name.underscore.camelize
|
33
|
+
end
|
34
|
+
|
35
|
+
def erb_file(file)
|
36
|
+
path = File.join(self.class.source_root, file)
|
37
|
+
ERB.new(::File.binread(path), nil, "-", "@output_buffer").result(binding)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
post '/<%= aggregate.pluralize %>/:aggregate_id/<%= command %>' do
|
2
|
+
command = Commands::<%= aggregate_class_name %>::<%= command_class_name %>::Command.new(json_params)
|
3
|
+
Commands::<%= aggregate_class_name %>::<%= command_class_name %>::CommandHandler.new.handle(command)
|
4
|
+
status 201
|
5
|
+
end
|
6
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'app/aggregates/<%= aggregate_name %>'
|
2
|
+
|
3
|
+
module <%= project_class_name %>
|
4
|
+
module Commands
|
5
|
+
module <%= aggregate_class_name %>
|
6
|
+
module <%= command_class_name %>
|
7
|
+
class Command
|
8
|
+
attr_reader :aggregate_id, :payload
|
9
|
+
|
10
|
+
def initialize(params)
|
11
|
+
@aggregate_id = params.delete(:aggregate_id)
|
12
|
+
@payload = params # Select the parameters you want to allow
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate
|
16
|
+
# Add validation here
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class CommandHandler
|
21
|
+
def initialize(repository: <%= project_class_name %>.repository)
|
22
|
+
@repository = repository
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle(command)
|
26
|
+
command.validate
|
27
|
+
|
28
|
+
aggregate = repository.load(Aggregates::<%= aggregate_class_name %>, command.aggregate_id)
|
29
|
+
aggregate.<%= command_name %>(command.payload)
|
30
|
+
repository.save(aggregate)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :repository
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= event_class_name %> = Class.new(EventSourcery::Event)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"name": "<%= project_class_name %>",
|
3
|
+
"description": "<%= project_class_name %>, an EventSourcery app",
|
4
|
+
"keywords": ["<%= project_name %>", "ruby", "event_sourcery", "cqrs"],
|
5
|
+
"formation": {
|
6
|
+
"web": {
|
7
|
+
"quantity": 1
|
8
|
+
},
|
9
|
+
"processors": {
|
10
|
+
"quantity": 1
|
11
|
+
}
|
12
|
+
},
|
13
|
+
"scripts": {
|
14
|
+
"postdeploy": "bundle exec rake db:migrate"
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'event_sourcery'
|
2
|
+
require 'event_sourcery/postgres'
|
3
|
+
|
4
|
+
Dir.glob(__dir__ + '/../app/events/*.rb').each { |f| require f }
|
5
|
+
Dir.glob(__dir__ + '/../app/reactors/*.rb').each { |f| require f }
|
6
|
+
Dir.glob(__dir__ + '/../app/projections/**/projector.rb').each { |f| require f }
|
7
|
+
|
8
|
+
module <%= project_class_name %>
|
9
|
+
class Config
|
10
|
+
attr_accessor :database_url
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.config
|
14
|
+
@config ||= Config.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure
|
18
|
+
yield config
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.environment
|
22
|
+
ENV.fetch('RACK_ENV', 'development')
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.event_store
|
26
|
+
EventSourcery::Postgres.config.event_store
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.event_source
|
30
|
+
EventSourcery::Postgres.config.event_store
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.tracker
|
34
|
+
EventSourcery::Postgres.config.event_tracker
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.event_sink
|
38
|
+
EventSourcery::Postgres.config.event_sink
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.projections_database
|
42
|
+
EventSourcery::Postgres.config.projections_database
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.repository
|
46
|
+
@repository ||= EventSourcery::Repository.new(
|
47
|
+
event_source: event_source,
|
48
|
+
event_sink: event_sink
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
<%= project_class_name %>.configure do |config|
|
54
|
+
config.database_url = ENV['DATABASE_URL'] || "postgres://127.0.0.1:5432/<%= project_name.underscore %>_#{<%= project_class_name %>.environment}"
|
55
|
+
end
|
56
|
+
|
57
|
+
EventSourcery::Postgres.configure do |config|
|
58
|
+
database = Sequel.connect(<%= project_class_name %>.config.database_url)
|
59
|
+
|
60
|
+
# NOTE: Often we choose to split our events and projections into separate
|
61
|
+
# databases. For the purposes of this example we'll use one.
|
62
|
+
config.event_store_database = database
|
63
|
+
config.projections_database = database
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'event_sourcery', git: 'https://github.com/envato/event_sourcery.git'
|
4
|
+
gem 'event_sourcery-postgres', git: 'https://github.com/envato/event_sourcery-postgres.git'
|
5
|
+
|
6
|
+
gem 'rake'
|
7
|
+
gem 'sinatra'
|
8
|
+
# NOTE: pg is an implicit dependency of event_sourcery-postgres but we need to
|
9
|
+
# lock to an older version for deprecation warnings.
|
10
|
+
gem 'pg', '0.20.0'
|
11
|
+
|
12
|
+
group :development, :test do
|
13
|
+
gem 'pry'
|
14
|
+
gem 'rspec'
|
15
|
+
gem 'rack-test'
|
16
|
+
gem 'database_cleaner'
|
17
|
+
gem 'better_errors'
|
18
|
+
gem 'shotgun'
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
$LOAD_PATH.unshift '.'
|
2
|
+
|
3
|
+
task :environment do
|
4
|
+
require 'config/environment'
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Run Event Stream Processors'
|
8
|
+
task run_processors: :environment do
|
9
|
+
puts 'Starting Event Stream processors'
|
10
|
+
|
11
|
+
event_source = <%= project_class_name %>.event_source
|
12
|
+
tracker = <%= project_class_name %>.tracker
|
13
|
+
db_connection = <%= project_class_name %>.projections_database
|
14
|
+
|
15
|
+
# Need to disconnect before starting the processors
|
16
|
+
# to ensure each forked process has its own connection
|
17
|
+
db_connection.disconnect
|
18
|
+
|
19
|
+
# Show our ESP logs in foreman immediately
|
20
|
+
$stdout.sync = true
|
21
|
+
|
22
|
+
processors = [
|
23
|
+
# Add your processors here, like so:
|
24
|
+
#
|
25
|
+
# EventSourceryTodoApp::Projections::CompletedTodos::Projector.new(
|
26
|
+
# tracker: tracker,
|
27
|
+
# db_connection: db_connection,
|
28
|
+
# ),
|
29
|
+
]
|
30
|
+
|
31
|
+
EventSourcery::EventProcessing::ESPRunner.new(
|
32
|
+
event_processors: processors,
|
33
|
+
event_source: event_source,
|
34
|
+
).start!
|
35
|
+
end
|
36
|
+
|
37
|
+
namespace :db do
|
38
|
+
desc 'Create database'
|
39
|
+
task create: :environment do
|
40
|
+
url = <%= project_class_name %>.config.database_url
|
41
|
+
database_name = File.basename(url)
|
42
|
+
database = Sequel.connect URI.join(url, '/template1').to_s
|
43
|
+
begin
|
44
|
+
database.run("CREATE DATABASE #{database_name}")
|
45
|
+
rescue StandardError => e
|
46
|
+
puts "Could not create database '#{database_name}': #{e.class.name} #{e.message}"
|
47
|
+
end
|
48
|
+
database.disconnect
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'Drop database'
|
52
|
+
task drop: :environment do
|
53
|
+
url = <%= project_class_name %>.config.database_url
|
54
|
+
database_name = File.basename(url)
|
55
|
+
database = Sequel.connect URI.join(url, '/template1').to_s
|
56
|
+
database.run("DROP DATABASE IF EXISTS #{database_name}")
|
57
|
+
database.disconnect
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'Migrate database'
|
61
|
+
task migrate: :environment do
|
62
|
+
database = EventSourcery::Postgres.config.event_store_database
|
63
|
+
begin
|
64
|
+
EventSourcery::Postgres::Schema.create_event_store(db: database)
|
65
|
+
rescue StandardError => e
|
66
|
+
puts "Could not create event store: #{e.class.name} #{e.message}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# <%= project_class_name %>
|
2
|
+
|
3
|
+
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
|
4
|
+
|
5
|
+
## Get started
|
6
|
+
|
7
|
+
Ensure you have Postgres and Ruby 2.3 or higher installed, then run the setup script:
|
8
|
+
|
9
|
+
```sh
|
10
|
+
$ ./script/setup
|
11
|
+
```
|
12
|
+
|
13
|
+
## Using the Application
|
14
|
+
|
15
|
+
Start the web server and processors (reactors and projectors):
|
16
|
+
|
17
|
+
```sh
|
18
|
+
$ foreman start
|
19
|
+
```
|
20
|
+
|
21
|
+
## Adding features
|
22
|
+
|
23
|
+
Generate a new aggregate, command and event:
|
24
|
+
|
25
|
+
```sh
|
26
|
+
$ eventsourcery generate:command recipe add
|
27
|
+
```
|
28
|
+
|
29
|
+
Generate a query and projection that subscribes to events:
|
30
|
+
|
31
|
+
```sh
|
32
|
+
$ eventsourcery generate:query active_recipes recipe_added
|
33
|
+
```
|
34
|
+
|
35
|
+
Generate a reactor that subscribes to events:
|
36
|
+
|
37
|
+
```sh
|
38
|
+
$ eventsourcery generate:reactor recipe_publisher recipe_added recipe_deleted
|
39
|
+
```
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
echo
|
4
|
+
echo "--- Installing bundled gems"
|
5
|
+
echo
|
6
|
+
|
7
|
+
bundle install
|
8
|
+
|
9
|
+
if ! type -t "foreman" > /dev/null; then
|
10
|
+
echo
|
11
|
+
echo "--- Installing foreman"
|
12
|
+
echo
|
13
|
+
|
14
|
+
gem install foreman
|
15
|
+
fi
|
16
|
+
|
17
|
+
echo
|
18
|
+
echo "--- Creating and migrating databases"
|
19
|
+
echo
|
20
|
+
|
21
|
+
bundle exec rake db:create db:migrate
|
22
|
+
RACK_ENV=test bundle exec rake db:create db:migrate
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
Dir.glob(__dir__ + '/../commands/**/*.rb').each { |f| require f }
|
4
|
+
Dir.glob(__dir__ + '/../projections/**/query.rb').each { |f| require f }
|
5
|
+
|
6
|
+
module <%= project_class_name %>
|
7
|
+
class Server < Sinatra::Base
|
8
|
+
BadRequest = Class.new(StandardError)
|
9
|
+
UnprocessableEntity = Class.new(StandardError)
|
10
|
+
|
11
|
+
# Ensure our error handlers are triggered in development
|
12
|
+
set :show_exceptions, :after_handler
|
13
|
+
|
14
|
+
configure :development do
|
15
|
+
require 'better_errors'
|
16
|
+
use BetterErrors::Middleware
|
17
|
+
BetterErrors.application_root = __dir__
|
18
|
+
end
|
19
|
+
|
20
|
+
error UnprocessableEntity do |error|
|
21
|
+
body "Unprocessable Entity: #{error.message}"
|
22
|
+
status 422
|
23
|
+
end
|
24
|
+
|
25
|
+
error BadRequest do |error|
|
26
|
+
body "Bad Request: #{error.message}"
|
27
|
+
status 400
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
content_type :json
|
32
|
+
end
|
33
|
+
|
34
|
+
def json_params
|
35
|
+
# Coerce this into a symbolised Hash so Sinatra data
|
36
|
+
# structures don't leak into the command layer
|
37
|
+
|
38
|
+
request_body = request.body.read
|
39
|
+
unless request_body.empty?
|
40
|
+
params.merge!(JSON.parse(request_body))
|
41
|
+
end
|
42
|
+
|
43
|
+
Hash[
|
44
|
+
params.map{ |k, v| [k.to_sym, v] }
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add your API routes here!
|
49
|
+
#
|
50
|
+
# eg.
|
51
|
+
# get '/todos' do
|
52
|
+
# ...
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# post '/todo/:id' do
|
56
|
+
# ...
|
57
|
+
# end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack/test'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'database_cleaner'
|
6
|
+
|
7
|
+
$LOAD_PATH << '.'
|
8
|
+
|
9
|
+
require 'app/web/server'
|
10
|
+
require 'config/environment'
|
11
|
+
require 'spec/support/request_helpers'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.include(Rack::Test::Methods, type: :request)
|
15
|
+
config.include(RequestHelpers, type: :request)
|
16
|
+
|
17
|
+
config.expect_with :rspec do |expectations|
|
18
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
19
|
+
end
|
20
|
+
|
21
|
+
config.mock_with :rspec do |mocks|
|
22
|
+
mocks.verify_partial_doubles = true
|
23
|
+
end
|
24
|
+
|
25
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
26
|
+
config.disable_monkey_patching!
|
27
|
+
config.order = :random
|
28
|
+
Kernel.srand config.seed
|
29
|
+
|
30
|
+
EventSourcery.configure do |config|
|
31
|
+
config.logger = Logger.new(nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
config.before do
|
35
|
+
DatabaseCleaner.strategy = :truncation
|
36
|
+
DatabaseCleaner.clean
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module <%= project_class_name %>
|
2
|
+
module Projections
|
3
|
+
module <%= query_class_name %>
|
4
|
+
class Projector
|
5
|
+
include EventSourcery::Postgres::Projector
|
6
|
+
|
7
|
+
projector_name :<%= query_name %>
|
8
|
+
|
9
|
+
table :query_<%= query_name %> do
|
10
|
+
# Add your projection table columns here, eg:
|
11
|
+
# column :todo_id, 'UUID NOT NULL'
|
12
|
+
# column :title, :text
|
13
|
+
# column :due_date, DateTime
|
14
|
+
end
|
15
|
+
<%- if event_names.empty? -%>
|
16
|
+
|
17
|
+
# project TodoAdded do |event|
|
18
|
+
# Modify your projection table here, eg:
|
19
|
+
# table.insert(
|
20
|
+
# todo_id: event.aggregate_id,
|
21
|
+
# title: event.body['title'],
|
22
|
+
# due_date: event.body['due_date'],
|
23
|
+
# )
|
24
|
+
# end
|
25
|
+
<%- else -%>
|
26
|
+
<% event_names.each do |event_name| %>
|
27
|
+
project <%= event_name.underscore.camelize %> do |event|
|
28
|
+
# Modify your projection table here, eg:
|
29
|
+
# table.insert(
|
30
|
+
# todo_id: event.aggregate_id,
|
31
|
+
# title: event.body['title'],
|
32
|
+
# due_date: event.body['due_date'],
|
33
|
+
# )
|
34
|
+
end
|
35
|
+
<%- end -%>
|
36
|
+
<%- end -%>
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module <%= project_class_name %>
|
2
|
+
module Reactors
|
3
|
+
class <%= reactor_class_name %>
|
4
|
+
include EventSourcery::Postgres::Reactor
|
5
|
+
|
6
|
+
processor_name :<%= reactor_name.underscore %>
|
7
|
+
|
8
|
+
# emits_events ExampleEvent, AnotherEvent
|
9
|
+
|
10
|
+
# table :reactor_<%= reactor_name.underscore %> do
|
11
|
+
# column :todo_id, :uuid, primary_key: true
|
12
|
+
# column :title, :text
|
13
|
+
# end
|
14
|
+
|
15
|
+
<%- if event_names.empty? -%>
|
16
|
+
# process TodoAdded do |event|
|
17
|
+
# table.insert(
|
18
|
+
# todo_id: event.aggregate_id,
|
19
|
+
# title: event.body['title'],
|
20
|
+
# )
|
21
|
+
# end
|
22
|
+
|
23
|
+
# process TodoCompleted do |event|
|
24
|
+
# todo = table.where(todo_id: event.aggregate_id).first
|
25
|
+
#
|
26
|
+
# emit_event(
|
27
|
+
# StakeholderNotifiedOfTodoCompletion.new(
|
28
|
+
# aggregate_id: event.aggregate_id,
|
29
|
+
# body: { title: todo[:title] },
|
30
|
+
# )
|
31
|
+
# )
|
32
|
+
# end
|
33
|
+
<%- else -%>
|
34
|
+
<% event_names.each do |event_name| %>
|
35
|
+
process <%= event_name.underscore.camelize %> do |event|
|
36
|
+
# Update scratch tables, emit events, ...
|
37
|
+
end
|
38
|
+
<%- end -%>
|
39
|
+
<%- end -%>
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: event_sourcery_generators
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sebastian von Conrad
|
8
|
+
- Pablo Lee
|
9
|
+
- Chun-wei Kuo
|
10
|
+
- Giancarlo Salamanca
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2017-06-16 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: thor
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - "~>"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.19'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.19'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - "~>"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '5.1'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '5.1'
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: verbs
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '2.1'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '2.1'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: bundler
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - "~>"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '1.12'
|
65
|
+
type: :development
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - "~>"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '1.12'
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: rake
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - "~>"
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '11.2'
|
79
|
+
type: :development
|
80
|
+
prerelease: false
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - "~>"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '11.2'
|
86
|
+
- !ruby/object:Gem::Dependency
|
87
|
+
name: rspec
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - "~>"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '3.6'
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '3.6'
|
100
|
+
description: An opinionated CLI tool for building event-sourced Ruby services with
|
101
|
+
EventSourcery
|
102
|
+
email:
|
103
|
+
- sebastian.von.conrad@envato.com
|
104
|
+
- pablo.lee@envato.com
|
105
|
+
- chun-wei.kuo@envato.com
|
106
|
+
- giancarlo.salamanca@envato.com
|
107
|
+
executables:
|
108
|
+
- eventsourcery
|
109
|
+
extensions: []
|
110
|
+
extra_rdoc_files: []
|
111
|
+
files:
|
112
|
+
- ".gitignore"
|
113
|
+
- ".rspec"
|
114
|
+
- CODE_OF_CONDUCT.md
|
115
|
+
- Gemfile
|
116
|
+
- LICENSE.txt
|
117
|
+
- README.md
|
118
|
+
- Rakefile
|
119
|
+
- bin/eventsourcery
|
120
|
+
- event_sourcery_generators.gemspec
|
121
|
+
- lib/event_sourcery_generators.rb
|
122
|
+
- lib/event_sourcery_generators/cli.rb
|
123
|
+
- lib/event_sourcery_generators/generators/command.rb
|
124
|
+
- lib/event_sourcery_generators/generators/project.rb
|
125
|
+
- lib/event_sourcery_generators/generators/query.rb
|
126
|
+
- lib/event_sourcery_generators/generators/reactor.rb
|
127
|
+
- lib/event_sourcery_generators/generators/templates/command/aggregate.rb.tt
|
128
|
+
- lib/event_sourcery_generators/generators/templates/command/aggregate/apply_event_method.rb.tt
|
129
|
+
- lib/event_sourcery_generators/generators/templates/command/aggregate/command_method.rb.tt
|
130
|
+
- lib/event_sourcery_generators/generators/templates/command/api_endpoint.rb.tt
|
131
|
+
- lib/event_sourcery_generators/generators/templates/command/command.rb.tt
|
132
|
+
- lib/event_sourcery_generators/generators/templates/command/event.rb.tt
|
133
|
+
- lib/event_sourcery_generators/generators/templates/project/app.json.tt
|
134
|
+
- lib/event_sourcery_generators/generators/templates/project/config.ru.tt
|
135
|
+
- lib/event_sourcery_generators/generators/templates/project/environment.rb.tt
|
136
|
+
- lib/event_sourcery_generators/generators/templates/project/gemfile.tt
|
137
|
+
- lib/event_sourcery_generators/generators/templates/project/procfile.tt
|
138
|
+
- lib/event_sourcery_generators/generators/templates/project/rakefile.tt
|
139
|
+
- lib/event_sourcery_generators/generators/templates/project/readme.md.tt
|
140
|
+
- lib/event_sourcery_generators/generators/templates/project/request_helpers.rb.tt
|
141
|
+
- lib/event_sourcery_generators/generators/templates/project/script_server.tt
|
142
|
+
- lib/event_sourcery_generators/generators/templates/project/script_setup.tt
|
143
|
+
- lib/event_sourcery_generators/generators/templates/project/server.rb.tt
|
144
|
+
- lib/event_sourcery_generators/generators/templates/project/spec_helper.rb.tt
|
145
|
+
- lib/event_sourcery_generators/generators/templates/query/api_endpoint.rb.tt
|
146
|
+
- lib/event_sourcery_generators/generators/templates/query/projector.rb.tt
|
147
|
+
- lib/event_sourcery_generators/generators/templates/query/projector_process.tt
|
148
|
+
- lib/event_sourcery_generators/generators/templates/query/query.rb.tt
|
149
|
+
- lib/event_sourcery_generators/generators/templates/reactor/reactor.rb.tt
|
150
|
+
- lib/event_sourcery_generators/generators/templates/reactor/reactor_process.tt
|
151
|
+
- lib/event_sourcery_generators/version.rb
|
152
|
+
homepage: https://github.com/envato/event_sourcery_generators
|
153
|
+
licenses: []
|
154
|
+
metadata: {}
|
155
|
+
post_install_message:
|
156
|
+
rdoc_options: []
|
157
|
+
require_paths:
|
158
|
+
- lib
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
requirements: []
|
170
|
+
rubyforge_project:
|
171
|
+
rubygems_version: 2.6.11
|
172
|
+
signing_key:
|
173
|
+
specification_version: 4
|
174
|
+
summary: Generators for EventSourcery
|
175
|
+
test_files: []
|