glossarist 2.8.18 → 2.9.0

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +175 -8
  3. data/Rakefile +4 -0
  4. data/config.yml +2 -3
  5. data/data/concept-model/README.md +35 -0
  6. data/data/concept-model/SOURCE.json +5 -0
  7. data/data/concept-model/glossarist.context.jsonld +209 -0
  8. data/data/concept-model/glossarist.ttl +960 -0
  9. data/data/concept-model/shapes/glossarist.shacl.ttl +575 -0
  10. data/glossarist.gemspec +2 -0
  11. data/lib/glossarist/asset_reference.rb +2 -0
  12. data/lib/glossarist/bibliographic_reference.rb +13 -0
  13. data/lib/glossarist/cli/export_command.rb +130 -7
  14. data/lib/glossarist/cli.rb +11 -2
  15. data/lib/glossarist/concept_document.rb +13 -0
  16. data/lib/glossarist/concept_reference.rb +6 -0
  17. data/lib/glossarist/concept_store.rb +2 -3
  18. data/lib/glossarist/dataset_register.rb +2 -2
  19. data/lib/glossarist/figure_reference.rb +0 -4
  20. data/lib/glossarist/formula_reference.rb +0 -4
  21. data/lib/glossarist/non_verbal_reference.rb +10 -0
  22. data/lib/glossarist/rdf/gloss_detailed_definition.rb +6 -1
  23. data/lib/glossarist/rdf/gloss_localized_concept.rb +65 -0
  24. data/lib/glossarist/rdf/lutaml_ext.rb +33 -0
  25. data/lib/glossarist/rdf.rb +2 -0
  26. data/lib/glossarist/reference.rb +33 -0
  27. data/lib/glossarist/table_reference.rb +0 -4
  28. data/lib/glossarist/tasks/shacl.rake +30 -0
  29. data/lib/glossarist/tasks/sync.rake +14 -0
  30. data/lib/glossarist/tasks/sync_model.rb +92 -0
  31. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +3 -2
  32. data/lib/glossarist/utilities/uuid.rb +5 -1
  33. data/lib/glossarist/validation/rules/related_concept_cycle_rule.rb +15 -1
  34. data/lib/glossarist/validation/shacl_validator.rb +97 -0
  35. data/lib/glossarist/validation.rb +1 -0
  36. data/lib/glossarist/version.rb +1 -1
  37. data/lib/glossarist.rb +1 -0
  38. metadata +41 -2
@@ -65,7 +65,11 @@ module Glossarist
65
65
  else
66
66
  match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
67
67
 
68
- unless match_data.present?
68
+ # `match_data` is a MatchData on success, nil on failure. Do not
69
+ # use ActiveSupport's `#present?` here — ActiveSupport is not a
70
+ # declared dependency of this gem, and `#present?` raises
71
+ # NoMethodError in bundles where it isn't loaded.
72
+ unless match_data
69
73
  raise ArgumentError,
70
74
  "Only UUIDs are valid namespace identifiers"
71
75
  end
@@ -54,11 +54,25 @@ module Glossarist
54
54
  graph
55
55
  end
56
56
 
57
+ # Returns a graph node identifier for the target of a relationship.
58
+ #
59
+ # For intra-edition references (ref.source is nil), the target is
60
+ # just ref.id — a clause identifier unique within the dataset.
61
+ #
62
+ # Returns nil for cross-edition references (ref.source is a URN,
63
+ # e.g. a +supersedes+ edge pointing at the previous edition's
64
+ # concept with the same clause id). Such edges cannot form
65
+ # cycles within the current dataset and are excluded from the
66
+ # graph. Without this exclusion, a cross-edition edge from
67
+ # concept 3.1.1.1 to its predecessor in another edition (which
68
+ # also has identifier 3.1.1.1) would look like a self-loop and
69
+ # trip the cycle detector with a false positive.
57
70
  def resolve_target_id(rel)
58
71
  ref = rel.ref
59
72
  return nil unless ref
73
+ return nil if ref.source
60
74
 
61
- ref.id || ref.source
75
+ ref.id
62
76
  end
63
77
 
64
78
  def detect_cycles(graph)
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rdf/turtle"
4
+ require "shacl"
5
+ require "pathname"
6
+
7
+ module Glossarist
8
+ module Validation
9
+ # Validates Turtle output against SHACL shapes.
10
+ #
11
+ # Shapes resolution order:
12
+ # 1. Explicit :shapes_path option
13
+ # 2. Vendored shapes at data/concept-model/shapes/glossarist.shacl.ttl
14
+ # (shipped with the gem, relative to the gem root)
15
+ class ShaclValidator
16
+ VENDORED_SHAPES_PATH =
17
+ File.expand_path(
18
+ "../../../data/concept-model/shapes/glossarist.shacl.ttl",
19
+ __dir__
20
+ ).freeze
21
+
22
+ attr_reader :shapes_path
23
+
24
+ def initialize(shapes_path: nil)
25
+ @shapes_path = shapes_path || self.class.default_shapes_path
26
+ end
27
+
28
+ def validate_files(paths)
29
+ validate_graphs(Array(paths).map { |p| load_graph(p) })
30
+ end
31
+
32
+ def validate_graphs(graphs)
33
+ shapes = SHACL::Shapes.from_graph(load_graph(@shapes_path))
34
+ failures = []
35
+
36
+ graphs.each do |graph|
37
+ report = shapes.execute(graph)
38
+ next if report.conform?
39
+
40
+ failures << Report.new(results: report.results)
41
+ end
42
+
43
+ AggregateReport.new(failures: failures)
44
+ end
45
+
46
+ class << self
47
+ def default_shapes_path
48
+ return VENDORED_SHAPES_PATH if File.exist?(VENDORED_SHAPES_PATH)
49
+
50
+ raise ArgumentError,
51
+ "No SHACL shapes path provided and the vendored shapes " \
52
+ "file (#{VENDORED_SHAPES_PATH}) is missing. Pass " \
53
+ "shapes_path: '/path/to/glossarist.shacl.ttl'."
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def load_graph(path)
60
+ return path if path.is_a?(RDF::Graph)
61
+
62
+ graph = RDF::Graph.new
63
+ RDF::Turtle::Reader.new(File.read(path)) do |reader|
64
+ reader.each_statement { |stmt| graph << stmt }
65
+ end
66
+ graph
67
+ end
68
+ end
69
+
70
+ Report = Struct.new(:results, keyword_init: true) do
71
+ def conformant?
72
+ results.empty?
73
+ end
74
+
75
+ def to_s
76
+ " #{results.length} violation(s)"
77
+ end
78
+ end
79
+
80
+ AggregateReport = Struct.new(:failures, keyword_init: true) do
81
+ def conformant?
82
+ failures.empty?
83
+ end
84
+
85
+ def to_s
86
+ lines = ["SHACL validation failed: #{failures.length} file(s) with violations"]
87
+ failures.each do |failure|
88
+ lines << failure.to_s
89
+ failure.results.each do |result|
90
+ lines << " #{result.path}: #{result.message}"
91
+ end
92
+ end
93
+ lines.join("\n")
94
+ end
95
+ end
96
+ end
97
+ end
@@ -8,5 +8,6 @@ module Glossarist
8
8
  autoload :Rules, "glossarist/validation/rules"
9
9
  autoload :BibliographyIndex, "glossarist/validation/bibliography_index"
10
10
  autoload :AssetIndex, "glossarist/validation/asset_index"
11
+ autoload :ShaclValidator, "glossarist/validation/shacl_validator"
11
12
  end
12
13
  end
@@ -4,5 +4,5 @@
4
4
  #
5
5
 
6
6
  module Glossarist
7
- VERSION = "2.8.18"
7
+ VERSION = "2.9.0"
8
8
  end
data/lib/glossarist.rb CHANGED
@@ -23,6 +23,7 @@ module Glossarist
23
23
  autoload :ConceptData, "glossarist/concept_data"
24
24
  autoload :ConceptRef, "glossarist/concept_ref"
25
25
  autoload :ConceptReference, "glossarist/concept_reference"
26
+ autoload :Reference, "glossarist/reference"
26
27
  autoload :ReferenceExtractor, "glossarist/reference_extractor"
27
28
  autoload :ReferenceResolver, "glossarist/reference_resolver"
28
29
  autoload :ResolutionAdapter, "glossarist/resolution_adapter"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glossarist
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.18
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-02 00:00:00.000000000 Z
11
+ date: 2026-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdf-turtle
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.3'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: relaton
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +106,20 @@ dependencies:
92
106
  - - "<"
93
107
  - !ruby/object:Gem::Version
94
108
  version: '3'
109
+ - !ruby/object:Gem::Dependency
110
+ name: shacl
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '0.4'
116
+ type: :runtime
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '0.4'
95
123
  - !ruby/object:Gem::Dependency
96
124
  name: sts
97
125
  requirement: !ruby/object:Gem::Requirement
@@ -170,6 +198,11 @@ files:
170
198
  - README.adoc
171
199
  - Rakefile
172
200
  - config.yml
201
+ - data/concept-model/README.md
202
+ - data/concept-model/SOURCE.json
203
+ - data/concept-model/glossarist.context.jsonld
204
+ - data/concept-model/glossarist.ttl
205
+ - data/concept-model/shapes/glossarist.shacl.ttl
173
206
  - exe/glossarist
174
207
  - glossarist.gemspec
175
208
  - lib/glossarist.rb
@@ -276,6 +309,7 @@ files:
276
309
  - lib/glossarist/rdf/gloss_pronunciation.rb
277
310
  - lib/glossarist/rdf/gloss_reference.rb
278
311
  - lib/glossarist/rdf/localized_literal.rb
312
+ - lib/glossarist/rdf/lutaml_ext.rb
279
313
  - lib/glossarist/rdf/namespaces.rb
280
314
  - lib/glossarist/rdf/namespaces/dcterms_namespace.rb
281
315
  - lib/glossarist/rdf/namespaces/glossarist_namespace.rb
@@ -288,6 +322,7 @@ files:
288
322
  - lib/glossarist/rdf/relationship_predicates.rb
289
323
  - lib/glossarist/rdf/v3.rb
290
324
  - lib/glossarist/rdf/v3/configuration.rb
325
+ - lib/glossarist/reference.rb
291
326
  - lib/glossarist/reference_extractor.rb
292
327
  - lib/glossarist/reference_resolver.rb
293
328
  - lib/glossarist/register_data.rb
@@ -313,6 +348,9 @@ files:
313
348
  - lib/glossarist/sts/term_mapper.rb
314
349
  - lib/glossarist/table.rb
315
350
  - lib/glossarist/table_reference.rb
351
+ - lib/glossarist/tasks/shacl.rake
352
+ - lib/glossarist/tasks/sync.rake
353
+ - lib/glossarist/tasks/sync_model.rb
316
354
  - lib/glossarist/transforms.rb
317
355
  - lib/glossarist/transforms/concept_to_gloss_transform.rb
318
356
  - lib/glossarist/transforms/concept_to_tbx_transform.rb
@@ -402,6 +440,7 @@ files:
402
440
  - lib/glossarist/validation/rules/source_urn_format_rule.rb
403
441
  - lib/glossarist/validation/rules/terms_presence_rule.rb
404
442
  - lib/glossarist/validation/rules/uuid_format_rule.rb
443
+ - lib/glossarist/validation/shacl_validator.rb
405
444
  - lib/glossarist/validation/validation_issue.rb
406
445
  - lib/glossarist/validation_result.rb
407
446
  - lib/glossarist/version.rb