glossarist 2.8.14 → 2.8.16
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 +4 -4
- data/CLAUDE.md +25 -0
- data/README.adoc +265 -18
- data/lib/glossarist/bibliography_data.rb +28 -20
- data/lib/glossarist/bibliography_entry.rb +15 -4
- data/lib/glossarist/collections/figure_collection.rb +20 -0
- data/lib/glossarist/collections/formula_collection.rb +20 -0
- data/lib/glossarist/collections/non_verbal_collection.rb +51 -0
- data/lib/glossarist/collections/table_collection.rb +20 -0
- data/lib/glossarist/collections.rb +8 -0
- data/lib/glossarist/figure.rb +39 -0
- data/lib/glossarist/figure_image.rb +30 -0
- data/lib/glossarist/figure_reference.rb +18 -0
- data/lib/glossarist/formula.rb +19 -0
- data/lib/glossarist/formula_reference.rb +18 -0
- data/lib/glossarist/localized_string.rb +44 -0
- data/lib/glossarist/managed_concept_data.rb +49 -0
- data/lib/glossarist/non_verb_rep.rb +14 -18
- data/lib/glossarist/non_verbal_entity.rb +45 -0
- data/lib/glossarist/non_verbal_reference.rb +23 -0
- data/lib/glossarist/reference_extractor.rb +28 -2
- data/lib/glossarist/shared_non_verbal_entity.rb +29 -0
- data/lib/glossarist/table.rb +19 -0
- data/lib/glossarist/table_reference.rb +18 -0
- data/lib/glossarist/transforms/concept_to_gloss_transform.rb +8 -2
- data/lib/glossarist/v3.rb +0 -8
- data/lib/glossarist/validation/asset_index.rb +7 -2
- data/lib/glossarist/validation/bibliography_index.rb +3 -32
- data/lib/glossarist/validation/rules/bibliography_yaml_rule.rb +1 -1
- data/lib/glossarist/validation/rules/gcr_context.rb +0 -1
- data/lib/glossarist/validation/rules/orphaned_images_rule.rb +1 -23
- data/lib/glossarist/version.rb +1 -1
- data/lib/glossarist.rb +11 -0
- metadata +17 -6
- data/lib/glossarist/v3/bibliography_entry.rb +0 -19
- data/lib/glossarist/v3/bibliography_file.rb +0 -27
- data/lib/glossarist/v3/image_entry.rb +0 -21
- data/lib/glossarist/v3/image_file.rb +0 -31
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A dataset-level figure entity (ISO 10241-1 §6.5 — non-verbal representation).
|
|
5
|
+
#
|
|
6
|
+
# Figures are authored once at `datasets/{ds}/figures/{fig-id}.yaml` and
|
|
7
|
+
# referenced by any number of concepts via stable ID — the same sharing
|
|
8
|
+
# pattern as bibliography entries. This is the rich, shareable counterpart
|
|
9
|
+
# to concept-owned NonVerbRep entries.
|
|
10
|
+
#
|
|
11
|
+
# A Figure may carry multiple image variants (SVG + PNG + dark/light) for
|
|
12
|
+
# responsive rendering and accessibility. Composite figures use recursive
|
|
13
|
+
# subfigures.
|
|
14
|
+
#
|
|
15
|
+
# Caption, description, and alt are localized (hash keyed by ISO 639 code).
|
|
16
|
+
class Figure < SharedNonVerbalEntity
|
|
17
|
+
attribute :images, FigureImage, collection: true
|
|
18
|
+
attribute :subfigures, Figure, collection: true
|
|
19
|
+
|
|
20
|
+
key_value do
|
|
21
|
+
map :images, to: :images
|
|
22
|
+
map :subfigures, to: :subfigures
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def find_by_id(target_id)
|
|
26
|
+
return self if id == target_id
|
|
27
|
+
|
|
28
|
+
Array(subfigures).each do |sub|
|
|
29
|
+
found = sub.find_by_id(target_id)
|
|
30
|
+
return found if found
|
|
31
|
+
end
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def all_ids
|
|
36
|
+
[id] + Array(subfigures).flat_map(&:all_ids)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# One image variant within a Figure. Multiple variants enable responsive
|
|
5
|
+
# images, format fallbacks, and accessibility (dark/light, language-specific).
|
|
6
|
+
#
|
|
7
|
+
# The `role` field drives consumer-side selection:
|
|
8
|
+
# vector — SVG (preferred for diagrams, resolution-independent)
|
|
9
|
+
# raster — PNG/JPG (preferred for photos)
|
|
10
|
+
# dark — optimized for dark backgrounds
|
|
11
|
+
# light — optimized for light backgrounds
|
|
12
|
+
# print — high-resolution for print output
|
|
13
|
+
class FigureImage < Lutaml::Model::Serializable
|
|
14
|
+
attribute :src, :string
|
|
15
|
+
attribute :format, :string
|
|
16
|
+
attribute :role, :string
|
|
17
|
+
attribute :width, :integer
|
|
18
|
+
attribute :height, :integer
|
|
19
|
+
attribute :scale, :integer
|
|
20
|
+
|
|
21
|
+
key_value do
|
|
22
|
+
map :src, to: :src
|
|
23
|
+
map :format, to: :format
|
|
24
|
+
map :role, to: :role
|
|
25
|
+
map :width, to: :width
|
|
26
|
+
map :height, to: :height
|
|
27
|
+
map :scale, to: :scale
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A reference from a concept to a dataset-level Figure entity.
|
|
5
|
+
#
|
|
6
|
+
# Produced by `figures: [id]` structural arrays and `{{fig:id}}` inline
|
|
7
|
+
# mentions. Both forms resolve through the same figure adapter.
|
|
8
|
+
class FigureReference < NonVerbalReference
|
|
9
|
+
key_value do
|
|
10
|
+
map :entity_id, to: :entity_id
|
|
11
|
+
map :display, to: :display
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dedup_key
|
|
15
|
+
[self.class.name, entity_id]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A dataset-level formula entity (ISO 10241-1 §6.5 — non-verbal representation).
|
|
5
|
+
#
|
|
6
|
+
# Formulas are authored at `datasets/{ds}/formulas/{formula-id}.yaml` and
|
|
7
|
+
# shared across concepts. The mathematical expression is stored in a
|
|
8
|
+
# notation format (LaTeX, MathML, AsciiMath). Caption, description, and
|
|
9
|
+
# alt are localized for accessibility.
|
|
10
|
+
class Formula < SharedNonVerbalEntity
|
|
11
|
+
attribute :expression, :hash
|
|
12
|
+
attribute :notation, :string
|
|
13
|
+
|
|
14
|
+
key_value do
|
|
15
|
+
map :expression, to: :expression
|
|
16
|
+
map :notation, to: :notation
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A reference from a concept to a dataset-level Formula entity.
|
|
5
|
+
#
|
|
6
|
+
# Produced by `formulas: [id]` structural arrays and `{{formula:id}}` inline
|
|
7
|
+
# mentions.
|
|
8
|
+
class FormulaReference < NonVerbalReference
|
|
9
|
+
key_value do
|
|
10
|
+
map :entity_id, to: :entity_id
|
|
11
|
+
map :display, to: :display
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dedup_key
|
|
15
|
+
[self.class.name, entity_id]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# Semantic operations on localized string fields.
|
|
5
|
+
#
|
|
6
|
+
# Localized strings are stored as hashes keyed by ISO 639 language code:
|
|
7
|
+
# { "eng" => "Mixed reflection", "fra" => "Réflexion mixte" }
|
|
8
|
+
#
|
|
9
|
+
# This module provides typed access and fallback logic. It does not
|
|
10
|
+
# introduce a wrapper class — the hash IS the localized string, matching
|
|
11
|
+
# how Section#names, DatasetRegister#description, etc. already work.
|
|
12
|
+
module LocalizedString
|
|
13
|
+
# Fetch a localized value with language fallback.
|
|
14
|
+
#
|
|
15
|
+
# @param hash [Hash, nil] the localized string hash
|
|
16
|
+
# @param lang [String, Symbol] the desired language code
|
|
17
|
+
# @param fallback [String, nil] fallback language (default "eng")
|
|
18
|
+
# @return [String, nil] the localized value, or nil if not found
|
|
19
|
+
def self.fetch(hash, lang, fallback = "eng")
|
|
20
|
+
return nil unless hash.is_a?(Hash)
|
|
21
|
+
|
|
22
|
+
direct = hash[lang.to_s] || hash[lang.to_sym]
|
|
23
|
+
return direct if direct
|
|
24
|
+
|
|
25
|
+
fallback && fallback.to_s != lang.to_s ? hash[fallback.to_s] || hash[fallback.to_sym] : nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Check if a localized string hash is nil or empty.
|
|
29
|
+
#
|
|
30
|
+
# @param hash [Hash, nil]
|
|
31
|
+
# @return [Boolean]
|
|
32
|
+
def self.empty?(hash)
|
|
33
|
+
hash.nil? || hash.empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Check if a localized string hash has any entries.
|
|
37
|
+
#
|
|
38
|
+
# @param hash [Hash, nil]
|
|
39
|
+
# @return [Boolean]
|
|
40
|
+
def self.present?(hash)
|
|
41
|
+
!empty?(hash)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -7,6 +7,9 @@ module Glossarist
|
|
|
7
7
|
attribute :localized_concepts, :hash
|
|
8
8
|
attribute :domains, ConceptReference, collection: true
|
|
9
9
|
attribute :tags, :string, collection: true
|
|
10
|
+
attribute :figures, FigureReference, collection: true
|
|
11
|
+
attribute :tables, TableReference, collection: true
|
|
12
|
+
attribute :formulas, FormulaReference, collection: true
|
|
10
13
|
attribute :sources, ConceptSource, collection: true
|
|
11
14
|
attribute :localizations, LocalizedConcept,
|
|
12
15
|
collection: Collections::LocalizationCollection,
|
|
@@ -21,6 +24,12 @@ module Glossarist
|
|
|
21
24
|
map %i[domains groups], to: :domains,
|
|
22
25
|
with: { from: :domains_from_yaml, to: :domains_to_yaml }
|
|
23
26
|
map :tags, to: :tags
|
|
27
|
+
map :figures, to: :figures,
|
|
28
|
+
with: { from: :figures_from_yaml, to: :figures_to_yaml }
|
|
29
|
+
map :tables, to: :tables,
|
|
30
|
+
with: { from: :tables_from_yaml, to: :tables_to_yaml }
|
|
31
|
+
map :formulas, to: :formulas,
|
|
32
|
+
with: { from: :formulas_from_yaml, to: :formulas_to_yaml }
|
|
24
33
|
map :sources, to: :sources
|
|
25
34
|
map :localizations, to: :localizations,
|
|
26
35
|
with: { from: :localizations_from_yaml, to: :localizations_to_yaml }
|
|
@@ -63,6 +72,46 @@ module Glossarist
|
|
|
63
72
|
doc["domains"] = model.domains.map(&:to_hash)
|
|
64
73
|
end
|
|
65
74
|
|
|
75
|
+
def figures_from_yaml(model, value)
|
|
76
|
+
model.figures = parse_non_verbal_refs(value, FigureReference)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def figures_to_yaml(model, doc)
|
|
80
|
+
serialize_non_verbal_refs(model.figures, doc, "figures")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def tables_from_yaml(model, value)
|
|
84
|
+
model.tables = parse_non_verbal_refs(value, TableReference)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def tables_to_yaml(model, doc)
|
|
88
|
+
serialize_non_verbal_refs(model.tables, doc, "tables")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def formulas_from_yaml(model, value)
|
|
92
|
+
model.formulas = parse_non_verbal_refs(value, FormulaReference)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def formulas_to_yaml(model, doc)
|
|
96
|
+
serialize_non_verbal_refs(model.formulas, doc, "formulas")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def parse_non_verbal_refs(value, ref_class)
|
|
102
|
+
return unless value.is_a?(Array)
|
|
103
|
+
|
|
104
|
+
value.map { |item| ref_class.of_yaml(item) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def serialize_non_verbal_refs(refs, doc, key)
|
|
108
|
+
return if refs.nil? || refs.empty?
|
|
109
|
+
|
|
110
|
+
doc[key] = refs.map do |ref|
|
|
111
|
+
ref.display ? { "ref" => ref.entity_id, "display" => ref.display } : ref.entity_id
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
66
115
|
def authoritative_source
|
|
67
116
|
return [] unless sources
|
|
68
117
|
|
|
@@ -1,30 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Glossarist
|
|
4
|
-
# A non-verbal representation
|
|
5
|
-
# ISO 10241-1 §6.5.
|
|
4
|
+
# A concept-local non-verbal representation (ISO 10241-1 §6.5).
|
|
6
5
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# NonVerbRep is the inline form attached directly to a concept's data.
|
|
7
|
+
# The dataset-shared form is Figure / Table / Formula. The two share the
|
|
8
|
+
# same a11y + provenance payload via NonVerbalEntity; NonVerbRep differs
|
|
9
|
+
# only in that it has no dataset-wide identity (no +id+, no +identifier+)
|
|
10
|
+
# — its identity is its position inside the parent concept.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
class NonVerbRep <
|
|
12
|
+
# +type+ discriminates the kind of non-verbal content: "image", "table",
|
|
13
|
+
# or "formula". When +type+ is "image", +images+ carries one or more
|
|
14
|
+
# FigureImage variants (responsive, format fallback, dark/light). The
|
|
15
|
+
# caption/description/alt fields are localized (hash keyed by ISO 639
|
|
16
|
+
# code) for accessibility.
|
|
17
|
+
class NonVerbRep < NonVerbalEntity
|
|
18
18
|
attribute :type, :string
|
|
19
|
-
attribute :
|
|
20
|
-
attribute :text, :string
|
|
21
|
-
attribute :sources, ConceptSource, collection: true
|
|
19
|
+
attribute :images, FigureImage, collection: true, initialize_empty: true
|
|
22
20
|
|
|
23
21
|
key_value do
|
|
24
22
|
map :type, to: :type
|
|
25
|
-
map :
|
|
26
|
-
map :text, to: :text
|
|
27
|
-
map :sources, to: :sources
|
|
23
|
+
map :images, to: :images
|
|
28
24
|
end
|
|
29
25
|
end
|
|
30
26
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# Shared payload for every non-verbal representation, whether it lives
|
|
5
|
+
# inline on a concept (NonVerbRep) or as a dataset-shared file
|
|
6
|
+
# (Figure / Table / Formula).
|
|
7
|
+
#
|
|
8
|
+
# The four attributes here are the common a11y + provenance payload every
|
|
9
|
+
# non-verbal entity carries, regardless of content type or scope:
|
|
10
|
+
#
|
|
11
|
+
# - +caption+: localized short title (a11y / indexing).
|
|
12
|
+
# - +description+: localized long description (a11y screen readers).
|
|
13
|
+
# - +alt+: localized alternative text (a11y short screen-reader label).
|
|
14
|
+
# - +sources+: bibliographic sources for the representation.
|
|
15
|
+
#
|
|
16
|
+
# Identity (+id+, +identifier+) belongs on subclasses that have it; see
|
|
17
|
+
# SharedNonVerbalEntity for the dataset-shared variant.
|
|
18
|
+
class NonVerbalEntity < Lutaml::Model::Serializable
|
|
19
|
+
attribute :caption, :hash
|
|
20
|
+
attribute :description, :hash
|
|
21
|
+
attribute :alt, :hash
|
|
22
|
+
attribute :sources, ConceptSource, collection: true
|
|
23
|
+
|
|
24
|
+
key_value do
|
|
25
|
+
map :caption, to: :caption
|
|
26
|
+
map :description, to: :description
|
|
27
|
+
map :alt, to: :alt
|
|
28
|
+
map :sources, to: :sources
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def find_by_id(_target_id)
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def all_ids
|
|
36
|
+
[]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.from_file(path)
|
|
40
|
+
return nil unless File.exist?(path)
|
|
41
|
+
|
|
42
|
+
from_yaml(File.read(path, encoding: "utf-8"))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# Abstract base for references to dataset-level non-verbal entities.
|
|
5
|
+
#
|
|
6
|
+
# FigureReference, TableReference, and FormulaReference all carry an
|
|
7
|
+
# entity ID and an optional display override. They are produced both by
|
|
8
|
+
# structural arrays (`figures: [id]` on ManagedConceptData) and by inline
|
|
9
|
+
# mentions (`{{fig:id}}` in text).
|
|
10
|
+
class NonVerbalReference < Lutaml::Model::Serializable
|
|
11
|
+
attribute :entity_id, :string
|
|
12
|
+
attribute :display, :string
|
|
13
|
+
|
|
14
|
+
def self.of_yaml(hash)
|
|
15
|
+
return new(entity_id: hash) if hash.is_a?(String)
|
|
16
|
+
|
|
17
|
+
new(
|
|
18
|
+
entity_id: hash["ref"] || hash["id"] || hash[:ref] || hash[:id],
|
|
19
|
+
display: hash["display"] || hash[:display],
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -170,9 +170,14 @@ module Glossarist
|
|
|
170
170
|
|
|
171
171
|
concept.localizations.each do |l10n|
|
|
172
172
|
Array(l10n.non_verb_rep).each do |nvr|
|
|
173
|
-
next unless nvr.is_a?(NonVerbRep)
|
|
173
|
+
next unless nvr.is_a?(NonVerbRep)
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
Array(nvr.images).each do |image|
|
|
176
|
+
next unless image.is_a?(FigureImage)
|
|
177
|
+
next if image.src.nil? || image.src.strip.empty?
|
|
178
|
+
|
|
179
|
+
refs << AssetReference.new(path: image.src.strip)
|
|
180
|
+
end
|
|
176
181
|
end
|
|
177
182
|
|
|
178
183
|
(l10n.data&.terms || []).each do |term|
|
|
@@ -226,6 +231,15 @@ module Glossarist
|
|
|
226
231
|
AssetReference.new(path: path.strip)
|
|
227
232
|
end
|
|
228
233
|
|
|
234
|
+
# Unified non-verbal entity mention resolver for fig:/table:/formula:.
|
|
235
|
+
# Strips the prefix and produces the appropriate reference type.
|
|
236
|
+
def resolve_non_verbal_mention(prefix, identifier, display, ref_class)
|
|
237
|
+
cleaned = identifier.delete_prefix(prefix).strip
|
|
238
|
+
return nil if cleaned.empty?
|
|
239
|
+
|
|
240
|
+
ref_class.new(entity_id: cleaned, display: display)
|
|
241
|
+
end
|
|
242
|
+
|
|
229
243
|
private
|
|
230
244
|
|
|
231
245
|
def gather_texts(lc_hash)
|
|
@@ -293,6 +307,18 @@ module Glossarist
|
|
|
293
307
|
ext.resolve_cite_key(identifier, display)
|
|
294
308
|
end
|
|
295
309
|
|
|
310
|
+
register_identifier_resolver("fig:") do |ext, identifier, display|
|
|
311
|
+
ext.resolve_non_verbal_mention("fig:", identifier, display, FigureReference)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
register_identifier_resolver("table:") do |ext, identifier, display|
|
|
315
|
+
ext.resolve_non_verbal_mention("table:", identifier, display, TableReference)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
register_identifier_resolver("formula:") do |ext, identifier, display|
|
|
319
|
+
ext.resolve_non_verbal_mention("formula:", identifier, display, FormulaReference)
|
|
320
|
+
end
|
|
321
|
+
|
|
296
322
|
register_identifier_resolver("urn:iec:std:iec:60050") do |ext, identifier, display|
|
|
297
323
|
ext.resolve_iec_urn(identifier, display)
|
|
298
324
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# Dataset-shared non-verbal entity — a NonVerbalEntity with a stable
|
|
5
|
+
# identity. Figure, Table, and Formula inherit from this; NonVerbRep
|
|
6
|
+
# (concept-local, positional) inherits from NonVerbalEntity directly.
|
|
7
|
+
#
|
|
8
|
+
# The +id+ is the stable identifier used for cross-referencing
|
|
9
|
+
# (e.g. +figures/fig_A.23.yaml+ → +id: fig_A.23+). The +identifier+ is
|
|
10
|
+
# the human-readable label (e.g. +"A.23"+) used for display and AsciiDoc
|
|
11
|
+
# xref targets like +<<fig_A.23>>+.
|
|
12
|
+
class SharedNonVerbalEntity < NonVerbalEntity
|
|
13
|
+
attribute :id, :string
|
|
14
|
+
attribute :identifier, :string
|
|
15
|
+
|
|
16
|
+
key_value do
|
|
17
|
+
map :id, to: :id
|
|
18
|
+
map :identifier, to: :identifier
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def find_by_id(target_id)
|
|
22
|
+
id == target_id ? self : nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def all_ids
|
|
26
|
+
[id].compact
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A dataset-level table entity (ISO 10241-1 §6.5 — non-verbal representation).
|
|
5
|
+
#
|
|
6
|
+
# Tables are authored at `datasets/{ds}/tables/{table-id}.yaml` and shared
|
|
7
|
+
# across concepts. The content is stored as structured data (rows/columns)
|
|
8
|
+
# or as a markup string (HTML, Markdown, AsciiDoc). Caption, description,
|
|
9
|
+
# and alt are localized for accessibility.
|
|
10
|
+
class Table < SharedNonVerbalEntity
|
|
11
|
+
attribute :content, :hash
|
|
12
|
+
attribute :format, :string
|
|
13
|
+
|
|
14
|
+
key_value do
|
|
15
|
+
map :content, to: :content
|
|
16
|
+
map :format, to: :format
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Glossarist
|
|
4
|
+
# A reference from a concept to a dataset-level Table entity.
|
|
5
|
+
#
|
|
6
|
+
# Produced by `tables: [id]` structural arrays and `{{table:id}}` inline
|
|
7
|
+
# mentions.
|
|
8
|
+
class TableReference < NonVerbalReference
|
|
9
|
+
key_value do
|
|
10
|
+
map :entity_id, to: :entity_id
|
|
11
|
+
map :display, to: :display
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dedup_key
|
|
15
|
+
[self.class.name, entity_id]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -303,8 +303,8 @@ desig_index)
|
|
|
303
303
|
Array(non_verb_reps).each_with_index.map do |nvr, idx|
|
|
304
304
|
Rdf::GlossNonVerbalRep.new(
|
|
305
305
|
representation_type: nvr.type,
|
|
306
|
-
representation_ref: nvr.
|
|
307
|
-
representation_text: nvr.
|
|
306
|
+
representation_ref: nvr.images.first&.src,
|
|
307
|
+
representation_text: localized_alt_for(nvr.alt, lang),
|
|
308
308
|
sources: build_gloss_sources(nvr.sources),
|
|
309
309
|
concept_id: concept_id.to_s,
|
|
310
310
|
lang_code: lang.to_s,
|
|
@@ -313,6 +313,12 @@ desig_index)
|
|
|
313
313
|
end
|
|
314
314
|
end
|
|
315
315
|
|
|
316
|
+
def localized_alt_for(alt, lang)
|
|
317
|
+
return nil unless alt.is_a?(Hash) && !alt.empty?
|
|
318
|
+
|
|
319
|
+
alt[lang.to_s] || alt[lang.to_sym] || alt.values.first
|
|
320
|
+
end
|
|
321
|
+
|
|
316
322
|
def build_gloss_domains(domains, concept_id)
|
|
317
323
|
Array(domains).map do |ref|
|
|
318
324
|
Rdf::GlossConceptReference.new(
|
data/lib/glossarist/v3.rb
CHANGED
|
@@ -13,10 +13,6 @@ module Glossarist
|
|
|
13
13
|
autoload :ManagedConceptData, "glossarist/v3/managed_concept_data"
|
|
14
14
|
autoload :ManagedConcept, "glossarist/v3/managed_concept"
|
|
15
15
|
autoload :ConceptDocument, "glossarist/v3/concept_document"
|
|
16
|
-
autoload :BibliographyEntry, "glossarist/v3/bibliography_entry"
|
|
17
|
-
autoload :BibliographyFile, "glossarist/v3/bibliography_file"
|
|
18
|
-
autoload :ImageEntry, "glossarist/v3/image_entry"
|
|
19
|
-
autoload :ImageFile, "glossarist/v3/image_file"
|
|
20
16
|
|
|
21
17
|
Configuration.register_model(Citation, id: :citation)
|
|
22
18
|
Configuration.register_model(ConceptSource, id: :concept_source)
|
|
@@ -28,9 +24,5 @@ module Glossarist
|
|
|
28
24
|
Configuration.register_model(ManagedConceptData, id: :managed_concept_data)
|
|
29
25
|
Configuration.register_model(ManagedConcept, id: :managed_concept)
|
|
30
26
|
Configuration.register_model(ConceptDocument, id: :concept_document)
|
|
31
|
-
Configuration.register_model(BibliographyEntry, id: :bibliography_entry)
|
|
32
|
-
Configuration.register_model(BibliographyFile, id: :bibliography_file)
|
|
33
|
-
Configuration.register_model(ImageEntry, id: :image_entry)
|
|
34
|
-
Configuration.register_model(ImageFile, id: :image_file)
|
|
35
27
|
end
|
|
36
28
|
end
|
|
@@ -95,9 +95,14 @@ module Glossarist
|
|
|
95
95
|
|
|
96
96
|
def register_non_verb_rep(index, l10n)
|
|
97
97
|
Array(l10n.non_verb_rep).each do |nvr|
|
|
98
|
-
next unless nvr.is_a?(NonVerbRep)
|
|
98
|
+
next unless nvr.is_a?(NonVerbRep)
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
Array(nvr.images).each do |image|
|
|
101
|
+
next unless image.is_a?(FigureImage)
|
|
102
|
+
next if image.src.nil? || image.src.strip.empty?
|
|
103
|
+
|
|
104
|
+
index.register(image.src.strip)
|
|
105
|
+
end
|
|
101
106
|
end
|
|
102
107
|
end
|
|
103
108
|
|
|
@@ -30,18 +30,15 @@ module Glossarist
|
|
|
30
30
|
|
|
31
31
|
concepts.each { |concept| index_concept_sources(index, concept) }
|
|
32
32
|
index_bibliography_file(index, dataset_path)
|
|
33
|
-
index_images_file(index, dataset_path)
|
|
34
33
|
|
|
35
34
|
index
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
def self.build_from_yaml(concepts, bibliography_yaml: nil
|
|
39
|
-
images_yaml: nil)
|
|
37
|
+
def self.build_from_yaml(concepts, bibliography_yaml: nil)
|
|
40
38
|
index = new
|
|
41
39
|
|
|
42
40
|
concepts.each { |concept| index_concept_sources(index, concept) }
|
|
43
41
|
index_bib_from_yaml_string(index, bibliography_yaml)
|
|
44
|
-
index_images_from_yaml_string(index, images_yaml)
|
|
45
42
|
|
|
46
43
|
index
|
|
47
44
|
end
|
|
@@ -103,7 +100,7 @@ images_yaml: nil)
|
|
|
103
100
|
def index_bibliography_file(index, dataset_path)
|
|
104
101
|
return unless dataset_path
|
|
105
102
|
|
|
106
|
-
bib =
|
|
103
|
+
bib = BibliographyData.from_file(
|
|
107
104
|
File.join(dataset_path, "bibliography.yaml"),
|
|
108
105
|
)
|
|
109
106
|
return unless bib
|
|
@@ -118,27 +115,10 @@ images_yaml: nil)
|
|
|
118
115
|
nil
|
|
119
116
|
end
|
|
120
117
|
|
|
121
|
-
def index_images_file(index, dataset_path)
|
|
122
|
-
return unless dataset_path
|
|
123
|
-
|
|
124
|
-
images = V3::ImageFile.from_file(
|
|
125
|
-
File.join(dataset_path, "images.yaml"),
|
|
126
|
-
)
|
|
127
|
-
return unless images
|
|
128
|
-
|
|
129
|
-
Array(images.entries).each do |entry|
|
|
130
|
-
next unless entry&.id
|
|
131
|
-
|
|
132
|
-
index.register(entry.id, entry)
|
|
133
|
-
end
|
|
134
|
-
rescue StandardError
|
|
135
|
-
nil
|
|
136
|
-
end
|
|
137
|
-
|
|
138
118
|
def index_bib_from_yaml_string(index, yaml_content)
|
|
139
119
|
return unless yaml_content
|
|
140
120
|
|
|
141
|
-
bib =
|
|
121
|
+
bib = BibliographyData.from_yaml(yaml_content)
|
|
142
122
|
bib.entries.each do |entry|
|
|
143
123
|
index.register(entry.id, entry)
|
|
144
124
|
index.register(entry.reference, entry) if entry.reference
|
|
@@ -146,15 +126,6 @@ images_yaml: nil)
|
|
|
146
126
|
rescue StandardError
|
|
147
127
|
nil
|
|
148
128
|
end
|
|
149
|
-
|
|
150
|
-
def index_images_from_yaml_string(index, yaml_content)
|
|
151
|
-
return unless yaml_content
|
|
152
|
-
|
|
153
|
-
images = V3::ImageFile.from_yaml(yaml_content)
|
|
154
|
-
images.entries.each { |entry| index.register(entry.id, entry) }
|
|
155
|
-
rescue StandardError
|
|
156
|
-
nil
|
|
157
|
-
end
|
|
158
129
|
end
|
|
159
130
|
end
|
|
160
131
|
end
|