Class: Glossarist::V3::AbstractHyperedge
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- Glossarist::V3::AbstractHyperedge
- Defined in:
- lib/glossarist/v3/abstract_hyperedge.rb
Overview
AbstractHyperedge — abstract base shape for all n-ary concept-system relations (PartitiveHyperedge, GenericHyperedge, future AssociativeRelation, SequentialRelation).
Carries the shared fields: comprehensive, members, completeness, criterion, sources, notes, status.
Concrete leaves override members to specify the typed member
class. Shared validations live here.
Direct Known Subclasses
Constant Summary collapse
- DEFAULT_COMPLETENESS =
"complete"
Instance Attribute Summary collapse
-
#file_id ⇒ Object
Per-file identity — set by RelationLoader on parse, used by HyperedgeWriter on serialize.
Instance Method Summary collapse
- #complete? ⇒ Boolean
-
#comprehensive_dir_name ⇒ Object
Comprehensive concept as a directory-safe name:
<source>-<id>lowercased, kebab-case, special chars (including dots) replaced with dashes. -
#coordinate? ⇒ Boolean
ISO 704: a rake connects to two or more members.
-
#criterion_slug ⇒ Object
Kebab-case slug derived from the English criterion.
-
#dangling_externals?(resolver = nil) ⇒ Boolean
True if any external comprehensive or member lacks a
provided_byedge — i.e., the decomposition dangles. -
#derived_file_id ⇒ Object
Per-file identity derived from comprehensive + criterion.
-
#external_comprehensive?(resolver = nil) ⇒ Boolean
True if the comprehensive resolves (via the supplied resolver) to a concept with status: external.
-
#external_members(resolver = nil) ⇒ Object
Array of members whose refs resolve to status: external.
-
#file_path(relations_dir) ⇒ Object
File path under
relations/directory. -
#initialize ⇒ AbstractHyperedge
constructor
A new instance of AbstractHyperedge.
- #partial? ⇒ Boolean
- #validate! ⇒ Object
Constructor Details
#initialize ⇒ AbstractHyperedge
Returns a new instance of AbstractHyperedge.
48 49 50 51 52 53 54 55 56 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 48 def initialize(*) if instance_of?(AbstractHyperedge) raise NotImplementedError, "AbstractHyperedge is abstract; instantiate " \ "PartitiveHyperedge or GenericHyperedge instead" end super end |
Instance Attribute Details
#file_id ⇒ Object
Per-file identity — set by RelationLoader on parse, used by
HyperedgeWriter on serialize. The wire field is $id (JSON
Schema convention); the value is <comp-id>/<criterion-slug>.
Not in key_value because lutaml::Model key_value does not
natively express $-prefixed keys; handled via custom
round-trip in HyperedgeWriter / RelationLoader.
36 37 38 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 36 def file_id @file_id end |
Instance Method Details
#complete? ⇒ Boolean
66 67 68 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 66 def complete? completeness == "complete" end |
#comprehensive_dir_name ⇒ Object
Comprehensive concept as a directory-safe name:
<source>-<id> lowercased, kebab-case, special chars
(including dots) replaced with dashes. Matches the concept-model
fixtures (vim-112-02-09, oiml-5-1, example-116-01-01).
159 160 161 162 163 164 165 166 167 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 159 def comprehensive_dir_name return nil unless comprehensive.is_a?(ConceptRef) parts = [comprehensive.source, comprehensive.id].compact.reject(&:empty?) return nil if parts.empty? parts.join("-").downcase.gsub(/[^a-z0-9-]/, "-") .gsub(/-{2,}/, "-").gsub(/\A-|-\z/, "") end |
#coordinate? ⇒ Boolean
ISO 704: a rake connects to two or more members. A single binary edge is not an n-ary relation.
76 77 78 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 76 def coordinate? members.length >= 2 end |
#criterion_slug ⇒ Object
Kebab-case slug derived from the English criterion. Falls back to "decomposition-N" when no English criterion exists (N is derived from the criterion hash for stability).
172 173 174 175 176 177 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 172 def criterion_slug eng = criterion.is_a?(Hash) ? (criterion["eng"] || criterion[:eng]) : nil return "decomposition-#{criterion_hash}" if eng.nil? || eng.to_s.empty? eng.to_s.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-|-\z/, "") end |
#dangling_externals?(resolver = nil) ⇒ Boolean
True if any external comprehensive or member lacks a
provided_by edge — i.e., the decomposition dangles. The
resolver is used twice: once to detect externals, once to
check each external's related edges.
119 120 121 122 123 124 125 126 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 119 def dangling_externals?(resolver = nil) return false unless resolver candidates = [] candidates << comprehensive if external_comprehensive?(resolver) candidates.concat(external_members(resolver).map(&:ref)) candidates.any? { |ref| !has_provided_by?(ref, resolver) } end |
#derived_file_id ⇒ Object
Per-file identity derived from comprehensive + criterion.
Format: <comprehensive-id-dir>/<criterion-slug> where the
dir is <source>-<id> (downcased, kebab-case) and the slug
is the English criterion (kebab-case) or a structural
fallback. Stable across runs for the same content.
Returns nil if comprehensive is empty.
135 136 137 138 139 140 141 142 143 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 135 def derived_file_id return nil unless comprehensive.is_a?(ConceptRef) && comprehensive.id comp_dir = comprehensive_dir_name return nil unless comp_dir slug = criterion_slug "#{comp_dir}/#{slug}" end |
#external_comprehensive?(resolver = nil) ⇒ Boolean
True if the comprehensive resolves (via the supplied resolver) to a concept with status: external.
93 94 95 96 97 98 99 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 93 def external_comprehensive?(resolver = nil) return false unless comprehensive.is_a?(ConceptRef) return false unless resolver concept = resolver.call(comprehensive) concept_is_external?(concept) end |
#external_members(resolver = nil) ⇒ Object
Array of members whose refs resolve to status: external. Empty when no resolver is supplied (detection is opt-in).
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 103 def external_members(resolver = nil) return [] unless resolver members.select do |m| next false unless m.is_a?(HyperedgeMember) next false unless m.ref.is_a?(ConceptRef) concept = resolver.call(m.ref) concept_is_external?(concept) end end |
#file_path(relations_dir) ⇒ Object
File path under relations/ directory. Uses #derived_file_id
unless #file_id was explicitly set (e.g., by RelationLoader
preserving the source path on parse).
148 149 150 151 152 153 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 148 def file_path(relations_dir) id = file_id || derived_file_id return nil unless id File.join(relations_dir, "#{id}.yaml") end |
#partial? ⇒ Boolean
70 71 72 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 70 def partial? completeness == "partial" end |
#validate! ⇒ Object
58 59 60 61 62 63 64 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 58 def validate! validate_comprehensive! validate_members! validate_self_loop! validate_completeness! self end |