Class: Opencdd::Klass

Inherits:
Entity
  • Object
show all
Defined in:
lib/opencdd/klass.rb

Constant Summary collapse

PARENT_PROPERTY_IDS =
[Opencdd::PropertyIds::MDC_P010_1, Opencdd::PropertyIds::MDC_P010].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(irdi: nil, properties:, schema: nil, meta_class_irdi: nil) ⇒ Klass

Returns a new instance of Klass.



15
16
17
18
19
# File 'lib/opencdd/klass.rb', line 15

def initialize(irdi: nil, properties:, schema: nil, meta_class_irdi: nil)
  super
  @children = []
  @declared_property_irdis = []
end

Instance Attribute Details

#childrenObject (readonly)

Read-only accessors for state that the Database mutates via the explicit mutator methods below. Exposing only readers (instead of attr_accessor) keeps the entity's invariants under the class's control: parent linkage, child registration, and declared-property tracking each have a single mutator that can guard against duplicates, cycles, and stale state.



13
14
15
# File 'lib/opencdd/klass.rb', line 13

def children
  @children
end

#databaseObject (readonly)

Read-only accessors for state that the Database mutates via the explicit mutator methods below. Exposing only readers (instead of attr_accessor) keeps the entity's invariants under the class's control: parent linkage, child registration, and declared-property tracking each have a single mutator that can guard against duplicates, cycles, and stale state.



13
14
15
# File 'lib/opencdd/klass.rb', line 13

def database
  @database
end

#declared_property_irdisObject (readonly)

Read-only accessors for state that the Database mutates via the explicit mutator methods below. Exposing only readers (instead of attr_accessor) keeps the entity's invariants under the class's control: parent linkage, child registration, and declared-property tracking each have a single mutator that can guard against duplicates, cycles, and stale state.



13
14
15
# File 'lib/opencdd/klass.rb', line 13

def declared_property_irdis
  @declared_property_irdis
end

#parent_irdiObject (readonly)

Read-only accessors for state that the Database mutates via the explicit mutator methods below. Exposing only readers (instead of attr_accessor) keeps the entity's invariants under the class's control: parent linkage, child registration, and declared-property tracking each have a single mutator that can guard against duplicates, cycles, and stale state.



13
14
15
# File 'lib/opencdd/klass.rb', line 13

def parent_irdi
  @parent_irdi
end

Instance Method Details

#add_child(klass) ⇒ Object



30
31
32
33
34
# File 'lib/opencdd/klass.rb', line 30

def add_child(klass)
  return self if @children.include?(klass)
  @children << klass
  self
end

#all_properties(database = @database) ⇒ Object



118
119
120
121
# File 'lib/opencdd/klass.rb', line 118

def all_properties(database = @database)
  return effective_properties if database
  properties_on_class(database)
end

#ancestorsObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/opencdd/klass.rb', line 80

def ancestors
  out = []
  cur = self
  while cur
    out << cur
    ref = cur.parent_irdi || cur.superclass_irdi
    break unless ref
    break if out.any? { |a| a.irdi == ref }
    parent_obj = cur.database&.find(ref)
    break unless parent_obj
    cur = parent_obj
  end
  out
end

#attach_database(database) ⇒ Object



42
43
44
45
# File 'lib/opencdd/klass.rb', line 42

def attach_database(database)
  @database = database
  self
end

#attach_parent_irdi(irdi) ⇒ Object

── Mutators (called by Opencdd::Database and Opencdd::Cddal::Builder during finalize/link phases). Single entry points keep invariant checks (dedup, validity) in one place. ──────



25
26
27
28
# File 'lib/opencdd/klass.rb', line 25

def attach_parent_irdi(irdi)
  @parent_irdi = irdi
  self
end

#categorical?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/opencdd/klass.rb', line 199

def categorical?
  class_type&.categorical?
end

#categorical_instances(database = @database) ⇒ Object

Returns the powertype instances of this categorical class — direct children that are themselves classes (ITEM_CLASS or VALUE_CLASS terminal types). Returns empty for non-powertype classes or when database is unavailable.



165
166
167
168
# File 'lib/opencdd/klass.rb', line 165

def categorical_instances(database = @database)
  return [] unless powertype? && database
  children.select { |c| c.item? || c.value_class? || c.powertype? }
end

#declare_property(irdi) ⇒ Object



36
37
38
39
40
# File 'lib/opencdd/klass.rb', line 36

def declare_property(irdi)
  return self if @declared_property_irdis.include?(irdi)
  @declared_property_irdis << irdi
  self
end

#descendantsObject



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/opencdd/klass.rb', line 95

def descendants
  out = []
  queue = children.dup
  seen = { irdi => true }
  until queue.empty?
    c = queue.shift
    next if seen[c.irdi]
    seen[c.irdi] = true
    out << c
    queue.concat(c.children)
  end
  out
end

#effective_properties(database = @database) ⇒ Object



123
124
125
126
# File 'lib/opencdd/klass.rb', line 123

def effective_properties(database = @database)
  return [] unless database
  database.effective_properties.for(self)
end

#is_case_of(database = @database) ⇒ Object



128
129
130
131
# File 'lib/opencdd/klass.rb', line 128

def is_case_of(database = @database)
  return [] unless database
  is_case_of_irdis.map { |i| database.find(i) }.compact
end

#item?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/opencdd/klass.rb', line 195

def item?
  class_type&.item?
end

#message?Boolean

Returns:

  • (Boolean)


207
208
209
# File 'lib/opencdd/klass.rb', line 207

def message?
  class_type&.message?
end

#parentObject



75
76
77
78
# File 'lib/opencdd/klass.rb', line 75

def parent
  return nil unless @parent_irdi && @database
  @database.find(@parent_irdi)
end

#parent_property_idObject



70
71
72
73
# File 'lib/opencdd/klass.rb', line 70

def parent_property_id
  return @parent_property_id if defined?(@parent_property_id)
  @parent_property_id = detect_parent_property_id
end

#powertype?Boolean

── Powertype semantics (CDD four-layer ontology) ───────────

A CATEGORICAL_CLASS at M1 occupies the powertype position: its subclasses ARE themselves classes, but they are also treated as instances of the categorical class for the purpose of CLASS_REFERENCE data types and sub_class_selection. This is the distinguishing capability of CDD vs UML/RDF/OWL.

Example (OceanRunner):

EngineType (CATEGORICAL_CLASS)
├── SingleDieselEngine  (ITEM_CLASS)
├── TwinDieselEngine    (ITEM_CLASS)
└── ElectricHybridEngine (ITEM_CLASS)

EngineType#powertype? returns true. EngineType#categorical_instances returns [SingleDiesel, TwinDiesel, ElectricHybrid] — the valid values for any CLASS_REFERENCE(EngineType) property.

Returns:

  • (Boolean)


157
158
159
# File 'lib/opencdd/klass.rb', line 157

def powertype?
  categorical?
end

#powertype_owners(database = @database) ⇒ Object

Walks the ancestor chain and returns the categorical classes this class is an instance of (in the powertype sense). For SingleDiesel: [EngineType]. For a configured product subclass under EngineType + InteriorPackage: [EngineType, InteriorPackage].



182
183
184
185
186
187
188
# File 'lib/opencdd/klass.rb', line 182

def powertype_owners(database = @database)
  return [] unless database
  ancestors.filter_map do |a|
    next if a == self
    a if a.powertype?
  end
end

#properties_on_class(database = @database) ⇒ Object



113
114
115
116
# File 'lib/opencdd/klass.rb', line 113

def properties_on_class(database = @database)
  return [] unless database
  declared_property_irdis.map { |i| database.find(i) }.compact
end

#sub_class_selection(database = @database) ⇒ Object



133
134
135
136
# File 'lib/opencdd/klass.rb', line 133

def sub_class_selection(database = @database)
  return [] unless database
  sub_class_selection_irdis.map { |i| database.find(i) }.compact
end

#sub_powertypes(database = @database) ⇒ Object

Sub-powertypes: categorical classes that specialize this one. E.g. PrimaryColor (CATEGORICAL) under Color (CATEGORICAL) is a sub-powertype. Useful for hierarchical option trees.



173
174
175
176
# File 'lib/opencdd/klass.rb', line 173

def sub_powertypes(database = @database)
  return [] unless powertype? && database
  children.select(&:powertype?)
end

#subclassesObject



109
110
111
# File 'lib/opencdd/klass.rb', line 109

def subclasses
  children
end

#value_class?Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/opencdd/klass.rb', line 203

def value_class?
  class_type&.value_class?
end