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.
Files changed (35) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -2
  3. data/README.md +4 -3
  4. data/dandy.gemspec +4 -4
  5. data/lib/dandy.rb +1 -0
  6. data/lib/dandy/app.rb +22 -11
  7. data/lib/dandy/chain.rb +7 -7
  8. data/lib/dandy/consumer.rb +32 -0
  9. data/lib/dandy/generators/cli.rb +5 -2
  10. data/lib/dandy/generators/templates/actions/common/close_db_session.rb +12 -0
  11. data/lib/dandy/generators/templates/actions/common/handle_errors_jet_set.rb +20 -0
  12. data/lib/dandy/generators/templates/app/app.jet_set.routes +7 -0
  13. data/lib/dandy/generators/templates/dandy.yml +1 -1
  14. data/lib/dandy/handler_executor.rb +28 -0
  15. data/lib/dandy/loaders/dependency_loader.rb +4 -2
  16. data/lib/dandy/loaders/type_loader.rb +2 -2
  17. data/lib/dandy/message.rb +50 -0
  18. data/lib/dandy/request.rb +10 -5
  19. data/lib/dandy/response.rb +11 -0
  20. data/lib/dandy/{safe_executor.rb → route_executor.rb} +14 -16
  21. data/lib/dandy/routing/handlers_builder.rb +25 -0
  22. data/lib/dandy/routing/message_handler.rb +15 -0
  23. data/lib/dandy/routing/parser.rb +14 -2
  24. data/lib/dandy/routing/{builder.rb → routes_builder.rb} +4 -4
  25. data/lib/dandy/routing/routing.rb +2 -1
  26. data/lib/dandy/routing/syntax.rb +7 -1
  27. data/lib/dandy/routing/syntax/dandy.rb +20 -0
  28. data/lib/dandy/routing/syntax/message.rb +19 -0
  29. data/lib/dandy/routing/syntax/message_name.rb +7 -0
  30. data/lib/dandy/routing/syntax/messages.rb +35 -0
  31. data/lib/dandy/routing/syntax/{sections.rb → requests.rb} +1 -1
  32. data/lib/dandy/routing/syntax_grammar.tt +18 -2
  33. data/lib/dandy/version.rb +1 -1
  34. data/lib/dandy/view_factory.rb +7 -1
  35. metadata +32 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f5fd46a75db6411e264b87e934aff42dd34b2b7e
4
- data.tar.gz: 681b74058c62074c072f59fab34c98ad21ac3e35
2
+ SHA256:
3
+ metadata.gz: f0a2a55e97bb758be7b7fd22226adc5757a7ad94fc48596448d0b10447e85abe
4
+ data.tar.gz: 232468091c7e5dca9f15a28b54dedc298003f24a0acc116f85ea79f64f83db09
5
5
  SHA512:
6
- metadata.gz: a9fc7ea134531646040be3368dcb0745e8bd8d19d4495bd38a0963728f8268c5d46f687f4bc7e0a76c0d55900f80d4ee07dbbbbb211cdce717a7aa809087fb85
7
- data.tar.gz: 5a2b123dd6e34b828450a519ebb2cbe2bb98b52aa960bb1933956433fdc60d7db6b3166d2db9004ae60ccd4ddb604184e91f6581de7273c7c9ba7b8be0fdb730
6
+ metadata.gz: a090b89c227d4acd9b2d4fcd2527a649acd147d60b23aee1ebef93c3eec4659311a1204487e304e04a02a7c2abd489b5800c7c6a0522ba63cbd893ccdac24bdd
7
+ data.tar.gz: dca5768ae6c078c5f1cc5f529489ac43d856b169b49617dfacab1df649779a60a2f8a36d4eaeff20ff862443124e204d7d0d12e5fd49328a211d2c29140e93f1
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4.1
5
- before_install: gem install bundler -v 1.15.4
4
+ - 2.6
5
+ before_install: gem install bundler
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. Using a browser, go to http://localhost:8000 and you'll see:
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 will explain most of Dandy aspects.
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.9.0'
34
- spec.add_dependency 'rack', '~> 2.0.3'
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.15'
44
- spec.add_development_dependency 'rake', '~> 10.0'
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
@@ -1,5 +1,6 @@
1
1
  require 'dandy/version'
2
2
  require 'dandy/app'
3
+ require 'dandy/consumer'
3
4
  require 'dandy/base/handle_errors'
4
5
 
5
6
  module Dandy
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/safe_executor'
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
- parse_routes
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, @safe_executor)
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::Builder,
68
- route_parser: Routing::Parser,
69
- safe_executor: SafeExecutor
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
- @route_parser = @container.resolve(:route_parser)
84
- @safe_executor = @container.resolve(:safe_executor)
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 parse_routes
90
- @routes = @route_parser.parse
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(:dandy_request)
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
@@ -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,12 @@
1
+ require 'sequel'
2
+ require 'jet_set'
3
+
4
+ class CloseDbSession
5
+ def initialize(sequel)
6
+ @sequel = sequel
7
+ end
8
+
9
+ def call
10
+ @sequel.disconnect
11
+ end
12
+ end
@@ -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,7 @@
1
+ :receive
2
+ .->
3
+ :before -> common/open_db_session
4
+ :after -> common/close_db_session
5
+
6
+ GET -> message@welcome -> :respond <- show_welcome
7
+ :catch -> common/handle_errors
@@ -2,7 +2,7 @@ path:
2
2
  dependencies:
3
3
  - app/actions
4
4
  views: app/views
5
- routes: app/app.routes
5
+ routes: app/app.dandy
6
6
  action:
7
7
  async_timeout: 10 # in seconds
8
8
  db:
@@ -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).using_lifetime(:scope).bound_to(:dandy_request)
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, safe_executor)
13
+ def initialize(route_matcher, container, route_executor)
14
14
  @container = container
15
15
  @route_matcher = route_matcher
16
- @safe_executor = safe_executor
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
- body = @safe_executor.execute(match.route, headers)
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' => headers['Accept']}, [body]]
60
+ result = [status, {'Content-Type' => 'application/json'}, [body]]
55
61
  end
56
62
 
57
- release
58
63
 
59
64
  result
60
65
  end
@@ -0,0 +1,11 @@
1
+ module Dandy
2
+ class Response
3
+ def self.format(result, headers)
4
+ if headers['Keys-Format'] == 'camel' && result
5
+ result = result.to_camelback_keys
6
+ end
7
+
8
+ JSON.generate(result)
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,7 @@
1
+ require 'dandy/response'
2
+
1
3
  module Dandy
2
- class SafeExecutor
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 : format_response(result, headers)
20
+ body = result.is_a?(String) ? result : Response.format(result, headers)
19
21
  rescue Exception => error
20
- @container
21
- .register_instance(error, :dandy_error)
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
- private
33
- def format_response(result, headers)
34
- if headers['Keys-Format'] == 'camel' && result
35
- result = result.to_camelback_keys
36
- end
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
- JSON.generate(result)
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
@@ -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
- @routes_builder.build(tree.parse)
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 Builder
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(sections)
13
+ def build(requests)
14
14
  result = []
15
15
 
16
- node = sections.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: sections.catch.command,
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
  })
@@ -1,5 +1,6 @@
1
1
  require 'treetop'
2
- require 'dandy/routing/builder'
2
+ require 'dandy/routing/routes_builder'
3
+ require 'dandy/routing/handlers_builder'
3
4
  require 'dandy/routing/parser'
4
5
  require 'dandy/routing/matcher'
5
6
  require 'dandy/routing/file_reader'
@@ -20,11 +20,17 @@ require_relative 'syntax/route'
20
20
  require_relative 'syntax/respond'
21
21
 
22
22
 
23
- require_relative 'syntax/sections'
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,7 @@
1
+ module Syntax
2
+ class MessageName < Treetop::Runtime::SyntaxNode
3
+ def parse
4
+ text_value.gsub('"','')
5
+ end
6
+ end
7
+ 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,5 +1,5 @@
1
1
  module Syntax
2
- class Sections < Treetop::Runtime::SyntaxNode
2
+ class Requests < Treetop::Runtime::SyntaxNode
3
3
  attr_reader :node, :catch
4
4
 
5
5
  def parse
@@ -1,6 +1,22 @@
1
1
  grammar Syntax
2
- rule sections
3
- ':receive' eol node catch <Sections>
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
@@ -1,3 +1,3 @@
1
1
  module Dandy
2
- VERSION = '0.12.1'.freeze
2
+ VERSION = '2.0.0-alpha'
3
3
  end
@@ -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.12.1
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: 2018-05-25 00:00:00.000000000 Z
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.9.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.9.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.0.3
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.0.3
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.15'
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.15'
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: '10.0'
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: '10.0'
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/routing/builder.rb
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: '0'
328
+ version: 1.3.1
316
329
  requirements: []
317
- rubyforge_project:
318
- rubygems_version: 2.6.12
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: []