dandy 0.12.1 → 2.0.0.pre.alpha
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/.travis.yml +2 -2
- data/README.md +4 -3
- data/dandy.gemspec +4 -4
- data/lib/dandy.rb +1 -0
- data/lib/dandy/app.rb +22 -11
- data/lib/dandy/chain.rb +7 -7
- data/lib/dandy/consumer.rb +32 -0
- data/lib/dandy/generators/cli.rb +5 -2
- data/lib/dandy/generators/templates/actions/common/close_db_session.rb +12 -0
- data/lib/dandy/generators/templates/actions/common/handle_errors_jet_set.rb +20 -0
- data/lib/dandy/generators/templates/app/app.jet_set.routes +7 -0
- data/lib/dandy/generators/templates/dandy.yml +1 -1
- data/lib/dandy/handler_executor.rb +28 -0
- data/lib/dandy/loaders/dependency_loader.rb +4 -2
- data/lib/dandy/loaders/type_loader.rb +2 -2
- data/lib/dandy/message.rb +50 -0
- data/lib/dandy/request.rb +10 -5
- data/lib/dandy/response.rb +11 -0
- data/lib/dandy/{safe_executor.rb → route_executor.rb} +14 -16
- data/lib/dandy/routing/handlers_builder.rb +25 -0
- data/lib/dandy/routing/message_handler.rb +15 -0
- data/lib/dandy/routing/parser.rb +14 -2
- data/lib/dandy/routing/{builder.rb → routes_builder.rb} +4 -4
- data/lib/dandy/routing/routing.rb +2 -1
- data/lib/dandy/routing/syntax.rb +7 -1
- data/lib/dandy/routing/syntax/dandy.rb +20 -0
- data/lib/dandy/routing/syntax/message.rb +19 -0
- data/lib/dandy/routing/syntax/message_name.rb +7 -0
- data/lib/dandy/routing/syntax/messages.rb +35 -0
- data/lib/dandy/routing/syntax/{sections.rb → requests.rb} +1 -1
- data/lib/dandy/routing/syntax_grammar.tt +18 -2
- data/lib/dandy/version.rb +1 -1
- data/lib/dandy/view_factory.rb +7 -1
- metadata +32 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f0a2a55e97bb758be7b7fd22226adc5757a7ad94fc48596448d0b10447e85abe
|
4
|
+
data.tar.gz: 232468091c7e5dca9f15a28b54dedc298003f24a0acc116f85ea79f64f83db09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a090b89c227d4acd9b2d4fcd2527a649acd147d60b23aee1ebef93c3eec4659311a1204487e304e04a02a7c2abd489b5800c7c6a0522ba63cbd893ccdac24bdd
|
7
|
+
data.tar.gz: dca5768ae6c078c5f1cc5f529489ac43d856b169b49617dfacab1df649779a60a2f8a36d4eaeff20ff862443124e204d7d0d12e5fd49328a211d2c29140e93f1
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Dandy is a minimalistic web API framework. Its main idea is to implement an approach
|
4
4
|
from Clean Architecture principles - "web is just a delivery mechanism".
|
5
|
-
Dandy is build on top of IoC container Hypo and forces to use dependency injection
|
5
|
+
Dandy is build on top of IoC container [Hypo](https://github.com/cylon-v/hypo) and forces to use dependency injection
|
6
6
|
approach everywhere.
|
7
7
|
|
8
8
|
## Basic Concepts
|
@@ -109,13 +109,14 @@ or just
|
|
109
109
|
$ rackup -p 8000 config.ru
|
110
110
|
```
|
111
111
|
|
112
|
-
4.
|
112
|
+
4. Run curl command `curl http://localhost:8000 -H "Accept: application/json"` and you'll see:
|
113
113
|
|
114
114
|
```json
|
115
115
|
{"message": "Welcome to dandy-app!"}
|
116
116
|
```
|
117
|
+
Please take attention - HTTP header "Accept: application/json" is a mandatory.
|
117
118
|
|
118
|
-
5. Investigate example application code, it
|
119
|
+
5. Investigate example application code, it explains most of Dandy aspects.
|
119
120
|
6. For more details visit our [Wiki](https://github.com/cylon-v/dandy/wiki).
|
120
121
|
|
121
122
|
## Development
|
data/dandy.gemspec
CHANGED
@@ -30,8 +30,8 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
31
|
spec.require_paths = ['lib']
|
32
32
|
|
33
|
-
spec.add_dependency 'hypo', '~> 0.
|
34
|
-
spec.add_dependency 'rack', '~> 2.
|
33
|
+
spec.add_dependency 'hypo', '~> 1.0.0'
|
34
|
+
spec.add_dependency 'rack', '~> 2.2.3'
|
35
35
|
spec.add_dependency 'thor', '~> 0.20.0'
|
36
36
|
spec.add_dependency 'treetop', '~> 1.6.8'
|
37
37
|
spec.add_dependency 'jbuilder', '~> 2.7.0'
|
@@ -40,8 +40,8 @@ Gem::Specification.new do |spec|
|
|
40
40
|
spec.add_dependency 'awrence', '~> 1.0.0'
|
41
41
|
spec.add_dependency 'plissken', '~> 1.2.0'
|
42
42
|
|
43
|
-
spec.add_development_dependency 'bundler', '~> 1
|
44
|
-
spec.add_development_dependency 'rake', '~>
|
43
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
44
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
45
45
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
46
46
|
spec.add_development_dependency 'rspec-mocks', '~> 3.6'
|
47
47
|
spec.add_development_dependency 'simplecov', '~> 0.15'
|
data/lib/dandy.rb
CHANGED
data/lib/dandy/app.rb
CHANGED
@@ -11,7 +11,8 @@ require 'dandy/view_builder_registry'
|
|
11
11
|
require 'dandy/view_factory'
|
12
12
|
require 'dandy/view_builders/json'
|
13
13
|
require 'dandy/routing/routing'
|
14
|
-
require 'dandy/
|
14
|
+
require 'dandy/route_executor'
|
15
|
+
require 'dandy/handler_executor'
|
15
16
|
|
16
17
|
module Dandy
|
17
18
|
class App
|
@@ -22,12 +23,12 @@ module Dandy
|
|
22
23
|
|
23
24
|
register_dependencies
|
24
25
|
load_basic_dependencies
|
25
|
-
|
26
|
+
parse_entrypoints
|
26
27
|
add_view_builders
|
27
28
|
end
|
28
29
|
|
29
30
|
def call(env)
|
30
|
-
request = Request.new(@route_matcher, @container, @
|
31
|
+
request = Request.new(@route_matcher, @container, @route_executor)
|
31
32
|
request.handle(env)
|
32
33
|
end
|
33
34
|
|
@@ -37,6 +38,10 @@ module Dandy
|
|
37
38
|
@view_builder_registry.add(view_builder, format)
|
38
39
|
end
|
39
40
|
|
41
|
+
def add_consumer(consumer)
|
42
|
+
consumer.connect(@message_handlers, @handler_executor)
|
43
|
+
end
|
44
|
+
|
40
45
|
private
|
41
46
|
|
42
47
|
def add_view_builders
|
@@ -46,7 +51,8 @@ module Dandy
|
|
46
51
|
def register_dependencies
|
47
52
|
instances = {
|
48
53
|
config_file_path: 'dandy.yml',
|
49
|
-
dandy_env: ENV['DANDY_ENV'] || 'development'
|
54
|
+
dandy_env: ENV['DANDY_ENV'] || 'development',
|
55
|
+
env: ENV
|
50
56
|
}
|
51
57
|
|
52
58
|
instances.keys.each do |name|
|
@@ -64,9 +70,11 @@ module Dandy
|
|
64
70
|
file_reader: Routing::FileReader,
|
65
71
|
syntax_parser: SyntaxParser,
|
66
72
|
syntax_error_interpreter: Routing::SyntaxErrorInterpreter,
|
67
|
-
routes_builder: Routing::
|
68
|
-
|
69
|
-
|
73
|
+
routes_builder: Routing::RoutesBuilder,
|
74
|
+
handlers_builder: Routing::HandlersBuilder,
|
75
|
+
dandy_parser: Routing::Parser,
|
76
|
+
route_executor: RouteExecutor,
|
77
|
+
handler_executor: HandlerExecutor
|
70
78
|
}
|
71
79
|
|
72
80
|
singletons.keys.each do |name|
|
@@ -80,14 +88,17 @@ module Dandy
|
|
80
88
|
@view_factory = @container.resolve(:view_factory)
|
81
89
|
@dependency_loader = @container.resolve(:dependency_loader)
|
82
90
|
@view_builder_registry = @container.resolve(:view_builder_registry)
|
83
|
-
@
|
84
|
-
@
|
91
|
+
@dandy_parser = @container.resolve(:dandy_parser)
|
92
|
+
@route_executor = @container.resolve(:route_executor)
|
93
|
+
@handler_executor = @container.resolve(:handler_executor)
|
85
94
|
|
86
95
|
@dependency_loader.load_components
|
87
96
|
end
|
88
97
|
|
89
|
-
def
|
90
|
-
|
98
|
+
def parse_entrypoints
|
99
|
+
entrypoints = @dandy_parser.parse
|
100
|
+
@routes = entrypoints[:routes]
|
101
|
+
@message_handlers = entrypoints[:message_handlers]
|
91
102
|
@route_matcher = Routing::Matcher.new(@routes)
|
92
103
|
end
|
93
104
|
end
|
data/lib/dandy/chain.rb
CHANGED
@@ -7,7 +7,7 @@ module Dandy
|
|
7
7
|
@async_timeout = dandy_config[:action][:async_timeout]
|
8
8
|
end
|
9
9
|
|
10
|
-
def run_commands(commands, last_command)
|
10
|
+
def run_commands(commands, last_command, scope)
|
11
11
|
threads = []
|
12
12
|
Thread.abort_on_exception = true
|
13
13
|
|
@@ -19,17 +19,17 @@ module Dandy
|
|
19
19
|
threads = []
|
20
20
|
|
21
21
|
if last_command && (command.name == last_command.name)
|
22
|
-
result = run_command(command)
|
22
|
+
result = run_command(command, scope)
|
23
23
|
else
|
24
|
-
run_command(command)
|
24
|
+
run_command(command, scope)
|
25
25
|
end
|
26
26
|
else
|
27
27
|
thread = Thread.new {
|
28
28
|
Timeout::timeout(@async_timeout) {
|
29
29
|
if last_command && (command.name == last_command.name)
|
30
|
-
result = run_command(command)
|
30
|
+
result = run_command(command, scope)
|
31
31
|
else
|
32
|
-
run_command(command)
|
32
|
+
run_command(command, scope)
|
33
33
|
end
|
34
34
|
}
|
35
35
|
}
|
@@ -47,7 +47,7 @@ module Dandy
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def run_command(command)
|
50
|
+
def run_command(command, scope)
|
51
51
|
if command.entity?
|
52
52
|
entity = @container.resolve(command.entity_name.to_sym)
|
53
53
|
method_name = command.entity_method.to_sym
|
@@ -65,7 +65,7 @@ module Dandy
|
|
65
65
|
@container
|
66
66
|
.register_instance(result, command.result_name.to_sym)
|
67
67
|
.using_lifetime(:scope)
|
68
|
-
.bound_to(
|
68
|
+
.bound_to(scope)
|
69
69
|
|
70
70
|
result
|
71
71
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'dandy/message'
|
2
|
+
|
3
|
+
module Dandy
|
4
|
+
class Consumer
|
5
|
+
def initialize(container)
|
6
|
+
@container = container
|
7
|
+
end
|
8
|
+
|
9
|
+
def connect(message_handlers, handler_executor)
|
10
|
+
@message_handlers = {}
|
11
|
+
@handler_executor = handler_executor
|
12
|
+
|
13
|
+
message_handlers.each do |handler|
|
14
|
+
@message_handlers[handler.name] = handler
|
15
|
+
end
|
16
|
+
|
17
|
+
subscribe
|
18
|
+
end
|
19
|
+
|
20
|
+
def subscribe
|
21
|
+
raise DandyError, 'Method subscribe is not implemented in your consumer'
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle(message_name, payload)
|
25
|
+
if @message_handlers.key? message_name
|
26
|
+
handler = @message_handlers[message_name]
|
27
|
+
message = Message.new(@container, handler, @handler_executor)
|
28
|
+
message.handle(payload)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/dandy/generators/cli.rb
CHANGED
@@ -19,16 +19,19 @@ module Dandy
|
|
19
19
|
copy_file 'templates/Gemfile_jet_set', "#{name}/Gemfile"
|
20
20
|
copy_file 'templates/db/mapping.rb', "#{name}/db/mapping.rb"
|
21
21
|
copy_file 'templates/actions/common/open_db_session.rb', "#{name}/app/actions/common/open_db_session.rb"
|
22
|
+
copy_file 'templates/actions/common/close_db_session.rb', "#{name}/app/actions/common/close_db_session.rb"
|
23
|
+
copy_file 'templates/actions/common/handle_errors_jet_set.rb', "#{name}/app/actions/common/handle_errors.rb"
|
24
|
+
copy_file 'templates/app/app.jet_set.routes', "#{name}/app/app.routes"
|
22
25
|
else
|
23
26
|
copy_file 'templates/app/app.rb', "#{name}/app/app.rb"
|
24
27
|
copy_file 'templates/Gemfile', "#{name}/Gemfile"
|
28
|
+
copy_file 'templates/actions/common/handle_errors.rb', "#{name}/app/actions/common/handle_errors.rb"
|
29
|
+
copy_file 'templates/app/app.routes', "#{name}/app/app.routes"
|
25
30
|
end
|
26
31
|
|
27
|
-
copy_file 'templates/app/app.routes', "#{name}/app/app.routes"
|
28
32
|
copy_file 'templates/dandy.yml', "#{name}/dandy.yml"
|
29
33
|
copy_file 'templates/config.ru', "#{name}/config.ru"
|
30
34
|
copy_file 'templates/views/show_welcome.json.jbuilder', "#{name}/app/views/show_welcome.json.jbuilder"
|
31
|
-
copy_file 'templates/actions/common/handle_errors.rb', "#{name}/app/actions/common/handle_errors.rb"
|
32
35
|
template 'templates/actions/welcome.tt', "#{name}/app/actions/welcome.rb", {app_name: name}
|
33
36
|
|
34
37
|
if options[:jet_set]
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class HandleErrors < Dandy::HandleErrors
|
2
|
+
def initialize(container, dandy_error, sequel)
|
3
|
+
super(container, dandy_error)
|
4
|
+
|
5
|
+
@sequel = sequel
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
@sequel.disconnect
|
10
|
+
|
11
|
+
# implement your own error handling logic here.
|
12
|
+
# by default let's print the error to standard output
|
13
|
+
puts @dandy_error.message
|
14
|
+
puts @dandy_error.backtrace
|
15
|
+
|
16
|
+
# use preferred HTTP status code for different cases
|
17
|
+
# i.e. set_http_status(403) for authorization issue
|
18
|
+
set_http_status(500)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dandy
|
2
|
+
class HandlerExecutor
|
3
|
+
def initialize(container, dandy_config)
|
4
|
+
@container = container
|
5
|
+
@dandy_config = dandy_config
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute(message_handler)
|
9
|
+
chain = Chain.new(@container, @dandy_config)
|
10
|
+
|
11
|
+
begin
|
12
|
+
chain.run_commands(message_handler.commands, message_handler.last_command, :dandy_message)
|
13
|
+
rescue Exception => error
|
14
|
+
handle_error(message_handler, error)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_error(message_handler, error)
|
19
|
+
@container
|
20
|
+
.register_instance(error, :dandy_error)
|
21
|
+
.using_lifetime(:scope)
|
22
|
+
.bound_to(:dandy_message)
|
23
|
+
|
24
|
+
command = @container.resolve(message_handler.catch.name.to_sym)
|
25
|
+
command.call
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -7,14 +7,16 @@ module Dandy
|
|
7
7
|
@dandy_env = dandy_env
|
8
8
|
end
|
9
9
|
|
10
|
-
def load_components
|
10
|
+
def load_components(scope = :dandy_request)
|
11
11
|
if @dandy_env == 'development'
|
12
12
|
# every time reload types in development mode
|
13
13
|
@types = @type_loader.load_types
|
14
14
|
end
|
15
15
|
|
16
16
|
@types.each do |type|
|
17
|
-
@container.register(type[:class], type[:path].to_sym)
|
17
|
+
@container.register(type[:class], type[:path].to_sym)
|
18
|
+
.using_lifetime(:scope)
|
19
|
+
.bound_to(scope)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -9,8 +9,8 @@ module Dandy
|
|
9
9
|
@directories.each do |directory|
|
10
10
|
dir = File.join(directory, '**/*')
|
11
11
|
files = Dir.glob(dir).reject {|file_path| File.directory?(file_path)}
|
12
|
-
|
13
|
-
files.each do |file|
|
12
|
+
test_patterns = %w(_spec.rb .spec.rb _test.rb .test.rb)
|
13
|
+
files.select {|f| !f.end_with?(*test_patterns)}.each do |file|
|
14
14
|
path = File.join(Dir.pwd, file)
|
15
15
|
require path
|
16
16
|
file_name = File.basename(file).gsub(File.extname(file), '')
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'awrence'
|
3
|
+
require 'plissken'
|
4
|
+
require 'rack/multipart'
|
5
|
+
require 'dandy/extensions/hash'
|
6
|
+
require 'dandy/view_factory'
|
7
|
+
require 'dandy/chain'
|
8
|
+
|
9
|
+
module Dandy
|
10
|
+
class Message
|
11
|
+
include Hypo::Scope
|
12
|
+
|
13
|
+
def initialize(container, handler, handler_executor)
|
14
|
+
@container = container
|
15
|
+
@handler = handler
|
16
|
+
@handler_executor = handler_executor
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle(data)
|
20
|
+
create_scope
|
21
|
+
register_data(data)
|
22
|
+
|
23
|
+
begin
|
24
|
+
result = @handler_executor.execute(@handler)
|
25
|
+
release
|
26
|
+
rescue Exception => error
|
27
|
+
result = @handler_executor.handle_error(@handler, error)
|
28
|
+
end
|
29
|
+
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_scope
|
36
|
+
@container
|
37
|
+
.register_instance(self, :dandy_message)
|
38
|
+
.using_lifetime(:scope)
|
39
|
+
.bound_to(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def register_data(data)
|
43
|
+
unless data.nil?
|
44
|
+
@container.register_instance(data, :dandy_data)
|
45
|
+
.using_lifetime(:scope)
|
46
|
+
.bound_to(:dandy_message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/dandy/request.rb
CHANGED
@@ -10,10 +10,10 @@ module Dandy
|
|
10
10
|
class Request
|
11
11
|
include Hypo::Scope
|
12
12
|
|
13
|
-
def initialize(route_matcher, container,
|
13
|
+
def initialize(route_matcher, container, route_executor)
|
14
14
|
@container = container
|
15
15
|
@route_matcher = route_matcher
|
16
|
-
@
|
16
|
+
@route_executor = route_executor
|
17
17
|
end
|
18
18
|
|
19
19
|
def handle(rack_env)
|
@@ -34,6 +34,7 @@ module Dandy
|
|
34
34
|
|
35
35
|
if match.nil?
|
36
36
|
result = [404, {'Content-Type' => headers['Accept']}, []]
|
37
|
+
release
|
37
38
|
else
|
38
39
|
status = match.route.http_status || default_http_status(match.route.http_verb)
|
39
40
|
register_params(match.params)
|
@@ -48,13 +49,17 @@ module Dandy
|
|
48
49
|
multipart = Rack::Multipart.parse_multipart(rack_env) || {}
|
49
50
|
register_context(multipart.values, :dandy_files)
|
50
51
|
|
51
|
-
|
52
|
+
begin
|
53
|
+
body = @route_executor.execute(match.route, headers)
|
54
|
+
release
|
55
|
+
rescue Exception => error
|
56
|
+
body = @route_executor.handle_error(match.route, headers, error)
|
57
|
+
end
|
52
58
|
|
53
59
|
status = @container.resolve(:dandy_status)
|
54
|
-
result = [status, {'Content-Type' =>
|
60
|
+
result = [status, {'Content-Type' => 'application/json'}, [body]]
|
55
61
|
end
|
56
62
|
|
57
|
-
release
|
58
63
|
|
59
64
|
result
|
60
65
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'dandy/response'
|
2
|
+
|
1
3
|
module Dandy
|
2
|
-
class
|
4
|
+
class RouteExecutor
|
3
5
|
def initialize(container, dandy_config, view_factory)
|
4
6
|
@container = container
|
5
7
|
@dandy_config = dandy_config
|
@@ -10,32 +12,28 @@ module Dandy
|
|
10
12
|
chain = Chain.new(@container, @dandy_config)
|
11
13
|
|
12
14
|
begin
|
13
|
-
result = chain.run_commands(route.commands, route.last_command)
|
15
|
+
result = chain.run_commands(route.commands, route.last_command, :dandy_request)
|
14
16
|
if route.view
|
15
17
|
result = @view_factory.create(route.view, headers['Accept'], {keys_format: headers['Keys-Format'] || 'snake'})
|
16
18
|
end
|
17
19
|
|
18
|
-
body = result.is_a?(String) ? result :
|
20
|
+
body = result.is_a?(String) ? result : Response.format(result, headers)
|
19
21
|
rescue Exception => error
|
20
|
-
|
21
|
-
|
22
|
-
.using_lifetime(:scope)
|
23
|
-
.bound_to(:dandy_request)
|
24
|
-
|
25
|
-
action = @container.resolve(route.catch.name.to_sym)
|
26
|
-
body = format_response(action.call, headers)
|
22
|
+
p error
|
23
|
+
body = handle_error(route, headers, error)
|
27
24
|
end
|
28
25
|
|
29
26
|
body
|
30
27
|
end
|
31
28
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
def handle_error(route, headers, error)
|
30
|
+
@container
|
31
|
+
.register_instance(error, :dandy_error)
|
32
|
+
.using_lifetime(:scope)
|
33
|
+
.bound_to(:dandy_request)
|
37
34
|
|
38
|
-
|
35
|
+
action = @container.resolve(route.catch.name.to_sym)
|
36
|
+
Response.format(action.call, headers)
|
39
37
|
end
|
40
38
|
end
|
41
39
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'dandy/routing/message_handler'
|
2
|
+
|
3
|
+
module Dandy
|
4
|
+
module Routing
|
5
|
+
class HandlersBuilder
|
6
|
+
def initialize
|
7
|
+
@parsed_items = []
|
8
|
+
@route_params = []
|
9
|
+
@current_parent = nil
|
10
|
+
@prev_route = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(section)
|
14
|
+
section.messages.map do |message|
|
15
|
+
MessageHandler.new({
|
16
|
+
name: message.name,
|
17
|
+
catch: section.catch.command,
|
18
|
+
last_command: message.command_list.last,
|
19
|
+
commands: section.before_commands + message.command_list + section.after_commands
|
20
|
+
})
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dandy
|
2
|
+
module Routing
|
3
|
+
class MessageHandler
|
4
|
+
attr_reader :name, :params, :catch,
|
5
|
+
:commands, :last_command
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
@name = hash[:name]
|
9
|
+
@commands = hash[:commands]
|
10
|
+
@last_command = hash[:last_command]
|
11
|
+
@catch = hash[:catch]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/dandy/routing/parser.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Dandy
|
2
2
|
module Routing
|
3
3
|
class Parser
|
4
|
-
def initialize(file_reader, routes_builder,
|
4
|
+
def initialize(file_reader, routes_builder, handlers_builder,
|
5
5
|
syntax_parser, syntax_error_interpreter)
|
6
6
|
@file_reader = file_reader
|
7
7
|
@routes_builder = routes_builder
|
8
|
+
@handlers_builder = handlers_builder
|
8
9
|
@syntax_parser = syntax_parser
|
9
10
|
@syntax_error_interpreter = syntax_error_interpreter
|
10
11
|
end
|
@@ -18,7 +19,18 @@ module Dandy
|
|
18
19
|
raise Dandy::SyntaxError, error_message
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
+
dandy = tree.parse
|
23
|
+
|
24
|
+
result = {}
|
25
|
+
if dandy.requests
|
26
|
+
result[:routes] = @routes_builder.build(dandy.requests)
|
27
|
+
end
|
28
|
+
|
29
|
+
if dandy.messages
|
30
|
+
result[:message_handlers] = @handlers_builder.build(dandy.messages)
|
31
|
+
end
|
32
|
+
|
33
|
+
result
|
22
34
|
end
|
23
35
|
end
|
24
36
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Dandy
|
4
4
|
module Routing
|
5
|
-
class
|
5
|
+
class RoutesBuilder
|
6
6
|
def initialize
|
7
7
|
@parsed_items = []
|
8
8
|
@route_params = []
|
@@ -10,10 +10,10 @@ module Dandy
|
|
10
10
|
@prev_route = nil
|
11
11
|
end
|
12
12
|
|
13
|
-
def build(
|
13
|
+
def build(requests)
|
14
14
|
result = []
|
15
15
|
|
16
|
-
node =
|
16
|
+
node = requests.node
|
17
17
|
restore_hierarchy(node, nil, node.to_hash)
|
18
18
|
|
19
19
|
@route_params.each do |route|
|
@@ -25,7 +25,7 @@ module Dandy
|
|
25
25
|
http_verb: action[:http_verb],
|
26
26
|
view: action[:view],
|
27
27
|
http_status: action[:http_status],
|
28
|
-
catch:
|
28
|
+
catch: requests.catch.command,
|
29
29
|
last_command: action[:commands].last,
|
30
30
|
commands: restore_callbacks(route, :before) + action[:commands] + restore_callbacks(route, :after)
|
31
31
|
})
|
data/lib/dandy/routing/syntax.rb
CHANGED
@@ -20,11 +20,17 @@ require_relative 'syntax/route'
|
|
20
20
|
require_relative 'syntax/respond'
|
21
21
|
|
22
22
|
|
23
|
-
require_relative 'syntax/
|
23
|
+
require_relative 'syntax/requests'
|
24
24
|
require_relative 'syntax/before_section'
|
25
25
|
require_relative 'syntax/tree_section'
|
26
26
|
require_relative 'syntax/after_section'
|
27
27
|
require_relative 'syntax/catch_section'
|
28
28
|
|
29
|
+
require_relative 'syntax/message_name'
|
30
|
+
require_relative 'syntax/message'
|
31
|
+
require_relative 'syntax/messages'
|
32
|
+
|
33
|
+
require_relative 'syntax/dandy'
|
34
|
+
|
29
35
|
module Syntax
|
30
36
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Syntax
|
2
|
+
class Dandy < Treetop::Runtime::SyntaxNode
|
3
|
+
attr_reader :requests, :messages
|
4
|
+
|
5
|
+
def parse
|
6
|
+
elements.each do |element|
|
7
|
+
element.elements.each do |nested|
|
8
|
+
if nested.is_a? Requests
|
9
|
+
@requests = nested.parse
|
10
|
+
end
|
11
|
+
|
12
|
+
if nested.is_a? Messages
|
13
|
+
@messages = nested.parse
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Syntax
|
2
|
+
class Message < Treetop::Runtime::SyntaxNode
|
3
|
+
attr_accessor :name, :command_list
|
4
|
+
|
5
|
+
def parse
|
6
|
+
elements.each do |element|
|
7
|
+
if element.is_a? MessageName
|
8
|
+
@name = element.parse
|
9
|
+
end
|
10
|
+
|
11
|
+
if element.is_a? Commands
|
12
|
+
@command_list = element.parse
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Syntax
|
2
|
+
class Messages < Treetop::Runtime::SyntaxNode
|
3
|
+
attr_reader :messages, :catch, :before_commands, :after_commands
|
4
|
+
|
5
|
+
def parse
|
6
|
+
@messages ||= []
|
7
|
+
@before_commands = []
|
8
|
+
@after_commands = []
|
9
|
+
|
10
|
+
elements.each do |element|
|
11
|
+
if element.elements
|
12
|
+
element.elements.each do |nested|
|
13
|
+
if nested.is_a? Message
|
14
|
+
@messages << nested.parse
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if element.is_a? BeforeSection
|
20
|
+
@before_commands = element.parse.commands
|
21
|
+
end
|
22
|
+
|
23
|
+
if element.is_a? AfterSection
|
24
|
+
@after_commands = element.parse.commands
|
25
|
+
end
|
26
|
+
|
27
|
+
if element.is_a? CatchSection
|
28
|
+
@catch = element.parse
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,6 +1,22 @@
|
|
1
1
|
grammar Syntax
|
2
|
-
rule
|
3
|
-
|
2
|
+
rule dandy
|
3
|
+
(requests) 0..1 (messages) 0..1 <Dandy>
|
4
|
+
end
|
5
|
+
|
6
|
+
rule requests
|
7
|
+
':request' eol node catch <Requests>
|
8
|
+
end
|
9
|
+
|
10
|
+
rule messages
|
11
|
+
':message' eol before after message+ catch <Messages>
|
12
|
+
end
|
13
|
+
|
14
|
+
rule message
|
15
|
+
indent message_name commands eol <Message>
|
16
|
+
end
|
17
|
+
|
18
|
+
rule message_name
|
19
|
+
'"' [a-z0-9_\-.]+ '"' <MessageName>
|
4
20
|
end
|
5
21
|
|
6
22
|
rule before
|
data/lib/dandy/version.rb
CHANGED
data/lib/dandy/view_factory.rb
CHANGED
@@ -12,8 +12,14 @@ module Dandy
|
|
12
12
|
|
13
13
|
def create(name, content_type, options = {})
|
14
14
|
type = content_type ? content_type.split('/')[1] : 'json'
|
15
|
-
template = @template_registry.get(name, type)
|
16
15
|
builder = @view_builder_registry.get(type)
|
16
|
+
|
17
|
+
if builder.nil?
|
18
|
+
type = 'json'
|
19
|
+
builder = @view_builder_registry.get(type)
|
20
|
+
end
|
21
|
+
|
22
|
+
template = @template_registry.get(name, type)
|
17
23
|
view = builder.new(template, @container, options)
|
18
24
|
view.process
|
19
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dandy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 2.0.0.pre.alpha
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Kalinkin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hypo
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 1.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 1.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.2.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
40
|
+
version: 2.2.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: thor
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,28 +142,28 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '1
|
145
|
+
version: '2.1'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '1
|
152
|
+
version: '2.1'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: rake
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '
|
159
|
+
version: '13.0'
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: '
|
166
|
+
version: '13.0'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: rspec
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -231,6 +231,7 @@ files:
|
|
231
231
|
- lib/dandy/base/handle_errors.rb
|
232
232
|
- lib/dandy/chain.rb
|
233
233
|
- lib/dandy/config.rb
|
234
|
+
- lib/dandy/consumer.rb
|
234
235
|
- lib/dandy/errors/dandy_error.rb
|
235
236
|
- lib/dandy/errors/syntax_error.rb
|
236
237
|
- lib/dandy/errors/view_engine_error.rb
|
@@ -239,9 +240,12 @@ files:
|
|
239
240
|
- lib/dandy/generators/templates/.gitignore
|
240
241
|
- lib/dandy/generators/templates/Gemfile
|
241
242
|
- lib/dandy/generators/templates/Gemfile_jet_set
|
243
|
+
- lib/dandy/generators/templates/actions/common/close_db_session.rb
|
242
244
|
- lib/dandy/generators/templates/actions/common/handle_errors.rb
|
245
|
+
- lib/dandy/generators/templates/actions/common/handle_errors_jet_set.rb
|
243
246
|
- lib/dandy/generators/templates/actions/common/open_db_session.rb
|
244
247
|
- lib/dandy/generators/templates/actions/welcome.tt
|
248
|
+
- lib/dandy/generators/templates/app/app.jet_set.routes
|
245
249
|
- lib/dandy/generators/templates/app/app.rb
|
246
250
|
- lib/dandy/generators/templates/app/app.routes
|
247
251
|
- lib/dandy/generators/templates/app/app_jet_set.rb
|
@@ -249,16 +253,22 @@ files:
|
|
249
253
|
- lib/dandy/generators/templates/dandy.yml
|
250
254
|
- lib/dandy/generators/templates/db/mapping.rb
|
251
255
|
- lib/dandy/generators/templates/views/show_welcome.json.jbuilder
|
256
|
+
- lib/dandy/handler_executor.rb
|
252
257
|
- lib/dandy/loaders/dependency_loader.rb
|
253
258
|
- lib/dandy/loaders/template_loader.rb
|
254
259
|
- lib/dandy/loaders/type_loader.rb
|
260
|
+
- lib/dandy/message.rb
|
255
261
|
- lib/dandy/request.rb
|
256
|
-
- lib/dandy/
|
262
|
+
- lib/dandy/response.rb
|
263
|
+
- lib/dandy/route_executor.rb
|
257
264
|
- lib/dandy/routing/file_reader.rb
|
265
|
+
- lib/dandy/routing/handlers_builder.rb
|
258
266
|
- lib/dandy/routing/match.rb
|
259
267
|
- lib/dandy/routing/matcher.rb
|
268
|
+
- lib/dandy/routing/message_handler.rb
|
260
269
|
- lib/dandy/routing/parser.rb
|
261
270
|
- lib/dandy/routing/route.rb
|
271
|
+
- lib/dandy/routing/routes_builder.rb
|
262
272
|
- lib/dandy/routing/routing.rb
|
263
273
|
- lib/dandy/routing/syntax.rb
|
264
274
|
- lib/dandy/routing/syntax/action.rb
|
@@ -268,6 +278,10 @@ files:
|
|
268
278
|
- lib/dandy/routing/syntax/catch_section.rb
|
269
279
|
- lib/dandy/routing/syntax/command.rb
|
270
280
|
- lib/dandy/routing/syntax/commands.rb
|
281
|
+
- lib/dandy/routing/syntax/dandy.rb
|
282
|
+
- lib/dandy/routing/syntax/message.rb
|
283
|
+
- lib/dandy/routing/syntax/message_name.rb
|
284
|
+
- lib/dandy/routing/syntax/messages.rb
|
271
285
|
- lib/dandy/routing/syntax/node.rb
|
272
286
|
- lib/dandy/routing/syntax/nodes.rb
|
273
287
|
- lib/dandy/routing/syntax/primitives/arrow.rb
|
@@ -280,14 +294,13 @@ files:
|
|
280
294
|
- lib/dandy/routing/syntax/primitives/parameter.rb
|
281
295
|
- lib/dandy/routing/syntax/primitives/path.rb
|
282
296
|
- lib/dandy/routing/syntax/primitives/result_name.rb
|
297
|
+
- lib/dandy/routing/syntax/requests.rb
|
283
298
|
- lib/dandy/routing/syntax/respond.rb
|
284
299
|
- lib/dandy/routing/syntax/route.rb
|
285
|
-
- lib/dandy/routing/syntax/sections.rb
|
286
300
|
- lib/dandy/routing/syntax/tree_section.rb
|
287
301
|
- lib/dandy/routing/syntax/view.rb
|
288
302
|
- lib/dandy/routing/syntax_error_interpreter.rb
|
289
303
|
- lib/dandy/routing/syntax_grammar.tt
|
290
|
-
- lib/dandy/safe_executor.rb
|
291
304
|
- lib/dandy/template_registry.rb
|
292
305
|
- lib/dandy/version.rb
|
293
306
|
- lib/dandy/view_builder.rb
|
@@ -299,7 +312,7 @@ licenses:
|
|
299
312
|
- MIT
|
300
313
|
metadata:
|
301
314
|
allowed_push_host: https://rubygems.org
|
302
|
-
post_install_message:
|
315
|
+
post_install_message:
|
303
316
|
rdoc_options: []
|
304
317
|
require_paths:
|
305
318
|
- lib
|
@@ -310,13 +323,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
310
323
|
version: '0'
|
311
324
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
312
325
|
requirements:
|
313
|
-
- - "
|
326
|
+
- - ">"
|
314
327
|
- !ruby/object:Gem::Version
|
315
|
-
version:
|
328
|
+
version: 1.3.1
|
316
329
|
requirements: []
|
317
|
-
|
318
|
-
|
319
|
-
signing_key:
|
330
|
+
rubygems_version: 3.2.15
|
331
|
+
signing_key:
|
320
332
|
specification_version: 4
|
321
333
|
summary: Dandy is a minimalistic web API framework.
|
322
334
|
test_files: []
|