flame 4.11.3.2 → 4.12.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b56a12a13e9cda2bdb36285b8f7051597d773875
4
- data.tar.gz: 8edf353e69d9254ad11ad1cff5cf8eca14519096
3
+ metadata.gz: 3b3c22d674ae570e3f8f2fd8874ec54f87dfb39b
4
+ data.tar.gz: a8ab56284dc70eb6babcf86a2dd80281757278dd
5
5
  SHA512:
6
- metadata.gz: eae397ed310ea64aaf0a07989655b0820734bffe9a9c1b62fda06ce75d6495f78496f9bc61e16ef7fe2f3de1207d76ff2f7c4c419e5c2b51ed6280e925305040
7
- data.tar.gz: 61723f2b18787782051b94bef9d4be923f93a3755d6b822576309e02f5e1b68b232025addbb9c127eae8717304c179e55eab879f06ea02b622ef847d60b265fe
6
+ metadata.gz: affe6a9c49a9eb2bd31ea0ed63540451e66a9986a35ed5a2d65cfd66363b13e0452eef7f8f194a00552203dfabfde31cd06550ac033256d04421b14d9398fe72
7
+ data.tar.gz: c40433fa6ef393e1d3630ea4817aeb490639cdb2c16934849947c88705b063c18ca452db88d5b5ee8091ab5acd3e7dee37c3e2bae946e6d74b0dc82914a95e37
data/bin/flame CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'thor'
4
5
  require 'fileutils'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
 
3
5
  require_relative 'flame/application'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'router'
2
4
  require_relative 'dispatcher'
3
5
 
@@ -56,7 +58,7 @@ module Flame
56
58
  ## defaults
57
59
  ## end
58
60
  def self.mount(ctrl, path = nil, &block)
59
- router.add_controller(ctrl, path, block)
61
+ router.add_controller(ctrl, path, &block)
60
62
  end
61
63
 
62
64
  ## Router for routing
@@ -71,7 +73,7 @@ module Flame
71
73
  ## Initialize default for config directories
72
74
  def self.default_config_dirs(root_dir:)
73
75
  result = { root_dir: File.realpath(root_dir) }
74
- %i(public views config tmp).each do |key|
76
+ %i[public views config tmp].each do |key|
75
77
  result[:"#{key}_dir"] = proc { File.join(config[:root_dir], key.to_s) }
76
78
  end
77
79
  result
@@ -17,7 +17,7 @@ module Flame
17
17
  def_delegators(
18
18
  :@dispatcher,
19
19
  :config, :request, :params, :halt, :session, :response, :status, :body,
20
- :default_body, :content_type
20
+ :default_body
21
21
  )
22
22
 
23
23
  ## Initialize the controller for request execution
@@ -58,12 +58,12 @@ module Flame
58
58
  # Set the Content-Disposition to "attachment" with the specified filename,
59
59
  # instructing the user agents to prompt to save.
60
60
  def attachment(filename = nil, disposition = :attachment)
61
- content_dis = 'Content-Disposition'.freeze
61
+ content_dis = 'Content-Disposition'
62
62
  response[content_dis] = disposition.to_s
63
63
  return unless filename
64
64
  response[content_dis] << "; filename=\"#{File.basename(filename)}\""
65
65
  ext = File.extname(filename)
66
- content_type(ext) unless ext.empty?
66
+ response.content_type = ext unless ext.empty?
67
67
  end
68
68
 
69
69
  ## Render a template with `Flame::Render` (based on Tilt-engine)
@@ -88,7 +88,7 @@ module Flame
88
88
  ## @param method [Symbol] name of the controller method
89
89
  def execute(method)
90
90
  # send method
91
- body send(method, *select_args(method))
91
+ body send(method, *select_args(method).values)
92
92
  end
93
93
 
94
94
  ## Default method for Internal Server Error, can be inherited
@@ -98,14 +98,13 @@ module Flame
98
98
 
99
99
  private
100
100
 
101
- def select_args(method)
102
- parameters = self.class.instance_method(method).parameters
103
- params_select = proc do |type|
104
- params.values_at(
105
- *parameters.select { |par| par.first == type }.map(&:last)
106
- )
101
+ def select_args(action)
102
+ # p action, params, parameters
103
+ method(action).parameters.each_with_object({}) do |parameter, result|
104
+ key = parameter.last
105
+ next if params[key].nil?
106
+ result[key] = params[key]
107
107
  end
108
- params_select.call(:req) + params_select.call(:opt).compact
109
108
  end
110
109
 
111
110
  def add_controller_class(args)
@@ -119,7 +118,7 @@ module Flame
119
118
  ## Default root path of the controller for requests
120
119
  def default_path
121
120
  modules = name.underscore.split('/')
122
- parts = modules[-1].split('_') - %w(index controller ctrl)
121
+ parts = modules[-1].split('_') - %w[index controller ctrl]
123
122
  return modules[-2] if parts.empty?
124
123
  parts.join('_')
125
124
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flame
2
4
  class Dispatcher
3
5
  ## Helper class for cookies
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gorilla-patch/symbolize'
2
4
 
3
5
  require_relative 'cookies'
@@ -25,9 +27,9 @@ module Flame
25
27
  ## Start of execution the request
26
28
  def run!
27
29
  catch :halt do
28
- try_route ||
29
- try_static ||
30
+ try_static ||
30
31
  try_static(File.join(__dir__, '..', '..', 'public')) ||
32
+ try_route ||
31
33
  halt(404)
32
34
  end
33
35
  response.write body
@@ -76,12 +78,6 @@ module Flame
76
78
  @app.config
77
79
  end
78
80
 
79
- ## Access to Content-Type header of response
80
- def content_type(ext = nil)
81
- return response[Rack::CONTENT_TYPE] unless ext
82
- response[Rack::CONTENT_TYPE] = Rack::Mime.mime_type(ext)
83
- end
84
-
85
81
  ## Build a path to the given controller and action, with any expected params
86
82
  ##
87
83
  ## @param ctrl [Flame::Controller] class of controller
@@ -96,32 +92,30 @@ module Flame
96
92
  def path_to(ctrl, action = :index, args = {})
97
93
  route = @app.class.router.find_route(controller: ctrl, action: action)
98
94
  raise Errors::RouteNotFoundError.new(ctrl, action) unless route
99
- params = Rack::Utils.build_nested_query args.delete(:params)
95
+ query = Rack::Utils.build_nested_query args.delete(:params)
96
+ query = nil if query&.empty?
100
97
  path = route.assign_arguments(args)
101
98
  path = '/' if path.empty?
102
- path << ("?#{params}" if params).to_s
99
+ URI::Generic.build(path: path, query: query).to_s
103
100
  end
104
101
 
105
102
  ## Interrupt the execution of route, and set new optional data
106
103
  ## (otherwise using existing)
107
- ## @param new_status_or_body [Integer, String]
108
- ## set new HTTP status code or new body
109
- ## @param new_body [String] set new body
110
- ## @param new_headers [String] merge new headers
104
+ ## @param new_status [Integer, nil]
105
+ ## set new HTTP status code
106
+ ## @param new_body [String, nil] set new body
107
+ ## @param new_headers [Hash, nil] merge new headers
108
+ ## @example Halt, no change status or body
109
+ ## halt
111
110
  ## @example Halt with 500, no change body
112
111
  ## halt 500
113
112
  ## @example Halt with 404, render template
114
113
  ## halt 404, render('errors/404')
115
114
  ## @example Halt with 200, set new headers
116
115
  ## halt 200, 'Cats!', 'Content-Type' => 'animal/cat'
117
- def halt(new_status_or_body = nil, new_body = nil, new_headers = {})
118
- case new_status_or_body
119
- when String then new_body = new_status_or_body
120
- when Integer then status new_status_or_body
121
- end
122
- # new_status.is_a?(String) ? () : (status new_status)
123
- body new_body if new_body
124
- default_body_of_nearest_route if body.empty?
116
+ def halt(new_status = nil, new_body = nil, new_headers = {})
117
+ status new_status if new_status
118
+ body new_body || (default_body_of_nearest_route if body.empty?)
125
119
  response.headers.merge!(new_headers)
126
120
  throw :halt
127
121
  end
@@ -134,7 +128,7 @@ module Flame
134
128
  "#{error.class} - #{error.message}:",
135
129
  *error.backtrace
136
130
  ].join("\n\t")
137
- @env['rack.errors'].puts(error_message)
131
+ @env[Rack::RACK_ERRORS].puts(error_message)
138
132
  end
139
133
 
140
134
  ## Generate default body of error page
@@ -152,17 +146,17 @@ module Flame
152
146
  path_parts: request.path_parts
153
147
  )
154
148
  return nil unless route
149
+ status 200
155
150
  execute_route(route)
156
151
  end
157
152
 
158
153
  ## Execute route
159
154
  ## @param route [Flame::Route] route that must be executed
160
- def execute_route(route)
161
- status 200
155
+ def execute_route(route, action = route.action)
162
156
  params.merge!(route.arguments(request.path_parts))
163
157
  # route.execute(self)
164
158
  controller = route.controller.new(self)
165
- controller.send(:execute, route.action)
159
+ controller.send(:execute, action)
166
160
  rescue => exception
167
161
  # p 'rescue from dispatcher'
168
162
  dump_error(exception)
@@ -182,8 +176,8 @@ module Flame
182
176
  ## or it's `default_body` method not defined
183
177
  return default_body unless route
184
178
  ## Execute `default_body` method for the founded route
185
- route.controller.new(self).send(:execute, :default_body)
186
- body default_body if body.empty?
179
+ execute_route(route, :default_body)
180
+ default_body if body.empty?
187
181
  end
188
182
  end
189
183
  end
@@ -1,60 +1,35 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flame
2
4
  module Errors
3
- module RouterError
4
- ## Error for Flame::Router.compare_actions
5
- class ActionsError < StandardError
6
- def initialize(ctrl, extra_actions)
7
- @ctrl = ctrl
8
- @extra_actions = extra_actions
9
- end
10
- end
11
-
12
- ## Error if routes have more actions, than controller
13
- class ExtraRoutesActionsError < ActionsError
14
- def message
15
- "Controller '#{@ctrl}' has no methods" \
16
- " '#{@extra_actions.join(', ')}' from routes"
17
- end
18
- end
19
-
20
- ## Error if controller has not assigned in routes actions
21
- class ExtraControllerActionsError < ActionsError
22
- def message
23
- "Routes for '#{@ctrl}' has no methods" \
24
- " '#{@extra_actions.join(', ')}'"
25
- end
26
- end
27
-
28
- ## Error for Flame::Router::RouteRefine.arguments_valid?
29
- class ArgumentsError < StandardError
30
- def initialize(ctrl, action, path, extra_args)
31
- @ctrl = ctrl
32
- @action = action
33
- @path = path
34
- @extra_args = extra_args
35
- end
36
- end
37
-
38
- ## Error if path has more arguments, than controller's method
39
- class ExtraPathArgumentsError < ArgumentsError
40
- def message
41
- "Method '#{@action}' from controller '#{@ctrl}'" \
42
- " does not know arguments '#{@extra_args.join(', ')}'" \
43
- " from path '#{@path}'"
44
- end
5
+ ## Error for Route initialization
6
+ class RouteArgumentsError < StandardError
7
+ def initialize(ctrl, action, path, extra)
8
+ @ctrl = ctrl
9
+ @action = action
10
+ @path = path
11
+ @extra = extra
12
+ @extra[:type_name] = {
13
+ req: 'required',
14
+ opt: 'optional'
15
+ }[@extra[:type]]
45
16
  end
46
17
 
47
- ## Error if path has no arguments, that controller's method required
48
- class ExtraActionArgumentsError < ArgumentsError
49
- def message
50
- "Path '#{@path}' does not contain required arguments" \
51
- " '#{@extra_args.join(', ')}' of method '#{@action}'" \
52
- " from controller '#{@ctrl}'"
18
+ def message
19
+ case @extra[:place]
20
+ when :ctrl
21
+ ## Error if path has no arguments, that controller's method has
22
+ "Path '#{@path}' has no #{@extra[:type_name]}" \
23
+ " arguments #{@extra[:args].inspect}"
24
+ when :path
25
+ ## Error if path has more arguments, than controller's method
26
+ "Action '#{@ctrl}##{@action}' has no #{@extra[:type_name]}" \
27
+ " arguments #{@extra[:args].inspect}"
53
28
  end
54
29
  end
55
30
  end
56
31
 
57
- ## Error for Flame::Router.find_path
32
+ ## Error for Flame::Dispatcher.path_to
58
33
  class RouteNotFoundError < StandardError
59
34
  def initialize(ctrl, method)
60
35
  @ctrl = ctrl
@@ -63,32 +38,19 @@ module Flame
63
38
 
64
39
  def message
65
40
  "Route with controller '#{@ctrl}' and method '#{@method}'" \
66
- ' not found in application routes'
41
+ ' not found in application routes'
67
42
  end
68
43
  end
69
44
 
70
- ## Error for Flame::Controller.path_to
45
+ ## Error for Flame::Dispatcher.path_to
71
46
  class ArgumentNotAssignedError < StandardError
72
- def initialize(path, path_part)
47
+ def initialize(path, argument)
73
48
  @path = path
74
- @path_part = path_part
75
- end
76
-
77
- def message
78
- "Argument '#{@path_part}' for path '#{@path}' is not assigned"
79
- end
80
- end
81
-
82
- ## Error for Flame::Router.find_path
83
- class UnexpectedTypeOfHookError < StandardError
84
- def initialize(hook, route)
85
- @hook = hook
86
- @route = route
49
+ @argument = argument
87
50
  end
88
51
 
89
52
  def message
90
- "Unexpected hook-block class '#{@hook.class}'" \
91
- " in route '#{@route}'"
53
+ "Argument '#{@argument}' for path '#{@path}' is not assigned"
92
54
  end
93
55
  end
94
56
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
 
3
5
  require 'tilt'
@@ -94,7 +96,7 @@ module Flame
94
96
  ## Find possible directories for the controller
95
97
  def controller_dirs
96
98
  parts = @ctrl.class.underscore.split('/').map do |part|
97
- (part.split('_') - %w(controller controllers ctrl)).join('_')
99
+ (part.split('_') - %w[controller controllers ctrl]).join('_')
98
100
  end
99
101
  combine_parts(parts).map! { |path| path.join('/') }
100
102
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flame
2
4
  ## Class for requests
3
5
  class Request < Rack::Request
@@ -1,5 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flame
2
4
  ## Class for responses
3
5
  class Response < Rack::Response
6
+ ## Set Content-Type header directly or by extension
7
+ ## @param value [String] value for header or extension of file
8
+ ## @return [String] setted value
9
+ ## @example Set value directly
10
+ ## content_type = 'text/css'
11
+ ## @example Set value by file extension
12
+ ## content_type = '.css'
13
+ def content_type=(value)
14
+ value = Rack::Mime.mime_type(value) if value.start_with? '.'
15
+ set_header Rack::CONTENT_TYPE, value
16
+ end
4
17
  end
5
18
  end
@@ -1,21 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'validators'
4
+
3
5
  module Flame
4
6
  class Router
5
- ARG_CHAR = ':'.freeze
6
- ARG_CHAR_OPT = '?'.freeze
7
+ ARG_CHAR = ':'
8
+ ARG_CHAR_OPT = '?'
7
9
 
8
10
  ## Class for Route in Router.routes
9
11
  class Route
10
12
  attr_reader :method, :controller, :action, :path, :path_parts
11
13
 
12
- def initialize(controller, action, method, path)
14
+ def initialize(controller, action, method, ctrl_path, action_path)
15
+ ## Merge action path with controller path
16
+ path = self.class.path_merge(ctrl_path, action_path)
13
17
  @controller = controller
14
18
  @action = action
15
19
  @method = method.to_sym.upcase
16
20
  ## MAKE PATH
17
21
  @path = path
18
- Validators::ArgumentsValidator.new(@controller, @path, @action).valid?
22
+ Validators::RouteArgumentsValidator.new(
23
+ @controller, action_path, @action
24
+ ).valid?
19
25
  @path_parts = @path.to_s.split('/').reject(&:empty?)
20
26
  freeze
21
27
  end
@@ -38,24 +44,38 @@ module Flame
38
44
  ## Assign arguments to path for `Controller.path_to`
39
45
  ## @param args [Hash] arguments for assigning
40
46
  def assign_arguments(args = {})
41
- parts = @path_parts.map { |part| assign_argument(part, args) }
42
- self.class.path_merge(parts.unshift(''))
47
+ parts = @path_parts.map { |part| assign_argument(part, args) }.compact
48
+ self.class.path_merge(parts.unshift(nil))
43
49
  end
44
50
 
45
51
  ## Extract arguments from request_parts for `execute`
46
52
  ## @param request_parts [Array] parts of the request (Array of String)
47
53
  def arguments(request_parts)
48
54
  @path_parts.each_with_index.with_object({}) do |(path_part, i), args|
49
- request_part = request_parts[i]
55
+ request_part = request_parts[i].to_s
50
56
  path_part_opt = path_part[1] == ARG_CHAR_OPT
51
57
  next args unless path_part[0] == ARG_CHAR
52
- break args if path_part_opt && request_part.nil?
58
+ break args if path_part_opt && request_part.empty?
53
59
  args[
54
60
  path_part[(path_part_opt ? 2 : 1)..-1].to_sym
55
61
  ] = URI.decode(request_part)
56
62
  end
57
63
  end
58
64
 
65
+ ## Method for Routes comparison
66
+ def ==(other)
67
+ %i[controller action method path_parts].reduce(true) do |result, method|
68
+ result && (
69
+ public_send(method) == other.public_send(method)
70
+ )
71
+ end
72
+ end
73
+
74
+ ## Compare by path parts count (more is matter)
75
+ def <=>(other)
76
+ other.path_parts.size <=> path_parts.size
77
+ end
78
+
59
79
  def self.path_merge(*parts)
60
80
  parts.join('/').gsub(%r{\/{2,}}, '/')
61
81
  end
@@ -79,19 +99,28 @@ module Flame
79
99
  end
80
100
 
81
101
  def compare_path_parts(request_parts)
82
- # p route_path
83
- req_path_parts = @path_parts.select { |part| part[1] != ARG_CHAR_OPT }
84
- return false if request_parts.count < req_path_parts.count
85
- # compare_parts(request_parts, self[:path_parts])
86
- request_parts.each_with_index do |request_part, i|
87
- path_part = @path_parts[i]
88
- # p request_part, path_part
89
- break false unless path_part
90
- next if path_part[0] == ARG_CHAR
91
- break false unless request_part == path_part
102
+ return false unless request_contain_required_path_parts?(request_parts)
103
+ [request_parts.size, @path_parts.size].max.times do |i|
104
+ break false unless compare_parts request_parts[i], @path_parts[i]
92
105
  end
93
106
  end
94
107
 
108
+ def compare_parts(request_part, path_part)
109
+ # p request_part, path_part
110
+ return unless path_part
111
+ return if request_part.nil? && path_part[1] != ARG_CHAR_OPT
112
+ # p request_part, path_part
113
+ return true if path_part[0] == ARG_CHAR
114
+ return true if request_part == path_part
115
+ end
116
+
117
+ def request_contain_required_path_parts?(request_parts)
118
+ req_path_parts = @path_parts.reject { |part| part[1] == ARG_CHAR_OPT }
119
+ fixed_path_parts = @path_parts.reject { |part| part[0] == ARG_CHAR }
120
+ (request_parts & fixed_path_parts) == fixed_path_parts &&
121
+ request_parts.count >= req_path_parts.count
122
+ end
123
+
95
124
  ## Helpers for `assign_arguments`
96
125
  def assign_argument(path_part, args = {})
97
126
  ## Not argument
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'route'
2
- require_relative 'validators'
3
4
 
4
5
  module Flame
5
6
  ## Router class for routing
@@ -13,14 +14,13 @@ module Flame
13
14
 
14
15
  ## Add the controller with it's methods to routes
15
16
  ## @param ctrl [Flame::Controller] class of the controller which will be added
16
- ## @param path [String] root path for controller's methods
17
- ## @param block [Proc, nil] block for routes refine
18
- def add_controller(ctrl, path, block = nil)
17
+ ## @param path [String, nil] root path for controller's methods
18
+ ## @yield block for routes refine
19
+ def add_controller(ctrl, path = nil, &block)
19
20
  ## @todo Add Regexp paths
20
21
 
21
22
  ## Add routes from controller to glob array
22
23
  route_refine = RouteRefine.new(self, ctrl, path, block)
23
- return unless Validators::ActionsValidator.new(route_refine).valid?
24
24
  concat_routes(route_refine)
25
25
  end
26
26
 
@@ -76,7 +76,7 @@ module Flame
76
76
  execute(&block)
77
77
  end
78
78
 
79
- %i(GET POST PUT PATCH DELETE).each do |request_method|
79
+ %i[GET POST PUT PATCH DELETE].each do |request_method|
80
80
  ## Define refine methods for all HTTP methods
81
81
  ## @overload post(path, action)
82
82
  ## Execute action on requested path and HTTP method
@@ -98,10 +98,11 @@ module Flame
98
98
  end
99
99
  ## Make path by controller method with parameners
100
100
  path = default_action_path(action, path) if prefix || path.nil?
101
- ## Merge action path with controller path
102
- path = Route.path_merge(@path, path)
103
- route = Route.new(@ctrl, action, method, path)
101
+ ## Init new Route
102
+ route = Route.new(@ctrl, action, method, @path, path)
103
+ ## Try to find route with the same action
104
104
  index = find_route_index(action: action)
105
+ ## Overwrite route if needed
105
106
  index ? @routes[index] = route : @routes.push(route)
106
107
  end
107
108
  end
@@ -132,7 +133,7 @@ module Flame
132
133
  ## @yield Block of code for routes refine
133
134
  def mount(ctrl, path = nil, &block)
134
135
  path = Route.path_merge(@path, path || ctrl.default_path)
135
- @router.add_controller(ctrl, path, block)
136
+ @router.add_controller(ctrl, path, &block)
136
137
  end
137
138
 
138
139
  private
@@ -141,7 +142,7 @@ module Flame
141
142
  def execute(&block)
142
143
  instance_exec(&block) if block
143
144
  defaults
144
- @routes.sort! { |a, b| b.path <=> a.path }
145
+ @routes.sort!
145
146
  end
146
147
 
147
148
  def find_route_index(attrs)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flame
2
4
  class Dispatcher
3
5
  ## Module for working with static files
@@ -19,7 +21,7 @@ module Flame
19
21
  def return_static(file)
20
22
  file_time = File.mtime(file)
21
23
  halt 304 if static_cached?(file_time)
22
- content_type File.extname(file)
24
+ response.content_type = File.extname(file)
23
25
  response[Rack::CACHE_CONTROL] = 'no-cache'
24
26
  response['Last-Modified'] = file_time.httpdate
25
27
  body File.read(file)
@@ -1,10 +1,11 @@
1
- require_relative 'route'
1
+ # frozen_string_literal: true
2
+
2
3
  require_relative 'errors'
3
4
 
4
5
  module Flame
5
6
  module Validators
6
7
  ## Compare arguments from path and from controller's action
7
- class ArgumentsValidator
8
+ class RouteArgumentsValidator
8
9
  def initialize(ctrl, path, action)
9
10
  @ctrl = ctrl
10
11
  @path = path
@@ -12,81 +13,54 @@ module Flame
12
13
  end
13
14
 
14
15
  def valid?
15
- ## Break path for ':arg' arguments
16
- @path_args = path_arguments(@path)
17
- ## Take all and required arguments from Controller#action
18
- @action_args = action_arguments(@action)
19
- ## Compare arguments from path and arguments from method
20
- no_extra_path_arguments? && no_extra_action_arguments?
16
+ ## Get hash of any extra arguments
17
+ extra = %i[req opt].find do |type|
18
+ found = extra_arguments(type).find do |place, args|
19
+ break { place: place, type: type, args: args } if args.any?
20
+ end
21
+ break found if found
22
+ end
23
+ ## Return true if no any extra argument
24
+ return true unless extra
25
+ ## Raise error with extra arguments
26
+ raise Errors::RouteArgumentsError.new(@ctrl, @action, @path, extra)
21
27
  end
22
28
 
23
29
  private
24
30
 
25
31
  ## Split path to args array
26
- def path_arguments(path)
27
- args = path.split('/').select { |part| part[0] == Router::ARG_CHAR }
28
- args.map do |arg|
29
- opt_arg = arg[1] == Router::ARG_CHAR_OPT
30
- arg[(opt_arg ? 2 : 1)..-1].to_sym
31
- end
32
+ def path_arguments
33
+ @path_arguments ||= @path.split('/')
34
+ .each_with_object(req: [], opt: []) do |part, hash|
35
+ ## Take only argument parts
36
+ next if part[0] != Router::ARG_CHAR
37
+ ## Clean argument from special chars
38
+ clean_part = part.delete(
39
+ Router::ARG_CHAR + Router::ARG_CHAR_OPT
40
+ ).to_sym
41
+ ## Memorize arguments
42
+ hash[part[1] != Router::ARG_CHAR_OPT ? :req : :opt] << clean_part
43
+ end
32
44
  end
33
45
 
34
46
  ## Take args from controller's action
35
- def action_arguments(action)
36
- parameters = @ctrl.instance_method(action).parameters
37
- req_parameters = parameters.select { |par| par[0] == :req }
38
- {
39
- all: parameters.map { |par| par[1] },
40
- req: req_parameters.map { |par| par[1] }
41
- }
47
+ def action_arguments
48
+ return @action_arguments if @action_arguments
49
+ ## Get all parameters (arguments) from method
50
+ ## Than collect and sort parameters into hash
51
+ @ctrl.instance_method(@action).parameters
52
+ .each_with_object(req: [], opt: []) do |param, hash|
53
+ ## Only required parameters must be in `:req`
54
+ hash[param[0]] << param[1]
55
+ end
42
56
  end
43
57
 
44
- def no_extra_path_arguments?
45
- ## Subtraction action args from path args
46
- extra_path_args = @path_args - @action_args[:all]
47
- return true if extra_path_args.empty?
48
- raise Errors::RouterError::ExtraPathArgumentsError.new(
49
- @ctrl, @action, @path, extra_path_args
50
- )
51
- end
52
-
53
- def no_extra_action_arguments?
54
- ## Subtraction path args from action required args
55
- extra_action_args = @action_args[:req] - @path_args
56
- return true if extra_action_args.empty?
57
- raise Errors::RouterError::ExtraActionArgumentsError.new(
58
- @ctrl, @action, @path, extra_action_args
59
- )
60
- end
61
- end
62
-
63
- ## Compare actions from routes and from controller
64
- class ActionsValidator
65
- def initialize(route_refine)
66
- @routes_actions = route_refine.routes.map(&:action)
67
- @ctrl = route_refine.ctrl
68
- end
69
-
70
- def valid?
71
- no_extra_routes_actions? && no_extra_controller_actions?
72
- end
73
-
74
- private
75
-
76
- def no_extra_routes_actions?
77
- extra_routes_actions = @routes_actions - @ctrl.actions
78
- return true if extra_routes_actions.empty?
79
- raise Errors::RouterError::ExtraRoutesActionsError.new(
80
- @ctrl, extra_routes_actions
81
- )
82
- end
83
-
84
- def no_extra_controller_actions?
85
- extra_ctrl_actions = @ctrl.actions - @routes_actions
86
- return true if extra_ctrl_actions.empty?
87
- raise Errors::RouterError::ExtraControllerActionsError.new(
88
- @ctrl, extra_ctrl_actions
89
- )
58
+ ## Calculate path and action extra arguments
59
+ def extra_arguments(type)
60
+ {
61
+ ctrl: action_arguments[type] - path_arguments[type],
62
+ path: path_arguments[type] - action_arguments[type]
63
+ }
90
64
  end
91
65
  end
92
66
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flame
4
- VERSION = '4.11.3.2'.freeze
4
+ VERSION = '4.12.2'
5
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  ## Framework
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :db do
2
4
  ## Require libs and config
3
5
  require 'sequel'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module <%= @module_name %>
2
4
  ## Class for application (mounting controllers)
3
5
  class Application
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## Require gems
2
4
  require 'bundler'
3
5
  Bundler.require
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
 
3
5
  ## Database initialize for Sequel
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module <%= @module_name %>
2
4
  ## Base controller for any others controllers
3
5
  class Controller < Flame::Controller
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  ## Functons
4
5
  def show_usage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flame
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.11.3.2
4
+ version: 4.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Popov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-27 00:00:00.000000000 Z
11
+ date: 2017-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -80,6 +80,104 @@ dependencies:
80
80
  version: '0'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: rubocop
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '0.48'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '0.48'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rake
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '12'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '12'
109
+ - !ruby/object:Gem::Dependency
110
+ name: bacon
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1'
123
+ - !ruby/object:Gem::Dependency
124
+ name: bacon-colored_output
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1.1'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '1.1'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rack-test
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ - !ruby/object:Gem::Dependency
152
+ name: simplecov
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ - !ruby/object:Gem::Dependency
166
+ name: codecov
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ type: :development
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ - !ruby/object:Gem::Dependency
180
+ name: pry
83
181
  requirement: !ruby/object:Gem::Requirement
84
182
  requirements:
85
183
  - - "~>"
@@ -92,6 +190,20 @@ dependencies:
92
190
  - - "~>"
93
191
  - !ruby/object:Gem::Version
94
192
  version: '0'
193
+ - !ruby/object:Gem::Dependency
194
+ name: pry-byebug
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '3'
200
+ type: :development
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: '3'
95
207
  description: Use controller's classes with instance methods as routing actions, mounting
96
208
  its in application class.
97
209
  email:
@@ -155,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
267
  version: '0'
156
268
  requirements: []
157
269
  rubyforge_project:
158
- rubygems_version: 2.6.10
270
+ rubygems_version: 2.6.11
159
271
  signing_key:
160
272
  specification_version: 4
161
273
  summary: Web-framework, based on MVC-pattern