Class: Opencdd::Parcel::SheetSchema

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/opencdd/parcel/sheet_schema.rb

Defined Under Namespace

Classes: Column

Constant Summary collapse

VARIANT_TO_CANONICAL =

Parcel-specific column-ID canonicalization. Maps the ParcelMaker variant headers (MDC_P004_1, MDC_P005, ...) to the canonical IEC 61360 IDs (MDC_P004, MDC_P006, ...).

Owned by SheetSchema because this mapping only exists for the Parcel sheet layout — the PropertyIds registry is ontology-only and shouldn't carry format-specific details.

{
  "MDC_P004_1" => "MDC_P004",
  "MDC_P004_2" => "MDC_P007",
  "MDC_P004_3" => "MDC_P005",
  "MDC_P005"   => "MDC_P006",
  "MDC_P007_1" => "MDC_P008",
  "MDC_P007_2" => "MDC_P009",
}.freeze
DIRECTIVE_ROWS =
%w[
  PROPERTY_ID
  ALTERNATE_ID
  SUPER_ALTERNATE_ID
  SUB_ALTERNATE_ID
  EQUIVALENT_ID
  SUPER_PROPERTY
  PROPERTY_NAME
  DEFINITION
  NOTE
  DATATYPE
  UNIT
  VARIABLE_PREFIX_UNIT
  UNIT_ID
  ALTERNATIVE_UNITS
  VALUE_FORMAT
  PATTERN
  RELATION
  DEFAULT_VALUE
  DEFAULT_DATA_SUPPLIER
  DEFAULT_DATA_VERSION
  REQUIREMENT
].freeze
DIRECTIVE_ROW_PREFIX =
"#".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSheetSchema

Returns a new instance of SheetSchema.



117
118
119
120
121
# File 'lib/opencdd/parcel/sheet_schema.rb', line 117

def initialize
  @columns = []
  @columns_by_id = {}
  @column_directives = {}
end

Instance Attribute Details

#column_directivesObject (readonly)

Returns the value of attribute column_directives.



115
116
117
# File 'lib/opencdd/parcel/sheet_schema.rb', line 115

def column_directives
  @column_directives
end

#columnsObject (readonly)

Returns the value of attribute columns.



115
116
117
# File 'lib/opencdd/parcel/sheet_schema.rb', line 115

def columns
  @columns
end

#columns_by_idObject (readonly)

Returns the value of attribute columns_by_id.



115
116
117
# File 'lib/opencdd/parcel/sheet_schema.rb', line 115

def columns_by_id
  @columns_by_id
end

#normalized_language_codesObject (readonly)

Returns the value of attribute normalized_language_codes.



115
116
117
# File 'lib/opencdd/parcel/sheet_schema.rb', line 115

def normalized_language_codes
  @normalized_language_codes
end

Class Method Details

.canonical_id(raw_id) ⇒ Object

Canonicalize a Parcel column ID. Splits language tags (.) so they round-trip cleanly. Returns the canonical ID (or the input unchanged if no mapping exists). Language codes are normalized to ISO 639-1 via Opencdd::Parcel::LanguageAliases.normalize.



27
28
29
30
31
32
33
34
35
36
# File 'lib/opencdd/parcel/sheet_schema.rb', line 27

def self.canonical_id(raw_id)
  return nil if raw_id.nil?
  s = raw_id.to_s.strip
  return nil if s.empty?
  match = s.match(/\.(?<lang>[A-Za-z0-9-]+)\z/)
  base = match ? match.pre_match : s
  lang = match && match[:lang]
  canonical = VARIANT_TO_CANONICAL[base] || base
  lang ? "#{canonical}.#{Opencdd::Parcel::LanguageAliases.normalize(lang)}" : canonical
end

.from_header_rows(rows) ⇒ Object



123
124
125
126
127
128
129
130
# File 'lib/opencdd/parcel/sheet_schema.rb', line 123

def self.from_header_rows(rows)
  schema = new
  rows.each do |row|
    schema.add_directive_row(row)
  end
  schema.finalize!
  schema
end

Instance Method Details

#[](property_id_or_name) ⇒ Object



217
218
219
# File 'lib/opencdd/parcel/sheet_schema.rb', line 217

def [](property_id_or_name)
  find_by_property_id(property_id_or_name) || find_by_name(property_id_or_name)
end

#add_column(column) ⇒ Object



152
153
154
155
156
# File 'lib/opencdd/parcel/sheet_schema.rb', line 152

def add_column(column)
  @columns << column
  @columns_by_id[column.property_id] = column
  self
end

#add_directive_row(row) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/opencdd/parcel/sheet_schema.rb', line 132

def add_directive_row(row)
  return self if row.nil? || row.empty?

  label_cell = row[0].to_s
  directive = parse_directive(label_cell)
  return self unless directive

  values = row[1..].to_a

  unless @column_directives.key?(directive)
    @column_directives[directive] = []
  end

  values.each_with_index do |val, idx|
    @column_directives[directive][idx] = val
  end

  self
end

#each(&block) ⇒ Object



233
234
235
# File 'lib/opencdd/parcel/sheet_schema.rb', line 233

def each(&block)
  @columns.each(&block)
end

#finalize!Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/opencdd/parcel/sheet_schema.rb', line 162

def finalize!
  ids = @column_directives["PROPERTY_ID"] || []
  if ids.empty? || ids.all? { |id| id.nil? || id.to_s.strip.empty? }
    ids = synthesize_ids_from_names
  end
  ids.each_with_index do |id, idx|
    next if id.nil? || id.to_s.strip.empty?

    col = Column.new(
      index: idx + 1,
      property_id: Opencdd::Parcel::SheetSchema.canonical_id(id.to_s.strip),
      raw_property_id: id.to_s.strip,
      alternate_id: lookup("ALTERNATE_ID", idx),
      super_alternate_id: lookup("SUPER_ALTERNATE_ID", idx),
      sub_alternate_id: lookup("SUB_ALTERNATE_ID", idx),
      equivalent_id: lookup("EQUIVALENT_ID", idx),
      super_property: lookup("SUPER_PROPERTY", idx),
      name_by_lang: lang_hash_for("PROPERTY_NAME", idx),
      definition_by_lang: lang_hash_for("DEFINITION", idx),
      note_by_lang: lang_hash_for("NOTE", idx),
      datatype: lookup("DATATYPE", idx),
      unit: lookup("UNIT", idx),
      variable_prefix_unit: lookup("VARIABLE_PREFIX_UNIT", idx),
      unit_id: lookup("UNIT_ID", idx),
      alternative_units: lookup("ALTERNATIVE_UNITS", idx),
      value_format: lookup("VALUE_FORMAT", idx),
      pattern: lookup("PATTERN", idx),
      relation: lookup("RELATION", idx),
      default_value: lookup("DEFAULT_VALUE", idx),
      default_data_supplier: lookup("DEFAULT_DATA_SUPPLIER", idx),
      default_data_version: lookup("DEFAULT_DATA_VERSION", idx),
      requirement: lookup("REQUIREMENT", idx),
    )
    @columns << col
    @columns_by_id[col.property_id] = col
  end

  @normalized_language_codes = compute_normalized_language_codes.freeze
  freeze
end

#finalize_for_scaffold!Object



158
159
160
# File 'lib/opencdd/parcel/sheet_schema.rb', line 158

def finalize_for_scaffold!
  freeze
end

#find_by_name(name, lang = :en) ⇒ Object



225
226
227
# File 'lib/opencdd/parcel/sheet_schema.rb', line 225

def find_by_name(name, lang = :en)
  @columns.find { |c| c.name(lang).to_s.casecmp(name.to_s).zero? }
end

#find_by_property_id(id) ⇒ Object



221
222
223
# File 'lib/opencdd/parcel/sheet_schema.rb', line 221

def find_by_property_id(id)
  @columns_by_id[id.to_s]
end

#sizeObject



229
230
231
# File 'lib/opencdd/parcel/sheet_schema.rb', line 229

def size
  @columns.size
end

#synthesize_ids_from_namesObject

Delegates to Entity::NameSynthesizer when the sheet has no #PROPERTY_ID directive row. See name_synthesizer.rb.



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/opencdd/parcel/sheet_schema.rb', line 205

def synthesize_ids_from_names
  names = nil
  @column_directives.each do |key, vals|
    base, = key.split(".", 2)
    next unless base == "PROPERTY_NAME"
    names = vals
    break
  end
  return [] unless names
  Opencdd::Entity::NameSynthesizer.synthesize(names)
end