-
Notifications
You must be signed in to change notification settings - Fork 0
before_typecast & validates_raw #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
09c9c5c
Add operational guide for agents working with structured_params
Syati 4bddc16
Add operational guide for agents working with structured_params
Syati ec04eb1
Add before_type_cast readers for attributes in StructuredParams
Syati d52d3c4
Add configuration file and RSpec skill documentation for testing
Syati c852ad8
Add raw parameter validation support to StructuredParams
Syati 6961b3b
Add raw validation support for StrictAgeParameter
Syati fe38d30
Add raw input validation support for score attribute in UserParams
Syati 786ba4e
Add raw input validation for age attribute in UserParams
Syati 01e2db6
Remove rbs_inline comments from parameter files and specs
Syati 3fd3e11
Preserve error metadata in validations by using errors.import method
Syati 70394e1
Clarify validation error messages for score attribute in documentation
Syati a18319b
Refactor RBS documentation for raw validation methods in validations.…
Syati File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| --- | ||
| name: rspec | ||
| description: Run and debug RSpec tests for the structured_params gem. Use when adding features, fixing bugs, or validating behavior changes in specs under spec/. | ||
| --- | ||
|
|
||
| # RSpec Skill | ||
|
|
||
| Run tests with minimal scope first, then widen only when needed. | ||
|
|
||
| ## Core Commands | ||
|
|
||
| ```bash | ||
| bundle exec rspec spec/attribute_methods_spec.rb | ||
| bundle exec rspec spec/params_spec.rb | ||
| bundle exec rspec | ||
| ``` | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. Run the most specific spec file related to the change. | ||
| 2. If failures include shared behavior, run adjacent spec files. | ||
| 3. Run full `bundle exec rspec` before finishing if behavior changed broadly. | ||
|
|
||
| ## Failure Triage | ||
|
|
||
| - `NoMethodError` around params fields: | ||
| Check `lib/structured_params/params.rb` and `lib/structured_params/attribute_methods.rb`. | ||
| - Nested error path mismatch: | ||
| Check `lib/structured_params/errors.rb` and structured validation behavior. | ||
| - Type-cast related mismatch: | ||
| Confirm expected value vs `*_before_type_cast` usage in specs. | ||
|
|
||
| ## Repository Notes | ||
|
|
||
| - Test helpers/classes are loaded from `spec/support/test_classes.rb`. | ||
| - Factory objects live under `spec/factories/`. | ||
| - This project uses `bundle exec` for all test commands. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| approval_policy = "on-request" | ||
| sandbox_mode = "workspace-write" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| # AGENTS.md | ||
|
|
||
| このリポジトリで作業するエージェント向けの運用ガイドです。変更前に全体像を確認し、最小差分で修正してください。 | ||
|
|
||
| ## プロジェクト概要 | ||
|
|
||
| - `structured_params` は Rails 向けの型付きパラメータ/フォームオブジェクト用 gem です。 | ||
| - コア実装は `lib/structured_params/` 配下にあります。 | ||
| - テストは RSpec、Lint は RuboCop、型検査は Steep を使います。 | ||
| - RBS シグネチャは `rbs-inline` から生成されます。 | ||
|
|
||
| ## 主要ディレクトリ | ||
|
|
||
| - `lib/structured_params.rb`: エントリーポイント | ||
| - `lib/structured_params/params.rb`: コアの `Params` 実装 | ||
| - `lib/structured_params/type/`: `array` / `object` 型ハンドラ | ||
| - `spec/`: RSpec テスト | ||
| - `docs/`: 利用者向けドキュメント | ||
| - `sig/`: `rbs-inline` により生成された RBS | ||
|
|
||
| ## セットアップと実行 | ||
|
|
||
| 初回セットアップ: | ||
|
|
||
| ```bash | ||
| bin/setup | ||
| ``` | ||
|
|
||
| 通常の確認: | ||
|
|
||
| ```bash | ||
| bundle exec rspec | ||
| bundle exec rubocop | ||
| bundle exec steep check | ||
| ``` | ||
|
|
||
| Ruby 3.2 系では `steep` や `.rubocop_rbs.yml` 前提のチェックが使えない場合があります。`Rakefile` は Ruby 3.3+ でのみ `steep` をデフォルトタスクに含めます。 | ||
|
|
||
| 個別実行例: | ||
|
|
||
| ```bash | ||
| bundle exec rspec spec/params_spec.rb | ||
| bundle exec rubocop lib/structured_params/params.rb | ||
| ``` | ||
|
|
||
| ## 変更時のルール | ||
|
|
||
| - `sig/**/*.rbs` は手編集しないでください。必要なら `bundle exec rbs-inline --output=sig lib/**/*.rb` で再生成します。 | ||
| - Ruby メソッドの型注釈は `rbs-inline` の `method_type_signature` スタイルを使ってください。 | ||
| - インスタンス変数の型注釈は `# @rbs` コメントを使ってください。 | ||
| - 既存の公開 API を変える場合は、README と `docs/` の整合も確認してください。 | ||
| - Strong Parameters、ネストした object/array、エラー整形は回帰しやすいので重点的に確認してください。 | ||
|
|
||
| ## テスト方針 | ||
|
|
||
| - 振る舞い変更には RSpec を追加または更新してください。 | ||
| - 既存 spec のスタイルに合わせ、必要に応じて `spec/factories/` と `spec/support/` を再利用してください。 | ||
| - 修正が型やシリアライズ、permit 生成に関わる場合は、関連 spec を広めに実行してください。 | ||
|
|
||
| ## コミット前チェック | ||
|
|
||
| `lefthook.yml` によりコミット前に以下が走ります。 | ||
|
|
||
| - `bundle exec rbs-inline --output=sig lib/**/*.rb` | ||
| - `bundle exec rubocop` | ||
| - `bundle exec rspec` | ||
| - `bundle exec steep check` | ||
|
|
||
| フックで失敗しない状態まで揃えてから完了扱いにしてください。 | ||
|
|
||
| ## ドキュメント更新の目安 | ||
|
|
||
| 以下を変えた場合はドキュメント更新を検討してください。 | ||
|
|
||
| - 新しい attribute オプションや型の追加 | ||
| - permit 挙動の変更 | ||
| - エラーフォーマットやバリデーション挙動の変更 | ||
| - Rails / Ruby サポート範囲の変更 | ||
|
|
||
| 利用者向け概要は `README.md`、詳細仕様は `docs/*.md`、日本語 README が必要なら `README_ja.md` も更新します。 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # rbs_inline: enabled | ||
| # frozen_string_literal: true | ||
|
|
||
| module StructuredParams | ||
| # Extends ActiveModel::Attributes to define +attr_before_type_cast+ accessors | ||
| # for each attribute, mirroring ActiveRecord::AttributeMethods::BeforeTypeCast. | ||
| # | ||
| # Example: | ||
| # class UserParams < StructuredParams::Params | ||
| # attribute :age, :integer | ||
| # end | ||
| # | ||
| # params = UserParams.new(age: "42abc") | ||
| # params.age # => 42 (type-cast) | ||
| # params.age_before_type_cast # => "42abc" (raw input) | ||
| module AttributeMethods | ||
| extend ActiveSupport::Concern | ||
|
|
||
| included do | ||
| # Override attribute to also define `attr_before_type_cast` | ||
| # via ActiveModel::Attribute#value_before_type_cast | ||
| #: (Symbol name, *untyped) -> void | ||
| def self.attribute(name, ...) | ||
| super | ||
| define_method(:"#{name}_before_type_cast") { @attributes[name.to_s].value_before_type_cast } | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # rbs_inline: enabled | ||
| # frozen_string_literal: true | ||
|
|
||
| module StructuredParams | ||
| # Provides +validates_raw+ which validates raw parameter values before type casting. | ||
| # | ||
| # Internally delegates to ActiveModel's +validates+ on the +_before_type_cast+ | ||
| # attribute, then remaps errors back to the original attribute name. | ||
| # This means all standard ActiveModel validators (format, numericality, etc.) | ||
| # work as-is on the raw input value. | ||
| # | ||
| # Example: | ||
| # class UserParams < StructuredParams::Params | ||
| # attribute :age, :integer | ||
| # validates_raw :age, format: { with: /\A\d+\z/, message: 'must be numeric string' } | ||
| # end | ||
| # | ||
| # params = UserParams.new(age: "abc") | ||
| # params.valid? # => false | ||
| # params.errors[:age] # => ["must be numeric string"] | ||
| module Validations | ||
| extend ActiveSupport::Concern | ||
|
|
||
| included do | ||
| class_attribute :validates_raw_btc_map, instance_accessor: false, default: {} | ||
| class_attribute :validates_raw_remap_validator_installed, instance_accessor: false, default: false | ||
| end | ||
|
|
||
| # @rbs module ClassMethods | ||
| class_methods do | ||
| # Validates raw attribute value before type casting. | ||
| # | ||
| # Accepts the same options as +validates+ (format, numericality, presence, etc.), | ||
| # but validates the raw input value before it is converted by ActiveModel::Attributes. | ||
| # | ||
| # Examples: | ||
| # validates_raw :age, format: { with: /\A\d+\z/ } | ||
| # validates_raw :score, numericality: { only_integer: true } | ||
| # validates_raw :code, format: { with: /\A[A-Z]+\z/, message: 'must be uppercase' } | ||
| # | ||
| #: (*Symbol, **untyped) -> void | ||
| def validates_raw(*attr_names, **options) | ||
| btc_map = attr_names.to_h { |attr| [attr.to_sym, :"#{attr}_before_type_cast"] } | ||
| validates(*btc_map.values, **options) | ||
| self.validates_raw_btc_map = validates_raw_btc_map.merge(btc_map) | ||
| validates_raw_install_remap_validator_once | ||
| end | ||
|
|
||
| #: () -> void | ||
| def validates_raw_install_remap_validator_once | ||
| return if validates_raw_remap_validator_installed | ||
|
|
||
| set_callback(:validate, :after, :validates_raw_remap_errors) | ||
|
|
||
| self.validates_raw_remap_validator_installed = true | ||
| end | ||
| private :validates_raw_install_remap_validator_once | ||
| end | ||
|
|
||
| private | ||
|
|
||
| #: () -> void | ||
| def validates_raw_remap_errors | ||
| self.class.validates_raw_btc_map.each do |attr, btc| | ||
| next if errors.where(btc).none? | ||
|
|
||
| errors.where(btc).dup.each { |e| errors.import(e, attribute: attr) } | ||
| errors.delete(btc) | ||
| end | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Generated from lib/structured_params/attribute_methods.rb with RBS::Inline | ||
|
|
||
| module StructuredParams | ||
| # Extends ActiveModel::Attributes to define +attr_before_type_cast+ accessors | ||
| # for each attribute, mirroring ActiveRecord::AttributeMethods::BeforeTypeCast. | ||
| # | ||
| # Example: | ||
| # class UserParams < StructuredParams::Params | ||
| # attribute :age, :integer | ||
| # end | ||
| # | ||
| # params = UserParams.new(age: "42abc") | ||
| # params.age # => 42 (type-cast) | ||
| # params.age_before_type_cast # => "42abc" (raw input) | ||
| module AttributeMethods | ||
| extend ActiveSupport::Concern | ||
|
|
||
| # Override attribute to also define `attr_before_type_cast` | ||
| # via ActiveModel::Attribute#value_before_type_cast | ||
| # : (Symbol name, *untyped) -> void | ||
| def self.attribute: (Symbol name, *untyped) -> void | ||
| end | ||
| end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.