glossarist 2.8.1 → 2.8.2

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CLAUDE.md +1 -1
  4. data/Gemfile +0 -1
  5. data/README.adoc +4 -1
  6. data/glossarist.gemspec +2 -1
  7. data/lib/glossarist/concept_document.rb +0 -2
  8. data/lib/glossarist/concept_manager.rb +0 -1
  9. data/lib/glossarist/concept_store.rb +94 -0
  10. data/lib/glossarist/managed_concept_data.rb +2 -0
  11. data/lib/glossarist/rdf/gloss_concept.rb +9 -3
  12. data/lib/glossarist/rdf/gloss_concept_date.rb +1 -1
  13. data/lib/glossarist/rdf/gloss_concept_source.rb +2 -2
  14. data/lib/glossarist/rdf/gloss_designation.rb +10 -4
  15. data/lib/glossarist/rdf/gloss_grammar_info.rb +2 -2
  16. data/lib/glossarist/rdf/gloss_localized_concept.rb +1 -1
  17. data/lib/glossarist/rdf/relationship_predicates.rb +72 -0
  18. data/lib/glossarist/rdf/v3/configuration.rb +0 -2
  19. data/lib/glossarist/rdf/v3.rb +4 -43
  20. data/lib/glossarist/rdf.rb +24 -22
  21. data/lib/glossarist/sts/importer.rb +0 -1
  22. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +36 -64
  23. data/lib/glossarist/v2/configuration.rb +0 -2
  24. data/lib/glossarist/v2/managed_concept_data.rb +1 -0
  25. data/lib/glossarist/v2.rb +12 -12
  26. data/lib/glossarist/v3/configuration.rb +0 -2
  27. data/lib/glossarist/v3/managed_concept_data.rb +1 -0
  28. data/lib/glossarist/v3.rb +16 -16
  29. data/lib/glossarist/validation/bibliography_index.rb +9 -7
  30. data/lib/glossarist/validation/rules.rb +18 -49
  31. data/lib/glossarist/version.rb +1 -1
  32. data/lib/glossarist.rb +9 -11
  33. metadata +21 -16
  34. data/lib/glossarist/rdf/ext/jsonld_transform_ext.rb +0 -208
  35. data/lib/glossarist/rdf/ext/mapping_ext.rb +0 -37
  36. data/lib/glossarist/rdf/ext/mapping_rule_ext.rb +0 -27
  37. data/lib/glossarist/rdf/ext/member_rule_ext.rb +0 -34
  38. data/lib/glossarist/rdf/ext/turtle_transform_ext.rb +0 -222
  39. data/lib/glossarist/rdf/ext.rb +0 -39
  40. data/lib/glossarist/rdf/relationships.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9161012e7bc694c31f1450dfdc28538de9b559c4ca3cbf6fd7aad8427976d44
4
- data.tar.gz: 465de2a3598f6a21fa007068b7fb4b282bd8e917fdb9e226636830bd24fc88ef
3
+ metadata.gz: f602beb2e985225705695343d1309f242117b6b59398f27b9b7d4966e2300c98
4
+ data.tar.gz: e5891cad0fd4efecac7140d007f36efe0a2f83609013a771ac02621199ba0306
5
5
  SHA512:
6
- metadata.gz: db1a01d3b4c1da4ec1e1ea9c15c976c0c11aaa1c53e7ac38ec2d6d3a87d6c2b23c26ac0606f16aba395e01bb7ada4c32401436af23cae94081582bc19aa155f1
7
- data.tar.gz: 4471a27273205c88f7f8f0eaa397a351ef23a9d5abc53c397665ac3d8a1f9321b29b289d5151da380bb742e217c0739595f34aff15b13fe4f0cb905c6f5dffb6
6
+ metadata.gz: 97a81b187d34665f43c2800b3ac7636de9ae71b83c832bb9fdba0f5d9895089f6c3229ba80d38b3e9b0479ab71f16bf282b924c4ee1f9292059c250ade950cfe
7
+ data.tar.gz: 5d5c43b11134a5f072d80d99c5110471dae8145a4c3212aa9cce49ac1c491fd478f748cd4f57adf97a5c3212a41c7ca679c31a07b6018cda6ecf77cdef3fff64
data/.rubocop.yml CHANGED
@@ -8,4 +8,4 @@ inherit_from:
8
8
  # ...
9
9
 
10
10
  AllCops:
11
- TargetRubyVersion: 2.5
11
+ TargetRubyVersion: 3.1
data/CLAUDE.md CHANGED
@@ -24,7 +24,7 @@ All model classes use `Lutaml::Model::Serializable` for serialization.
24
24
  - **`Concept`** (`concept.rb`) — base concept with `ConceptData` (definition, terms/designations, notes, examples, sources, dates, language_code). Parent of `LocalizedConcept`.
25
25
  - **`LocalizedConcept`** (`localized_concept.rb`) — extends `Concept` with `classification`, `entry_status`, `review_type`.
26
26
  - **`ConceptData`** (`concept_data.rb`) — the data payload inside `Concept`: definition, terms, examples, notes, sources, non_verb_rep (collection of `NonVerbRep` resource references), language_code (ISO 639), script (ISO 15924), system (ISO 24229 conversion system code). Uses `DetailedDefinition` collections for definition/examples/notes.
27
- - **`ManagedConceptData`** (`managed_concept_data.rb`) — the data payload inside `ManagedConcept`: id, localized_concepts hash (lang_code => uuid), domains (ConceptReference collection — upper concept references replacing the old `groups` string array), sources.
27
+ - **`ManagedConceptData`** (`managed_concept_data.rb`) — the data payload inside `ManagedConcept`: id, localized_concepts hash (lang_code => uuid), domains (ConceptReference collection — terminological domain references), tags (string collection organizational tags for grouping/filtering, not rendered as domains), sources.
28
28
 
29
29
  ### NonVerbRep (Resource Reference)
30
30
 
data/Gemfile CHANGED
@@ -5,7 +5,6 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "canon"
8
- gem "lutaml-model", "~> 0.8.0"
9
8
  gem "nokogiri"
10
9
  gem "rake", "~> 13.0"
11
10
  gem "relaton", "~> 2.1.0"
data/README.adoc CHANGED
@@ -101,7 +101,8 @@ related:: Array of <<related-concept,RelatedConcept>>
101
101
  status:: Enum for the normative status of the term.
102
102
  dates:: Array of <<concept-date,ConceptDate>>
103
103
  localized_concepts:: Hash of all localizations where keys are language codes and values are uuid of the localized concept.
104
- domains:: Array of <<concept-reference,ConceptReference>> — upper concepts (subject areas, concept schemes, organizing concepts) that this concept belongs to across all languages. Each domain is a typed reference (e.g. `{ concept_id: "103", ref_type: "domain" }`).
104
+ domains:: Array of <<concept-reference,ConceptReference>> — terminological domain references (subject areas, concept schemes) that this concept belongs to. Each domain is a typed reference (e.g. `{ concept_id: "103", ref_type: "domain" }`). These are rendered as `<domain>` in output.
105
+ tags:: Array of strings — organizational tags for grouping and filtering concepts (e.g. `["time-scale-units"]`). Tags are not rendered as terminological domains; they serve as metadata for document structure and retrieval.
105
106
  localizations:: Hash of all localizations for this concept where keys are language codes and values are instances of <<localized-concept,LocalizedConcept>>.
106
107
 
107
108
  There are two ways to initialize and populate a managed concept
@@ -121,6 +122,7 @@ concept = Glossarist::ManagedConcept.new({
121
122
  "domains" => [
122
123
  { "concept_id" => "103", "ref_type" => "domain" },
123
124
  ],
125
+ "tags" => ["time-scales"],
124
126
  },
125
127
  })
126
128
  ----
@@ -134,6 +136,7 @@ concept.id = "123"
134
136
  concept.data.domains = [
135
137
  Glossarist::ConceptReference.new(concept_id: "103", ref_type: "domain"),
136
138
  ]
139
+ concept.data.tags = ["time-scales"]
137
140
  concept.localizations = <Array of localized concepts or localized concept hashes>
138
141
  ----
139
142
 
data/glossarist.gemspec CHANGED
@@ -31,7 +31,8 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ["lib"]
33
33
 
34
- spec.add_dependency "lutaml-model", "~> 0.8.5"
34
+ spec.add_dependency "lutaml-model", "~> 0.8.15"
35
+ spec.add_dependency "lutaml-store", "~> 0.1.1"
35
36
  spec.add_dependency "paint", "~> 2.3"
36
37
  spec.add_dependency "relaton", ">= 2.0.0", "< 3"
37
38
  spec.add_dependency "rubyzip", ">= 2.3", "< 3"
@@ -23,10 +23,8 @@ module Glossarist
23
23
  def self.for_version(version)
24
24
  case version.to_s
25
25
  when "2"
26
- require_relative "v2"
27
26
  V2::ConceptDocument
28
27
  else
29
- require_relative "v3"
30
28
  V3::ConceptDocument
31
29
  end
32
30
  end
@@ -16,7 +16,6 @@ module Glossarist
16
16
 
17
17
  def localized_concept_class
18
18
  if version.to_s == "2"
19
- require_relative "v2"
20
19
  V2::LocalizedConcept
21
20
  else
22
21
  LocalizedConcept
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lutaml/store"
4
+
5
+ module Glossarist
6
+ class ConceptStore
7
+ # Custom serializer that preserves both uuid and identifier through
8
+ # YAML string storage. ManagedConcept's key_value mapping writes both
9
+ # uuid and identifier to the same "id" key, so a naive to_hash/from_hash
10
+ # round-trip loses one of them. Storing the YAML string preserves the
11
+ # model exactly, and explicit metadata fields let the store index and
12
+ # query by uuid/identifier without deserializing.
13
+ class Serializer
14
+ def serialize(model)
15
+ {
16
+ "_yaml" => model.to_yaml,
17
+ "_uuid" => model.uuid,
18
+ "_identifier" => model.identifier,
19
+ }
20
+ end
21
+
22
+ def deserialize(data, model_class)
23
+ model = model_class.from_yaml(data["_yaml"])
24
+ model.assign_uuid(data["_uuid"]) if data["_uuid"]
25
+ model.identifier = data["_identifier"] if data["_identifier"]
26
+ model
27
+ end
28
+ end
29
+
30
+ attr_reader :db
31
+
32
+ def initialize(adapter: :memory)
33
+ @db = Lutaml::Store::DatabaseStore.new(
34
+ adapter: adapter,
35
+ models: [managed_concept_registration],
36
+ )
37
+ end
38
+
39
+ def save(concept)
40
+ db.save(concept)
41
+ end
42
+
43
+ def fetch(uuid)
44
+ db.fetch(model: ManagedConcept, uuid: uuid)
45
+ end
46
+
47
+ def fetch_by_id(identifier)
48
+ db.where(model: ManagedConcept, identifier: identifier).first
49
+ end
50
+
51
+ def update(uuid, **attributes)
52
+ db.update(model: ManagedConcept, uuid: uuid, attributes: attributes)
53
+ end
54
+
55
+ def delete(uuid)
56
+ db.destroy(model: ManagedConcept, uuid: uuid)
57
+ end
58
+
59
+ def all
60
+ db.all(model: ManagedConcept)
61
+ end
62
+
63
+ def count
64
+ db.count(model: ManagedConcept)
65
+ end
66
+
67
+ def exists?(uuid)
68
+ db.exists?(model: ManagedConcept, uuid: uuid)
69
+ end
70
+
71
+ def clear
72
+ all.each { |concept| delete(concept.uuid) }
73
+ end
74
+
75
+ def load_from_directory(path, format: :yaml, layout: :separate)
76
+ db.import_all(ManagedConcept, path: path, format: format, layout: layout)
77
+ end
78
+
79
+ def save_to_directory(path, format: :yaml, layout: :separate)
80
+ db.save_all(all, path: path, format: format, layout: layout)
81
+ end
82
+
83
+ private
84
+
85
+ def managed_concept_registration
86
+ {
87
+ model: ManagedConcept,
88
+ key: :uuid,
89
+ dir: "concept",
90
+ serializer: Serializer.new,
91
+ }
92
+ end
93
+ end
94
+ end
@@ -6,6 +6,7 @@ module Glossarist
6
6
  attribute :uri, :string
7
7
  attribute :localized_concepts, :hash
8
8
  attribute :domains, ConceptReference, collection: true
9
+ attribute :tags, :string, collection: true
9
10
  attribute :sources, ConceptSource, collection: true
10
11
  attribute :localizations, LocalizedConcept,
11
12
  collection: Collections::LocalizationCollection,
@@ -19,6 +20,7 @@ module Glossarist
19
20
  map %i[localized_concepts localizedConcepts], to: :localized_concepts
20
21
  map %i[domains groups], to: :domains,
21
22
  with: { from: :domains_from_yaml, to: :domains_to_yaml }
23
+ map :tags, to: :tags
22
24
  map :sources, to: :sources
23
25
  map :localizations, to: :localizations,
24
26
  with: { from: :localizations_from_yaml, to: :localizations_to_yaml }
@@ -5,8 +5,6 @@ require "lutaml/model"
5
5
  module Glossarist
6
6
  module Rdf
7
7
  class GlossConcept < Lutaml::Model::Serializable
8
- include Relationships
9
-
10
8
  attribute :identifier, :string
11
9
  attribute :status, :string
12
10
  attribute :localizations, GlossLocalizedConcept, collection: true
@@ -14,6 +12,10 @@ module Glossarist
14
12
  attribute :domains, GlossConceptReference, collection: true
15
13
  attribute :dates, GlossConceptDate, collection: true
16
14
 
15
+ RelationshipPredicates::CONCEPT_REL_PREDICATES.each_key do |type|
16
+ attribute :"#{type}_targets", :string, collection: true
17
+ end
18
+
17
19
  rdf do
18
20
  namespace Namespaces::GlossaristNamespace,
19
21
  Namespaces::SkosNamespace,
@@ -27,7 +29,7 @@ module Glossarist
27
29
  types "gloss:Concept", "skos:Concept"
28
30
 
29
31
  predicate :identifier, namespace: Namespaces::GlossaristNamespace, to: :identifier
30
- predicate :hasStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
32
+ predicate :hasStatus, namespace: Namespaces::GlossaristNamespace, to: :status, uri_reference: true
31
33
 
32
34
  members :localizations,
33
35
  link: "gloss:hasLocalization"
@@ -37,6 +39,10 @@ module Glossarist
37
39
  link: "gloss:hasDomain"
38
40
  members :dates,
39
41
  link: "gloss:hasDate"
42
+
43
+ RelationshipPredicates::CONCEPT_REL_PREDICATES.each do |type, (ns, name)|
44
+ predicate name, namespace: ns, to: :"#{type}_targets", uri_reference: true
45
+ end
40
46
  end
41
47
  end
42
48
 
@@ -17,7 +17,7 @@ module Glossarist
17
17
  types "gloss:ConceptDate"
18
18
 
19
19
  predicate :dateValue, namespace: Namespaces::GlossaristNamespace, to: :date_value
20
- predicate :dateType, namespace: Namespaces::GlossaristNamespace, to: :date_type, as: :uri
20
+ predicate :dateType, namespace: Namespaces::GlossaristNamespace, to: :date_type, uri_reference: true
21
21
  end
22
22
  end
23
23
  end
@@ -17,8 +17,8 @@ module Glossarist
17
17
 
18
18
  types "gloss:ConceptSource"
19
19
 
20
- predicate :sourceStatus, namespace: Namespaces::GlossaristNamespace, to: :status, as: :uri
21
- predicate :sourceType, namespace: Namespaces::GlossaristNamespace, to: :type, as: :uri
20
+ predicate :sourceStatus, namespace: Namespaces::GlossaristNamespace, to: :status, uri_reference: true
21
+ predicate :sourceType, namespace: Namespaces::GlossaristNamespace, to: :type, uri_reference: true
22
22
  predicate :modification, namespace: Namespaces::GlossaristNamespace, to: :modification
23
23
 
24
24
  members :origin, link: "gloss:sourceOrigin"
@@ -6,8 +6,8 @@ module Glossarist
6
6
  module Rdf
7
7
  COMMON_DESIGNATION_PREDICATES = lambda { |dsl|
8
8
  dsl.predicate :literalForm, namespace: Namespaces::SkosxlNamespace, to: :designation
9
- dsl.predicate :normativeStatus, namespace: Namespaces::GlossaristNamespace, to: :normative_status, as: :uri
10
- dsl.predicate :hasTermType, namespace: Namespaces::GlossaristNamespace, to: :term_type, as: :uri
9
+ dsl.predicate :normativeStatus, namespace: Namespaces::GlossaristNamespace, to: :normative_status, uri_reference: true
10
+ dsl.predicate :hasTermType, namespace: Namespaces::GlossaristNamespace, to: :term_type, uri_reference: true
11
11
  dsl.predicate :isInternational, namespace: Namespaces::GlossaristNamespace, to: :international
12
12
  dsl.predicate :isAbsent, namespace: Namespaces::GlossaristNamespace, to: :absent
13
13
  dsl.predicate :geographicalArea, namespace: Namespaces::GlossaristNamespace, to: :language
@@ -16,6 +16,10 @@ module Glossarist
16
16
  dsl.predicate :conversionSystem, namespace: Namespaces::GlossaristNamespace, to: :system
17
17
  dsl.members :pronunciations, link: "gloss:hasPronunciation"
18
18
  dsl.members :sources
19
+
20
+ RelationshipPredicates::DESIGNATION_REL_PREDICATES.each do |type, (ns, name)|
21
+ dsl.predicate name, namespace: ns, to: :"#{type}_targets", uri_reference: true
22
+ end
19
23
  }.freeze
20
24
 
21
25
  DESIGNATION_NAMESPACES = [
@@ -27,8 +31,6 @@ module Glossarist
27
31
  ].freeze
28
32
 
29
33
  class GlossDesignation < Lutaml::Model::Serializable
30
- include Relationships
31
-
32
34
  attribute :designation, :string
33
35
  attribute :normative_status, :string
34
36
  attribute :type, :string
@@ -44,6 +46,10 @@ module Glossarist
44
46
  attribute :pronunciations, GlossPronunciation, collection: true
45
47
  attribute :sources, GlossConceptSource, collection: true
46
48
 
49
+ RelationshipPredicates::DESIGNATION_REL_PREDICATES.each_key do |type|
50
+ attribute :"#{type}_targets", :string, collection: true
51
+ end
52
+
47
53
  rdf do
48
54
  namespace(*DESIGNATION_NAMESPACES)
49
55
 
@@ -19,8 +19,8 @@ module Glossarist
19
19
 
20
20
  types "gloss:GrammarInfo"
21
21
 
22
- predicate :gender, namespace: Namespaces::GlossaristNamespace, to: :gender, as: :uri
23
- predicate :number, namespace: Namespaces::GlossaristNamespace, to: :number, as: :uri
22
+ predicate :gender, namespace: Namespaces::GlossaristNamespace, to: :gender, uri_reference: true
23
+ predicate :number, namespace: Namespaces::GlossaristNamespace, to: :number, uri_reference: true
24
24
  predicate :isNoun, namespace: Namespaces::GlossaristNamespace, to: :noun?
25
25
  predicate :isVerb, namespace: Namespaces::GlossaristNamespace, to: :verb?
26
26
  predicate :isAdjective, namespace: Namespaces::GlossaristNamespace, to: :adjective?
@@ -33,7 +33,7 @@ module Glossarist
33
33
  types "gloss:LocalizedConcept", "skos:Concept"
34
34
 
35
35
  predicate :language, namespace: Namespaces::DctermsNamespace, to: :language_code
36
- predicate :hasEntryStatus, namespace: Namespaces::GlossaristNamespace, to: :entry_status, as: :uri
36
+ predicate :hasEntryStatus, namespace: Namespaces::GlossaristNamespace, to: :entry_status, uri_reference: true
37
37
  predicate :domain, namespace: Namespaces::GlossaristNamespace, to: :domain
38
38
  predicate :release, namespace: Namespaces::GlossaristNamespace, to: :release
39
39
  predicate :lineageSimilarity, namespace: Namespaces::GlossaristNamespace, to: :lineage_similarity
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Glossarist
4
+ module Rdf
5
+ # Canonical data-driven maps for relationship predicates.
6
+ #
7
+ # Each entry maps a relationship type symbol to [namespace_module, predicate_name].
8
+ # These maps drive:
9
+ # 1. Attribute declarations in RDF view classes (one typed collection per predicate)
10
+ # 2. RDF predicate mappings with uri_reference: true
11
+ # 3. Transform grouping logic in ConceptToGlossTransform
12
+ module RelationshipPredicates
13
+ CONCEPT_REL_PREDICATES = {
14
+ broader: [Namespaces::SkosNamespace, :broader],
15
+ narrower: [Namespaces::SkosNamespace, :narrower],
16
+ broader_generic: [Namespaces::IsoThesNamespace, :broaderGeneric],
17
+ narrower_generic: [Namespaces::IsoThesNamespace, :narrowerGeneric],
18
+ broader_partitive: [Namespaces::IsoThesNamespace, :broaderPartitive],
19
+ narrower_partitive: [Namespaces::IsoThesNamespace, :narrowerPartitive],
20
+ broader_instantial: [Namespaces::IsoThesNamespace, :broaderInstantial],
21
+ narrower_instantial: [Namespaces::IsoThesNamespace, :narrowerInstantial],
22
+ equivalent: [Namespaces::SkosNamespace, :exactMatch],
23
+ close_match: [Namespaces::SkosNamespace, :closeMatch],
24
+ broad_match: [Namespaces::SkosNamespace, :broadMatch],
25
+ narrow_match: [Namespaces::SkosNamespace, :narrowMatch],
26
+ related_match: [Namespaces::SkosNamespace, :relatedMatch],
27
+ see: [Namespaces::SkosNamespace, :related],
28
+ deprecates: [Namespaces::GlossaristNamespace, :deprecates],
29
+ supersedes: [Namespaces::GlossaristNamespace, :supersedes],
30
+ superseded_by: [Namespaces::GlossaristNamespace, :supersededBy],
31
+ compare: [Namespaces::GlossaristNamespace, :compares],
32
+ contrast: [Namespaces::GlossaristNamespace, :contrasts],
33
+ sequentially_related_concept: [Namespaces::GlossaristNamespace, :sequentiallyRelated],
34
+ spatially_related_concept: [Namespaces::GlossaristNamespace, :spatiallyRelated],
35
+ temporally_related_concept: [Namespaces::GlossaristNamespace, :temporallyRelated],
36
+ related_concept_broader: [Namespaces::GlossaristNamespace, :relatedConceptBroader],
37
+ related_concept_narrower: [Namespaces::GlossaristNamespace, :relatedConceptNarrower],
38
+ }.freeze
39
+
40
+ DESIGNATION_REL_PREDICATES = {
41
+ homograph: [Namespaces::GlossaristNamespace, :hasHomograph],
42
+ false_friend: [Namespaces::GlossaristNamespace, :hasFalseFriend],
43
+ abbreviated_form_for: [Namespaces::GlossaristNamespace, :abbreviatedFormFor],
44
+ short_form_for: [Namespaces::GlossaristNamespace, :shortFormFor],
45
+ }.freeze
46
+
47
+ ALL_REL_PREDICATES = CONCEPT_REL_PREDICATES.merge(DESIGNATION_REL_PREDICATES).freeze
48
+
49
+ def self.related_targets_by_type(related_concepts, predicate_map)
50
+ targets = group_targets(related_concepts, predicate_map)
51
+ predicate_map.each_key.to_h do |type|
52
+ [:"#{type}_targets", targets[:"#{type}_targets"] || []]
53
+ end
54
+ end
55
+
56
+ def self.group_targets(related_concepts, predicate_map)
57
+ valid = valid_related(related_concepts, predicate_map)
58
+ valid
59
+ .group_by { |rc| rc.type.to_sym }
60
+ .transform_values { |rcs| rcs.map { |rc| "concept/#{rc.ref.id}" } }
61
+ .transform_keys { |type| :"#{type}_targets" }
62
+ end
63
+
64
+ def self.valid_related(related_concepts, predicate_map)
65
+ Array(related_concepts).select do |rc|
66
+ rc.ref&.id && predicate_map.key?(rc.type.to_sym)
67
+ end
68
+ end
69
+ private_class_method :group_targets, :valid_related
70
+ end
71
+ end
72
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../context_configuration"
4
-
5
3
  module Glossarist
6
4
  module Rdf
7
5
  module V3
@@ -1,51 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Load shared infrastructure first
4
- require_relative "ext"
5
- require_relative "namespaces"
6
- require_relative "relationships"
7
- require_relative "localized_literal"
8
-
9
- # V3 Configuration must be loaded before view classes are registered
10
- require_relative "v3/configuration"
11
-
12
- # Load all view class files (must precede V3 constant assignments)
13
- require_relative "gloss_locality"
14
- require_relative "gloss_reference"
15
- require_relative "gloss_concept_source"
16
- require_relative "gloss_detailed_definition"
17
- require_relative "gloss_pronunciation"
18
- require_relative "gloss_grammar_info"
19
- require_relative "gloss_non_verbal_rep"
20
- require_relative "gloss_concept_date"
21
- require_relative "gloss_designation"
22
- require_relative "gloss_localized_concept"
23
- require_relative "gloss_concept"
24
-
25
3
  module Glossarist
26
4
  module Rdf
27
- # V3 is the current (and only) RDF schema version.
28
- #
29
- # All RDF view classes produce v3 gloss ontology output:
30
- # namespace URI: https://www.glossarist.org/ontologies/v3/
31
- #
32
- # Each version has its own Configuration module with a unique CONTEXT_ID
33
- # so that V3 and (future) V4 classes are isolated in separate
34
- # Lutaml::Model::GlobalContext registries.
35
- #
36
- # When v4 is added:
37
- # - Create Rdf::V4::Configuration with CONTEXT_ID = :glossarist_rdf_v4
38
- # - Create V4 view classes (standalone or inheriting from V3)
39
- # - Register V4 classes in Rdf::V4::Configuration
40
- # - Update ConceptToGlossTransform to support v4
41
- # - V3 and V4 coexist — consumers choose which to use
42
5
  module V3
43
- # Namespace
44
- GlossaristNamespace = Namespaces::GlossaristNamespace
6
+ autoload :Configuration, "glossarist/rdf/v3/configuration"
45
7
 
46
- # Single source of truth: add new view classes here once.
47
- # Each entry is registered in the V3 type registry and
48
- # re-exported as a V3:: constant.
49
8
  VIEW_CLASS_NAMES = %i[
50
9
  GlossLocality
51
10
  GlossPronunciation
@@ -70,7 +29,9 @@ module Glossarist
70
29
 
71
30
  VIEW_CLASS_NAMES.each do |name|
72
31
  klass = ::Glossarist::Rdf.const_get(name)
73
- registry_id = name.to_s.gsub(/([A-Z])/) { |c| "_#{c.downcase}" }.sub(/^_/, "").to_sym
32
+ registry_id = name.to_s
33
+ .gsub(/([A-Z])/) { |c| "_#{c.downcase}" }
34
+ .sub(/^_/, "").to_sym
74
35
  Configuration.register_model(klass, id: registry_id)
75
36
  const_set(name, klass)
76
37
  end
@@ -1,30 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Load lutaml-model RDF extensions before any RDF view classes
4
- require_relative "rdf/ext"
3
+ require "lutaml/rdf"
4
+ require "lutaml/turtle"
5
+ require "lutaml/jsonld"
5
6
 
6
7
  module Glossarist
7
8
  module Rdf
8
- autoload :Namespaces, "#{__dir__}/rdf/namespaces"
9
- autoload :LocalizedLiteral, "#{__dir__}/rdf/localized_literal"
10
- autoload :Relationships, "#{__dir__}/rdf/relationships"
11
- autoload :GlossLocality, "#{__dir__}/rdf/gloss_locality"
12
- autoload :GlossCitation, "#{__dir__}/rdf/gloss_citation"
13
- autoload :GlossConceptSource, "#{__dir__}/rdf/gloss_concept_source"
9
+ autoload :Namespaces, "#{__dir__}/rdf/namespaces"
10
+ autoload :LocalizedLiteral, "#{__dir__}/rdf/localized_literal"
11
+ autoload :RelationshipPredicates, "#{__dir__}/rdf/relationship_predicates"
12
+ autoload :GlossLocality, "#{__dir__}/rdf/gloss_locality"
13
+ autoload :GlossCitation, "#{__dir__}/rdf/gloss_citation"
14
+ autoload :GlossConceptSource, "#{__dir__}/rdf/gloss_concept_source"
14
15
  autoload :GlossDetailedDefinition, "#{__dir__}/rdf/gloss_detailed_definition"
15
- autoload :GlossPronunciation, "#{__dir__}/rdf/gloss_pronunciation"
16
- autoload :GlossGrammarInfo, "#{__dir__}/rdf/gloss_grammar_info"
17
- autoload :GlossNonVerbalRep, "#{__dir__}/rdf/gloss_non_verbal_rep"
18
- autoload :GlossConceptReference, "#{__dir__}/rdf/gloss_concept_reference"
19
- autoload :GlossConceptDate, "#{__dir__}/rdf/gloss_concept_date"
20
- autoload :GlossDesignation, "#{__dir__}/rdf/gloss_designation"
21
- autoload :GlossExpression, "#{__dir__}/rdf/gloss_designation"
22
- autoload :GlossAbbreviation, "#{__dir__}/rdf/gloss_designation"
23
- autoload :GlossSymbol, "#{__dir__}/rdf/gloss_designation"
24
- autoload :GlossLetterSymbol, "#{__dir__}/rdf/gloss_designation"
25
- autoload :GlossGraphicalSymbol, "#{__dir__}/rdf/gloss_designation"
26
- autoload :GlossLocalizedConcept, "#{__dir__}/rdf/gloss_localized_concept"
27
- autoload :GlossConcept, "#{__dir__}/rdf/gloss_concept"
28
- autoload :GlossDocument, "#{__dir__}/rdf/gloss_concept"
16
+ autoload :GlossPronunciation, "#{__dir__}/rdf/gloss_pronunciation"
17
+ autoload :GlossGrammarInfo, "#{__dir__}/rdf/gloss_grammar_info"
18
+ autoload :GlossNonVerbalRep, "#{__dir__}/rdf/gloss_non_verbal_rep"
19
+ autoload :GlossConceptReference, "#{__dir__}/rdf/gloss_concept_reference"
20
+ autoload :GlossConceptDate, "#{__dir__}/rdf/gloss_concept_date"
21
+ autoload :GlossDesignation, "#{__dir__}/rdf/gloss_designation"
22
+ autoload :GlossExpression, "#{__dir__}/rdf/gloss_designation"
23
+ autoload :GlossAbbreviation, "#{__dir__}/rdf/gloss_designation"
24
+ autoload :GlossSymbol, "#{__dir__}/rdf/gloss_designation"
25
+ autoload :GlossLetterSymbol, "#{__dir__}/rdf/gloss_designation"
26
+ autoload :GlossGraphicalSymbol, "#{__dir__}/rdf/gloss_designation"
27
+ autoload :GlossLocalizedConcept, "#{__dir__}/rdf/gloss_localized_concept"
28
+ autoload :GlossConcept, "#{__dir__}/rdf/gloss_concept"
29
+ autoload :GlossDocument, "#{__dir__}/rdf/gloss_concept"
30
+ autoload :V3, "#{__dir__}/rdf/v3"
29
31
  end
30
32
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "tmpdir"
4
- require_relative "import_result"
5
4
 
6
5
  module Glossarist
7
6
  module Sts