rivulet-rb 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 +7 -0
- data/bin/rivulet +4 -0
- data/lib/rivulet/application.rb +90 -0
- data/lib/rivulet/cli/console.rb +15 -0
- data/lib/rivulet/cli/db/migrate.rb +17 -0
- data/lib/rivulet/cli/generate/handler/operation.rb +75 -0
- data/lib/rivulet/cli/generate/handler/step.rb +91 -0
- data/lib/rivulet/cli/generate/handler.rb +135 -0
- data/lib/rivulet/cli/generate/migration.rb +31 -0
- data/lib/rivulet/cli/generate/operation.rb +111 -0
- data/lib/rivulet/cli/generate/resource.rb +25 -0
- data/lib/rivulet/cli/generate/service/operation.rb +118 -0
- data/lib/rivulet/cli/generate/service/projection.rb +89 -0
- data/lib/rivulet/cli/generate/service/step.rb +91 -0
- data/lib/rivulet/cli/generate/service.rb +143 -0
- data/lib/rivulet/cli/new.rb +191 -0
- data/lib/rivulet/cli/routes.rb +15 -0
- data/lib/rivulet/cli.rb +43 -0
- data/lib/rivulet/container.rb +28 -0
- data/lib/rivulet/operation.rb +21 -0
- data/lib/rivulet/operations/dispatch_request.rb +21 -0
- data/lib/rivulet/operations/migrate.rb +23 -0
- data/lib/rivulet/operations/print_routes.rb +17 -0
- data/lib/rivulet/operations/run_console.rb +25 -0
- data/lib/rivulet/operations/startup.rb +23 -0
- data/lib/rivulet/projection.rb +6 -0
- data/lib/rivulet/request.rb +18 -0
- data/lib/rivulet/response.rb +12 -0
- data/lib/rivulet/routing/mapper.rb +78 -0
- data/lib/rivulet/routing/route.rb +14 -0
- data/lib/rivulet/step.rb +22 -0
- data/lib/rivulet/steps/build_config.rb +26 -0
- data/lib/rivulet/steps/build_context.rb +76 -0
- data/lib/rivulet/steps/compile_response.rb +113 -0
- data/lib/rivulet/steps/dispatch.rb +17 -0
- data/lib/rivulet/steps/load_app.rb +20 -0
- data/lib/rivulet/steps/load_db.rb +24 -0
- data/lib/rivulet/steps/load_routes.rb +28 -0
- data/lib/rivulet/steps/load_settings.rb +42 -0
- data/lib/rivulet/steps/print_routes.rb +123 -0
- data/lib/rivulet/steps/run_console.rb +26 -0
- data/lib/rivulet/steps/run_migrations.rb +50 -0
- data/lib/rivulet/steps/validate_response.rb +42 -0
- data/lib/rivulet/telemetry/node.rb +8 -0
- data/lib/rivulet/telemetry/sequel_extension.rb +19 -0
- data/lib/rivulet/telemetry/timing_wrapper.rb +12 -0
- data/lib/rivulet/telemetry.rb +62 -0
- data/lib/rivulet/version.rb +3 -0
- data/lib/rivulet.rb +66 -0
- metadata +342 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Rivulet
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Generate
|
|
7
|
+
class Service
|
|
8
|
+
class Operation < Dry::CLI::Command
|
|
9
|
+
desc "Generate an operation"
|
|
10
|
+
argument :name, required: true, desc: "Operation name in service.operation format (e.g. users.create)"
|
|
11
|
+
|
|
12
|
+
def call(name:, **)
|
|
13
|
+
service_name, operation_name = name.split('.')
|
|
14
|
+
service_dir = underscore(service_name)
|
|
15
|
+
operation_dir = underscore(operation_name)
|
|
16
|
+
service_module = camelize(service_dir)
|
|
17
|
+
operation_module = camelize(operation_dir)
|
|
18
|
+
base = "app/services/#{service_dir}"
|
|
19
|
+
|
|
20
|
+
mkdir "#{base}/projections"
|
|
21
|
+
write "#{base}/operations/#{operation_dir}.rb", operation_template(service_module, operation_module)
|
|
22
|
+
write "#{base}/contracts/#{operation_dir}.rb", contract_template(service_module, operation_module)
|
|
23
|
+
register_operation(base, service_dir, service_module, operation_dir, operation_module)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def underscore(str)
|
|
29
|
+
str
|
|
30
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
31
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
32
|
+
.downcase
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def camelize(str)
|
|
36
|
+
str.split('_').map(&:capitalize).join
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def mkdir(path)
|
|
40
|
+
Dir.mkdir(path) unless Dir.exist?(path)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write(path, content)
|
|
44
|
+
File.write(path, content)
|
|
45
|
+
puts " create #{path}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def operation_template(service_module, operation_module)
|
|
49
|
+
<<~RUBY
|
|
50
|
+
module Services
|
|
51
|
+
module #{service_module}
|
|
52
|
+
module Operations
|
|
53
|
+
class #{operation_module} < Rivulet::Operation
|
|
54
|
+
def call(input = {})
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
RUBY
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def contract_template(service_module, operation_module)
|
|
64
|
+
<<~RUBY
|
|
65
|
+
module Services
|
|
66
|
+
module #{service_module}
|
|
67
|
+
module Contracts
|
|
68
|
+
class #{operation_module} < ApplicationContract
|
|
69
|
+
params do
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
RUBY
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def register_operation(base, service_dir, service_module, operation_dir, operation_module)
|
|
79
|
+
container_file = "#{base}/container.rb"
|
|
80
|
+
op_registration = " register('#{operation_dir}') { Services::#{service_module}::Operations::#{operation_module}.new }\n"
|
|
81
|
+
contract_registration = " register('#{operation_dir}') { Services::#{service_module}::Contracts::#{operation_module}.new }\n"
|
|
82
|
+
|
|
83
|
+
if File.exist?(container_file)
|
|
84
|
+
content = File.read(container_file)
|
|
85
|
+
content.sub!(/( namespace\('operations'\) do\n)/, "\\1#{op_registration}")
|
|
86
|
+
content.sub!(/( namespace\('contracts'\) do\n)/, "\\1#{contract_registration}")
|
|
87
|
+
File.write(container_file, content)
|
|
88
|
+
puts " update #{container_file}"
|
|
89
|
+
else
|
|
90
|
+
write container_file, container_template(service_module, operation_dir, operation_module)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def container_template(service_module, operation_dir, operation_module)
|
|
95
|
+
<<~RUBY
|
|
96
|
+
module Services
|
|
97
|
+
module #{service_module}
|
|
98
|
+
class Container
|
|
99
|
+
extend Dry::Core::Container::Mixin
|
|
100
|
+
|
|
101
|
+
namespace('operations') do
|
|
102
|
+
register('#{operation_dir}') { Services::#{service_module}::Operations::#{operation_module}.new }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
namespace('contracts') do
|
|
106
|
+
register('#{operation_dir}') { Services::#{service_module}::Contracts::#{operation_module}.new }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
RUBY
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Rivulet
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Generate
|
|
7
|
+
class Service
|
|
8
|
+
class Projection < Dry::CLI::Command
|
|
9
|
+
desc "Generate a projection"
|
|
10
|
+
argument :name, required: true, desc: "Step name in service.projection format (e.g. users.common)"
|
|
11
|
+
|
|
12
|
+
def call(name:, **)
|
|
13
|
+
service_name, step_name = name.split('.')
|
|
14
|
+
service_dir = underscore(service_name)
|
|
15
|
+
projection_dir = underscore(step_name)
|
|
16
|
+
service_module = camelize(service_dir)
|
|
17
|
+
projection_class = camelize(projection_dir)
|
|
18
|
+
base = "app/services/#{service_dir}"
|
|
19
|
+
|
|
20
|
+
write "#{base}/projections/#{projection_dir}.rb", projection_template(service_module, projection_class)
|
|
21
|
+
register_projection(base, service_module, projection_dir, projection_class)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def underscore(str)
|
|
27
|
+
str
|
|
28
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
29
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
30
|
+
.downcase
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def camelize(str)
|
|
34
|
+
str.split('_').map(&:capitalize).join
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def write(path, content)
|
|
38
|
+
File.write(path, content)
|
|
39
|
+
puts " create #{path}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def projection_template(service_module, projection_class)
|
|
43
|
+
<<~RUBY
|
|
44
|
+
module Services
|
|
45
|
+
module #{service_module}
|
|
46
|
+
module Projections
|
|
47
|
+
class #{projection_class} < Rivulet::Projection
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
RUBY
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def register_projection(base, service_module, projection_name, projection_class)
|
|
56
|
+
container_file = "#{base}/container.rb"
|
|
57
|
+
projection_registration = " register('#{projection_name}') { Services::#{service_module}::Projections::#{projection_class}.new }\n"
|
|
58
|
+
|
|
59
|
+
if File.exist?(container_file)
|
|
60
|
+
content = File.read(container_file)
|
|
61
|
+
content.sub!(/( namespace\('projections'\) do\n)/, "\\1#{projection_registration}")
|
|
62
|
+
File.write(container_file, content)
|
|
63
|
+
puts " update #{container_file}"
|
|
64
|
+
else
|
|
65
|
+
write container_file, container_template(service_module, projection_name, projection_class)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def container_template(service_module, projection_name, projection_class)
|
|
70
|
+
<<~RUBY
|
|
71
|
+
module Services
|
|
72
|
+
module #{service_module}
|
|
73
|
+
class Container
|
|
74
|
+
extend Dry::Core::Container::Mixin
|
|
75
|
+
|
|
76
|
+
namespace('projections') do
|
|
77
|
+
register('#{projection_name}') { Services::#{service_module}::Projections::#{projection_class}.new }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
RUBY
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Rivulet
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Generate
|
|
7
|
+
class Service
|
|
8
|
+
class Step < Dry::CLI::Command
|
|
9
|
+
desc "Generate a step"
|
|
10
|
+
argument :name, required: true, desc: "Step name in service.step format (e.g. users.create)"
|
|
11
|
+
|
|
12
|
+
def call(name:, **)
|
|
13
|
+
service_name, step_name = name.split('.')
|
|
14
|
+
service_dir = underscore(service_name)
|
|
15
|
+
step_dir = underscore(step_name)
|
|
16
|
+
service_module = camelize(service_dir)
|
|
17
|
+
step_class = camelize(step_dir)
|
|
18
|
+
base = "app/services/#{service_dir}"
|
|
19
|
+
|
|
20
|
+
write "#{base}/steps/#{step_dir}.rb", step_template(service_module, step_class)
|
|
21
|
+
register_step(base, service_module, step_dir, step_class)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def underscore(str)
|
|
27
|
+
str
|
|
28
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
29
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
30
|
+
.downcase
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def camelize(str)
|
|
34
|
+
str.split('_').map(&:capitalize).join
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def write(path, content)
|
|
38
|
+
File.write(path, content)
|
|
39
|
+
puts " create #{path}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def step_template(service_module, step_class)
|
|
43
|
+
<<~RUBY
|
|
44
|
+
module Services
|
|
45
|
+
module #{service_module}
|
|
46
|
+
module Steps
|
|
47
|
+
class #{step_class} < Rivulet::Step
|
|
48
|
+
def call(input)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
RUBY
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def register_step(base, service_module, step_name, step_class)
|
|
58
|
+
container_file = "#{base}/container.rb"
|
|
59
|
+
step_registration = " register('#{step_name}') { Services::#{service_module}::Steps::#{step_class}.new }\n"
|
|
60
|
+
|
|
61
|
+
if File.exist?(container_file)
|
|
62
|
+
content = File.read(container_file)
|
|
63
|
+
content.sub!(/( namespace\('steps'\) do\n)/, "\\1#{step_registration}")
|
|
64
|
+
File.write(container_file, content)
|
|
65
|
+
puts " update #{container_file}"
|
|
66
|
+
else
|
|
67
|
+
write container_file, container_template(service_module, step_name, step_class)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def container_template(service_module, step_name, step_class)
|
|
72
|
+
<<~RUBY
|
|
73
|
+
module Services
|
|
74
|
+
module #{service_module}
|
|
75
|
+
class Container
|
|
76
|
+
extend Dry::Core::Container::Mixin
|
|
77
|
+
|
|
78
|
+
namespace('steps') do
|
|
79
|
+
register('#{step_name}') { Services::#{service_module}::Steps::#{step_class}.new }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
RUBY
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
require 'dry/inflector'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
module Rivulet
|
|
5
|
+
module CLI
|
|
6
|
+
module Commands
|
|
7
|
+
module Generate
|
|
8
|
+
class Service < Dry::CLI::Command
|
|
9
|
+
desc "Generate a service"
|
|
10
|
+
argument :name, required: true, desc: "Service name (e.g. Users or users)"
|
|
11
|
+
|
|
12
|
+
option :create, type: :boolean, aliases: ['-c'], desc: 'Add "create" operation'
|
|
13
|
+
option :read, type: :boolean, aliases: ['-r'], desc: 'Add "get" operation'
|
|
14
|
+
option :update, type: :boolean, aliases: ['-u'], desc: 'Add "update" operation'
|
|
15
|
+
option :delete, type: :boolean, aliases: ['-d'], desc: 'Add "delete" operation'
|
|
16
|
+
option :list, type: :boolean, aliases: ['-l'], desc: 'Add "list" operation'
|
|
17
|
+
|
|
18
|
+
SUBDIRS = %w[contracts operations steps].freeze
|
|
19
|
+
|
|
20
|
+
def call(name:, **options)
|
|
21
|
+
dir_name = underscore(name)
|
|
22
|
+
module_name = camelize(dir_name)
|
|
23
|
+
base = "app/services/#{dir_name}"
|
|
24
|
+
singular_name = Dry::Inflector.new.singularize(name)
|
|
25
|
+
|
|
26
|
+
SUBDIRS.each { |d| create_dir "#{base}/#{d}" }
|
|
27
|
+
write "#{base}/service.rb", service_template(module_name)
|
|
28
|
+
create_container(base, module_name) unless File.exist?("#{base}/container.rb")
|
|
29
|
+
register_service(dir_name, module_name)
|
|
30
|
+
|
|
31
|
+
if options[:create]
|
|
32
|
+
Operation.new.call(name: "#{name}.create_#{singular_name}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if options[:read]
|
|
36
|
+
Operation.new.call(name: "#{name}.get_#{singular_name}")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if options[:update]
|
|
40
|
+
Operation.new.call(name: "#{name}.update_#{singular_name}")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if options[:delete]
|
|
44
|
+
Operation.new.call(name: "#{name}.delete_#{singular_name}")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
if options[:list]
|
|
48
|
+
Operation.new.call(name: "#{name}.list_#{name}")
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def underscore(str)
|
|
55
|
+
str
|
|
56
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
57
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
58
|
+
.downcase
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def camelize(str)
|
|
62
|
+
str.split('_').map(&:capitalize).join
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def create_dir(path)
|
|
66
|
+
FileUtils.mkdir_p(path)
|
|
67
|
+
puts " create #{path}/"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def create_container(base, module_name)
|
|
71
|
+
write "#{base}/container.rb", container_template(module_name)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def write(path, content)
|
|
75
|
+
File.write(path, content)
|
|
76
|
+
puts " create #{path}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def service_template(module_name)
|
|
80
|
+
<<~RUBY
|
|
81
|
+
module Services
|
|
82
|
+
module #{module_name}
|
|
83
|
+
class Service
|
|
84
|
+
NAMESPACE = 'operations'
|
|
85
|
+
|
|
86
|
+
def method_missing(name, input = {}, options = {}, &block)
|
|
87
|
+
key = [NAMESPACE, name].join('.')
|
|
88
|
+
super unless Container.key?(key)
|
|
89
|
+
|
|
90
|
+
Container[key].call(input, **options, &block)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def respond_to_missing?(name, include_private = false)
|
|
94
|
+
key = [NAMESPACE, name].join('.')
|
|
95
|
+
Container.key?(key) || super
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
RUBY
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def container_template(module_name)
|
|
104
|
+
<<~RUBY
|
|
105
|
+
module Services
|
|
106
|
+
module #{module_name}
|
|
107
|
+
class Container
|
|
108
|
+
extend Dry::Core::Container::Mixin
|
|
109
|
+
import Services::Shared::Namespace
|
|
110
|
+
|
|
111
|
+
namespace('operations') do
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
namespace('steps') do
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
namespace('contracts') do
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
namespace('projections') do
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
RUBY
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def register_service(dir_name, module_name)
|
|
129
|
+
services_file = 'app/services.rb'
|
|
130
|
+
return unless File.exist?(services_file)
|
|
131
|
+
|
|
132
|
+
content = File.read(services_file)
|
|
133
|
+
registration = " register('#{dir_name}') { Services::#{module_name}::Service.new }\n"
|
|
134
|
+
|
|
135
|
+
updated = content.sub(/^end\s*\z/, "#{registration}end\n")
|
|
136
|
+
File.write(services_file, updated)
|
|
137
|
+
puts " update #{services_file}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
|
|
3
|
+
module Rivulet
|
|
4
|
+
module CLI
|
|
5
|
+
module Commands
|
|
6
|
+
class New < Dry::CLI::Command
|
|
7
|
+
desc "Create a new Rivulet application"
|
|
8
|
+
argument :name, required: true, desc: "Application name"
|
|
9
|
+
|
|
10
|
+
DIRS = %w[
|
|
11
|
+
app/handlers
|
|
12
|
+
app/handlers/shared
|
|
13
|
+
app/handlers/shared/steps
|
|
14
|
+
app/handlers/shared/utils
|
|
15
|
+
app/services
|
|
16
|
+
app/services/shared
|
|
17
|
+
app/services/shared/steps
|
|
18
|
+
app/services/shared/utils
|
|
19
|
+
app/models
|
|
20
|
+
config
|
|
21
|
+
db/migrations
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
def call(name:, **)
|
|
25
|
+
DIRS.each { |d| create_dir "#{name}/#{d}" }
|
|
26
|
+
|
|
27
|
+
write name, 'Gemfile', gemfile
|
|
28
|
+
write name, 'config.ru', config_ru
|
|
29
|
+
write name, 'config/application.rb', application_config(name)
|
|
30
|
+
write name, 'config/routes.rb', routes_config
|
|
31
|
+
write name, 'falcon.rb', falcon_config
|
|
32
|
+
write name, 'app/handlers.rb', handlers_container
|
|
33
|
+
write name, 'app/handlers/shared/container.rb', handlers_shared_container
|
|
34
|
+
write name, 'app/handlers/shared/namespace.rb', handlers_shared_namespace
|
|
35
|
+
write name, 'app/services.rb', services_container
|
|
36
|
+
write name, 'app/services/shared/container.rb', services_shared_container
|
|
37
|
+
write name, 'app/services/shared/namespace.rb', services_shared_namespace
|
|
38
|
+
write name, 'app/application_contract.rb', application_contract_template
|
|
39
|
+
|
|
40
|
+
puts "\nDone! Next steps:\n cd #{name}\n bundle install\n bundle exec falcon host falcon.rb"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def create_dir(path)
|
|
46
|
+
FileUtils.mkdir_p(path)
|
|
47
|
+
puts " create #{path}/"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write(root, relative_path, content)
|
|
51
|
+
File.write(File.join(root, relative_path), content)
|
|
52
|
+
puts " create #{relative_path}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def gemfile
|
|
56
|
+
<<~RUBY
|
|
57
|
+
source 'https://rubygems.org'
|
|
58
|
+
|
|
59
|
+
gem 'rivulet-rb'
|
|
60
|
+
gem 'falcon'
|
|
61
|
+
RUBY
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def config_ru
|
|
65
|
+
<<~RUBY
|
|
66
|
+
require 'rivulet'
|
|
67
|
+
|
|
68
|
+
run Rivulet.app.startup
|
|
69
|
+
RUBY
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def application_config(name)
|
|
73
|
+
<<~RUBY
|
|
74
|
+
Rivulet.configure do |config|
|
|
75
|
+
# config.database.dsn = ENV.fetch('DATABASE_URL', 'sqlite://db/#{name}.sqlite3')
|
|
76
|
+
|
|
77
|
+
# config.sendfile.enabled = true
|
|
78
|
+
# config.sendfile.variation = 'x-accel-redirect'
|
|
79
|
+
# config.sendfile.mappings = [['/var/www/', '/files/']]
|
|
80
|
+
|
|
81
|
+
config.logger.name = :#{name}
|
|
82
|
+
config.logger.level = :info
|
|
83
|
+
end
|
|
84
|
+
RUBY
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def falcon_config
|
|
88
|
+
<<~RUBY
|
|
89
|
+
require 'falcon/environment/rack'
|
|
90
|
+
require 'falcon/environment/server'
|
|
91
|
+
|
|
92
|
+
service "app" do
|
|
93
|
+
include Falcon::Environment::Server
|
|
94
|
+
include Falcon::Environment::Rackup
|
|
95
|
+
end
|
|
96
|
+
RUBY
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def routes_config
|
|
100
|
+
<<~RUBY
|
|
101
|
+
# get :posts, to: 'posts#index'
|
|
102
|
+
|
|
103
|
+
Rivulet.routes.draw do
|
|
104
|
+
end
|
|
105
|
+
RUBY
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def handlers_container
|
|
109
|
+
<<~RUBY
|
|
110
|
+
module Handlers
|
|
111
|
+
extend Dry::Core::Container::Mixin
|
|
112
|
+
end
|
|
113
|
+
RUBY
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def handlers_shared_container
|
|
117
|
+
<<~RUBY
|
|
118
|
+
module Handlers
|
|
119
|
+
module Shared
|
|
120
|
+
class Container
|
|
121
|
+
extend Dry::Core::Container::Mixin
|
|
122
|
+
import Namespace
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
RUBY
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def handlers_shared_namespace
|
|
130
|
+
<<~RUBY
|
|
131
|
+
module Handlers
|
|
132
|
+
module Shared
|
|
133
|
+
Namespace = Dry::Core::Container::Namespace.new('shared') do
|
|
134
|
+
namespace('steps') do
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
namespace('utils') do
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
RUBY
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def services_container
|
|
146
|
+
<<~RUBY
|
|
147
|
+
module Services
|
|
148
|
+
extend Dry::Core::Container::Mixin
|
|
149
|
+
end
|
|
150
|
+
RUBY
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def services_shared_container
|
|
154
|
+
<<~RUBY
|
|
155
|
+
module Services
|
|
156
|
+
module Shared
|
|
157
|
+
class Container
|
|
158
|
+
extend Dry::Core::Container::Mixin
|
|
159
|
+
import Namespace
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
RUBY
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def services_shared_namespace
|
|
167
|
+
<<~RUBY
|
|
168
|
+
module Services
|
|
169
|
+
module Shared
|
|
170
|
+
Namespace = Dry::Core::Container::Namespace.new('shared') do
|
|
171
|
+
namespace('steps') do
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
namespace('utils') do
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
RUBY
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def application_contract_template
|
|
183
|
+
<<~RUBY
|
|
184
|
+
class ApplicationContract < Dry::Validation::Contract
|
|
185
|
+
end
|
|
186
|
+
RUBY
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
data/lib/rivulet/cli.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'dry/cli'
|
|
2
|
+
require_relative 'cli/new'
|
|
3
|
+
require_relative 'cli/console'
|
|
4
|
+
require_relative 'cli/routes'
|
|
5
|
+
require_relative 'cli/db/migrate'
|
|
6
|
+
require_relative 'cli/generate/operation'
|
|
7
|
+
require_relative 'cli/generate/handler'
|
|
8
|
+
require_relative 'cli/generate/handler/operation'
|
|
9
|
+
require_relative 'cli/generate/handler/step'
|
|
10
|
+
require_relative 'cli/generate/migration'
|
|
11
|
+
require_relative 'cli/generate/resource'
|
|
12
|
+
require_relative 'cli/generate/service'
|
|
13
|
+
require_relative 'cli/generate/service/operation'
|
|
14
|
+
require_relative 'cli/generate/service/step'
|
|
15
|
+
require_relative 'cli/generate/service/projection'
|
|
16
|
+
|
|
17
|
+
module Rivulet
|
|
18
|
+
module CLI
|
|
19
|
+
module Commands
|
|
20
|
+
extend Dry::CLI::Registry
|
|
21
|
+
|
|
22
|
+
register 'new', Commands::New
|
|
23
|
+
register 'console', Commands::Console, aliases: ['c']
|
|
24
|
+
register 'routes', Commands::Routes
|
|
25
|
+
|
|
26
|
+
register 'generate', aliases: ['g'] do |prefix|
|
|
27
|
+
prefix.register 'resource', Commands::Generate::Resource
|
|
28
|
+
prefix.register 'service', Commands::Generate::Service
|
|
29
|
+
prefix.register 'service operation', Commands::Generate::Service::Operation
|
|
30
|
+
prefix.register 'service step', Commands::Generate::Service::Step
|
|
31
|
+
prefix.register 'service projection', Commands::Generate::Service::Projection
|
|
32
|
+
prefix.register 'handler', Commands::Generate::Handler
|
|
33
|
+
prefix.register 'handler operation', Commands::Generate::Handler::Operation
|
|
34
|
+
prefix.register 'handler step', Commands::Generate::Handler::Step
|
|
35
|
+
prefix.register 'migration', Commands::Generate::Migration
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
register 'db' do |prefix|
|
|
39
|
+
prefix.register 'migrate', Commands::DB::Migrate
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|