Module: Unitsdb::Commands::Qudt::Matcher

Defined in:
lib/unitsdb/commands/qudt/matcher.rb

Overview

Matcher for QUDT and UnitsDB entities

Class Method Summary collapse

Class Method Details

.dimensions_match?(qudt_dimension, db_dimension) ⇒ Boolean

Check if QUDT dimension vector matches UnitsDB dimension

Returns:

  • (Boolean)


522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 522

def dimensions_match?(qudt_dimension, db_dimension)
  return false unless qudt_dimension.is_a?(Unitsdb::QudtDimensionVector)

  # Map QUDT dimension exponents to UnitsDB dimension structure
  qudt_exponents = {
    length: qudt_dimension.dimension_exponent_for_length || 0,
    mass: qudt_dimension.dimension_exponent_for_mass || 0,
    time: qudt_dimension.dimension_exponent_for_time || 0,
    electric_current: qudt_dimension.dimension_exponent_for_electric_current || 0,
    thermodynamic_temperature: qudt_dimension.dimension_exponent_for_thermodynamic_temperature || 0,
    amount_of_substance: qudt_dimension.dimension_exponent_for_amount_of_substance || 0,
    luminous_intensity: qudt_dimension.dimension_exponent_for_luminous_intensity || 0,
  }

  # Get UnitsDB dimension exponents from direct properties
  db_exponents = {
    length: get_dimension_power(db_dimension, :length),
    mass: get_dimension_power(db_dimension, :mass),
    time: get_dimension_power(db_dimension, :time),
    electric_current: get_dimension_power(db_dimension,
                                          :electric_current),
    thermodynamic_temperature: get_dimension_power(db_dimension,
                                                   :thermodynamic_temperature),
    amount_of_substance: get_dimension_power(db_dimension,
                                             :amount_of_substance),
    luminous_intensity: get_dimension_power(db_dimension,
                                            :luminous_intensity),
  }

  # Compare all dimension exponents
  qudt_exponents == db_exponents
end

.find_db_match_for_qudt(qudt_entity, db_entities, entity_type) ⇒ Object

Find a matching UnitsDB entity for a QUDT entity



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 95

def find_db_match_for_qudt(qudt_entity, db_entities, entity_type)
  result = { match: nil, potential_match: nil }

  # Different matching logic based on entity type
  case entity_type
  when "units"
    result = match_unit_qudt_to_db(qudt_entity, db_entities)
  when "quantities"
    result = match_quantity_qudt_to_db(qudt_entity, db_entities)
  when "dimensions"
    result = match_dimension_qudt_to_db(qudt_entity, db_entities)
  when "unit_systems"
    result = match_unit_system_qudt_to_db(qudt_entity, db_entities)
  when "prefixes"
    result = match_prefix_qudt_to_db(qudt_entity, db_entities)
  end

  result
end

.find_qudt_match_for_db(db_entity, qudt_entities, entity_type) ⇒ Object

Find a matching QUDT entity for a UnitsDB entity



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 116

def find_qudt_match_for_db(db_entity, qudt_entities, entity_type)
  result = { match: nil }

  # Different matching logic based on entity type
  case entity_type
  when "units"
    result = match_unit_db_to_qudt(db_entity, qudt_entities)
  when "quantities"
    result = match_quantity_db_to_qudt(db_entity, qudt_entities)
  when "dimensions"
    result = match_dimension_db_to_qudt(db_entity, qudt_entities)
  when "unit_systems"
    result = match_unit_system_db_to_qudt(db_entity, qudt_entities)
  when "prefixes"
    result = match_prefix_db_to_qudt(db_entity, qudt_entities)
  end

  result
end

.find_referenced_qudt_entity(db_entity, qudt_entities) ⇒ Object

Find the referenced QUDT entity based on the reference URI



79
80
81
82
83
84
85
86
87
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 79

def find_referenced_qudt_entity(db_entity, qudt_entities)
  return nil unless db_entity.references

  qudt_ref = db_entity.references.find { |ref| ref.authority == "qudt" }
  return nil unless qudt_ref

  ref_uri = qudt_ref.uri
  qudt_entities.find { |qudt_entity| qudt_entity.uri == ref_uri }
end

.find_unit_by_si_reference(si_uri, db_units) ⇒ Object

Find a UnitsDB unit that has an SI reference matching the given SI URI



579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 579

def find_unit_by_si_reference(si_uri, db_units)
  return nil unless si_uri

  # Extract the SI unit identifier from the URI
  # Example: "http://qudt.org/vocab/unit/M" -> "M"
  si_identifier = si_uri.split("/").last

  # Look for a UnitsDB unit that has an SI reference with this identifier
  db_units.find do |db_unit|
    next unless db_unit.references

    db_unit.references.any? do |ref|
      ref.authority == "si" && (
        ref.uri&.end_with?(si_identifier) ||
        ref.uri&.include?(si_identifier)
      )
    end
  end
end

.get_dimension_power(db_dimension, dimension_type) ⇒ Object

Get dimension power from UnitsDB dimension entity. Dimension declares all seven dimension-type attrs as DimensionDetails; DimensionDetails always has power.



558
559
560
561
562
563
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 558

def get_dimension_power(db_dimension, dimension_type)
  property = db_dimension.public_send(dimension_type)
  return 0 unless property

  property.power || 0
end

.get_entity_id(_entity) ⇒ Object

Get the ID of a UnitsDB entity



90
91
92
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 90

def get_entity_id(_entity)
  nil
end

.has_qudt_reference?(entity) ⇒ Boolean

Check if a UnitsDB entity already has a QUDT reference

Returns:

  • (Boolean)


72
73
74
75
76
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 72

def has_qudt_reference?(entity)
  return false unless entity.references

  entity.references.any? { |ref| ref.authority == "qudt" }
end

.manually_verified?(entity) ⇒ Boolean

Check if an entity has been manually verified (has a special flag)

Returns:

  • (Boolean)


726
727
728
729
730
731
732
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 726

def manually_verified?(entity)
  return false unless entity.references

  entity.references.any? do |_ref|
    false
  end
end

.match_db_to_qudt(entity_type, qudt_entities, db_entities) ⇒ Object

Match UnitsDB entities to QUDT entities (UnitsDB → QUDT)



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 39

def match_db_to_qudt(entity_type, qudt_entities, db_entities)
  puts "Matching UnitsDB #{entity_type} to QUDT #{entity_type}..."

  # Initialize result arrays
  matches = []
  missing_refs = []
  unmatched_db = []

  # Process each UnitsDB entity
  db_entities.each do |db_entity|
    # Skip entities that already have QUDT references
    if has_qudt_reference?(db_entity)
      matches << { db_entity: db_entity,
                   qudt_entity: find_referenced_qudt_entity(db_entity,
                                                            qudt_entities) }
      next
    end

    match_data = find_qudt_match_for_db(db_entity, qudt_entities,
                                        entity_type)

    if match_data[:match]
      missing_refs << { db_entity: db_entity,
                        qudt_entity: match_data[:match] }
    else
      unmatched_db << db_entity
    end
  end

  [matches, missing_refs, unmatched_db]
end

.match_dimension_db_to_qudt(db_dimension, qudt_dimensions) ⇒ Object

Match UnitsDB dimension to QUDT dimension vector



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 385

def match_dimension_db_to_qudt(db_dimension, qudt_dimensions)
  result = { match: nil }

  # Try dimensional analysis match first (most reliable)
  dimensional_match = qudt_dimensions.find do |qudt_dimension|
    dimensions_match?(qudt_dimension, db_dimension)
  end

  if dimensional_match
    result[:match] = dimensional_match
    return result
  end

  # Try name match as fallback
  if db_dimension.names && !db_dimension.names.empty?
    db_dimension_names = db_dimension.names.map do |name_obj|
      name_obj.value.downcase
    end

    name_match = qudt_dimensions.find do |qudt_dimension|
      qudt_dimension.label && db_dimension_names.include?(qudt_dimension.label.downcase)
    end

    result[:match] = name_match if name_match
  end

  result
end

.match_dimension_qudt_to_db(qudt_dimension, db_dimensions) ⇒ Object

Match QUDT dimension vector to UnitsDB dimension



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 355

def match_dimension_qudt_to_db(qudt_dimension, db_dimensions)
  result = { match: nil, potential_match: nil }

  # Try dimensional analysis match first (most reliable for dimension vectors)
  dimensional_match = db_dimensions.find do |db_dimension|
    dimensions_match?(qudt_dimension, db_dimension)
  end

  if dimensional_match
    result[:match] = dimensional_match
    return result
  end

  # Try exact label match as fallback
  if qudt_dimension.label
    label_match = db_dimensions.find do |db_dimension|
      db_dimension.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_dimension.label.downcase
      end
    end

    if label_match
      result[:potential_match] = label_match
    end
  end

  result
end

.match_prefix_db_to_qudt(db_prefix, qudt_prefixes) ⇒ Object

Match UnitsDB prefix to QUDT prefix



666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 666

def match_prefix_db_to_qudt(db_prefix, qudt_prefixes)
  result = { match: nil }

  # PRIORITY 1: Try symbol match first (most reliable)
  if db_prefix.symbols && !db_prefix.symbols.empty?
    symbol_match = qudt_prefixes.find do |qudt_prefix|
      qudt_prefix.symbol && db_prefix.symbols.any? do |symbol|
        qudt_prefix.symbol.downcase == symbol.ascii&.downcase ||
          qudt_prefix.symbol.downcase == symbol.unicode&.downcase
      end
    end

    if symbol_match
      result[:match] = symbol_match
      return result
    end
  end

  # PRIORITY 2: Try exact name match
  if db_prefix.names && !db_prefix.names.empty?
    db_prefix_names = db_prefix.names.map do |name_obj|
      name_obj.value.downcase
    end

    name_match = qudt_prefixes.find do |qudt_prefix|
      qudt_prefix.label && db_prefix_names.include?(qudt_prefix.label.downcase)
    end

    if name_match
      result[:match] = name_match
      return result
    end

    # PRIORITY 3: Try normalized name matching
    normalized_match = qudt_prefixes.find do |qudt_prefix|
      qudt_prefix.label && db_prefix_names.any? do |db_name|
        normalize_name(qudt_prefix.label) == normalize_name(db_name)
      end
    end

    if normalized_match
      result[:match] = normalized_match
      return result
    end
  end

  # PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
  if false
    multiplier_match = qudt_prefixes.find do |qudt_prefix|
      qudt_prefix.prefix_multiplier &&
        (qudt_prefix.prefix_multiplier - db_prefix.factor).abs < 1e-10
    end

    result[:match] = multiplier_match if multiplier_match
  end

  result
end

.match_prefix_qudt_to_db(qudt_prefix, db_prefixes) ⇒ Object

Match QUDT prefix to UnitsDB prefix



600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 600

def match_prefix_qudt_to_db(qudt_prefix, db_prefixes)
  result = { match: nil, potential_match: nil }

  # PRIORITY 1: Try UCUM code match first (most reliable for prefixes)
  if qudt_prefix.ucum_code
    ucum_match = db_prefixes.find do |db_prefix|
      (db_prefix.references || [])&.any? do |ref|
        ref.authority == "ucum" && ref.uri&.include?(qudt_prefix.ucum_code)
      end
    end

    if ucum_match
      result[:match] = ucum_match
      return result
    end
  end

  # PRIORITY 2: Try symbol match (very reliable for prefixes)
  if qudt_prefix.symbol
    symbol_match = db_prefixes.find do |db_prefix|
      db_prefix.symbols&.any? do |symbol|
        symbol.ascii&.downcase == qudt_prefix.symbol.downcase ||
          symbol.unicode&.downcase == qudt_prefix.symbol.downcase
      end
    end

    if symbol_match
      result[:match] = symbol_match
      return result
    end
  end

  # PRIORITY 3: Try exact label match
  if qudt_prefix.label
    label_match = db_prefixes.find do |db_prefix|
      db_prefix.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_prefix.label.downcase
      end
    end

    if label_match
      result[:match] = label_match
      return result
    end
  end

  # PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
  # Skipped: Unitsdb::Prefix has no `factor` attribute in 2.0.

  # PRIORITY 5: Try normalized name matching
  if qudt_prefix.label
    normalized_match = db_prefixes.find do |db_prefix|
      db_prefix.names&.any? do |name_obj|
        normalize_name(qudt_prefix.label) == normalize_name(name_obj.value)
      end
    end

    if normalized_match
      result[:potential_match] = normalized_match
    end
  end

  result
end

.match_quantity_db_to_qudt(db_quantity, qudt_quantities) ⇒ Object

Match UnitsDB quantity to QUDT quantity kind



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 323

def match_quantity_db_to_qudt(db_quantity, qudt_quantities)
  result = { match: nil }

  # Try name match first
  if db_quantity.names && !db_quantity.names.empty?
    db_quantity_names = db_quantity.names.map do |name_obj|
      name_obj.value.downcase
    end

    name_match = qudt_quantities.find do |qudt_quantity|
      qudt_quantity.label && db_quantity_names.include?(qudt_quantity.label.downcase)
    end

    if name_match
      result[:match] = name_match
      return result
    end

    # Try normalized name matching
    normalized_match = qudt_quantities.find do |qudt_quantity|
      qudt_quantity.label && db_quantity_names.any? do |db_name|
        normalize_name(qudt_quantity.label) == normalize_name(db_name)
      end
    end

    result[:match] = normalized_match if normalized_match
  end

  result
end

.match_quantity_qudt_to_db(qudt_quantity, db_quantities) ⇒ Object

Match QUDT quantity kind to UnitsDB quantity



259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 259

def match_quantity_qudt_to_db(qudt_quantity, db_quantities)
  result = { match: nil, potential_match: nil }

  # Try exact label match first
  if qudt_quantity.label
    label_match = db_quantities.find do |db_quantity|
      db_quantity.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_quantity.label.downcase
      end
    end

    if label_match
      result[:match] = label_match
      return result
    end
  end

  # Try symbol match if available
  if qudt_quantity.symbol
    symbol_match = db_quantities.find do |db_quantity|
      db_quantity.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_quantity.symbol.downcase
      end
    end

    if symbol_match
      result[:match] = symbol_match
      return result
    end
  end

  # Try normalized name matching (remove common variations)
  if qudt_quantity.label
    normalized_match = db_quantities.find do |db_quantity|
      db_quantity.names&.any? do |name_obj|
        normalize_name(qudt_quantity.label) == normalize_name(name_obj.value)
      end
    end

    if normalized_match
      result[:match] = normalized_match
      return result
    end
  end

  # Try partial name match for potential matches
  if qudt_quantity.label
    partial_matches = db_quantities.select do |db_quantity|
      db_quantity.names&.any? do |name_obj|
        name_obj.value.downcase.include?(qudt_quantity.label.downcase) ||
          qudt_quantity.label.downcase.include?(name_obj.value.downcase)
      end
    end

    if partial_matches.any?
      result[:potential_match] =
        partial_matches.first
    end
  end

  result
end

.match_qudt_to_db(entity_type, qudt_entities, db_entities) ⇒ Object

Match QUDT entities to UnitsDB entities (QUDT → UnitsDB)



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 11

def match_qudt_to_db(entity_type, qudt_entities, db_entities)
  puts "Matching QUDT #{entity_type} to UnitsDB #{entity_type}..."

  # Initialize result arrays
  matches = []
  missing_matches = []
  unmatched_qudt = []

  # Process each QUDT entity
  qudt_entities.each do |qudt_entity|
    match_data = find_db_match_for_qudt(qudt_entity, db_entities,
                                        entity_type)

    if match_data[:match]
      matches << { qudt_entity: qudt_entity,
                   db_entity: match_data[:match] }
    elsif match_data[:potential_match]
      missing_matches << { qudt_entity: qudt_entity,
                           db_entity: match_data[:potential_match] }
    else
      unmatched_qudt << qudt_entity
    end
  end

  [matches, missing_matches, unmatched_qudt]
end

.match_unit_db_to_qudt(db_unit, qudt_units) ⇒ Object

Match UnitsDB unit to QUDT unit



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 212

def match_unit_db_to_qudt(db_unit, qudt_units)
  result = { match: nil }

  # PRIORITY 1: Try symbol match first (most reliable)
  if db_unit.symbols && !db_unit.symbols.empty?
    symbol_match = qudt_units.find do |qudt_unit|
      qudt_unit.symbol && db_unit.symbols.any? do |symbol|
        qudt_unit.symbol.downcase == symbol.ascii&.downcase ||
          qudt_unit.symbol.downcase == symbol.unicode&.downcase
      end
    end

    if symbol_match
      result[:match] = symbol_match
      return result
    end
  end

  # PRIORITY 2: Try exact name match
  if db_unit.names && !db_unit.names.empty?
    db_unit_names = db_unit.names.map do |name_obj|
      name_obj.value.downcase
    end

    name_match = qudt_units.find do |qudt_unit|
      qudt_unit.label && db_unit_names.include?(qudt_unit.label.downcase)
    end

    if name_match
      result[:match] = name_match
      return result
    end

    # PRIORITY 3: Try normalized name matching
    normalized_match = qudt_units.find do |qudt_unit|
      qudt_unit.label && db_unit_names.any? do |db_name|
        normalize_name(qudt_unit.label) == normalize_name(db_name)
      end
    end

    result[:match] = normalized_match if normalized_match
  end

  result
end

.match_unit_qudt_to_db(qudt_unit, db_units) ⇒ Object

Match QUDT unit to UnitsDB unit



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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
202
203
204
205
206
207
208
209
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 137

def match_unit_qudt_to_db(qudt_unit, db_units)
  result = { match: nil, potential_match: nil }

  # PRIORITY 0: Try SI exact match first (highest confidence)
  if qudt_unit.si_exact_match
    si_match = find_unit_by_si_reference(qudt_unit.si_exact_match,
                                         db_units)
    if si_match
      result[:match] = si_match
      return result
    end
  end

  # PRIORITY 1: Try symbol match (most reliable)
  if qudt_unit.symbol
    symbol_match = db_units.find do |db_unit|
      db_unit.symbols&.any? do |symbol|
        symbol.ascii&.downcase == qudt_unit.symbol.downcase ||
          symbol.unicode&.downcase == qudt_unit.symbol.downcase
      end
    end

    if symbol_match
      result[:match] = symbol_match
      return result
    end
  end

  # PRIORITY 2: Try exact label match
  if qudt_unit.label
    label_match = db_units.find do |db_unit|
      db_unit.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_unit.label.downcase
      end
    end

    if label_match
      result[:match] = label_match
      return result
    end
  end

  # PRIORITY 3: Try normalized name matching (remove common variations)
  if qudt_unit.label
    normalized_match = db_units.find do |db_unit|
      db_unit.names&.any? do |name_obj|
        normalize_name(qudt_unit.label) == normalize_name(name_obj.value)
      end
    end

    if normalized_match
      result[:match] = normalized_match
      return result
    end
  end

  # PRIORITY 4: Try partial name match for potential matches (be conservative)
  if qudt_unit.label && qudt_unit.label.length > 3
    partial_matches = db_units.select do |db_unit|
      db_unit.names&.any? do |name_obj|
        name_obj.value.downcase.include?(qudt_unit.label.downcase) ||
          qudt_unit.label.downcase.include?(name_obj.value.downcase)
      end
    end

    if partial_matches.any?
      result[:potential_match] =
        partial_matches.first
    end
  end

  result
end

.match_unit_system_db_to_qudt(db_system, qudt_systems) ⇒ Object

Match UnitsDB unit system to QUDT system of units



479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 479

def match_unit_system_db_to_qudt(db_system, qudt_systems)
  result = { match: nil }

  # Try name match first
  if db_system.names && !db_system.names.empty?
    db_system_names = db_system.names.map do |name_obj|
      name_obj.value.downcase
    end

    name_match = qudt_systems.find do |qudt_system|
      (qudt_system.label && db_system_names.include?(qudt_system.label.downcase)) ||
        (qudt_system.abbreviation && db_system_names.include?(qudt_system.abbreviation.downcase))
    end

    if name_match
      result[:match] = name_match
      return result
    end

    # Try smart matching for known systems
    smart_match = qudt_systems.find do |qudt_system|
      db_system_names.any? do |db_name|
        if db_name.include?("si") && qudt_system.abbreviation&.downcase == "si"
          true
        elsif db_name.include?("cgs") && qudt_system.abbreviation&.downcase == "cgs"
          true
        elsif db_name.include?("imperial") && qudt_system.abbreviation&.downcase == "imperial"
          true
        elsif (db_name.include?("us") || db_name.include?("customary")) && qudt_system.abbreviation&.downcase == "us customary"
          true
        else
          false
        end
      end
    end

    result[:match] = smart_match if smart_match
  end

  result
end

.match_unit_system_qudt_to_db(qudt_system, db_unit_systems) ⇒ Object

Match QUDT system of units to UnitsDB unit system



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 415

def match_unit_system_qudt_to_db(qudt_system, db_unit_systems)
  result = { match: nil, potential_match: nil }

  # Try exact label match first
  if qudt_system.label
    label_match = db_unit_systems.find do |db_system|
      db_system.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_system.label.downcase
      end
    end

    if label_match
      result[:match] = label_match
      return result
    end
  end

  # Try abbreviation match
  if qudt_system.abbreviation
    abbrev_match = db_unit_systems.find do |db_system|
      db_system.names&.any? do |name_obj|
        name_obj.value.downcase == qudt_system.abbreviation.downcase
      end
    end

    if abbrev_match
      result[:match] = abbrev_match
      return result
    end
  end

  # Try smart matching for known systems
  if qudt_system.abbreviation
    smart_match = db_unit_systems.find do |db_system|
      db_system.names&.any? do |name_obj|
        case qudt_system.abbreviation.downcase
        when "si"
          # Match SI abbreviation to any system containing "si"
          name_obj.value.downcase.include?("si")
        when "cgs"
          # Match CGS abbreviation to any system containing "cgs"
          name_obj.value.downcase.include?("cgs")
        when "imperial"
          # Match Imperial to any system containing "imperial"
          name_obj.value.downcase.include?("imperial")
        when "us customary"
          # Match US Customary to any system containing "us" or "customary"
          name_obj.value.downcase.include?("us") || name_obj.value.downcase.include?("customary")
        else
          false
        end
      end
    end

    if smart_match
      result[:match] = smart_match
      return result
    end
  end

  result
end

.normalize_name(name) ⇒ Object

Normalize names by removing common variations and punctuation



566
567
568
569
570
571
572
573
574
575
576
# File 'lib/unitsdb/commands/qudt/matcher.rb', line 566

def normalize_name(name)
  return "" unless name

  name.downcase
    .gsub(/\s+/, " ")           # normalize whitespace
    .gsub(/[-_]/, " ")          # convert dashes/underscores to spaces
    .gsub(/[()\\]/, "") # remove parentheses and brackets
    .gsub(/\bof\b/, "")         # remove "of"
    .gsub(/\bper\b/, "/")       # convert "per" to "/"
    .strip
end