structured_params 0.9.1 → 0.9.2
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/structured_params/attribute_methods.rb +29 -0
- data/lib/structured_params/params.rb +6 -0
- data/lib/structured_params/validations.rb +72 -0
- data/lib/structured_params/version.rb +1 -1
- data/lib/structured_params.rb +2 -0
- data/sig/structured_params/attribute_methods.rbs +23 -0
- data/sig/structured_params/params.rbs +8 -0
- data/sig/structured_params/validations.rbs +47 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99bd6bd346b7e55ee390e747bb9ff232aa84af52e0198b48d162b42e7caed5f8
|
|
4
|
+
data.tar.gz: b4746d75c8201e0751e1d413155697a2f23da1d0da667491749838db0a6c0c19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2aef79c11cbb97312962a39869726aa7ce95ef1e1b3f29974d3d8bc1d1637487ef7cb85dbe47742866db1db9572e83999bb52095fe634247c1170cafd0ff5433
|
|
7
|
+
data.tar.gz: b2a6bce45a08f4521979084f2ecd6b20385b7aeec3794ae2cfb8bd57d6888e87ffdae4dae10a4887b07e47417afc80d256235e25bc8ce5c9c96a3316391f81ab
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.2] - 2026-04-02
|
|
4
|
+
|
|
5
|
+
## What's Changed
|
|
6
|
+
* Clarify gemspec summary to describe type-safe parameter validation by @Syati in https://github.com/Syati/structured_params/pull/13
|
|
7
|
+
* Addressing PR comments by @Syati in https://github.com/Syati/structured_params/pull/14
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
**Full Changelog**: https://github.com/Syati/structured_params/compare/v0.9.1...v0.9.2
|
|
11
|
+
|
|
3
12
|
## [0.9.1] - 2026-03-18
|
|
4
13
|
|
|
5
14
|
**Full Changelog**: https://github.com/Syati/structured_params/compare/v0.9.0...v0.9.1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module StructuredParams
|
|
5
|
+
# Extends ActiveModel::Attributes to define +attr_before_type_cast+ accessors
|
|
6
|
+
# for each attribute, mirroring ActiveRecord::AttributeMethods::BeforeTypeCast.
|
|
7
|
+
#
|
|
8
|
+
# Example:
|
|
9
|
+
# class UserParams < StructuredParams::Params
|
|
10
|
+
# attribute :age, :integer
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# params = UserParams.new(age: "42abc")
|
|
14
|
+
# params.age # => 42 (type-cast)
|
|
15
|
+
# params.age_before_type_cast # => "42abc" (raw input)
|
|
16
|
+
module AttributeMethods
|
|
17
|
+
extend ActiveSupport::Concern
|
|
18
|
+
|
|
19
|
+
included do
|
|
20
|
+
# Override attribute to also define `attr_before_type_cast`
|
|
21
|
+
# via ActiveModel::Attribute#value_before_type_cast
|
|
22
|
+
#: (Symbol name, *untyped) -> void
|
|
23
|
+
def self.attribute(name, ...)
|
|
24
|
+
super
|
|
25
|
+
define_method(:"#{name}_before_type_cast") { @attributes[name.to_s].value_before_type_cast }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -11,9 +11,13 @@ module StructuredParams
|
|
|
11
11
|
# Strong Parameters example (API):
|
|
12
12
|
# class UserParams < StructuredParams::Params
|
|
13
13
|
# attribute :name, :string
|
|
14
|
+
# attribute :age, :integer
|
|
14
15
|
# attribute :address, :object, value_class: AddressParams
|
|
15
16
|
# attribute :hobbies, :array, value_class: HobbyParams
|
|
16
17
|
# attribute :tags, :array, value_type: :string
|
|
18
|
+
#
|
|
19
|
+
# # Validate raw input before type casting (e.g., "12x" for integer fields)
|
|
20
|
+
# validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
|
|
17
21
|
# end
|
|
18
22
|
#
|
|
19
23
|
# # In controller:
|
|
@@ -49,6 +53,8 @@ module StructuredParams
|
|
|
49
53
|
class Params
|
|
50
54
|
include ActiveModel::Model
|
|
51
55
|
include ActiveModel::Attributes
|
|
56
|
+
include AttributeMethods
|
|
57
|
+
include Validations
|
|
52
58
|
|
|
53
59
|
# @rbs @errors: ::StructuredParams::Errors?
|
|
54
60
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module StructuredParams
|
|
5
|
+
# Provides +validates_raw+ which validates raw parameter values before type casting.
|
|
6
|
+
#
|
|
7
|
+
# Internally delegates to ActiveModel's +validates+ on the +_before_type_cast+
|
|
8
|
+
# attribute, then remaps errors back to the original attribute name.
|
|
9
|
+
# This means all standard ActiveModel validators (format, numericality, etc.)
|
|
10
|
+
# work as-is on the raw input value.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
# class UserParams < StructuredParams::Params
|
|
14
|
+
# attribute :age, :integer
|
|
15
|
+
# validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# params = UserParams.new(age: "abc")
|
|
19
|
+
# params.valid? # => false
|
|
20
|
+
# params.errors[:age] # => ["must be numeric string"]
|
|
21
|
+
module Validations
|
|
22
|
+
extend ActiveSupport::Concern
|
|
23
|
+
|
|
24
|
+
included do
|
|
25
|
+
class_attribute :validates_raw_btc_map, instance_accessor: false, default: {}
|
|
26
|
+
class_attribute :validates_raw_remap_validator_installed, instance_accessor: false, default: false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# @rbs module ClassMethods
|
|
30
|
+
class_methods do
|
|
31
|
+
# Validates raw attribute value before type casting.
|
|
32
|
+
#
|
|
33
|
+
# Accepts the same options as +validates+ (format, numericality, presence, etc.),
|
|
34
|
+
# but validates the raw input value before it is converted by ActiveModel::Attributes.
|
|
35
|
+
#
|
|
36
|
+
# Examples:
|
|
37
|
+
# validates_raw :age, format: { with: /\A\d+\z/ }
|
|
38
|
+
# validates_raw :score, numericality: { only_integer: true }
|
|
39
|
+
# validates_raw :code, format: { with: /\A[A-Z]+\z/, message: 'must be uppercase' }
|
|
40
|
+
#
|
|
41
|
+
#: (*Symbol, **untyped) -> void
|
|
42
|
+
def validates_raw(*attr_names, **options)
|
|
43
|
+
btc_map = attr_names.to_h { |attr| [attr.to_sym, :"#{attr}_before_type_cast"] }
|
|
44
|
+
validates(*btc_map.values, **options)
|
|
45
|
+
self.validates_raw_btc_map = validates_raw_btc_map.merge(btc_map)
|
|
46
|
+
validates_raw_install_remap_validator_once
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#: () -> void
|
|
50
|
+
def validates_raw_install_remap_validator_once
|
|
51
|
+
return if validates_raw_remap_validator_installed
|
|
52
|
+
|
|
53
|
+
set_callback(:validate, :after, :validates_raw_remap_errors)
|
|
54
|
+
|
|
55
|
+
self.validates_raw_remap_validator_installed = true
|
|
56
|
+
end
|
|
57
|
+
private :validates_raw_install_remap_validator_once
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
#: () -> void
|
|
63
|
+
def validates_raw_remap_errors
|
|
64
|
+
self.class.validates_raw_btc_map.each do |attr, btc|
|
|
65
|
+
next if errors.where(btc).none?
|
|
66
|
+
|
|
67
|
+
errors.where(btc).dup.each { |e| errors.import(e, attribute: attr) }
|
|
68
|
+
errors.delete(btc)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/structured_params.rb
CHANGED
|
@@ -10,6 +10,8 @@ require_relative 'structured_params/version'
|
|
|
10
10
|
|
|
11
11
|
# errors
|
|
12
12
|
require_relative 'structured_params/errors'
|
|
13
|
+
require_relative 'structured_params/attribute_methods'
|
|
14
|
+
require_relative 'structured_params/validations'
|
|
13
15
|
|
|
14
16
|
# types (load first for module definition)
|
|
15
17
|
require_relative 'structured_params/type/object'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Generated from lib/structured_params/attribute_methods.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module StructuredParams
|
|
4
|
+
# Extends ActiveModel::Attributes to define +attr_before_type_cast+ accessors
|
|
5
|
+
# for each attribute, mirroring ActiveRecord::AttributeMethods::BeforeTypeCast.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
# class UserParams < StructuredParams::Params
|
|
9
|
+
# attribute :age, :integer
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# params = UserParams.new(age: "42abc")
|
|
13
|
+
# params.age # => 42 (type-cast)
|
|
14
|
+
# params.age_before_type_cast # => "42abc" (raw input)
|
|
15
|
+
module AttributeMethods
|
|
16
|
+
extend ActiveSupport::Concern
|
|
17
|
+
|
|
18
|
+
# Override attribute to also define `attr_before_type_cast`
|
|
19
|
+
# via ActiveModel::Attribute#value_before_type_cast
|
|
20
|
+
# : (Symbol name, *untyped) -> void
|
|
21
|
+
def self.attribute: (Symbol name, *untyped) -> void
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -10,9 +10,13 @@ module StructuredParams
|
|
|
10
10
|
# Strong Parameters example (API):
|
|
11
11
|
# class UserParams < StructuredParams::Params
|
|
12
12
|
# attribute :name, :string
|
|
13
|
+
# attribute :age, :integer
|
|
13
14
|
# attribute :address, :object, value_class: AddressParams
|
|
14
15
|
# attribute :hobbies, :array, value_class: HobbyParams
|
|
15
16
|
# attribute :tags, :array, value_type: :string
|
|
17
|
+
#
|
|
18
|
+
# # Validate raw input before type casting (e.g., "12x" for integer fields)
|
|
19
|
+
# validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
|
|
16
20
|
# end
|
|
17
21
|
#
|
|
18
22
|
# # In controller:
|
|
@@ -50,6 +54,10 @@ module StructuredParams
|
|
|
50
54
|
|
|
51
55
|
include ActiveModel::Attributes
|
|
52
56
|
|
|
57
|
+
include AttributeMethods
|
|
58
|
+
|
|
59
|
+
include Validations
|
|
60
|
+
|
|
53
61
|
@errors: ::StructuredParams::Errors?
|
|
54
62
|
|
|
55
63
|
self.@structured_attributes: Hash[Symbol, singleton(::StructuredParams::Params)]?
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Generated from lib/structured_params/validations.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module StructuredParams
|
|
4
|
+
# Provides +validates_raw+ which validates raw parameter values before type casting.
|
|
5
|
+
#
|
|
6
|
+
# Internally delegates to ActiveModel's +validates+ on the +_before_type_cast+
|
|
7
|
+
# attribute, then remaps errors back to the original attribute name.
|
|
8
|
+
# This means all standard ActiveModel validators (format, numericality, etc.)
|
|
9
|
+
# work as-is on the raw input value.
|
|
10
|
+
#
|
|
11
|
+
# Example:
|
|
12
|
+
# class UserParams < StructuredParams::Params
|
|
13
|
+
# attribute :age, :integer
|
|
14
|
+
# validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' }
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# params = UserParams.new(age: "abc")
|
|
18
|
+
# params.valid? # => false
|
|
19
|
+
# params.errors[:age] # => ["must be numeric string"]
|
|
20
|
+
module Validations
|
|
21
|
+
extend ActiveSupport::Concern
|
|
22
|
+
|
|
23
|
+
# @rbs module ClassMethods
|
|
24
|
+
module ClassMethods
|
|
25
|
+
# Validates raw attribute value before type casting.
|
|
26
|
+
#
|
|
27
|
+
# Accepts the same options as +validates+ (format, numericality, presence, etc.),
|
|
28
|
+
# but validates the raw input value before it is converted by ActiveModel::Attributes.
|
|
29
|
+
#
|
|
30
|
+
# Examples:
|
|
31
|
+
# validates_raw :age, format: { with: /\A\d+\z/ }
|
|
32
|
+
# validates_raw :score, numericality: { only_integer: true }
|
|
33
|
+
# validates_raw :code, format: { with: /\A[A-Z]+\z/, message: 'must be uppercase' }
|
|
34
|
+
#
|
|
35
|
+
# : (*Symbol, **untyped) -> void
|
|
36
|
+
def validates_raw: (*Symbol, **untyped) -> void
|
|
37
|
+
|
|
38
|
+
# : () -> void
|
|
39
|
+
def validates_raw_install_remap_validator_once: () -> void
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# : () -> void
|
|
45
|
+
def validates_raw_remap_errors: () -> void
|
|
46
|
+
end
|
|
47
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: structured_params
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mizuki Yamamoto
|
|
@@ -59,16 +59,20 @@ files:
|
|
|
59
59
|
- CHANGELOG.md
|
|
60
60
|
- LICENSE.txt
|
|
61
61
|
- lib/structured_params.rb
|
|
62
|
+
- lib/structured_params/attribute_methods.rb
|
|
62
63
|
- lib/structured_params/errors.rb
|
|
63
64
|
- lib/structured_params/params.rb
|
|
64
65
|
- lib/structured_params/type/array.rb
|
|
65
66
|
- lib/structured_params/type/object.rb
|
|
67
|
+
- lib/structured_params/validations.rb
|
|
66
68
|
- lib/structured_params/version.rb
|
|
67
69
|
- sig/structured_params.rbs
|
|
70
|
+
- sig/structured_params/attribute_methods.rbs
|
|
68
71
|
- sig/structured_params/errors.rbs
|
|
69
72
|
- sig/structured_params/params.rbs
|
|
70
73
|
- sig/structured_params/type/array.rbs
|
|
71
74
|
- sig/structured_params/type/object.rbs
|
|
75
|
+
- sig/structured_params/validations.rbs
|
|
72
76
|
- sig/structured_params/version.rbs
|
|
73
77
|
homepage: https://github.com/Syati/structured_params
|
|
74
78
|
licenses:
|
|
@@ -95,5 +99,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
95
99
|
requirements: []
|
|
96
100
|
rubygems_version: 3.6.9
|
|
97
101
|
specification_version: 4
|
|
98
|
-
summary:
|
|
102
|
+
summary: Type-safe parameter validation and form objects for Rails.
|
|
99
103
|
test_files: []
|