hanami-controller 2.2.0.beta1 → 2.2.0.beta2

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