glossarist 2.13.6 → 2.13.7
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/config.yml +15 -0
- data/lib/glossarist/cli/export_command.rb +5 -5
- data/lib/glossarist/concept_ref.rb +49 -0
- data/lib/glossarist/gcr_package.rb +2 -2
- data/lib/glossarist/gcr_validator.rb +19 -1
- data/lib/glossarist/glossary_definition.rb +16 -3
- data/lib/glossarist/glossary_store.rb +70 -0
- data/lib/glossarist/managed_concept.rb +2 -2
- data/lib/glossarist/rdf/gloss_concept.rb +3 -0
- data/lib/glossarist/rdf/gloss_generic_member.rb +34 -0
- data/lib/glossarist/rdf/gloss_generic_relation.rb +44 -0
- data/lib/glossarist/rdf/gloss_nary_member.rb +43 -0
- data/lib/glossarist/rdf/gloss_nary_relation.rb +56 -0
- data/lib/glossarist/rdf/gloss_partitive_member.rb +5 -28
- data/lib/glossarist/rdf/gloss_partitive_relation.rb +6 -19
- data/lib/glossarist/rdf.rb +4 -0
- data/lib/glossarist/tasks/shacl.rake +4 -1
- data/lib/glossarist/tasks/sync.rake +4 -1
- data/lib/glossarist/tasks.rb +9 -0
- data/lib/glossarist/transforms/concept_to_gloss_transform.rb +72 -52
- data/lib/glossarist/v3/abstract_hyperedge.rb +187 -0
- data/lib/glossarist/v3/definition_type.rb +30 -0
- data/lib/glossarist/v3/detailed_definition.rb +4 -0
- data/lib/glossarist/v3/generic_hyperedge.rb +34 -0
- data/lib/glossarist/v3/generic_member.rb +17 -0
- data/lib/glossarist/v3/hyperedge_index.rb +89 -0
- data/lib/glossarist/v3/hyperedge_member.rb +97 -0
- data/lib/glossarist/v3/hyperedge_registry.rb +70 -0
- data/lib/glossarist/v3/hyperedge_writer.rb +87 -0
- data/lib/glossarist/v3/managed_concept.rb +53 -2
- data/lib/glossarist/v3/managed_concept_data.rb +0 -1
- data/lib/glossarist/v3/partitive_hyperedge.rb +53 -0
- data/lib/glossarist/v3/partitive_member.rb +8 -105
- data/lib/glossarist/v3/relation_loader.rb +98 -0
- data/lib/glossarist/v3.rb +25 -8
- data/lib/glossarist/validation/rules/concept_context.rb +10 -2
- data/lib/glossarist/validation/rules/{partitive_relation_rule.rb → hyperedge_coherence_rule.rb} +22 -16
- data/lib/glossarist/version.rb +1 -1
- data/lib/glossarist.rb +1 -0
- metadata +17 -3
- data/lib/glossarist/v3/partitive_relation.rb +0 -114
|
@@ -9,13 +9,21 @@ module Glossarist
|
|
|
9
9
|
# rules examining the same concept share one extraction pass (DRY,
|
|
10
10
|
# single source of truth). Rules ask the context for references rather
|
|
11
11
|
# than instantiating their own ReferenceExtractor.
|
|
12
|
+
#
|
|
13
|
+
# In V3, n-ary relations (PartitiveHyperedge, GenericHyperedge) are
|
|
14
|
+
# per-file (see Glossarist::V3::RelationLoader). Each concept's
|
|
15
|
+
# relations are looked up via the relations lookup passed here.
|
|
16
|
+
# Pass an explicit `relations:` list when constructing the context
|
|
17
|
+
# — the loader does not run on demand so the validator behaviour
|
|
18
|
+
# is fully deterministic given the load.
|
|
12
19
|
class ConceptContext
|
|
13
|
-
attr_reader :concept, :file_name, :collection_context
|
|
20
|
+
attr_reader :concept, :file_name, :collection_context, :relations
|
|
14
21
|
|
|
15
|
-
def initialize(concept, file_name:, collection_context:)
|
|
22
|
+
def initialize(concept, file_name:, collection_context:, relations: [])
|
|
16
23
|
@concept = concept
|
|
17
24
|
@file_name = file_name
|
|
18
25
|
@collection_context = collection_context
|
|
26
|
+
@relations = Array(relations)
|
|
19
27
|
end
|
|
20
28
|
|
|
21
29
|
def concept_id
|
data/lib/glossarist/validation/rules/{partitive_relation_rule.rb → hyperedge_coherence_rule.rb}
RENAMED
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
module Glossarist
|
|
4
4
|
module Validation
|
|
5
5
|
module Rules
|
|
6
|
-
# Validates semantic invariants of
|
|
7
|
-
# that the model constructor
|
|
6
|
+
# Validates semantic invariants of n-ary relation entries
|
|
7
|
+
# (PartitiveHyperedge, GenericHyperedge) that the model constructor
|
|
8
|
+
# does NOT enforce. The relations are passed in via the
|
|
9
|
+
# ConceptContext (per-file storage — see Glossarist::V3::RelationLoader).
|
|
8
10
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
+
# Checks:
|
|
12
|
+
# - error when a relation has fewer than 2 members
|
|
13
|
+
# (ISO 704: "two or more"; single binary should use a
|
|
11
14
|
# has_part edge instead)
|
|
12
15
|
# - error when two relations share the same comprehensive
|
|
13
|
-
# AND the same non-
|
|
16
|
+
# AND the same non-empty criterion (duplicate decomposition;
|
|
14
17
|
# ISO 12620 coordinate-concept coherence)
|
|
15
18
|
# - warning when a relation has no criterion (cannot
|
|
16
19
|
# distinguish from siblings sharing the comprehensive)
|
|
@@ -21,12 +24,16 @@ module Glossarist
|
|
|
21
24
|
# at least one designation
|
|
22
25
|
#
|
|
23
26
|
# The model constructor already rejects empty comprehensive,
|
|
24
|
-
# empty
|
|
27
|
+
# empty members list, self-loops, invalid enum values, and
|
|
25
28
|
# the optional + at_least_one combination.
|
|
26
|
-
class
|
|
29
|
+
class HyperedgeCoherenceRule < Base
|
|
27
30
|
DEFAULT_PRESENCE = "required"
|
|
28
31
|
DEFAULT_COUNT = "exactly_one"
|
|
29
32
|
|
|
33
|
+
# Stable identifier for downstream issue trackers / config.
|
|
34
|
+
# Originally assigned when the rule was partitive-only; kept
|
|
35
|
+
# after the rename to GenericHyperedge + n-ary generalization
|
|
36
|
+
# so existing suppression configs continue to work.
|
|
30
37
|
def code = "GLS-221"
|
|
31
38
|
def category = :schema
|
|
32
39
|
def severity = "error"
|
|
@@ -36,18 +43,17 @@ module Glossarist
|
|
|
36
43
|
concept = context.concept
|
|
37
44
|
return false unless concept.is_a?(V3::ManagedConcept)
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
context.relations&.any? || external?(concept)
|
|
40
47
|
end
|
|
41
48
|
|
|
42
49
|
def check(context)
|
|
43
50
|
concept = context.concept
|
|
44
51
|
fname = context.file_name
|
|
52
|
+
relations = context.relations
|
|
45
53
|
issues = []
|
|
46
54
|
|
|
47
55
|
return issues unless concept.is_a?(V3::ManagedConcept)
|
|
48
56
|
|
|
49
|
-
relations = Array(concept.partitive_relations)
|
|
50
|
-
|
|
51
57
|
relations.each_with_index do |rel, idx|
|
|
52
58
|
check_cardinality(rel, idx, fname, issues)
|
|
53
59
|
check_criterion_present(rel, idx, fname, issues)
|
|
@@ -67,10 +73,10 @@ module Glossarist
|
|
|
67
73
|
end
|
|
68
74
|
|
|
69
75
|
def check_cardinality(rel, idx, fname, issues)
|
|
70
|
-
return if rel.
|
|
76
|
+
return if rel.members.length >= 2
|
|
71
77
|
|
|
72
78
|
issues << issue(
|
|
73
|
-
"
|
|
79
|
+
"relation #{idx + 1} has fewer than 2 members " \
|
|
74
80
|
"(ISO 704 requires two or more); a single binary has_part edge " \
|
|
75
81
|
"should be used instead",
|
|
76
82
|
location: fname,
|
|
@@ -81,7 +87,7 @@ module Glossarist
|
|
|
81
87
|
return if rel.criterion && !rel.criterion.empty?
|
|
82
88
|
|
|
83
89
|
issues << issue(
|
|
84
|
-
"
|
|
90
|
+
"relation #{idx + 1} has no criterion; cannot verify " \
|
|
85
91
|
"distinctness from sibling relations sharing the comprehensive " \
|
|
86
92
|
"(ISO 12620 coordinate-concept coherence)",
|
|
87
93
|
severity: "warning",
|
|
@@ -97,14 +103,14 @@ module Glossarist
|
|
|
97
103
|
# legal; the warning encourages an explicit, reviewed choice
|
|
98
104
|
# rather than an accidental non-default.
|
|
99
105
|
def check_member_dimensions(rel, idx, fname, issues)
|
|
100
|
-
rel.
|
|
106
|
+
rel.members.each_with_index do |member, mi|
|
|
101
107
|
non_default = []
|
|
102
108
|
non_default << "presence='#{member.presence}'" if member.presence != DEFAULT_PRESENCE
|
|
103
109
|
non_default << "count='#{member.count}'" if member.count != DEFAULT_COUNT
|
|
104
110
|
next if non_default.empty?
|
|
105
111
|
|
|
106
112
|
issues << issue(
|
|
107
|
-
"
|
|
113
|
+
"relation #{idx + 1}.members[#{mi}] uses " \
|
|
108
114
|
"non-default #{non_default.join(' ')} " \
|
|
109
115
|
"(defaults: presence=#{DEFAULT_PRESENCE}, count=#{DEFAULT_COUNT}) " \
|
|
110
116
|
"— confirm the dimensions are intentional",
|
|
@@ -129,7 +135,7 @@ module Glossarist
|
|
|
129
135
|
next if idxs.length == 1
|
|
130
136
|
|
|
131
137
|
issues << issue(
|
|
132
|
-
"duplicate
|
|
138
|
+
"duplicate relation for comprehensive " \
|
|
133
139
|
"#{key.first.inspect} with criterion #{key.last.inspect} " \
|
|
134
140
|
"(relations ##{idxs.map { |i| i + 1 }.join(', ')}); " \
|
|
135
141
|
"two relations sharing comprehensive AND criterion are the " \
|
data/lib/glossarist/version.rb
CHANGED
data/lib/glossarist.rb
CHANGED
|
@@ -85,6 +85,7 @@ module Glossarist
|
|
|
85
85
|
autoload :VERSION, "glossarist/version"
|
|
86
86
|
autoload :GlossaryDefinition, "glossarist/glossary_definition"
|
|
87
87
|
autoload :GlossaryStore, "glossarist/glossary_store"
|
|
88
|
+
autoload :Tasks, "glossarist/tasks"
|
|
88
89
|
|
|
89
90
|
LANG_CODES = %w[eng ara deu fra spa ita jpn kor pol por srp swe zho rus fin
|
|
90
91
|
dan nld msa nob nno].freeze
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glossarist
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.13.
|
|
4
|
+
version: 2.13.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -307,9 +307,13 @@ files:
|
|
|
307
307
|
- lib/glossarist/rdf/gloss_figure.rb
|
|
308
308
|
- lib/glossarist/rdf/gloss_figure_image.rb
|
|
309
309
|
- lib/glossarist/rdf/gloss_formula.rb
|
|
310
|
+
- lib/glossarist/rdf/gloss_generic_member.rb
|
|
311
|
+
- lib/glossarist/rdf/gloss_generic_relation.rb
|
|
310
312
|
- lib/glossarist/rdf/gloss_grammar_info.rb
|
|
311
313
|
- lib/glossarist/rdf/gloss_locality.rb
|
|
312
314
|
- lib/glossarist/rdf/gloss_localized_concept.rb
|
|
315
|
+
- lib/glossarist/rdf/gloss_nary_member.rb
|
|
316
|
+
- lib/glossarist/rdf/gloss_nary_relation.rb
|
|
313
317
|
- lib/glossarist/rdf/gloss_non_verbal_rep.rb
|
|
314
318
|
- lib/glossarist/rdf/gloss_partitive_member.rb
|
|
315
319
|
- lib/glossarist/rdf/gloss_partitive_relation.rb
|
|
@@ -359,6 +363,7 @@ files:
|
|
|
359
363
|
- lib/glossarist/sts/term_mapper.rb
|
|
360
364
|
- lib/glossarist/table.rb
|
|
361
365
|
- lib/glossarist/table_reference.rb
|
|
366
|
+
- lib/glossarist/tasks.rb
|
|
362
367
|
- lib/glossarist/tasks/shacl.rake
|
|
363
368
|
- lib/glossarist/tasks/sync.rake
|
|
364
369
|
- lib/glossarist/tasks/sync_model.rb
|
|
@@ -386,6 +391,7 @@ files:
|
|
|
386
391
|
- lib/glossarist/v2/managed_concept_data.rb
|
|
387
392
|
- lib/glossarist/v2/related_concept.rb
|
|
388
393
|
- lib/glossarist/v3.rb
|
|
394
|
+
- lib/glossarist/v3/abstract_hyperedge.rb
|
|
389
395
|
- lib/glossarist/v3/citation.rb
|
|
390
396
|
- lib/glossarist/v3/concept_data.rb
|
|
391
397
|
- lib/glossarist/v3/concept_date.rb
|
|
@@ -393,14 +399,22 @@ files:
|
|
|
393
399
|
- lib/glossarist/v3/concept_ref.rb
|
|
394
400
|
- lib/glossarist/v3/concept_source.rb
|
|
395
401
|
- lib/glossarist/v3/configuration.rb
|
|
402
|
+
- lib/glossarist/v3/definition_type.rb
|
|
396
403
|
- lib/glossarist/v3/detailed_definition.rb
|
|
404
|
+
- lib/glossarist/v3/generic_hyperedge.rb
|
|
405
|
+
- lib/glossarist/v3/generic_member.rb
|
|
406
|
+
- lib/glossarist/v3/hyperedge_index.rb
|
|
407
|
+
- lib/glossarist/v3/hyperedge_member.rb
|
|
408
|
+
- lib/glossarist/v3/hyperedge_registry.rb
|
|
409
|
+
- lib/glossarist/v3/hyperedge_writer.rb
|
|
397
410
|
- lib/glossarist/v3/localized_concept.rb
|
|
398
411
|
- lib/glossarist/v3/managed_concept.rb
|
|
399
412
|
- lib/glossarist/v3/managed_concept_data.rb
|
|
400
413
|
- lib/glossarist/v3/multiplicity.rb
|
|
414
|
+
- lib/glossarist/v3/partitive_hyperedge.rb
|
|
401
415
|
- lib/glossarist/v3/partitive_member.rb
|
|
402
|
-
- lib/glossarist/v3/partitive_relation.rb
|
|
403
416
|
- lib/glossarist/v3/related_concept.rb
|
|
417
|
+
- lib/glossarist/v3/relation_loader.rb
|
|
404
418
|
- lib/glossarist/validation.rb
|
|
405
419
|
- lib/glossarist/validation/asset_index.rb
|
|
406
420
|
- lib/glossarist/validation/bibliography_index.rb
|
|
@@ -430,6 +444,7 @@ files:
|
|
|
430
444
|
- lib/glossarist/validation/rules/entry_status_rule.rb
|
|
431
445
|
- lib/glossarist/validation/rules/filename_id_rule.rb
|
|
432
446
|
- lib/glossarist/validation/rules/gcr_context.rb
|
|
447
|
+
- lib/glossarist/validation/rules/hyperedge_coherence_rule.rb
|
|
433
448
|
- lib/glossarist/validation/rules/image_reference_rule.rb
|
|
434
449
|
- lib/glossarist/validation/rules/l10n_uuid_integrity_rule.rb
|
|
435
450
|
- lib/glossarist/validation/rules/language_code_format_rule.rb
|
|
@@ -442,7 +457,6 @@ files:
|
|
|
442
457
|
- lib/glossarist/validation/rules/orphaned_bibliography_rule.rb
|
|
443
458
|
- lib/glossarist/validation/rules/orphaned_images_rule.rb
|
|
444
459
|
- lib/glossarist/validation/rules/orphaned_l10n_files_rule.rb
|
|
445
|
-
- lib/glossarist/validation/rules/partitive_relation_rule.rb
|
|
446
460
|
- lib/glossarist/validation/rules/preferred_term_rule.rb
|
|
447
461
|
- lib/glossarist/validation/rules/ref_shape_rule.rb
|
|
448
462
|
- lib/glossarist/validation/rules/registry.rb
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Glossarist
|
|
4
|
-
module V3
|
|
5
|
-
# PartitiveRelation — an ISO 704 / ISO 1087-1 / ISO 12620
|
|
6
|
-
# partitive relation connecting a comprehensive concept
|
|
7
|
-
# (superordinate concept partitive) to two or more partitive
|
|
8
|
-
# concepts (subordinate concepts partitive) which fitted together
|
|
9
|
-
# constitute the comprehensive.
|
|
10
|
-
#
|
|
11
|
-
# Shown as a rake or bracket in source diagrams. All partitives
|
|
12
|
-
# within one relation are coordinate concepts: they share the
|
|
13
|
-
# comprehensive AND share the criterion of subdivision.
|
|
14
|
-
#
|
|
15
|
-
# Per-partitive metadata (ISO 704:2022, MECE decomposition):
|
|
16
|
-
# - presence (required, optional) — line style: solid vs dashed
|
|
17
|
-
# - count (exactly_one, at_least_one, multiple) — line count
|
|
18
|
-
# - is_delimiting — orthogonal flag; a delimiting part behaves
|
|
19
|
-
# like a delimiting characteristic (distinguishes the
|
|
20
|
-
# comprehensive from coordinate concepts)
|
|
21
|
-
#
|
|
22
|
-
# Replaces the prior PartitiveHyperedge class. The "hyperedge"
|
|
23
|
-
# framing was graph-theoretic; ISO calls this a *relation*.
|
|
24
|
-
class PartitiveRelation < Lutaml::Model::Serializable
|
|
25
|
-
DEFAULT_COMPLETENESS = "complete"
|
|
26
|
-
|
|
27
|
-
attribute :comprehensive, ConceptRef
|
|
28
|
-
attribute :partitives, PartitiveMember, collection: true
|
|
29
|
-
attribute :completeness, :string,
|
|
30
|
-
values: Glossarist::GlossaryDefinition::COMPLETENESS_VALUES,
|
|
31
|
-
default: -> { DEFAULT_COMPLETENESS }
|
|
32
|
-
attribute :criterion, :hash
|
|
33
|
-
|
|
34
|
-
key_value do
|
|
35
|
-
map :comprehensive, to: :comprehensive
|
|
36
|
-
map :partitives, to: :partitives
|
|
37
|
-
map :completeness, to: :completeness
|
|
38
|
-
map :criterion, to: :criterion
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def validate!
|
|
42
|
-
validate_comprehensive!
|
|
43
|
-
validate_partitives!
|
|
44
|
-
validate_self_loop!
|
|
45
|
-
validate_completeness!
|
|
46
|
-
self
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def complete?
|
|
50
|
-
completeness == "complete"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def partial?
|
|
54
|
-
completeness == "partial"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# ISO 704: a partitive relation connects to two or more
|
|
58
|
-
# partitives. A single binary has_part edge is not a
|
|
59
|
-
# PartitiveRelation.
|
|
60
|
-
def coordinate?
|
|
61
|
-
partitives.length >= 2
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
private
|
|
65
|
-
|
|
66
|
-
def validate_comprehensive!
|
|
67
|
-
return if comprehensive.is_a?(ConceptRef) &&
|
|
68
|
-
(comprehensive.source || comprehensive.id || comprehensive.text)
|
|
69
|
-
|
|
70
|
-
raise ArgumentError,
|
|
71
|
-
"PartitiveRelation#comprehensive must be a non-empty " \
|
|
72
|
-
"ConceptRef (source, id, or text required)"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def validate_partitives!
|
|
76
|
-
if partitives.empty?
|
|
77
|
-
raise ArgumentError, "PartitiveRelation requires at least one partitive"
|
|
78
|
-
end
|
|
79
|
-
unless coordinate?
|
|
80
|
-
raise ArgumentError,
|
|
81
|
-
"PartitiveRelation requires ≥2 partitives (ISO 704); a single " \
|
|
82
|
-
"binary has_part edge should be used instead"
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
partitives.each(&:validate!)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def validate_self_loop!
|
|
89
|
-
return unless comprehensive.is_a?(ConceptRef)
|
|
90
|
-
|
|
91
|
-
comp_key = [comprehensive.source, comprehensive.id]
|
|
92
|
-
partitives.each do |member|
|
|
93
|
-
next unless member.ref.is_a?(ConceptRef)
|
|
94
|
-
next unless [member.ref.source, member.ref.id] == comp_key
|
|
95
|
-
|
|
96
|
-
raise ArgumentError,
|
|
97
|
-
"PartitiveRelation#partitives cannot include the comprehensive"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def validate_completeness!
|
|
102
|
-
return if completeness.nil?
|
|
103
|
-
|
|
104
|
-
unless Glossarist::GlossaryDefinition::COMPLETENESS_VALUES
|
|
105
|
-
.include?(completeness)
|
|
106
|
-
raise ArgumentError,
|
|
107
|
-
"PartitiveRelation#completeness has invalid value " \
|
|
108
|
-
"#{completeness.inspect}; must be one of " \
|
|
109
|
-
"#{GlossaryDefinition::COMPLETENESS_VALUES.join(', ')}"
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|