Module: Unitsdb::Commands::Ucum::Matcher

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

Overview

Matcher for UCUM and UnitsDB entities

Class Method Summary collapse

Class Method Details

.find_db_match_for_ucum(ucum_entity, db_entities, entity_type) ⇒ Object

Find a matching UnitsDB entity for a UCUM entity



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 88

def find_db_match_for_ucum(ucum_entity, db_entities, entity_type)
  result = { match: nil, potential_match: nil }

  # Different matching logic based on entity type
  case entity_type
  when "prefixes"
    result = match_prefix_ucum_to_db(ucum_entity, db_entities)
  when "units"
    result = match_unit_ucum_to_db(ucum_entity, db_entities)
  end

  result
end

.find_referenced_ucum_entity(db_entity, ucum_entities) ⇒ Object

Find the referenced UCUM entity based on the reference URI



72
73
74
75
76
77
78
79
80
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 72

def find_referenced_ucum_entity(db_entity, ucum_entities)
  return nil unless db_entity.respond_to?(:references) && db_entity.references

  ucum_ref = db_entity.references.find { |ref| ref.authority == "ucum" }
  return nil unless ucum_ref

  ref_uri = ucum_ref.uri
  ucum_entities.find { |ucum_entity| ucum_entity.identifier == ref_uri }
end

.find_ucum_match_for_db(db_entity, ucum_entities, entity_type) ⇒ Object

Find a matching UCUM entity for a UnitsDB entity



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 103

def find_ucum_match_for_db(db_entity, ucum_entities, entity_type)
  result = { match: nil }

  # Different matching logic based on entity type
  case entity_type
  when "prefixes"
    result = match_prefix_db_to_ucum(db_entity, ucum_entities)
  when "units"
    result = match_unit_db_to_ucum(db_entity, ucum_entities)
  end

  result
end

.get_entity_id(entity) ⇒ Object

Get the ID of a UnitsDB entity



83
84
85
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 83

def get_entity_id(entity)
  entity.respond_to?(:id) ? entity.id : nil
end

.has_ucum_reference?(entity) ⇒ Boolean

Check if a UnitsDB entity already has a UCUM reference

Returns:

  • (Boolean)


65
66
67
68
69
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 65

def has_ucum_reference?(entity)
  return false unless entity.respond_to?(:references) && entity.references

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

.match_db_to_ucum(entity_type, ucum_entities, db_entities) ⇒ Object

Match UnitsDB entities to UCUM entities (UnitsDB → UCUM)



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 36

def match_db_to_ucum(entity_type, ucum_entities, db_entities)
  puts "Matching UnitsDB #{entity_type} to UCUM #{entity_type}..."

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

  # Process each UnitsDB entity
  db_entities.send(entity_type).each do |db_entity|
    # Skip entities that already have UCUM references
    if has_ucum_reference?(db_entity)
      matches << { db_entity: db_entity, ucum_entity: find_referenced_ucum_entity(db_entity, ucum_entities) }
      next
    end

    match_data = find_ucum_match_for_db(db_entity, ucum_entities, entity_type)

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

  [matches, missing_refs, unmatched_db]
end

.match_prefix_db_to_ucum(db_prefix, ucum_prefixes) ⇒ Object

Match UnitsDB prefix to UCUM prefix



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
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 164

def match_prefix_db_to_ucum(db_prefix, ucum_prefixes)
  result = { match: nil }

  # Try exact name match first
  if db_prefix.names && !db_prefix.names.empty?
    db_prefix_names = db_prefix.names.map { |name_obj| name_obj.value.downcase }

    name_match = ucum_prefixes.find do |ucum_prefix|
      db_prefix_names.include?(ucum_prefix.name.downcase)
    end

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

  # Try symbol match
  if db_prefix.symbols && !db_prefix.symbols.empty?
    symbol_match = ucum_prefixes.find do |ucum_prefix|
      db_prefix.symbols.any? do |symbol|
        ucum_prefix.print_symbol == symbol.ascii ||
          ucum_prefix.print_symbol == symbol.unicode
      end
    end

    result[:match] = symbol_match if symbol_match
  end

  result
end

.match_prefix_ucum_to_db(ucum_prefix, db_prefixes) ⇒ Object

Match UCUM prefix to UnitsDB prefix



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 118

def match_prefix_ucum_to_db(ucum_prefix, db_prefixes)
  result = { match: nil, potential_match: nil }

  # Try exact name match first
  name_match = db_prefixes.find do |db_prefix|
    db_prefix.names&.any? do |name_obj|
      name_obj.value.downcase == ucum_prefix.name.downcase
    end
  end

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

  # Try symbol match
  symbol_match = db_prefixes.find do |db_prefix|
    db_prefix.symbols&.any? do |symbol|
      symbol.ascii == ucum_prefix.print_symbol ||
        symbol.unicode == ucum_prefix.print_symbol
    end
  end

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

  # Try value match if available (using base^power)
  if ucum_prefix.value&.value
    value_match = db_prefixes.find do |db_prefix|
      if db_prefix.base && db_prefix.power
        calculated_value = db_prefix.base**db_prefix.power
        calculated_value.to_s == ucum_prefix.value.value
      else
        false
      end
    end

    result[:potential_match] = value_match if value_match
  end

  result
end

.match_ucum_to_db(entity_type, ucum_entities, db_entities) ⇒ Object

Match UCUM entities to UnitsDB entities (UCUM → UnitsDB)



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

def match_ucum_to_db(entity_type, ucum_entities, db_entities)
  puts "Matching UCUM #{entity_type} to UnitsDB #{entity_type}..."

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

  # Process each UCUM entity
  ucum_entities.each do |ucum_entity|
    match_data = find_db_match_for_ucum(ucum_entity, db_entities, entity_type)

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

  [matches, missing_matches, unmatched_ucum]
end

.match_unit_db_to_ucum(db_unit, ucum_units) ⇒ Object

Match UnitsDB unit to UCUM unit



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
# File 'lib/unitsdb/commands/ucum/matcher.rb', line 259

def match_unit_db_to_ucum(db_unit, ucum_units)
  result = { match: nil }

  # Try name match first
  if db_unit.names && !db_unit.names.empty?
    db_unit_names = db_unit.names.map { |name_obj| name_obj.value.downcase }

    name_match = ucum_units.find do |ucum_unit|
      case ucum_unit
      when Unitsdb::UcumBaseUnit
        db_unit_names.include?(ucum_unit.name.downcase)
      when Unitsdb::UcumUnit
        ucum_names = ucum_unit.name.is_a?(Array) ? ucum_unit.name : [ucum_unit.name]
        ucum_names.any? { |name| db_unit_names.include?(name.downcase) }
      else
        false
      end
    end

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

  # Try symbol match
  if db_unit.symbols && !db_unit.symbols.empty?
    symbol_match = ucum_units.find do |ucum_unit|
      db_unit.symbols.any? do |symbol|
        ucum_unit.print_symbol == symbol.ascii ||
          ucum_unit.print_symbol == symbol.unicode
      end
    end

    result[:match] = symbol_match if symbol_match
  end

  result
end

.match_unit_ucum_to_db(ucum_unit, db_units) ⇒ Object

Match UCUM unit to UnitsDB unit



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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/ucum/matcher.rb', line 197

def match_unit_ucum_to_db(ucum_unit, db_units)
  result = { match: nil, potential_match: nil }

  # Get UCUM unit name(s)
  ucum_names = case ucum_unit
               when Unitsdb::UcumBaseUnit
                 [ucum_unit.name]
               when Unitsdb::UcumUnit
                 ucum_unit.name.is_a?(Array) ? ucum_unit.name : [ucum_unit.name]
               else
                 []
               end

  # Try name match
  ucum_names.each do |ucum_name|
    name_match = db_units.find do |db_unit|
      db_unit.names&.any? do |name_obj|
        name_obj.value.downcase == ucum_name.downcase
      end
    end

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

  # Try symbol match
  symbol_match = db_units.find do |db_unit|
    db_unit.symbols&.any? do |symbol|
      symbol.ascii == ucum_unit.print_symbol ||
        symbol.unicode == ucum_unit.print_symbol
    end
  end

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

  # Try property/dimension match for potential matches
  property = case ucum_unit
             when Unitsdb::UcumBaseUnit
               ucum_unit.property
             when Unitsdb::UcumUnit
               ucum_unit.property
             end

  if property
    property_matches = db_units.select do |db_unit|
      db_unit.quantity_references&.any? do |qref|
        qref.id&.downcase&.include?(property.downcase)
      end
    end

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

  result
end