hanami-controller 2.2.0.beta1 → 2.2.0.beta2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97114bc3e9ab406fe26bc05b1022f79b9f1bcf1bcbf23b84cecffa6bdb306ec4
4
- data.tar.gz: 8016185016dab18fda2fc40c028572240d000d09c2d1e37197430b46ab2a0e71
3
+ metadata.gz: 60b2a7ff4db376b8ef573c5141910b643630febd016d1019d5df4f17a2b29c76
4
+ data.tar.gz: 3c721bd675ef9cfbb397666dc21080fa8c2c4d2cc771f43dec87eef84511dc1b
5
5
  SHA512:
6
- metadata.gz: 44991c54305b783db097a835e63385ab09b8a62a8e90032a59eb8c456a72ffcd0169d155bf0070ed3409da75ff4748801e1aef71b353c1c5c25d6a92739a5d03
7
- data.tar.gz: 1c0e08f6390616ac3f811b701cc2cd7d1365d64d182a0e6e73c506842acb248724126ef38b4582e7d028404fae13c16a6493eae720f931f0bc758682d5d5a26b
6
+ metadata.gz: 7a1aa20043ecad3e5e79a008f142bc9274f6df4d1ebae9929454263214ecbec0c9449016b376879d296737f5df69e2bfbf5be4da5d5c0bbb128a38fea5d84203
7
+ data.tar.gz: 543ef54c68b7f0280dce88da5ceb2ca7917a49c045ca7285946c44604023243f16f92b16e57c347c5c1387d475783a6856f8e014d95795285c82f63c2968e959
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Complete, fast and testable actions for Rack
4
4
 
5
+ ## v2.2.0.beta1 - 2024-09-25
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley, Krzysztof Piotrowski] Add support for using full dry-validation contracts for action param validation, via `Hanami::Action.contract` (#453, #454)
10
+
5
11
  ## v2.2.0.beta1 - 2024-07-16
6
12
 
7
13
  ### Changed
@@ -131,14 +131,14 @@ module Hanami
131
131
  return false unless verify_csrf_token?(req, res)
132
132
 
133
133
  missing_csrf_token?(req, res) ||
134
- !::Rack::Utils.secure_compare(req.session[CSRF_TOKEN], req.params[CSRF_TOKEN])
134
+ !::Rack::Utils.secure_compare(req.session[CSRF_TOKEN], req.params.raw[CSRF_TOKEN.to_s])
135
135
  end
136
136
 
137
137
  # Verify the CSRF token was passed in params.
138
138
  #
139
139
  # @api private
140
140
  def missing_csrf_token?(req, *)
141
- Hanami::Utils::Blank.blank?(req.params[CSRF_TOKEN])
141
+ Hanami::Utils::Blank.blank?(req.params.raw[CSRF_TOKEN.to_s])
142
142
  end
143
143
 
144
144
  # Generates a random CSRF Token
@@ -1,9 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "hanami/validations/form"
3
+ require "rack/request"
4
+ require "hanami/utils/hash"
4
5
 
5
6
  module Hanami
6
7
  class Action
8
+ # Provides access to params included in a Rack request.
9
+ #
10
+ # Offers useful access to params via methods like {#[]}, {#get} and {#to_h}.
11
+ #
12
+ # These params are available via {Request#params}.
13
+ #
14
+ # This class is used by default when {Hanami::Action::Validatable} is not included, or when no
15
+ # {Validatable::ClassMethods#params params} validation schema is defined.
16
+ #
17
+ # @see Hanami::Action::Request#params
18
+
7
19
  # A set of params requested by the client
8
20
  #
9
21
  # It's able to extract the relevant params from a Rack env of from an Hash.
@@ -14,8 +26,23 @@ module Hanami
14
26
  # * Default: it returns the given hash as it is. It's useful for testing purposes.
15
27
  #
16
28
  # @since 0.1.0
17
- class Params < BaseParams
18
- include Hanami::Validations::Form
29
+ class Params
30
+ # Permits all params and returns them as symbolized keys. Stands in for a
31
+ # `Dry::Validation::Contract` when neither {Action.params} nor {Action.contract} are called.
32
+ #
33
+ # @see {Params#initialize}
34
+ #
35
+ # @since 2.2.0
36
+ # @api private
37
+ class DefaultContract
38
+ def self.call(attrs) = Result.new(attrs)
39
+
40
+ class Result
41
+ def initialize(attrs) = @attrs = Utils::Hash.deep_symbolize(attrs)
42
+ def to_h = @attrs
43
+ def errors = {}
44
+ end
45
+ end
19
46
 
20
47
  # Params errors
21
48
  #
@@ -107,46 +134,57 @@ module Hanami
107
134
  end
108
135
  end
109
136
 
110
- # This is a Hanami::Validations extension point
137
+ # Defines validations for the params, using the `params` schema of a dry-validation contract.
138
+ #
139
+ # @param block [Proc] the schema definition
111
140
  #
141
+ # @see https://dry-rb.org/gems/dry-validation/
142
+ #
143
+ # @api public
112
144
  # @since 0.7.0
113
- # @api private
114
- def self._base_rules
115
- lambda do
116
- optional(:_csrf_token).filled(:str?)
145
+ def self.params(&block)
146
+ unless defined?(Dry::Validation::Contract)
147
+ message = %(To use `.params`, please add the "hanami-validations" gem to your Gemfile)
148
+ raise NoMethodError, message
117
149
  end
150
+
151
+ @_contract = Class.new(Dry::Validation::Contract) { params(&block || -> {}) }.new
152
+ end
153
+
154
+ class << self
155
+ # @api private
156
+ # @since 2.2.0
157
+ attr_reader :_contract
118
158
  end
119
159
 
120
- # Define params validations
160
+ # @attr_reader env [Hash] the Rack env
121
161
  #
122
- # @param blk [Proc] the validations definitions
162
+ # @since 0.7.0
163
+ # @api private
164
+ attr_reader :env
165
+
166
+ # @attr_reader raw [Hash] the raw params from the request
123
167
  #
124
168
  # @since 0.7.0
169
+ # @api private
170
+ attr_reader :raw
171
+
172
+ # Returns structured error messages
125
173
  #
126
- # @see https://guides.hanamirb.org/validations/overview
174
+ # @return [Hash]
127
175
  #
128
- # @example
129
- # class Signup < Hanami::Action
130
- # MEGABYTE = 1024 ** 2
131
- #
132
- # params do
133
- # required(:first_name).filled(:str?)
134
- # required(:last_name).filled(:str?)
135
- # required(:email).filled?(:str?, format?: /\A.+@.+\z/)
136
- # required(:password).filled(:str?).confirmation
137
- # required(:terms_of_service).filled(:bool?)
138
- # required(:age).filled(:int?, included_in?: 18..99)
139
- # optional(:avatar).filled(size?: 1..(MEGABYTE * 3))
140
- # end
176
+ # @since 0.7.0
141
177
  #
142
- # def handle(req, *)
143
- # halt 400 unless req.params.valid?
144
- # # ...
145
- # end
146
- # end
147
- def self.params(&blk)
148
- validations(&blk || -> {})
149
- end
178
+ # @example
179
+ # params.errors
180
+ # # => {
181
+ # :email=>["is missing", "is in invalid format"],
182
+ # :name=>["is missing"],
183
+ # :tos=>["is missing"],
184
+ # :age=>["is missing"],
185
+ # :address=>["is missing"]
186
+ # }
187
+ attr_reader :errors
150
188
 
151
189
  # Initialize the params and freeze them.
152
190
  #
@@ -156,40 +194,75 @@ module Hanami
156
194
  #
157
195
  # @since 0.1.0
158
196
  # @api private
159
- def initialize(env)
197
+ def initialize(env:, contract: nil)
160
198
  @env = env
161
- super(_extract_params)
162
- validation = validate
199
+ @raw = _extract_params
200
+
201
+ # Fall back to the default contract here, rather than in the `._contract` method itself.
202
+ # This allows `._contract` to return nil when there is no user-defined contract, which is
203
+ # important for the backwards compatibility behavior in `Validatable::ClassMethods#params`.
204
+ contract ||= self.class._contract || DefaultContract
205
+ validation = contract.call(raw)
206
+
163
207
  @params = validation.to_h
164
- @errors = Errors.new(validation.messages)
208
+ @errors = Errors.new(validation.errors.to_h)
209
+
165
210
  freeze
166
211
  end
167
212
 
168
- # Returns raw params from Rack env
213
+ # Returns the value for the given params key.
169
214
  #
170
- # @return [Hash]
215
+ # @param key [Symbol] the key
216
+ #
217
+ # @return [Object,nil] the associated value, if found
171
218
  #
172
- # @since 0.3.2
173
- def raw
174
- @input
219
+ # @since 0.7.0
220
+ # @api public
221
+ def [](key)
222
+ @params[key]
175
223
  end
176
224
 
177
- # Returns structured error messages
225
+ # Returns an value associated with the given params key.
178
226
  #
179
- # @return [Hash]
227
+ # You can access nested attributes by listing all the keys in the path. This uses the same key
228
+ # path semantics as `Hash#dig`.
180
229
  #
181
- # @since 0.7.0
230
+ # @param keys [Array<Symbol,Integer>] the key
231
+ #
232
+ # @return [Object,NilClass] return the associated value, if found
182
233
  #
183
234
  # @example
184
- # params.errors
185
- # # => {
186
- # :email=>["is missing", "is in invalid format"],
187
- # :name=>["is missing"],
188
- # :tos=>["is missing"],
189
- # :age=>["is missing"],
190
- # :address=>["is missing"]
191
- # }
192
- attr_reader :errors
235
+ # require "hanami/controller"
236
+ #
237
+ # module Deliveries
238
+ # class Create < Hanami::Action
239
+ # def handle(req, *)
240
+ # req.params.get(:customer_name) # => "Luca"
241
+ # req.params.get(:uknown) # => nil
242
+ #
243
+ # req.params.get(:address, :city) # => "Rome"
244
+ # req.params.get(:address, :unknown) # => nil
245
+ #
246
+ # req.params.get(:tags, 0) # => "foo"
247
+ # req.params.get(:tags, 1) # => "bar"
248
+ # req.params.get(:tags, 999) # => nil
249
+ #
250
+ # req.params.get(nil) # => nil
251
+ # end
252
+ # end
253
+ # end
254
+ #
255
+ # @since 0.7.0
256
+ # @api public
257
+ def get(*keys)
258
+ @params.dig(*keys)
259
+ end
260
+
261
+ # This is for compatibility with Hanami::Helpers::FormHelper::Values
262
+ #
263
+ # @api private
264
+ # @since 0.8.0
265
+ alias_method :dig, :get
193
266
 
194
267
  # Returns flat collection of full error messages
195
268
  #
@@ -234,6 +307,21 @@ module Hanami
234
307
  errors.empty?
235
308
  end
236
309
 
310
+ # Iterates over the params.
311
+ #
312
+ # Calls the given block with each param key-value pair; returns the full hash of params.
313
+ #
314
+ # @yieldparam key [Symbol]
315
+ # @yieldparam value [Object]
316
+ #
317
+ # @return [to_h]
318
+ #
319
+ # @since 0.7.1
320
+ # @api public
321
+ def each(&blk)
322
+ to_h.each(&blk)
323
+ end
324
+
237
325
  # Serialize validated params to Hash
238
326
  #
239
327
  # @return [::Hash]
@@ -252,6 +340,36 @@ module Hanami
252
340
  def deconstruct_keys(*)
253
341
  to_hash
254
342
  end
343
+
344
+ private
345
+
346
+ # @since 0.7.0
347
+ # @api private
348
+ def _extract_params
349
+ result = {}
350
+
351
+ if env.key?(Action::RACK_INPUT)
352
+ result.merge! ::Rack::Request.new(env).params
353
+ result.merge! _router_params
354
+ else
355
+ result.merge! _router_params(env)
356
+ env[Action::REQUEST_METHOD] ||= Action::DEFAULT_REQUEST_METHOD
357
+ end
358
+
359
+ result
360
+ end
361
+
362
+ # @since 0.7.0
363
+ # @api private
364
+ def _router_params(fallback = {})
365
+ env.fetch(ROUTER_PARAMS) do
366
+ if session = fallback.delete(Action::RACK_SESSION)
367
+ fallback[Action::RACK_SESSION] = Utils::Hash.deep_symbolize(session)
368
+ end
369
+
370
+ fallback
371
+ end
372
+ end
255
373
  end
256
374
  end
257
375
  end
@@ -18,10 +18,7 @@ module Hanami
18
18
  class Request < ::Rack::Request
19
19
  # Returns the request's params.
20
20
  #
21
- # For an action with {Validatable} included, this will be a {Params} instance, otherwise a
22
- # {BaseParams}.
23
- #
24
- # @return [BaseParams,Params]
21
+ # @return [Params]
25
22
  #
26
23
  # @since 2.0.0
27
24
  # @api public
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "params"
4
-
5
3
  module Hanami
6
4
  class Action
7
5
  # Support for validating params when calling actions.
@@ -28,34 +26,32 @@ module Hanami
28
26
  # @since 0.1.0
29
27
  # @api private
30
28
  module ClassMethods
31
- # Whitelist valid parameters to be passed to Hanami::Action#call.
32
- #
33
- # This feature isn't mandatory, but higly recommended for security
34
- # reasons.
29
+ # Defines a validation schema for the params passed to {Hanami::Action#call}.
35
30
  #
36
- # Because params come into your application from untrusted sources, it's
37
- # a good practice to filter only the wanted keys that serve for your
38
- # specific use case.
31
+ # This feature isn't mandatory, but is highly recommended for secure handling of params:
32
+ # because params come from an untrusted source, it's good practice to filter these to only
33
+ # the keys and types required for your action's use case.
39
34
  #
40
- # Once whitelisted, the params are available as an Hash with symbols
41
- # as keys.
35
+ # The given block is evaluated inside a `params` schema of a `Dry::Validation::Contract`
36
+ # class. This constrains the validation to simple structure and type rules only. If you want
37
+ # to use all the features of dry-validation contracts, use {#contract} instead.
42
38
  #
43
- # It accepts an anonymous block where all the params can be listed.
44
- # It internally creates an inner class which inherits from
45
- # Hanami::Action::Params.
39
+ # The resulting contract becomes part of a dedicated params class for the action, inheriting
40
+ # from {Hanami::Action::Params}.
46
41
  #
47
- # Alternatively, it accepts an concrete class that should inherit from
48
- # Hanami::Action::Params.
42
+ # Instead of defining the params validation schema inline, you can alternatively provide a
43
+ # concrete params class, which should inherit from {Hanami::Action::Params}.
49
44
  #
50
45
  # @param klass [Class,nil] a Hanami::Action::Params subclass
51
- # @param blk [Proc] a block which defines the whitelisted params
46
+ # @param block [Proc] the params schema definition
52
47
  #
53
48
  # @return void
54
49
  #
50
+ # @see #contract
55
51
  # @see Hanami::Action::Params
56
- # @see https://guides.hanamirb.org//validations/overview
52
+ # @see https://dry-rb.org/gems/dry-validation/
57
53
  #
58
- # @example Anonymous Block
54
+ # @example Inline definition
59
55
  # require "hanami/controller"
60
56
  #
61
57
  # class Signup < Hanami::Action
@@ -78,9 +74,11 @@ module Hanami
78
74
  # require "hanami/controller"
79
75
  #
80
76
  # class SignupParams < Hanami::Action::Params
81
- # required(:first_name)
82
- # required(:last_name)
83
- # required(:email)
77
+ # params do
78
+ # required(:first_name)
79
+ # required(:last_name)
80
+ # required(:email)
81
+ # end
84
82
  # end
85
83
  #
86
84
  # class Signup < Hanami::Action
@@ -95,15 +93,106 @@ module Hanami
95
93
  # end
96
94
  # end
97
95
  #
96
+ # @api public
98
97
  # @since 0.3.0
98
+ def params(klass = nil, &block)
99
+ contract_class =
100
+ if klass.nil?
101
+ Class.new(Dry::Validation::Contract) { params(&block) }
102
+ elsif klass < Params
103
+ # Handle subclasses of Hanami::Action::Params.
104
+ klass._contract.class
105
+ else
106
+ klass
107
+ end
108
+
109
+ config.contract_class = contract_class
110
+ end
111
+
112
+ # Defines a validation contract for the params passed to {Hanami::Action#call}.
113
+ #
114
+ # This feature isn't mandatory, but is highly recommended for secure handling of params:
115
+ # because params come from an untrusted source, it's good practice to filter these to only
116
+ # the keys and types required for your action's use case.
117
+ #
118
+ # The given block is evaluated inside a `Dry::Validation::Contract` class. This allows you
119
+ # to use all features of dry-validation contracts
120
+ #
121
+ # The resulting contract becomes part of a dedicated params class for the action, inheriting
122
+ # from {Hanami::Action::Params}.
123
+ #
124
+ # Instead of defining the params validation contract inline, you can alternatively provide a
125
+ # concrete params class, which should inherit from {Hanami::Action::Params}.
126
+ #
127
+ # @param klass [Class,nil] a Hanami::Action::Params subclass
128
+ # @param block [Proc] the params schema definition
129
+ #
130
+ # @return void
131
+ #
132
+ # @see #params
133
+ # @see Hanami::Action::Params
134
+ # @see https://dry-rb.org/gems/dry-validation/
135
+ #
136
+ # @example Inline definition
137
+ # require "hanami/controller"
138
+ #
139
+ # class Signup < Hanami::Action
140
+ # contract do
141
+ # params do
142
+ # required(:first_name)
143
+ # required(:last_name)
144
+ # required(:email)
145
+ # end
146
+ #
147
+ # rule(:email) do
148
+ # # custom rule logic here
149
+ # end
150
+ # end
151
+ #
152
+ # def handle(req, *)
153
+ # puts req.params.class # => Signup::Params
154
+ # puts req.params.class.superclass # => Hanami::Action::Params
155
+ #
156
+ # puts req.params[:first_name] # => "Luca"
157
+ # puts req.params[:admin] # => nil
158
+ # end
159
+ # end
160
+ #
161
+ # @example Concrete class
162
+ # require "hanami/controller"
163
+ #
164
+ # class SignupParams < Hanami::Action::Params
165
+ # contract do
166
+ # params do
167
+ # required(:first_name)
168
+ # required(:last_name)
169
+ # required(:email)
170
+ # end
171
+ #
172
+ # rule(:email) do
173
+ # # custom rule logic here
174
+ # end
175
+ # end
176
+ # end
177
+ #
178
+ # class Signup < Hanami::Action
179
+ # params SignupParams
180
+ #
181
+ # def handle(req, *)
182
+ # puts req.params.class # => SignupParams
183
+ # puts req.params.class.superclass # => Hanami::Action::Params
184
+ #
185
+ # req.params[:first_name] # => "Luca"
186
+ # req.params[:admin] # => nil
187
+ # end
188
+ # end
189
+ #
99
190
  # @api public
100
- def params(klass = nil, &blk)
101
- if klass.nil?
102
- klass = const_set(PARAMS_CLASS_NAME, Class.new(Params))
103
- klass.class_eval { params(&blk) }
104
- end
191
+ # @since 2.2.0
192
+ def contract(klass = nil, &block)
193
+ contract_class = klass || Class.new(Dry::Validation::Contract, &block)
105
194
 
106
- @params_class = klass
195
+ config.contract_class = contract_class
107
196
  end
108
197
  end
109
198
  end
data/lib/hanami/action.rb CHANGED
@@ -39,7 +39,7 @@ module Hanami
39
39
  loader.ignore(
40
40
  "#{root}/hanami-controller.rb",
41
41
  "#{root}/hanami/controller/version.rb",
42
- "#{root}/hanami/action/{constants,errors,params,validatable}.rb"
42
+ "#{root}/hanami/action/{constants,errors,validatable}.rb"
43
43
  )
44
44
  loader.inflector.inflect("csrf_protection" => "CSRFProtection")
45
45
  end
@@ -72,6 +72,7 @@ module Hanami
72
72
  setting :public_directory, default: Config::DEFAULT_PUBLIC_DIRECTORY
73
73
  setting :before_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
74
74
  setting :after_callbacks, default: Utils::Callbacks::Chain.new, mutable: true
75
+ setting :contract_class
75
76
 
76
77
  # @!scope class
77
78
 
@@ -105,37 +106,30 @@ module Hanami
105
106
  include Validatable if defined?(Validatable)
106
107
  end
107
108
  end
108
-
109
- if instance_variable_defined?(:@params_class)
110
- subclass.instance_variable_set(:@params_class, @params_class)
111
- end
112
109
  end
113
110
 
114
- # Returns the class which defines the params
115
- #
116
- # Returns the class which has been provided to define the
117
- # params. By default this will be Hanami::Action::Params.
111
+ # Placeholder for the `.params` method. Raises an error when the hanami-validations gem is not
112
+ # installed.
118
113
  #
119
- # @return [Class] A params class (when whitelisted) or
120
- # Hanami::Action::Params
114
+ # @raise [NoMethodError]
121
115
  #
122
- # @api private
123
- # @since 0.7.0
124
- def self.params_class
125
- @params_class || BaseParams
116
+ # @api public
117
+ # @since 2.0.0
118
+ def self.params(_klass = nil)
119
+ message = %(To use `.params`, please add the "hanami-validations" gem to your Gemfile)
120
+ raise NoMethodError, message
126
121
  end
127
122
 
128
- # Placeholder implementation for params class method
129
- #
130
- # Raises a developer friendly error to include `hanami/validations`.
123
+ # Placeholder for the `.contract` method. Raises an error when the hanami-validations gem is not
124
+ # installed.
131
125
  #
132
126
  # @raise [NoMethodError]
133
127
  #
134
128
  # @api public
135
- # @since 2.0.0
136
- def self.params(_klass = nil)
137
- raise NoMethodError,
138
- "To use `params`, please add 'hanami/validations' gem to your Gemfile"
129
+ # @since 2.2.0
130
+ def self.contract
131
+ message = %(To use `.contract`, please add the "hanami-validations" gem to your Gemfile)
132
+ raise NoMethodError, message
139
133
  end
140
134
 
141
135
  # @overload self.append_before(*callbacks, &block)
@@ -287,12 +281,21 @@ module Hanami
287
281
  config.handle_exception(...)
288
282
  end
289
283
 
284
+ # @since 2.0.0
285
+ # @api private
286
+ private attr_reader :config
287
+
288
+ # @since 2.2.0
289
+ # @api private
290
+ private attr_reader :contract
291
+
290
292
  # Returns a new action
291
293
  #
292
294
  # @since 2.0.0
293
295
  # @api public
294
- def initialize(config: self.class.config)
296
+ def initialize(config: self.class.config, contract: nil)
295
297
  @config = config
298
+ @contract = contract || config.contract_class&.new # TODO: tests showing this overridden by a dep
296
299
  freeze
297
300
  end
298
301
 
@@ -305,7 +308,7 @@ module Hanami
305
308
  response = nil
306
309
 
307
310
  halted = catch :halt do
308
- params = self.class.params_class.new(env)
311
+ params = Params.new(env: env, contract: contract)
309
312
  request = build_request(
310
313
  env: env,
311
314
  params: params,
@@ -401,10 +404,6 @@ module Hanami
401
404
 
402
405
  private
403
406
 
404
- # @since 2.0.0
405
- # @api private
406
- attr_reader :config
407
-
408
407
  # @since 2.0.0
409
408
  # @api private
410
409
  def enforce_accepted_mime_types(request)
@@ -8,6 +8,6 @@ module Hanami
8
8
  #
9
9
  # @since 0.1.0
10
10
  # @api public
11
- VERSION = "2.2.0.beta1"
11
+ VERSION = "2.2.0.beta2"
12
12
  end
13
13
  end
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.2.0.beta1
4
+ version: 2.2.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-16 00:00:00.000000000 Z
11
+ date: 2024-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -175,7 +175,6 @@ files:
175
175
  - hanami-controller.gemspec
176
176
  - lib/hanami-controller.rb
177
177
  - lib/hanami/action.rb
178
- - lib/hanami/action/base_params.rb
179
178
  - lib/hanami/action/cache.rb
180
179
  - lib/hanami/action/cache/cache_control.rb
181
180
  - lib/hanami/action/cache/conditional_get.rb
@@ -222,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
221
  - !ruby/object:Gem::Version
223
222
  version: '0'
224
223
  requirements: []
225
- rubygems_version: 3.5.9
224
+ rubygems_version: 3.5.16
226
225
  signing_key:
227
226
  specification_version: 4
228
227
  summary: Complete, fast and testable actions for Rack and Hanami
@@ -1,170 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rack/request"
4
- require "hanami/utils/hash"
5
-
6
- module Hanami
7
- class Action
8
- # Provides access to params included in a Rack request.
9
- #
10
- # Offers useful access to params via methods like {#[]}, {#get} and {#to_h}.
11
- #
12
- # These params are available via {Request#params}.
13
- #
14
- # This class is used by default when {Hanami::Action::Validatable} is not included, or when no
15
- # {Validatable::ClassMethods#params params} validation schema is defined.
16
- #
17
- # @see Hanami::Action::Request#params
18
- #
19
- # @api private
20
- # @since 0.7.0
21
- class BaseParams
22
- # @attr_reader env [Hash] the Rack env
23
- #
24
- # @since 0.7.0
25
- # @api private
26
- attr_reader :env
27
-
28
- # @attr_reader raw [Hash] the raw params from the request
29
- #
30
- # @since 0.7.0
31
- # @api private
32
- attr_reader :raw
33
-
34
- # Returns a new frozen params object for the Rack env.
35
- #
36
- # @param env [Hash] a Rack env or an hash of params.
37
- #
38
- # @since 0.7.0
39
- # @api private
40
- def initialize(env)
41
- @env = env
42
- @raw = _extract_params
43
- @params = Utils::Hash.deep_symbolize(@raw)
44
- freeze
45
- end
46
-
47
- # Returns the value for the given params key.
48
- #
49
- # @param key [Symbol] the key
50
- #
51
- # @return [Object,nil] the associated value, if found
52
- #
53
- # @since 0.7.0
54
- # @api public
55
- def [](key)
56
- @params[key]
57
- end
58
-
59
- # Returns an value associated with the given params key.
60
- #
61
- # You can access nested attributes by listing all the keys in the path. This uses the same key
62
- # path semantics as `Hash#dig`.
63
- #
64
- # @param keys [Array<Symbol,Integer>] the key
65
- #
66
- # @return [Object,NilClass] return the associated value, if found
67
- #
68
- # @example
69
- # require "hanami/controller"
70
- #
71
- # module Deliveries
72
- # class Create < Hanami::Action
73
- # def handle(req, *)
74
- # req.params.get(:customer_name) # => "Luca"
75
- # req.params.get(:uknown) # => nil
76
- #
77
- # req.params.get(:address, :city) # => "Rome"
78
- # req.params.get(:address, :unknown) # => nil
79
- #
80
- # req.params.get(:tags, 0) # => "foo"
81
- # req.params.get(:tags, 1) # => "bar"
82
- # req.params.get(:tags, 999) # => nil
83
- #
84
- # req.params.get(nil) # => nil
85
- # end
86
- # end
87
- # end
88
- #
89
- # @since 0.7.0
90
- # @api public
91
- def get(*keys)
92
- @params.dig(*keys)
93
- end
94
-
95
- # This is for compatibility with Hanami::Helpers::FormHelper::Values
96
- #
97
- # @api private
98
- # @since 0.8.0
99
- alias_method :dig, :get
100
-
101
- # Returns true at all times, providing a common interface with {Params}.
102
- #
103
- # @return [TrueClass] always returns true
104
- #
105
- # @see Hanami::Action::Params#valid?
106
- #
107
- # @api public
108
- # @since 0.7.0
109
- def valid?
110
- true
111
- end
112
-
113
- # Returns a hash of the parsed request params.
114
- #
115
- # @return [Hash]
116
- #
117
- # @since 0.7.0
118
- # @api public
119
- def to_h
120
- @params
121
- end
122
- alias_method :to_hash, :to_h
123
-
124
- # Iterates over the params.
125
- #
126
- # Calls the given block with each param key-value pair; returns the full hash of params.
127
- #
128
- # @yieldparam key [Symbol]
129
- # @yieldparam value [Object]
130
- #
131
- # @return [to_h]
132
- #
133
- # @since 0.7.1
134
- # @api public
135
- def each(&blk)
136
- to_h.each(&blk)
137
- end
138
-
139
- private
140
-
141
- # @since 0.7.0
142
- # @api private
143
- def _extract_params
144
- result = {}
145
-
146
- if env.key?(Action::RACK_INPUT)
147
- result.merge! ::Rack::Request.new(env).params
148
- result.merge! _router_params
149
- else
150
- result.merge! _router_params(env)
151
- env[Action::REQUEST_METHOD] ||= Action::DEFAULT_REQUEST_METHOD
152
- end
153
-
154
- result
155
- end
156
-
157
- # @since 0.7.0
158
- # @api private
159
- def _router_params(fallback = {})
160
- env.fetch(ROUTER_PARAMS) do
161
- if session = fallback.delete(Action::RACK_SESSION)
162
- fallback[Action::RACK_SESSION] = Utils::Hash.deep_symbolize(session)
163
- end
164
-
165
- fallback
166
- end
167
- end
168
- end
169
- end
170
- end