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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7df8a9794d83f7ff21ab449fcc1c8d294ef6fcc2f07efa3f06312847efd98351
4
- data.tar.gz: 06b6b58ad9d4b5969ae944a4d84b49cb7eb163c8096ced05d345384b418ad651
3
+ metadata.gz: 99bd6bd346b7e55ee390e747bb9ff232aa84af52e0198b48d162b42e7caed5f8
4
+ data.tar.gz: b4746d75c8201e0751e1d413155697a2f23da1d0da667491749838db0a6c0c19
5
5
  SHA512:
6
- metadata.gz: 9c67223de7d299fc05e4edb7d3f07a662ab08517f1fd515ecd20b5fed2bcbd9c1415a91ec64ec96ca71d79e584eb456b56e3a16ca1e5877f75c837f0be4817a3
7
- data.tar.gz: a219e6a26311d776b6b68c3dee2a0ea40bc7faf4cbb00cf55fd9f390e3594bb862514aff5fc833477540bac3acf3f6173e08c97026379369b8bd6fd6019bcfcf
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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StructuredParams
5
- VERSION = '0.9.1' #: string
5
+ VERSION = '0.9.2' #: string
6
6
  end
@@ -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.1
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: StructuredParams allows you to validate pass parameter.
102
+ summary: Type-safe parameter validation and form objects for Rails.
99
103
  test_files: []