glossarist 2.8.10 → 2.8.12

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d52bb386f776f12beb9671c25c5f1ce8330ff8349df68d734c80fa3937cec6f
4
- data.tar.gz: 43cab5da334046a266967ba590d9791ee56f1fe283110075c880ddb8f5ec8344
3
+ metadata.gz: 284d64ec4a9bac75c0639dd3254a715e881d46949240f430db9d6322cec09379
4
+ data.tar.gz: a349a57dba2f2e5b79c93561dcfa2fd54ee1627326d66b3cf2d6b66cbcca2f3c
5
5
  SHA512:
6
- metadata.gz: 6364fe8da9e37fdf669b2064fa244ad7f97f745cc4059243e4d1a337e710aff0ad1f1a6034573504b6106708cc9ed153e8fd9a6f1396d504c5d8b45e917c6e15
7
- data.tar.gz: 71ac705f2149e4995b1476a2802a3f5361e8d8733435d3fda15b7f2033d4ac62c72183b11770032bda22c6e6de8fadc8798f80c6f9af636b2e06828571d16d30
6
+ metadata.gz: 270a84779887cf795087a0fb56f923240b26c028bef18c6b436b5129cfcc0985a020e9ab5b2ce2b2b6e5f472f75de7c79546d56fe0a94465f068d3f5ee28617a
7
+ data.tar.gz: 1411213954c8fbbdb95bc9e5c4bc8455d55edf4df1944714dcd8a0ffac4733d64ed16bd32ae6c259691739dda04418fe9bcf91ba2af04451505a0b0d61168c55
data/config.yml CHANGED
@@ -39,10 +39,17 @@ designation:
39
39
 
40
40
  related_concept:
41
41
  type:
42
- # Lifecycle (ISO 10241-1)
42
+ # Lifecycle (ISO 10241-1 / ISO 19135)
43
43
  - deprecates
44
+ - deprecated_by
44
45
  - supersedes
45
46
  - superseded_by
47
+ - replaces
48
+ - replaced_by
49
+ - invalidates
50
+ - invalidated_by
51
+ - retires
52
+ - retired_by
46
53
  # Hierarchical (ISO 10241-1 / ISO 25964)
47
54
  - narrower
48
55
  - broader
@@ -52,9 +59,13 @@ related_concept:
52
59
  # Hierarchical sub-types — ISO 25964 partitive (BTP/NTP)
53
60
  - broader_partitive
54
61
  - narrower_partitive
62
+ - has_part
63
+ - is_part_of
55
64
  # Hierarchical sub-types — ISO 25964 instantial (BTI/NTI)
56
65
  - broader_instantial
57
66
  - narrower_instantial
67
+ - instance_of
68
+ - has_instance
58
69
  # Equivalence (ISO 10241-1 / ISO 25964 exactMatch / SKOS)
59
70
  - equivalent
60
71
  - exact_match
@@ -69,17 +80,30 @@ related_concept:
69
80
  - contrast
70
81
  # Associative (ISO 10241-1 / ISO 25964 RT / TBX crossReference)
71
82
  - see
83
+ - references
72
84
  # Associative sub-types (ISO 25964 / TBX)
73
85
  - related_concept
74
86
  - related_concept_broader
75
87
  - related_concept_narrower
76
88
  # Associative — spatial/temporal (ISO 25964 / TBX)
77
- - sequentially_related_concept
78
- - spatially_related_concept
79
- - temporally_related_concept
89
+ - sequentially_related
90
+ - spatially_related
91
+ - temporally_related
80
92
  # Lexical (ISO 12620 / TBX)
81
93
  - homograph
82
94
  - false_friend
95
+ # Register management (ISO 19135)
96
+ - has_concept
97
+ - is_concept_of
98
+ - has_definition
99
+ - definition_of
100
+ - inherits
101
+ - inherited_by
102
+ # Versioning / definitional (ISO 19135)
103
+ - has_version
104
+ - version_of
105
+ - current_version
106
+ - current_version_of
83
107
 
84
108
  iso12620:
85
109
  term_type:
@@ -86,7 +86,7 @@ module Glossarist
86
86
  def all_sources
87
87
  list = sources.to_a
88
88
  self.class.detailed_definition_fields.each do |field|
89
- send(field).each { |d| list.concat(d.sources.to_a) }
89
+ public_send(field).each { |d| list.concat(d.sources.to_a) }
90
90
  end
91
91
  Array(terms).each { |t| list.concat(Array(t.sources)) }
92
92
  list
@@ -95,7 +95,7 @@ module Glossarist
95
95
  def text_content
96
96
  texts = []
97
97
  self.class.detailed_definition_fields.each do |field|
98
- send(field).each { |d| texts << d.content if d.content }
98
+ public_send(field).each { |d| texts << d.content if d.content }
99
99
  end
100
100
  texts
101
101
  end
@@ -17,7 +17,7 @@ module Glossarist
17
17
 
18
18
  key_value do
19
19
  map :term, to: :term
20
- map :concept_id, to: :concept_id
20
+ map %i[concept_id id], to: :concept_id
21
21
  map :source, to: :source
22
22
  map :ref_type, to: :ref_type
23
23
  map :urn, to: :urn
@@ -67,7 +67,11 @@ module Glossarist
67
67
 
68
68
  def normalize_definition(definition)
69
69
  definition.gsub(/{{([^}]*)}}/) do |_match|
70
- "\\textbf{\\gls{#{Regexp.last_match[1].tr('_', '-')}}}"
70
+ inner = Regexp.last_match[1]
71
+ # Mention syntax: {{identifier}} or {{identifier, render term}}
72
+ # Use the identifier (first part before comma) as the gloss label.
73
+ label = inner.split(",", 2).first.strip.tr("_", "-")
74
+ "\\textbf{\\gls{#{label}}}"
71
75
  end
72
76
  end
73
77
 
@@ -13,19 +13,28 @@ module Glossarist
13
13
  attribute :status, :string,
14
14
  values: Glossarist::GlossaryDefinition::CONCEPT_STATUSES
15
15
 
16
- attribute :identifier, :string
17
- alias :id :identifier
18
- alias :id= :identifier=
19
-
20
16
  attribute :uuid, :string
21
17
 
22
18
  attribute :version, :string
23
19
  attribute :schema_version, :string
24
20
 
21
+ # identifier and id are aliases for uuid — the concept's canonical
22
+ # identity. There is one source of truth: uuid, serialized to the
23
+ # YAML "id" key. Having separate identifier/uuid attributes that both
24
+ # map to the same key caused dual-mapping fragility.
25
+ def identifier
26
+ uuid
27
+ end
28
+
29
+ def identifier=(value)
30
+ self.uuid = value
31
+ end
32
+
33
+ alias :id :identifier
34
+ alias :id= :identifier=
35
+
25
36
  key_value do
26
37
  map :data, to: :data
27
- map :identifier,
28
- with: { to: :identifier_to_yaml, from: :identifier_from_yaml }
29
38
  map :related, to: :related
30
39
  map :dates, to: :dates
31
40
  map :sources, to: :sources
@@ -74,15 +83,6 @@ module Glossarist
74
83
  )
75
84
  end
76
85
 
77
- def identifier_to_yaml(model, doc)
78
- value = model.identifier || model.id
79
- doc["id"] = value if value && !doc["id"]
80
- end
81
-
82
- def identifier_from_yaml(model, value)
83
- model.identifier = value || model.identifier
84
- end
85
-
86
86
  def localized_concepts=(localized_concepts_collection) # rubocop:disable Metrics/AbcSize
87
87
  return unless localized_concepts_collection
88
88
 
@@ -27,16 +27,17 @@ module Glossarist
27
27
  related_match: [Namespaces::SkosNamespace, :relatedMatch],
28
28
  see: [Namespaces::SkosNamespace, :related],
29
29
  deprecates: [Namespaces::GlossaristNamespace, :deprecates],
30
+ deprecated_by: [Namespaces::GlossaristNamespace, :deprecatedBy],
30
31
  supersedes: [Namespaces::GlossaristNamespace, :supersedes],
31
32
  superseded_by: [Namespaces::GlossaristNamespace, :supersededBy],
32
33
  compare: [Namespaces::GlossaristNamespace, :compares],
33
34
  contrast: [Namespaces::GlossaristNamespace, :contrasts],
34
- sequentially_related_concept: [Namespaces::GlossaristNamespace,
35
- :sequentiallyRelated],
36
- spatially_related_concept: [Namespaces::GlossaristNamespace,
37
- :spatiallyRelated],
38
- temporally_related_concept: [Namespaces::GlossaristNamespace,
39
- :temporallyRelated],
35
+ sequentially_related: [Namespaces::GlossaristNamespace,
36
+ :sequentiallyRelated],
37
+ spatially_related: [Namespaces::GlossaristNamespace,
38
+ :spatiallyRelated],
39
+ temporally_related: [Namespaces::GlossaristNamespace,
40
+ :temporallyRelated],
40
41
  related_concept_broader: [Namespaces::GlossaristNamespace,
41
42
  :relatedConceptBroader],
42
43
  related_concept_narrower: [Namespaces::GlossaristNamespace,
@@ -253,9 +253,10 @@ module Glossarist
253
253
  end
254
254
 
255
255
  def extract_ref_text(ref)
256
- if ref.respond_to?(:content) && ref.content.is_a?(Array)
256
+ case ref
257
+ when ::Sts::IsoSts::StdRef
257
258
  normalize_whitespace(ref.content.join.to_s)
258
- elsif ref.respond_to?(:value)
259
+ when ::Sts::NisoSts::StandardRef
259
260
  normalize_whitespace(ref.value.to_s)
260
261
  else
261
262
  ""
@@ -122,7 +122,7 @@ module Glossarist
122
122
 
123
123
  dd_attrs = if data
124
124
  data.class.detailed_definition_fields.to_h do |field|
125
- [field, build_gloss_definitions(data.send(field))]
125
+ [field, build_gloss_definitions(data.public_send(field))]
126
126
  end
127
127
  else
128
128
  { definition: [], notes: [], examples: [] }
@@ -9,15 +9,13 @@ module Glossarist
9
9
 
10
10
  key_value do
11
11
  map :data, to: :data
12
- map :id, with: { to: :identifier_to_yaml, from: :identifier_from_yaml }
13
- map :identifier,
14
- with: { to: :identifier_to_yaml, from: :identifier_from_yaml }
15
12
  map :related, to: :related
16
13
  map :dates, to: :dates
17
14
  map %i[date_accepted dateAccepted],
18
15
  with: { from: :date_accepted_from_yaml, to: :date_accepted_to_yaml }
19
16
  map :status, to: :status
20
- map :uuid, to: :uuid, with: { from: :uuid_from_yaml, to: :uuid_to_yaml }
17
+ map %i[id uuid], to: :uuid,
18
+ with: { from: :uuid_from_yaml, to: :uuid_to_yaml }
21
19
  map :sources, to: :sources
22
20
  end
23
21
  end
@@ -9,15 +9,13 @@ module Glossarist
9
9
 
10
10
  key_value do
11
11
  map :data, to: :data
12
- map :id, with: { to: :identifier_to_yaml, from: :identifier_from_yaml }
13
- map :identifier,
14
- with: { to: :identifier_to_yaml, from: :identifier_from_yaml }
15
12
  map :related, to: :related
16
13
  map :dates, to: :dates
17
14
  map %i[date_accepted dateAccepted],
18
15
  with: { from: :date_accepted_from_yaml, to: :date_accepted_to_yaml }
19
16
  map :status, to: :status
20
- map :uuid, to: :uuid, with: { from: :uuid_from_yaml, to: :uuid_to_yaml }
17
+ map %i[id uuid], to: :uuid,
18
+ with: { from: :uuid_from_yaml, to: :uuid_to_yaml }
21
19
  map :schema_version, to: :schema_version
22
20
  map :sources, to: :sources
23
21
  end
@@ -14,30 +14,20 @@ module Glossarist
14
14
  end
15
15
 
16
16
  def check(context)
17
- concept = context.concept
18
17
  fname = context.file_name
19
- extractor = ReferenceExtractor.new
20
18
  issues = []
21
19
 
22
- concept.localizations.each do |l10n|
23
- lang = l10n.language_code || "unknown"
24
-
25
- l10n.text_content.each do |text|
26
- next unless text
27
-
28
- extractor.extract_from_text(text).each do |ref|
29
- next unless ref.is_a?(BibliographicReference)
30
- next if context.bibliography_index.resolve?(ref.anchor)
31
-
32
- issues << issue(
33
- "unresolved bibliography reference <<#{ref.anchor}>>",
34
- code: code, severity: severity,
35
- location: "#{fname}/#{lang}",
36
- suggestion: "add '#{ref.anchor}' as a source, " \
37
- "or verify it exists in bibliography.yaml"
38
- )
39
- end
40
- end
20
+ context.references.each do |ref|
21
+ next unless ref.is_a?(BibliographicReference)
22
+ next if context.bibliography_index.resolve?(ref.anchor)
23
+
24
+ issues << issue(
25
+ "unresolved bibliography reference <<#{ref.anchor}>>",
26
+ code: code, severity: severity,
27
+ location: fname,
28
+ suggestion: "add '#{ref.anchor}' as a source, " \
29
+ "or verify it exists in bibliography.yaml"
30
+ )
41
31
  end
42
32
 
43
33
  issues
@@ -19,7 +19,7 @@ module Glossarist
19
19
  issues = []
20
20
 
21
21
  check_unique_source_ids(concept, fname, issues)
22
- check_unresolved_mentions(concept, fname, issues)
22
+ check_unresolved_mentions(context, concept, fname, issues)
23
23
 
24
24
  issues
25
25
  end
@@ -46,8 +46,8 @@ module Glossarist
46
46
  end
47
47
  end
48
48
 
49
- def check_unresolved_mentions(concept, fname, issues)
50
- keys = cite_mention_keys(concept)
49
+ def check_unresolved_mentions(context, concept, fname, issues)
50
+ keys = cite_mention_keys(context)
51
51
  return if keys.empty?
52
52
 
53
53
  known_ids = concept.all_sources.filter_map(&:id).to_set
@@ -63,9 +63,8 @@ module Glossarist
63
63
  end
64
64
  end
65
65
 
66
- def cite_mention_keys(concept)
67
- extractor = ReferenceExtractor.new
68
- extractor.extract_from_managed_concept(concept)
66
+ def cite_mention_keys(context)
67
+ context.references
69
68
  .select(&:cite?)
70
69
  .filter_map(&:concept_id)
71
70
  end
@@ -3,6 +3,12 @@
3
3
  module Glossarist
4
4
  module Validation
5
5
  module Rules
6
+ # Shared context for concept-scoped validation rules.
7
+ #
8
+ # Provides lazy-memoized access to extracted references so that multiple
9
+ # rules examining the same concept share one extraction pass (DRY,
10
+ # single source of truth). Rules ask the context for references rather
11
+ # than instantiating their own ReferenceExtractor.
6
12
  class ConceptContext
7
13
  attr_reader :concept, :file_name, :collection_context
8
14
 
@@ -16,6 +22,24 @@ module Glossarist
16
22
  @concept.data&.id&.to_s
17
23
  end
18
24
 
25
+ # All references extracted from the concept's text fields
26
+ # (definitions, notes, examples) via {{...}} mentions, <<xrefs>>,
27
+ # and image::...[] references. Includes ConceptReference,
28
+ # BibliographicReference, and AssetReference objects.
29
+ # Memoized — extracted once per concept, shared across all rules.
30
+ def references
31
+ @references ||= ReferenceExtractor.new
32
+ .extract_from_managed_concept(@concept)
33
+ end
34
+
35
+ # All asset references (NonVerbRep, GraphicalSymbol) extracted
36
+ # from the concept's model attributes.
37
+ # Memoized — extracted once per concept, shared across all rules.
38
+ def asset_references
39
+ @asset_references ||= ReferenceExtractor.new
40
+ .extract_asset_refs_from_concept(@concept)
41
+ end
42
+
19
43
  def bibliography_index
20
44
  @collection_context.bibliography_index
21
45
  end
@@ -14,12 +14,10 @@ module Glossarist
14
14
  end
15
15
 
16
16
  def check(context)
17
- concept = context.concept
18
17
  fname = context.file_name
19
- extractor = ReferenceExtractor.new
20
18
  issues = []
21
19
 
22
- refs = extractor.extract_from_managed_concept(concept)
20
+ refs = context.references
23
21
  .select { |r| r.is_a?(ConceptReference) && r.local? }
24
22
 
25
23
  refs.each do |ref|
@@ -14,33 +14,22 @@ module Glossarist
14
14
  end
15
15
 
16
16
  def check(context)
17
- concept = context.concept
18
17
  fname = context.file_name
19
- extractor = ReferenceExtractor.new
20
18
  issues = []
21
19
 
22
- concept.localizations.each do |l10n|
23
- lang = l10n.language_code || "unknown"
24
-
25
- l10n.text_content.each do |text|
26
- next unless text
27
-
28
- extractor.extract_from_text(text).each do |ref|
29
- next unless ref.is_a?(AssetReference)
30
- next if context.asset_index.resolve?(ref.path)
20
+ context.references.each do |ref|
21
+ next unless ref.is_a?(AssetReference)
22
+ next if context.asset_index.resolve?(ref.path)
31
23
 
32
- issues << issue(
33
- "unresolved image reference #{ref.path}",
34
- code: "GLS-103", severity: severity,
35
- location: "#{fname}/#{lang}",
36
- suggestion: "add '#{ref.path}' to the dataset's images/ directory"
37
- )
38
- end
39
- end
24
+ issues << issue(
25
+ "unresolved image reference #{ref.path}",
26
+ code: "GLS-103", severity: severity,
27
+ location: fname,
28
+ suggestion: "add '#{ref.path}' to the dataset's images/ directory"
29
+ )
40
30
  end
41
31
 
42
- asset_refs = extractor.extract_asset_refs_from_concept(concept)
43
- asset_refs.each do |ref|
32
+ context.asset_references.each do |ref|
44
33
  next if context.asset_index.resolve?(ref.path)
45
34
 
46
35
  issues << issue(
@@ -4,5 +4,5 @@
4
4
  #
5
5
 
6
6
  module Glossarist
7
- VERSION = "2.8.10"
7
+ VERSION = "2.8.12"
8
8
  end
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.10
4
+ version: 2.8.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-13 00:00:00.000000000 Z
11
+ date: 2026-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model