dandy 0.12.1 → 2.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
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: []