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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +15 -0
  3. data/lib/glossarist/cli/export_command.rb +5 -5
  4. data/lib/glossarist/concept_ref.rb +49 -0
  5. data/lib/glossarist/gcr_package.rb +2 -2
  6. data/lib/glossarist/gcr_validator.rb +19 -1
  7. data/lib/glossarist/glossary_definition.rb +16 -3
  8. data/lib/glossarist/glossary_store.rb +70 -0
  9. data/lib/glossarist/managed_concept.rb +2 -2
  10. data/lib/glossarist/rdf/gloss_concept.rb +3 -0
  11. data/lib/glossarist/rdf/gloss_generic_member.rb +34 -0
  12. data/lib/glossarist/rdf/gloss_generic_relation.rb +44 -0
  13. data/lib/glossarist/rdf/gloss_nary_member.rb +43 -0
  14. data/lib/glossarist/rdf/gloss_nary_relation.rb +56 -0
  15. data/lib/glossarist/rdf/gloss_partitive_member.rb +5 -28
  16. data/lib/glossarist/rdf/gloss_partitive_relation.rb +6 -19
  17. data/lib/glossarist/rdf.rb +4 -0
  18. data/lib/glossarist/tasks/shacl.rake +4 -1
  19. data/lib/glossarist/tasks/sync.rake +4 -1
  20. data/lib/glossarist/tasks.rb +9 -0
  21. data/lib/glossarist/transforms/concept_to_gloss_transform.rb +72 -52
  22. data/lib/glossarist/v3/abstract_hyperedge.rb +187 -0
  23. data/lib/glossarist/v3/definition_type.rb +30 -0
  24. data/lib/glossarist/v3/detailed_definition.rb +4 -0
  25. data/lib/glossarist/v3/generic_hyperedge.rb +34 -0
  26. data/lib/glossarist/v3/generic_member.rb +17 -0
  27. data/lib/glossarist/v3/hyperedge_index.rb +89 -0
  28. data/lib/glossarist/v3/hyperedge_member.rb +97 -0
  29. data/lib/glossarist/v3/hyperedge_registry.rb +70 -0
  30. data/lib/glossarist/v3/hyperedge_writer.rb +87 -0
  31. data/lib/glossarist/v3/managed_concept.rb +53 -2
  32. data/lib/glossarist/v3/managed_concept_data.rb +0 -1
  33. data/lib/glossarist/v3/partitive_hyperedge.rb +53 -0
  34. data/lib/glossarist/v3/partitive_member.rb +8 -105
  35. data/lib/glossarist/v3/relation_loader.rb +98 -0
  36. data/lib/glossarist/v3.rb +25 -8
  37. data/lib/glossarist/validation/rules/concept_context.rb +10 -2
  38. data/lib/glossarist/validation/rules/{partitive_relation_rule.rb → hyperedge_coherence_rule.rb} +22 -16
  39. data/lib/glossarist/version.rb +1 -1
  40. data/lib/glossarist.rb +1 -0
  41. metadata +17 -3
  42. 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
@@ -3,14 +3,17 @@
3
3
  module Glossarist
4
4
  module Validation
5
5
  module Rules
6
- # Validates semantic invariants of PartitiveRelation entries
7
- # that the model constructor does NOT enforce. Specifically:
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
- # - error when a relation has fewer than 2 partitives
10
- # (ISO 704: "two or more"; single binary should use
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-nil criterion (duplicate decomposition;
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 partitives list, self-loops, invalid enum values, and
27
+ # empty members list, self-loops, invalid enum values, and
25
28
  # the optional + at_least_one combination.
26
- class PartitiveRelationRule < Base
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
- concept.partitive_relations&.any? || external?(concept)
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.partitives.length >= 2
76
+ return if rel.members.length >= 2
71
77
 
72
78
  issues << issue(
73
- "partitive_relation #{idx + 1} has fewer than 2 partitives " \
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
- "partitive_relation #{idx + 1} has no criterion; cannot verify " \
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.partitives.each_with_index do |member, mi|
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
- "partitive_relation #{idx + 1}.partitives[#{mi}] uses " \
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 PartitiveRelation for comprehensive " \
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 " \
@@ -4,5 +4,5 @@
4
4
  #
5
5
 
6
6
  module Glossarist
7
- VERSION = "2.13.6"
7
+ VERSION = "2.13.7"
8
8
  end
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.6
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