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.
-
#ellipsis_members ⇒ Object
Array of members whose refs are marked ellipsis: true.
-
#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 are marked external: true (inline form) OR resolve (via the supplied resolver) to status: external.
-
#file_path(relations_dir) ⇒ Object
File path under
relations/directory. -
#has_ellipsis_member? ⇒ Boolean
True if any member has a ConceptRef with ellipsis: true.
-
#has_external_comprehensive? ⇒ Boolean
True if the comprehensive ConceptRef has external: true.
-
#has_external_members? ⇒ Boolean
True if any member has a ConceptRef with external: true.
-
#initialize ⇒ AbstractHyperedge
constructor
A new instance of AbstractHyperedge.
-
#inline_external_members ⇒ Object
Array of members whose refs are marked external: true.
- #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).
188 189 190 191 192 193 194 195 196 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 188 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).
201 202 203 204 205 206 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 201 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.
121 122 123 124 125 126 127 128 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 121 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.
164 165 166 167 168 169 170 171 172 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 164 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 |
#ellipsis_members ⇒ Object
Array of members whose refs are marked ellipsis: true.
153 154 155 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 153 def ellipsis_members members.select { |m| m.is_a?(HyperedgeMember) && m.ref&.ellipsis? } end |
#external_comprehensive?(resolver = nil) ⇒ Boolean
True if the comprehensive resolves (via the supplied resolver) to a concept with status: external. Also true when the comprehensive ConceptRef itself has external: true (inline form).
94 95 96 97 98 99 100 101 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 94 def external_comprehensive?(resolver = nil) return true if comprehensive.is_a?(ConceptRef) && comprehensive.external? 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 are marked external: true (inline form) OR resolve (via the supplied resolver) to status: external.
105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 105 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).
177 178 179 180 181 182 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 177 def file_path(relations_dir) id = file_id || derived_file_id return nil unless id File.join(relations_dir, "#{id}.yaml") end |
#has_ellipsis_member? ⇒ Boolean
True if any member has a ConceptRef with ellipsis: true.
143 144 145 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 143 def has_ellipsis_member? members.any? { |m| m.is_a?(HyperedgeMember) && m.ref&.ellipsis? } end |
#has_external_comprehensive? ⇒ Boolean
True if the comprehensive ConceptRef has external: true.
138 139 140 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 138 def has_external_comprehensive? comprehensive.is_a?(ConceptRef) && comprehensive.external? end |
#has_external_members? ⇒ Boolean
True if any member has a ConceptRef with external: true.
133 134 135 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 133 def has_external_members? members.any? { |m| m.is_a?(HyperedgeMember) && m.ref&.external? } end |
#inline_external_members ⇒ Object
Array of members whose refs are marked external: true.
148 149 150 |
# File 'lib/glossarist/v3/abstract_hyperedge.rb', line 148 def inline_external_members members.select { |m| m.is_a?(HyperedgeMember) && m.ref&.external? } 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 |