hanami-controller 2.0.0.beta4 → 2.0.0

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.
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