lutaml-path 0.1.0 → 0.1.1

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.
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # The resolution specs exercise real lutaml-model instances. The gem
6
+ # works without lutaml-model loaded (the resolver's model branch is
7
+ # defined?-guarded), so when the dependency cannot load — an adapter
8
+ # gem missing on an exotic platform, say — the suite skips instead of
9
+ # failing at file load.
10
+ begin
11
+ require "lutaml/model"
12
+ LUTAML_MODEL_AVAILABLE = true
13
+ rescue LoadError, StandardError
14
+ LUTAML_MODEL_AVAILABLE = false
15
+ end
16
+
17
+ # Conformance corpus for RS 3002 "LutaML path for instance data",
18
+ # resolved against real lutaml-model instances shaped like the
19
+ # specification's own examples (contributor / organization / role /
20
+ # docidentifier / date).
21
+ # The model-fixture stack mirrors the specification's example model
22
+ # (contributor / organization / role / docidentifier); it is the
23
+ # conformance corpus, not incidental setup.
24
+ RSpec.describe "Lutaml::Path.resolve over lutaml-model instances" do
25
+ before do
26
+ skip "lutaml-model is not loadable in this bundle" unless LUTAML_MODEL_AVAILABLE
27
+ end
28
+ let(:role_class) do
29
+ klass = Class.new(Lutaml::Model::Serializable) do
30
+ attribute :type, :string
31
+
32
+ json { map "type", to: :type }
33
+ end
34
+ stub_const("LpSpec::Role", klass)
35
+ klass
36
+ end
37
+
38
+ let(:organization_class) do
39
+ klass = Class.new(Lutaml::Model::Serializable) do
40
+ attribute :name, :string
41
+ attribute :type, :string
42
+
43
+ json do
44
+ map "name", to: :name
45
+ map "type", to: :type
46
+ end
47
+ end
48
+ stub_const("LpSpec::Organization", klass)
49
+ klass
50
+ end
51
+
52
+ let(:contributor_class) do
53
+ role = role_class
54
+ org = organization_class
55
+ klass = Class.new(Lutaml::Model::Serializable) do
56
+ attribute :role, role
57
+ attribute :organization, org
58
+
59
+ json do
60
+ map "role", to: :role
61
+ map "organization", to: :organization
62
+ end
63
+ end
64
+ stub_const("LpSpec::Contributor", klass)
65
+ klass
66
+ end
67
+
68
+ let(:docidentifier_class) do
69
+ klass = Class.new(Lutaml::Model::Serializable) do
70
+ attribute :type, :string
71
+ attribute :value, :string
72
+
73
+ json do
74
+ map "type", to: :type
75
+ map "id", to: :value
76
+ end
77
+ end
78
+ stub_const("LpSpec::Docidentifier", klass)
79
+ klass
80
+ end
81
+
82
+ let(:document_class) do
83
+ contributor = contributor_class
84
+ identifier = docidentifier_class
85
+ klass = Class.new(Lutaml::Model::Serializable) do
86
+ attribute :title, :string
87
+ attribute :contributor, contributor, collection: true
88
+ attribute :docidentifier, identifier, collection: true
89
+
90
+ json do
91
+ map "title", to: :title
92
+ map "contributor", to: :contributor
93
+ map "docidentifier", to: :docidentifier
94
+ end
95
+ end
96
+ stub_const("LpSpec::Document", klass)
97
+ klass
98
+ end
99
+
100
+ let(:document) do
101
+ document_class.from_json(
102
+ <<~JSON
103
+ {
104
+ "title": "Standard X",
105
+ "contributor": [
106
+ {"role": {"type": "publisher"},
107
+ "organization": {"name": "ISO", "type": "standards"}},
108
+ {"role": {"type": "author"},
109
+ "organization": {"name": "ACME", "type": "company"}},
110
+ {"role": {"type": "author"},
111
+ "organization": {"name": "IEC", "type": "standards"}}
112
+ ],
113
+ "docidentifier": [
114
+ {"type": "ISBN", "id": "978-1"},
115
+ {"type": "ISSN", "id": "1234-5"},
116
+ {"type": "DOI", "id": "10.1/x"}
117
+ ]
118
+ }
119
+ JSON
120
+ )
121
+ end
122
+
123
+ def resolve(path)
124
+ Lutaml::Path.resolve(document, path)
125
+ end
126
+
127
+ it "resolves a simple attribute chain to a single value" do
128
+ expect(resolve("title")).to eq("Standard X")
129
+ end
130
+
131
+ it "resolves a collection attribute to its elements" do
132
+ expect(resolve("contributor").length).to eq(3)
133
+ end
134
+
135
+ it "resolves a nested chain through a collection element" do
136
+ expect(resolve("contributor[role.type='publisher'].organization.name"))
137
+ .to eq(["ISO"])
138
+ end
139
+
140
+ it "filters with multiple conditions" do
141
+ expect(resolve("contributor[role.type='author' && organization.type='standards'].organization.name")
142
+ .sort).to eq(%w[IEC])
143
+ end
144
+
145
+ it "filters with list membership" do
146
+ expect(resolve("docidentifier[type in ('ISBN','ISSN')].value").sort)
147
+ .to eq(%w[1234-5 978-1])
148
+ end
149
+
150
+ it "filters with negation" do
151
+ expect(resolve("docidentifier[type!='ISBN'].value").sort)
152
+ .to eq(["10.1/x", "1234-5"])
153
+ end
154
+
155
+ it "filters with existence" do
156
+ expect(resolve("contributor[exists].organization.name").sort)
157
+ .to eq(%w[ACME IEC ISO])
158
+ end
159
+
160
+ it "matches wildcard condition values" do
161
+ expect(resolve("contributor[organization.type='stand*'].organization.name").sort)
162
+ .to eq(%w[IEC ISO])
163
+ end
164
+
165
+ it "resolves wildcard segments across the collection" do
166
+ expect(resolve("*.type").compact.sort)
167
+ .to eq(%w[DOI ISBN ISSN])
168
+ end
169
+
170
+ it "resolves a deep hierarchy wildcard with a filter" do
171
+ expect(resolve("contributor.**[name='ISO']")).to contain_exactly(
172
+ an_object_having_attributes(name: "ISO")
173
+ )
174
+ end
175
+
176
+ it "resolves against plain hashes the same way" do
177
+ data = { "contributor" => [{ "role" => { "type" => "publisher" } }] }
178
+
179
+ expect(Lutaml::Path.resolve(data, "contributor[role.type='publisher']")).not_to be_empty
180
+ expect(Lutaml::Path.resolve(data, "contributor.role.type")).to eq("publisher")
181
+ end
182
+ end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-path
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-12 00:00:00.000000000 Z
11
+ date: 2026-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: parslet
14
+ name: lutaml-model
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '0.8'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '0.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parslet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
27
41
  description: Parser for element paths
28
42
  email:
29
43
  - open.source@ribose.com
@@ -31,7 +45,8 @@ executables: []
31
45
  extensions: []
32
46
  extra_rdoc_files: []
33
47
  files:
34
- - ".github/workflows/main.yml"
48
+ - ".github/workflows/rake.yml"
49
+ - ".github/workflows/release.yml"
35
50
  - ".gitignore"
36
51
  - ".rspec"
37
52
  - ".rubocop.yml"
@@ -43,14 +58,22 @@ files:
43
58
  - bin/console
44
59
  - bin/setup
45
60
  - lib/lutaml/path.rb
61
+ - lib/lutaml/path/abstract_path.rb
62
+ - lib/lutaml/path/condition.rb
63
+ - lib/lutaml/path/condition_evaluator.rb
46
64
  - lib/lutaml/path/element_path.rb
65
+ - lib/lutaml/path/errors.rb
66
+ - lib/lutaml/path/instance_path.rb
47
67
  - lib/lutaml/path/parser.rb
48
68
  - lib/lutaml/path/path_segment.rb
69
+ - lib/lutaml/path/resolver.rb
70
+ - lib/lutaml/path/step.rb
49
71
  - lib/lutaml/path/transformer.rb
50
72
  - lib/lutaml/path/version.rb
51
73
  - lutaml-path.gemspec
52
74
  - sig/lutaml/path.rbs
53
75
  - spec/lutaml/path_spec.rb
76
+ - spec/lutaml/resolver_spec.rb
54
77
  - spec/spec_helper.rb
55
78
  homepage: https://github.com/lutaml/lutaml-path
56
79
  licenses:
@@ -1,27 +0,0 @@
1
- name: Ruby
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
-
8
- pull_request:
9
-
10
- jobs:
11
- build:
12
- runs-on: ubuntu-latest
13
- name: Ruby ${{ matrix.ruby }}
14
- strategy:
15
- matrix:
16
- ruby:
17
- - '3.3.2'
18
-
19
- steps:
20
- - uses: actions/checkout@v4
21
- - name: Set up Ruby
22
- uses: ruby/setup-ruby@v1
23
- with:
24
- ruby-version: ${{ matrix.ruby }}
25
- bundler-cache: true
26
- - name: Run the default task
27
- run: bundle exec rake