Skip to content

Add JsonMask.except and JsonMask.compile_except exclusion masks - #1

Closed
thijsnado wants to merge 1 commit into
mainfrom
exclusion-masks
Closed

thijsnado wants to merge 1 commit into
mainfrom
exclusion-masks

Conversation

@thijsnado

Copy link
Copy Markdown

Summary

Adds an exclusion counterpart to the existing selection API: JsonMask.except(value, fields) and JsonMask.compile_except(fields) remove the fields a selector matches and pass every other field through unchanged.

JsonMask.except(response, "email,permissions(email)")

Exclusion masks reuse the existing parser, grammar, and limits — the selector language is unchanged and stays Google partial-response compliant. The new ExclusionProjector mirrors Projector with inverted semantics:

  • A matched leaf selection removes the field and its whole subtree.
  • A sub-selection or slash path keeps the parent and recurses (permissions(email) keeps permissions, removes each entry's email).
  • Arrays are traversed transparently and items are never dropped.
  • Scalars and nil under a nested exclusion are kept as-is (nothing deeper to remove).
  • Wildcards remove every field at their level; missing fields are a no-op; nil/blank selectors remove nothing and return the value unchanged.

CompiledMask gains an internal projector: collaborator so both mask kinds share the compile/reuse/fields-accessor behavior. ExclusionProjector is a private constant, matching Projector.

Motivation

Wistia's MCP server wants Drive-style default representations: sensitive fields (e.g. registrant emails on analytics tools) omitted from responses unless a caller explicitly selects them. Building that default requires "everything except these paths" projection, which the inclusion-only grammar can't express — this API provides it server-side without extending the wire syntax.

Testing

  • 13 new tests covering top-level and nested exclusion, array traversal, scalars/nils under nested exclusions, wildcards, missing fields, blank selectors, symbol keys, input non-mutation, compiled reuse, parser limits, and malformed selectors.
  • bundle exec rake (tests + RuboCop): 44 runs, 105 assertions, 0 failures; 14 files inspected, no offenses.

Version bumped to 0.2.0 with a CHANGELOG entry; README documents the new API.

🤖 Generated with Claude Code

Applies a selector as an exclusion: matched fields are removed and every
other field passes through unchanged. Uses the same grammar, parser
limits, and traversal rules as selection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thijsnado
thijsnado requested a review from rsheldiii August 21, 2026 17:29
@thijsnado

Copy link
Copy Markdown
Author

Closing: this adds exclusion masking, which goes beyond the nemtsov/json-mask reference implementation this gem mirrors (inclusion-only mask/compile). We'll keep the gem in line with the reference project and build the "everything except these fields" behavior on the consumer side instead, by compiling enumerated inclusion selectors derived from the OpenAPI schemas.

@thijsnado thijsnado closed this Aug 21, 2026
@thijsnado
thijsnado deleted the exclusion-masks branch August 21, 2026 17:47
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