Skip to content

Fix Array/Set custom-type coercer dropping symbolized hash keys#2699

Open
ericproulx wants to merge 1 commit intomasterfrom
fix/custom-type-coercer-symbolize-collection
Open

Fix Array/Set custom-type coercer dropping symbolized hash keys#2699
ericproulx wants to merge 1 commit intomasterfrom
fix/custom-type-coercer-symbolize-collection

Conversation

@ericproulx
Copy link
Copy Markdown
Contributor

Summary

  • Bug fix: in Grape::Validations::Types::CustomTypeCoercer#enforce_symbolized_keys, the Array/Set branch built a symbolized copy via non-mutating deep_symbolize_keys and discarded it, returning the original string-keyed hashes. Swapped the inner block to map! so the symbolized values replace the originals (matching the Hash branch's contract).
  • Readability refactors in the same class:
    • Hoist [Array, Set] and [:coerced?, :parsed?] to private frozen constants (COLLECTION_TYPES, TYPE_CHECK_METHODS) — one allocation at load time, named intent.
    • Lift trailing if/elsif/else chains in infer_type_check, recursive_type_check, and the new build_coercion_method into guard clauses; the simple default sits at top indentation.
    • Extract hash_symbolizer, collection_symbolizer, symbolize_if_hash, and enumerable_type_check helpers so the dispatch lists read uniformly and the per-item logic has a name.
    • Collapse infer_coercion_method + symbolize-wrap chain in initialize into a single build_coercion_method entry point.
    • Reorder private methods to follow call order from initialize.
  • Regression spec at spec/grape/validations/types/custom_type_coercer_spec.rb covers Array and Set symbolization paths through the public API. The Array case is the regression test for the bug above; before the fix it returned [{"foo" => "bar"}] instead of [{foo: "bar"}].

Test plan

  • bundle exec rspec spec/grape/validations/types/custom_type_coercer_spec.rb — both examples pass
  • bundle exec rspec — full suite green (2,256 examples)
  • bundle exec rubocop lib/grape/validations/types/custom_type_coercer.rb spec/grape/validations/types/custom_type_coercer_spec.rb — clean

🤖 Generated with Claude Code

The Array/Set branch of `enforce_symbolized_keys` built a symbolized
copy via non-mutating `deep_symbolize_keys` and discarded it, so the
returned collection still carried string-keyed hashes. Switch to
`map!` so the symbolized values replace the originals, matching the
Hash branch's contract.

While here, refactor the class for readability: hoist the
`[Array, Set]` and `[:coerced?, :parsed?]` arrays to private frozen
constants, lift trailing `if/else` chains into guard clauses, extract
`hash_symbolizer` / `collection_symbolizer` / `enumerable_type_check`
helpers, collapse the `infer_coercion_method` + symbolize-wrap chain
into a single `build_coercion_method` entry point, and reorder the
private methods to follow call order from `initialize`.

Add `spec/grape/validations/types/custom_type_coercer_spec.rb`
covering the Array and Set symbolization paths through the public
API. The Array case is the regression test for the bug above.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ericproulx ericproulx force-pushed the fix/custom-type-coercer-symbolize-collection branch from 5f67d67 to 051b7da Compare May 8, 2026 11:55
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Danger Report

No issues found.

View run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant