hanami-controller 2.0.0.beta4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/hanami/action.rb CHANGED
@@ -1,30 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "dry/core"
5
- require "dry/types"
6
- require "hanami/validations"
7
- require "hanami/action/validatable"
8
- rescue LoadError # rubocop:disable Lint/SuppressedException
9
- end
10
-
11
3
  require "dry/configurable"
12
- require "hanami/utils/callbacks"
13
4
  require "hanami/utils"
14
- require "hanami/utils/string"
5
+ require "hanami/utils/callbacks"
15
6
  require "hanami/utils/kernel"
7
+ require "hanami/utils/string"
16
8
  require "rack"
17
9
  require "rack/utils"
10
+ require "zeitwerk"
18
11
 
19
- require_relative "action/config"
20
12
  require_relative "action/constants"
21
- require_relative "action/base_params"
22
- require_relative "action/halt"
23
- require_relative "action/mime"
24
- require_relative "action/rack/file"
25
- require_relative "action/request"
26
- require_relative "action/response"
27
- require_relative "action/error"
13
+ require_relative "action/errors"
28
14
 
29
15
  module Hanami
30
16
  # An HTTP endpoint
@@ -42,18 +28,37 @@ module Hanami
42
28
  #
43
29
  # @api public
44
30
  class Action
31
+ # @since 2.0.0
32
+ # @api private
33
+ def self.gem_loader
34
+ @gem_loader ||= Zeitwerk::Loader.new.tap do |loader|
35
+ root = File.expand_path("..", __dir__)
36
+ loader.tag = "hanami-controller"
37
+ loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami-controller.rb")
38
+ loader.push_dir(root)
39
+ loader.ignore(
40
+ "#{root}/hanami-controller.rb",
41
+ "#{root}/hanami/controller/version.rb",
42
+ "#{root}/hanami/action/{constants,errors,params,validatable}.rb"
43
+ )
44
+ loader.inflector.inflect("csrf_protection" => "CSRFProtection")
45
+ end
46
+ end
47
+
48
+ gem_loader.setup
49
+
50
+ # Make conditional requires after Zeitwerk setup so any internal autoloading works as expected
51
+ begin
52
+ require "hanami/validations"
53
+ require_relative "action/validatable"
54
+ rescue LoadError # rubocop:disable Lint/SuppressedException
55
+ end
56
+
45
57
  extend Dry::Configurable(config_class: Config)
46
58
 
47
59
  # See {Config} for individual setting accessor API docs
48
60
  setting :handled_exceptions, default: {}
49
- setting :formats, default: Config::DEFAULT_FORMATS
50
- setting :default_request_format, constructor: -> (format) {
51
- Utils::Kernel.Symbol(format) unless format.nil?
52
- }
53
- setting :default_response_format, constructor: -> (format) {
54
- Utils::Kernel.Symbol(format) unless format.nil?
55
- }
56
- setting :accepted_formats, default: []
61
+ setting :formats, default: Config::Formats.new, mutable: true
57
62
  setting :default_charset
58
63
  setting :default_headers, default: {}, constructor: -> (headers) { headers.compact }
59
64
  setting :cookies, default: {}, constructor: -> (cookie_options) {
@@ -65,8 +70,8 @@ module Hanami
65
70
  Pathname(File.expand_path(dir || Dir.pwd)).realpath
66
71
  }
67
72
  setting :public_directory, default: Config::DEFAULT_PUBLIC_DIRECTORY
68
- setting :before_callbacks, default: Utils::Callbacks::Chain.new, cloneable: true
69
- setting :after_callbacks, default: Utils::Callbacks::Chain.new, cloneable: true
73
+ setting :before_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
74
+ setting :after_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
70
75
 
71
76
  # @!scope class
72
77
 
@@ -75,7 +80,7 @@ module Hanami
75
80
  #
76
81
  # @example Access inside class body
77
82
  # class Show < Hanami::Action
78
- # config.default_response_format = :json
83
+ # config.format :json
79
84
  # end
80
85
  #
81
86
  # @return [Config]
@@ -126,71 +131,72 @@ module Hanami
126
131
  #
127
132
  # @raise [NoMethodError]
128
133
  #
129
- # @api private
134
+ # @api public
130
135
  # @since 2.0.0
131
136
  def self.params(_klass = nil)
132
137
  raise NoMethodError,
133
138
  "To use `params`, please add 'hanami/validations' gem to your Gemfile"
134
139
  end
135
140
 
136
- # Define a callback for an Action.
137
- # The callback will be executed **before** the action is called, in the
138
- # order they are added.
141
+ # @overload self.append_before(*callbacks, &block)
142
+ # Define a callback for an Action.
143
+ # The callback will be executed **before** the action is called, in the
144
+ # order they are added.
139
145
  #
140
- # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
141
- # each of them is representing a name of a method available in the
142
- # context of the Action.
146
+ # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
147
+ # each of them is representing a name of a method available in the
148
+ # context of the Action.
143
149
  #
144
- # @param blk [Proc] an anonymous function to be executed
150
+ # @param blk [Proc] an anonymous function to be executed
145
151
  #
146
- # @return [void]
152
+ # @return [void]
147
153
  #
148
- # @since 0.3.2
154
+ # @since 0.3.2
149
155
  #
150
- # @see Hanami::Action::Callbacks::ClassMethods#append_after
156
+ # @see Hanami::Action::Callbacks::ClassMethods#append_after
151
157
  #
152
- # @example Method names (symbols)
153
- # require "hanami/controller"
158
+ # @example Method names (symbols)
159
+ # require "hanami/controller"
154
160
  #
155
- # class Show < Hanami::Action
156
- # before :authenticate, :set_article
161
+ # class Show < Hanami::Action
162
+ # before :authenticate, :set_article
157
163
  #
158
- # def handle(req, res)
159
- # end
164
+ # def handle(req, res)
165
+ # end
160
166
  #
161
- # private
162
- # def authenticate
163
- # # ...
164
- # end
167
+ # private
168
+ # def authenticate
169
+ # # ...
170
+ # end
165
171
  #
166
- # # `params` in the method signature is optional
167
- # def set_article(params)
168
- # @article = Article.find params[:id]
172
+ # # `params` in the method signature is optional
173
+ # def set_article(params)
174
+ # @article = Article.find params[:id]
175
+ # end
169
176
  # end
170
- # end
171
177
  #
172
- # # The order of execution will be:
173
- # #
174
- # # 1. #authenticate
175
- # # 2. #set_article
176
- # # 3. #call
178
+ # # The order of execution will be:
179
+ # #
180
+ # # 1. #authenticate
181
+ # # 2. #set_article
182
+ # # 3. #call
177
183
  #
178
- # @example Anonymous functions (Procs)
179
- # require "hanami/controller"
184
+ # @example Anonymous functions (Procs)
185
+ # require "hanami/controller"
180
186
  #
181
- # class Show < Hanami::Action
182
- # before { ... } # 1 do some authentication stuff
183
- # before {|req, res| @article = Article.find params[:id] } # 2
187
+ # class Show < Hanami::Action
188
+ # before { ... } # 1 do some authentication stuff
189
+ # before {|req, res| @article = Article.find params[:id] } # 2
184
190
  #
185
- # def handle(req, res)
191
+ # def handle(req, res)
192
+ # end
186
193
  # end
187
- # end
188
194
  #
189
- # # The order of execution will be:
190
- # #
191
- # # 1. authentication
192
- # # 2. set the article
193
- # # 3. `#handle`
195
+ # # The order of execution will be:
196
+ # #
197
+ # # 1. authentication
198
+ # # 2. set the article
199
+ # # 3. `#handle`
194
200
  def self.append_before(...)
195
201
  config.before_callbacks.append(...)
196
202
  end
@@ -200,21 +206,22 @@ module Hanami
200
206
  alias_method :before, :append_before
201
207
  end
202
208
 
203
- # Define a callback for an Action.
204
- # The callback will be executed **after** the action is called, in the
205
- # order they are added.
209
+ # @overload self.append_after(*callbacks, &block)
210
+ # Define a callback for an Action.
211
+ # The callback will be executed **after** the action is called, in the
212
+ # order they are added.
206
213
  #
207
- # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
208
- # each of them is representing a name of a method available in the
209
- # context of the Action.
214
+ # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
215
+ # each of them is representing a name of a method available in the
216
+ # context of the Action.
210
217
  #
211
- # @param blk [Proc] an anonymous function to be executed
218
+ # @param blk [Proc] an anonymous function to be executed
212
219
  #
213
- # @return [void]
220
+ # @return [void]
214
221
  #
215
- # @since 0.3.2
222
+ # @since 0.3.2
216
223
  #
217
- # @see Hanami::Action::Callbacks::ClassMethods#append_before
224
+ # @see Hanami::Action::Callbacks::ClassMethods#append_before
218
225
  def self.append_after(...)
219
226
  config.after_callbacks.append(...)
220
227
  end
@@ -224,72 +231,52 @@ module Hanami
224
231
  alias_method :after, :append_after
225
232
  end
226
233
 
227
- # Define a callback for an Action.
228
- # The callback will be executed **before** the action is called.
229
- # It will add the callback at the beginning of the callbacks' chain.
234
+ # @overload self.prepend_before(*callbacks, &block)
235
+ # Define a callback for an Action.
236
+ # The callback will be executed **before** the action is called.
237
+ # It will add the callback at the beginning of the callbacks' chain.
230
238
  #
231
- # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
232
- # each of them is representing a name of a method available in the
233
- # context of the Action.
239
+ # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
240
+ # each of them is representing a name of a method available in the
241
+ # context of the Action.
234
242
  #
235
- # @param blk [Proc] an anonymous function to be executed
243
+ # @param blk [Proc] an anonymous function to be executed
236
244
  #
237
- # @return [void]
245
+ # @return [void]
238
246
  #
239
- # @since 0.3.2
247
+ # @since 0.3.2
240
248
  #
241
- # @see Hanami::Action::Callbacks::ClassMethods#prepend_after
249
+ # @see Hanami::Action::Callbacks::ClassMethods#prepend_after
242
250
  def self.prepend_before(...)
243
251
  config.before_callbacks.prepend(...)
244
252
  end
245
253
 
246
- # Define a callback for an Action.
247
- # The callback will be executed **after** the action is called.
248
- # It will add the callback at the beginning of the callbacks' chain.
254
+ # @overload self.prepend_after(*callbacks, &block)
255
+ # Define a callback for an Action.
256
+ # The callback will be executed **after** the action is called.
257
+ # It will add the callback at the beginning of the callbacks' chain.
249
258
  #
250
- # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
251
- # each of them is representing a name of a method available in the
252
- # context of the Action.
259
+ # @param callbacks [Symbol, Array<Symbol>] a single or multiple symbol(s)
260
+ # each of them is representing a name of a method available in the
261
+ # context of the Action.
253
262
  #
254
- # @param blk [Proc] an anonymous function to be executed
263
+ # @param blk [Proc] an anonymous function to be executed
255
264
  #
256
- # @return [void]
265
+ # @return [void]
257
266
  #
258
- # @since 0.3.2
267
+ # @since 0.3.2
259
268
  #
260
- # @see Hanami::Action::Callbacks::ClassMethods#prepend_before
269
+ # @see Hanami::Action::Callbacks::ClassMethods#prepend_before
261
270
  def self.prepend_after(...)
262
271
  config.after_callbacks.prepend(...)
263
272
  end
264
273
 
265
- # Restrict the access to the specified mime type symbols.
266
- #
267
- # @param formats[Array<Symbol>] one or more symbols representing mime type(s)
268
- #
269
- # @raise [Hanami::Controller::UnknownFormatError] if the symbol cannot
270
- # be converted into a mime type
271
- #
272
- # @since 0.1.0
273
- #
274
274
  # @see Config#format
275
275
  #
276
- # @example
277
- # require "hanami/controller"
278
- #
279
- # class Show < Hanami::Action
280
- # accept :html, :json
281
- #
282
- # def handle(req, res)
283
- # # ...
284
- # end
285
- # end
286
- #
287
- # # When called with "*/*" => 200
288
- # # When called with "text/html" => 200
289
- # # When called with "application/json" => 200
290
- # # When called with "application/xml" => 415
291
- def self.accept(*formats)
292
- config.accepted_formats = formats
276
+ # @since 2.0.0
277
+ # @api public
278
+ def self.format(...)
279
+ config.format(...)
293
280
  end
294
281
 
295
282
  # @see Config#handle_exception
@@ -327,7 +314,7 @@ module Hanami
327
314
  response = build_response(
328
315
  request: request,
329
316
  config: config,
330
- content_type: Mime.calculate_content_type_with_charset(config, request, config.accepted_mime_types),
317
+ content_type: Mime.response_content_type_with_charset(request, config),
331
318
  env: env,
332
319
  headers: config.default_headers,
333
320
  sessions_enabled: sessions_enabled?
@@ -421,7 +408,7 @@ module Hanami
421
408
  # @since 2.0.0
422
409
  # @api private
423
410
  def enforce_accepted_mime_types(request)
424
- return if config.accepted_formats.empty?
411
+ return if config.formats.empty?
425
412
 
426
413
  Mime.enforce_accept(request, config) { return halt 406 }
427
414
  Mime.enforce_content_type(request, config) { return halt 415 }
@@ -586,20 +573,6 @@ module Hanami
586
573
  res.body = Response::EMPTY_BODY
587
574
  end
588
575
 
589
- # @since 2.0.0
590
- # @api private
591
- def format(value)
592
- case value
593
- when Symbol
594
- format = Utils::Kernel.Symbol(value)
595
- [format, Action::Mime.format_to_mime_type(format, config)]
596
- when String
597
- [Action::Mime.detect_format(value, config), value]
598
- else
599
- raise Hanami::Controller::UnknownFormatError.new(value)
600
- end
601
- end
602
-
603
576
  # Finalize the response
604
577
  #
605
578
  # Prepare the data before the response will be returned to the webserver
@@ -2,9 +2,12 @@
2
2
 
3
3
  module Hanami
4
4
  module Controller
5
- # Defines the version
5
+ # The current hanami-controller version.
6
+ #
7
+ # @return [String]
6
8
  #
7
9
  # @since 0.1.0
8
- VERSION = "2.0.0.beta4"
10
+ # @api public
11
+ VERSION = "2.0.0"
9
12
  end
10
13
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "hanami/action"
4
4
  require "hanami/controller/version"
5
- require "hanami/controller/error"
6
5
 
7
6
  # Hanami
8
7
  #
@@ -10,37 +9,10 @@ require "hanami/controller/error"
10
9
  module Hanami
11
10
  # A set of logically grouped actions
12
11
  #
13
- # @since 0.1.0
14
- #
15
12
  # @see Hanami::Action
16
13
  #
17
- # @example
18
- # require "hanami/controller"
19
- #
20
- # module Articles
21
- # class Index < Hanami::Action
22
- # # ...
23
- # end
24
- #
25
- # class Show < Hanami::Action
26
- # # ...
27
- # end
28
- # end
14
+ # @since 0.1.0
15
+ # @api public
29
16
  module Controller
30
- # Unknown format error
31
- #
32
- # This error is raised when a action sets a format that it isn't recognized
33
- # both by `Hanami::Action::Configuration` and the list of Rack mime types
34
- #
35
- # @since 0.2.0
36
- #
37
- # @see Hanami::Action::Mime#format=
38
- class UnknownFormatError < Hanami::Controller::Error
39
- # @since 0.2.0
40
- # @api private
41
- def initialize(format)
42
- super("Cannot find a corresponding Mime type for '#{format}'. Please configure it with Hanami::Controller::Configuration#format.") # rubocop:disable Layout/LineLength
43
- end
44
- end
45
17
  end
46
18
  end
@@ -3,6 +3,8 @@
3
3
  require "rack/utils"
4
4
 
5
5
  module Hanami
6
+ # @since 0.1.0
7
+ # @api private
6
8
  module Http
7
9
  # An HTTP status
8
10
  #
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "hanami/controller"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-24 00:00:00.000000000 Z
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,34 +30,62 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.0.beta
33
+ version: '2.0'
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.beta
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dry-configurable
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.13'
48
- - - ">="
47
+ version: '1.0'
48
+ - - "<"
49
49
  - !ruby/object:Gem::Version
50
- version: 0.13.0
50
+ version: '2'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - "~>"
56
56
  - !ruby/object:Gem::Version
57
- version: '0.13'
58
- - - ">="
57
+ version: '1.0'
58
+ - - "<"
59
59
  - !ruby/object:Gem::Version
60
- version: 0.13.0
60
+ version: '2'
61
+ - !ruby/object:Gem::Dependency
62
+ name: dry-core
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: zeitwerk
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.6'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.6'
61
89
  - !ruby/object:Gem::Dependency
62
90
  name: bundler
63
91
  requirement: !ruby/object:Gem::Requirement
@@ -145,6 +173,7 @@ files:
145
173
  - LICENSE.md
146
174
  - README.md
147
175
  - hanami-controller.gemspec
176
+ - lib/hanami-controller.rb
148
177
  - lib/hanami/action.rb
149
178
  - lib/hanami/action/base_params.rb
150
179
  - lib/hanami/action/cache.rb
@@ -153,14 +182,16 @@ files:
153
182
  - lib/hanami/action/cache/directives.rb
154
183
  - lib/hanami/action/cache/expires.rb
155
184
  - lib/hanami/action/config.rb
185
+ - lib/hanami/action/config/formats.rb
156
186
  - lib/hanami/action/constants.rb
157
187
  - lib/hanami/action/cookie_jar.rb
158
188
  - lib/hanami/action/cookies.rb
159
189
  - lib/hanami/action/csrf_protection.rb
160
- - lib/hanami/action/error.rb
190
+ - lib/hanami/action/errors.rb
161
191
  - lib/hanami/action/flash.rb
162
192
  - lib/hanami/action/halt.rb
163
193
  - lib/hanami/action/mime.rb
194
+ - lib/hanami/action/mime/request_mime_weight.rb
164
195
  - lib/hanami/action/params.rb
165
196
  - lib/hanami/action/rack/file.rb
166
197
  - lib/hanami/action/request.rb
@@ -169,7 +200,6 @@ files:
169
200
  - lib/hanami/action/validatable.rb
170
201
  - lib/hanami/action/view_name_inferrer.rb
171
202
  - lib/hanami/controller.rb
172
- - lib/hanami/controller/error.rb
173
203
  - lib/hanami/controller/version.rb
174
204
  - lib/hanami/http/status.rb
175
205
  homepage: http://hanamirb.org
@@ -188,9 +218,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
218
  version: '3.0'
189
219
  required_rubygems_version: !ruby/object:Gem::Requirement
190
220
  requirements:
191
- - - ">"
221
+ - - ">="
192
222
  - !ruby/object:Gem::Version
193
- version: 1.3.1
223
+ version: '0'
194
224
  requirements: []
195
225
  rubygems_version: 3.3.7
196
226
  signing_key:
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
4
- module Controller
5
- # @since 0.5.0
6
- class Error < ::StandardError
7
- end
8
- end
9
- end