Skip to content

feat: resolve instance paths against model data (RS 3002 evaluation half) - #10

Merged
ronaldtse merged 5 commits into
mainfrom
rs3002
Oct 14, 2026
Merged

ronaldtse merged 5 commits into
mainfrom
rs3002

Conversation

@ronaldtse

Copy link
Copy Markdown
Contributor

Instance-path resolution: the RS 3002 evaluation half

The gem parses instance data paths (RS 3002 "LutaML path for instance
data") — grammar, filters, conditions, 87 green examples — but
resolution was deliberately out of scope: InstancePath#match?
raises rather than silently matching names while ignoring conditions.

This adds the evaluation half, without touching the parser, the AST,
or a single existing example:

  • Lutaml::Path::Resolver walks InstancePath#steps over real
    model data: lutaml-model Serializable instances (attribute readers
    via the class contract), plain hashes, and their collections.
    Base steps anchor the root, attribute steps read named children
    (segment patterns through the existing fnmatch contract), **
    selects every descendant, and a step's condition filters the
    candidates.
  • Lutaml::Path::Filter::ConditionEvaluator evaluates the
    Condition AST the parser already produces: comparisons (=, !=,
    >, <, >=, <= with numeric coercion when both sides are
    numeric), list membership (in), existence, &&/||/! with
    parentheses and nesting, and wildcard values via
    File.fnmatch(..., FNM_EXTGLOB) — matching the segment matcher's
    own glob semantics.
  • API: Lutaml::Path.resolve(root, path) and
    InstancePath#resolve(root). Plain chains resolve to a single
    value; filters, patterns, and deep wildcards return collections.
  • gemspec: lutaml-model (>= 0.8) joins parslet — resolution
    reads model attributes through the Serializable contract.

The new specs port RS 3002's own instance-data examples (the
contributor / organization / role / docidentifier corpus) end-to-end
against real lutaml-model instances, including hash-rooted data,
chained and nested filters, wildcards, and deep hierarchy matches.

Suite: 98 examples, 0 failures (87 existing + 11 new). Rubocop clean.

Instance paths were parse-only: InstancePath#match? raised by design
rather than silently matching names while ignoring conditions. This
adds the evaluation half:

- Resolver walks InstancePath#steps over lutaml-model Serializable
  instances, hashes, and enumerables: base steps anchor the root,
  attribute steps read named children (segment patterns via the
  existing fnmatch contract), ** selects every descendant, and step
  conditions filter the candidates.
- ConditionEvaluator evaluates the Condition AST (comparisons with
  numeric coercion and FNM_EXTGLOB wildcard values, list membership,
  existence, &&/||/!) against the same name-resolution.
- Lutaml::Path.resolve(root, path) and InstancePath#resolve: plain
  chains resolve to a single value; filters, patterns, and deep
  wildcards return collections.
- gemspec: lutaml-model (>= 0.8) joins parslet — resolution reads
  model attributes through the Serializable contract.

The parser, AST, and the 87 existing examples are untouched; the
new specs port RS 3002's own instance-data examples (the
contributor/organization/role/docidentifier corpus) end-to-end.
Suite 98/0; rubocop clean.
- Gemfile.lock was committed with a darwin-only resolution; the repo
  does not track a lockfile, so it is removed and ignored again.
  Windows cells failed at load because that lock admitted no nokogiri
  platform, and moxml's adapter lookup raised inside
  require "lutaml/model".
- The resolution specs now skip cleanly when lutaml-model cannot
  load: the resolver's model branch is defined?-guarded, so the
  parser suite stays meaningful without the integration.
- nokogiri joins the test Gemfile so the model-backed specs run on
  every CI platform rather than only where a transitive resolver
  happens to pull an adapter.
@ronaldtse
ronaldtse merged commit 199c810 into main Oct 14, 2026
14 checks passed
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