unitsdb 2.2.1 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/opal.yml +36 -0
  3. data/.gitignore +3 -0
  4. data/Gemfile +1 -0
  5. data/Rakefile +3 -1
  6. data/lib/unitsdb/cli.rb +5 -41
  7. data/lib/unitsdb/commands/_modify.rb +1 -34
  8. data/lib/unitsdb/commands/check_si/si_formatter.rb +6 -6
  9. data/lib/unitsdb/commands/check_si/si_matcher.rb +202 -292
  10. data/lib/unitsdb/commands/check_si/si_updater.rb +16 -36
  11. data/lib/unitsdb/commands/entity_presenter.rb +98 -0
  12. data/lib/unitsdb/commands/get.rb +16 -113
  13. data/lib/unitsdb/commands/qudt/formatter.rb +16 -27
  14. data/lib/unitsdb/commands/qudt/matcher.rb +18 -28
  15. data/lib/unitsdb/commands/qudt/updater.rb +8 -11
  16. data/lib/unitsdb/commands/qudt.rb +1 -34
  17. data/lib/unitsdb/commands/search.rb +33 -188
  18. data/lib/unitsdb/commands/thor.rb +41 -0
  19. data/lib/unitsdb/commands/ucum/formatter.rb +9 -18
  20. data/lib/unitsdb/commands/ucum/matcher.rb +4 -4
  21. data/lib/unitsdb/commands/ucum/updater.rb +3 -5
  22. data/lib/unitsdb/commands/ucum.rb +1 -34
  23. data/lib/unitsdb/commands/validate/qudt_references.rb +29 -70
  24. data/lib/unitsdb/commands/validate/references.rb +5 -303
  25. data/lib/unitsdb/commands/validate/si_references.rb +30 -66
  26. data/lib/unitsdb/commands/validate/ucum_references.rb +30 -64
  27. data/lib/unitsdb/commands/validate.rb +1 -36
  28. data/lib/unitsdb/commands.rb +2 -0
  29. data/lib/unitsdb/config.rb +170 -4
  30. data/lib/unitsdb/database/loader.rb +135 -0
  31. data/lib/unitsdb/database/reference_validator.rb +227 -0
  32. data/lib/unitsdb/database/uniqueness_validator.rb +80 -0
  33. data/lib/unitsdb/database.rb +127 -588
  34. data/lib/unitsdb/dimension.rb +2 -27
  35. data/lib/unitsdb/dimension_details.rb +2 -0
  36. data/lib/unitsdb/dimension_reference.rb +2 -0
  37. data/lib/unitsdb/dimensions.rb +2 -2
  38. data/lib/unitsdb/external_reference.rb +2 -0
  39. data/lib/unitsdb/identifier.rb +2 -0
  40. data/lib/unitsdb/localized_string.rb +2 -0
  41. data/lib/unitsdb/opal.rb +43 -0
  42. data/lib/unitsdb/prefix.rb +2 -13
  43. data/lib/unitsdb/prefix_reference.rb +2 -0
  44. data/lib/unitsdb/prefixes.rb +2 -2
  45. data/lib/unitsdb/quantities.rb +2 -1
  46. data/lib/unitsdb/quantity.rb +2 -2
  47. data/lib/unitsdb/quantity_reference.rb +2 -2
  48. data/lib/unitsdb/qudt.rb +5 -0
  49. data/lib/unitsdb/root_unit_reference.rb +2 -2
  50. data/lib/unitsdb/scale.rb +2 -2
  51. data/lib/unitsdb/scale_properties.rb +2 -1
  52. data/lib/unitsdb/scale_reference.rb +2 -0
  53. data/lib/unitsdb/scales.rb +2 -1
  54. data/lib/unitsdb/si_derived_base.rb +2 -1
  55. data/lib/unitsdb/symbol_presentations.rb +2 -2
  56. data/lib/unitsdb/ucum.rb +7 -0
  57. data/lib/unitsdb/unit.rb +2 -34
  58. data/lib/unitsdb/unit_reference.rb +2 -0
  59. data/lib/unitsdb/unit_system.rb +2 -2
  60. data/lib/unitsdb/unit_system_reference.rb +2 -0
  61. data/lib/unitsdb/unit_systems.rb +2 -2
  62. data/lib/unitsdb/units.rb +2 -2
  63. data/lib/unitsdb/version.rb +1 -1
  64. data/lib/unitsdb.rb +134 -27
  65. data/unitsdb.gemspec +1 -0
  66. metadata +23 -2
@@ -13,24 +13,9 @@ module Unitsdb
13
13
  module_function
14
14
 
15
15
  # Update references in YAML file (TTL → DB direction)
16
- def update_references(entity_type, missing_matches, db_entities,
16
+ def update_references(entity_type, missing_matches, _db_entities,
17
17
  output_file, include_potential = false)
18
- # Use the database objects to access the data directly
19
- original_yaml_file = db_entities.first.send(:yaml_file) if db_entities&.first.respond_to?(
20
- :yaml_file, true
21
- )
22
-
23
- # If we can't get the path from the database object, use the output file path as a fallback
24
- if original_yaml_file.nil? || !File.exist?(original_yaml_file)
25
- puts "Warning: Could not determine original YAML file path. Using output file as template."
26
- original_yaml_file = output_file
27
-
28
- # Create an empty template if output file doesn't exist
29
- unless File.exist?(original_yaml_file)
30
- FileUtils.mkdir_p(File.dirname(original_yaml_file))
31
- File.write(original_yaml_file, { entity_type => [] }.to_yaml)
32
- end
33
- end
18
+ original_yaml_file = resolve_yaml_file(output_file, entity_type)
34
19
 
35
20
  # Load the original YAML file
36
21
  yaml_content = File.read(original_yaml_file)
@@ -111,23 +96,7 @@ module Unitsdb
111
96
  # Update references in YAML file (DB → TTL direction)
112
97
  def update_db_references(entity_type, missing_refs, output_file,
113
98
  include_potential = false)
114
- # Try to get the original YAML file from the first entity
115
- first_entity = missing_refs.first&.dig(:db_entity)
116
- original_yaml_file = first_entity.send(:yaml_file) if first_entity.respond_to?(
117
- :yaml_file, true
118
- )
119
-
120
- # If we can't get the path from the database object, use the output file path as a fallback
121
- if original_yaml_file.nil? || !File.exist?(original_yaml_file)
122
- puts "Warning: Could not determine original YAML file path. Using output file as template."
123
- original_yaml_file = output_file
124
-
125
- # Create an empty template if output file doesn't exist
126
- unless File.exist?(original_yaml_file)
127
- FileUtils.mkdir_p(File.dirname(original_yaml_file))
128
- File.write(original_yaml_file, { entity_type => [] }.to_yaml)
129
- end
130
- end
99
+ original_yaml_file = resolve_yaml_file(output_file, entity_type)
131
100
 
132
101
  # Load the original YAML file
133
102
  yaml_content = File.read(original_yaml_file)
@@ -146,7 +115,7 @@ module Unitsdb
146
115
  # Check if it's an exact match or if we're including potential matches
147
116
  match_type = match_types[ttl_entity[:uri]] || "Exact match" # Default to exact match
148
117
  match_pair_key = "#{entity_id}:#{ttl_entity[:uri]}"
149
- match_details = Unitsdb::Commands::CheckSi::SiMatcher.instance_variable_get(:@match_details)&.dig(match_pair_key)
118
+ match_details = Unitsdb::Commands::CheckSi::SiMatcher.match_details&.dig(match_pair_key)
150
119
 
151
120
  if match_details && %w[symbol_match
152
121
  partial_match].include?(match_details[:match_desc])
@@ -208,9 +177,20 @@ module Unitsdb
208
177
  write_yaml_file(output_file, output_data)
209
178
  end
210
179
 
180
+ # Resolve which YAML file to read from. Caller supplies
181
+ # `output_file` as the canonical path; if it doesn't exist
182
+ # yet we seed it with an empty `{entity_type => []}` template.
183
+ def resolve_yaml_file(output_file, entity_type)
184
+ unless File.exist?(output_file)
185
+ FileUtils.mkdir_p(File.dirname(output_file))
186
+ File.write(output_file, { entity_type => [] }.to_yaml)
187
+ end
188
+ output_file
189
+ end
190
+
211
191
  # Helper to write YAML file
192
+ # Ensure the output directory exists
212
193
  def write_yaml_file(output_file, output_data)
213
- # Ensure the output directory exists
214
194
  output_dir = File.dirname(output_file)
215
195
  FileUtils.mkdir_p(output_dir)
216
196
 
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ module Commands
5
+ # Present a single entity as text for the Get/Search CLI commands.
6
+ # Pulls every displayable field off the typed model — no
7
+ # `respond_to?` feature detection. New entity types extend
8
+ # `TYPE_NAME` and `extras`; nothing else changes.
9
+ class EntityPresenter
10
+ TYPE_NAME = {
11
+ Unitsdb::Unit => "Unit",
12
+ Unitsdb::Prefix => "Prefix",
13
+ Unitsdb::Quantity => "Quantity",
14
+ Unitsdb::Dimension => "Dimension",
15
+ Unitsdb::UnitSystem => "UnitSystem",
16
+ }.freeze
17
+
18
+ def initialize(entity)
19
+ @entity = entity
20
+ end
21
+
22
+ # Human-readable type label, e.g. "Unit", "Prefix".
23
+ def type_name
24
+ TYPE_NAME[@entity.class] || @entity.class.name.split("::").last
25
+ end
26
+
27
+ # Best-effort display name: first localized name value → short → "N/A".
28
+ def display_name
29
+ name = @entity.names.first
30
+ return name.value.to_s if name&.value
31
+ return @entity.short.to_s if @entity.short
32
+
33
+ "N/A"
34
+ end
35
+
36
+ # Multi-line "details" output for `unitsdb get ID`.
37
+ def print_details
38
+ puts "Entity details:"
39
+ puts " - Type: #{type_name}"
40
+ puts " - Name: #{display_name}"
41
+ puts " - Description: #{@entity.short}" if show_short?
42
+ print_identifiers(header: " - Identifiers:", item_indent: " ")
43
+ print_extras
44
+ print_references
45
+ end
46
+
47
+ # Single-block summary used by `unitsdb search` per result.
48
+ def print_summary
49
+ puts " - #{type_name}: #{display_name}"
50
+ print_identifiers(header: " IDs:", item_indent: " ")
51
+ puts " Description: #{@entity.short}" if show_short?
52
+ puts ""
53
+ end
54
+
55
+ private
56
+
57
+ def show_short?
58
+ @entity.short && @entity.short != display_name
59
+ end
60
+
61
+ def print_identifiers(header:, item_indent:)
62
+ identifiers = @entity.identifiers
63
+ if identifiers.empty?
64
+ puts "#{header} None"
65
+ return
66
+ end
67
+
68
+ puts header
69
+ identifiers.each do |id|
70
+ puts "#{item_indent}- #{id.id} (Type: #{id.type || 'N/A'})"
71
+ end
72
+ end
73
+
74
+ def print_extras
75
+ case @entity
76
+ when Unitsdb::Unit
77
+ print_unit_symbols
78
+ end
79
+ end
80
+
81
+ def print_unit_symbols
82
+ return unless @entity.symbols.any?
83
+
84
+ puts " - Symbols:"
85
+ @entity.symbols.each { |s| puts " - #{s}" }
86
+ end
87
+
88
+ def print_references
89
+ return unless @entity.references.any?
90
+
91
+ puts " - References:"
92
+ @entity.references.each do |ref|
93
+ puts " - #{ref.type}: #{ref.uri}"
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -1,133 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
4
-
5
3
  module Unitsdb
6
4
  module Commands
7
5
  class Get < Base
8
6
  def get(id)
9
- # Database path is guaranteed by Thor's global option
10
7
  id_type = @options[:id_type]
11
8
  format = @options[:format] || "text"
12
9
 
13
- begin
14
- database = load_database(@options[:database])
15
-
16
- # Search by ID
17
- entity = database.get_by_id(id: id, type: id_type)
18
-
19
- unless entity
20
- puts "No entity found with ID: '#{id}'"
21
- return
22
- end
10
+ database = load_database(@options[:database])
11
+ entity = database.get_by_id(id: id, type: id_type)
23
12
 
24
- # Output based on format
25
- if %w[json yaml].include?(format.downcase)
26
- begin
27
- puts entity.send("to_#{format.downcase}")
28
- return
29
- rescue NoMethodError
30
- raise Unitsdb::Errors::InvalidFormatError,
31
- "Unable to convert entity to #{format.upcase} format: output format not supported for this entity type"
32
- end
33
- end
34
-
35
- # Default text output
36
- print_entity_details(entity)
37
- rescue Unitsdb::Errors::DatabaseError => e
38
- raise Unitsdb::Errors::DatabaseLoadError,
39
- "Failed to load database: #{e.message}"
40
- rescue StandardError => e
41
- raise Unitsdb::Errors::CLIRuntimeError, "Search failed: #{e.message}"
13
+ if entity.nil?
14
+ puts "No entity found with ID: '#{id}'"
15
+ return
42
16
  end
43
- end
44
-
45
- private
46
-
47
- def print_entity_details(entity)
48
- # Determine entity type
49
- entity_type = get_entity_type(entity)
50
-
51
- # Get name
52
- name = get_entity_name(entity)
53
17
 
54
- puts "Entity details:"
55
- puts " - Type: #{entity_type}"
56
- puts " - Name: #{name}"
57
-
58
- # Print description if available
59
- puts " - Description: #{entity.short}" if entity.respond_to?(:short) && entity.short && entity.short != name
60
-
61
- # Print all identifiers
62
- if entity.identifiers&.any?
63
- puts " - Identifiers:"
64
- entity.identifiers.each do |id|
65
- puts " - #{id.id} (Type: #{id.type || 'N/A'})"
66
- end
18
+ if %w[json yaml].include?(format.downcase)
19
+ print_serialized(entity, format.downcase)
67
20
  else
68
- puts " - Identifiers: None"
69
- end
70
-
71
- # Print additional properties based on entity type
72
- case entity
73
- when Unitsdb::Unit
74
- puts " - Symbols:" if entity.respond_to?(:symbols) && entity.symbols&.any?
75
- if entity.respond_to?(:symbols) && entity.symbols&.any?
76
- entity.symbols.each do |s|
77
- puts " - #{s}"
78
- end
79
- end
80
-
81
- puts " - Definition: #{entity.definition}" if entity.respond_to?(:definition) && entity.definition
82
-
83
- if entity.respond_to?(:dimensions) && entity.dimensions&.any?
84
- puts " - Dimensions:"
85
- entity.dimensions.each { |d| puts " - #{d}" }
86
- end
87
- when Unitsdb::Quantity
88
- puts " - Dimensions: #{entity.dimension}" if entity.respond_to?(:dimension) && entity.dimension
89
- when Unitsdb::Prefix
90
- puts " - Value: #{entity.value}" if entity.respond_to?(:value) && entity.value
91
- puts " - Symbol: #{entity.symbol}" if entity.respond_to?(:symbol) && entity.symbol
92
- when Unitsdb::Dimension
93
- # Any dimension-specific properties
94
- when Unitsdb::UnitSystem
95
- puts " - Organization: #{entity.organization}" if entity.respond_to?(:organization) && entity.organization
96
- end
97
-
98
- # Print references if available
99
- return unless entity.respond_to?(:references) && entity.references&.any?
100
-
101
- puts " - References:"
102
- entity.references.each do |ref|
103
- puts " - #{ref.type}: #{ref.uri}"
21
+ EntityPresenter.new(entity).print_details
104
22
  end
23
+ rescue Unitsdb::Errors::DatabaseError => e
24
+ raise Unitsdb::Errors::DatabaseLoadError,
25
+ "Failed to load database: #{e.message}"
26
+ rescue StandardError => e
27
+ raise Unitsdb::Errors::CLIRuntimeError, "Get failed: #{e.message}"
105
28
  end
106
29
 
107
- def get_entity_type(entity)
108
- case entity
109
- when Unitsdb::Unit
110
- "Unit"
111
- when Unitsdb::Prefix
112
- "Prefix"
113
- when Unitsdb::Quantity
114
- "Quantity"
115
- when Unitsdb::Dimension
116
- "Dimension"
117
- when Unitsdb::UnitSystem
118
- "UnitSystem"
119
- else
120
- "Unknown"
121
- end
122
- end
123
-
124
- def get_entity_name(entity)
125
- # Using early returns is still preferable for simple conditions
126
- return entity.names.first if entity.respond_to?(:names) && entity.names&.any?
127
- return entity.name if entity.respond_to?(:name) && entity.name
128
- return entity.short if entity.respond_to?(:short) && entity.short
30
+ private
129
31
 
130
- "N/A" # Default if no name found
32
+ def print_serialized(entity, format)
33
+ puts entity.public_send("to_#{format}")
131
34
  end
132
35
  end
133
36
  end
@@ -90,17 +90,15 @@ unmatched_qudt)
90
90
  details = "DIMENSION VECTOR: #{entity.label || 'No label'}"
91
91
  details += "\n URI: #{entity.uri}"
92
92
  details += "\n Description: #{entity.description}" if entity.description
93
- if entity.respond_to?(:dimension_exponent_for_length)
94
- exponents = []
95
- exponents << "L:#{entity.dimension_exponent_for_length}" if entity.dimension_exponent_for_length != 0
96
- exponents << "M:#{entity.dimension_exponent_for_mass}" if entity.dimension_exponent_for_mass != 0
97
- exponents << "T:#{entity.dimension_exponent_for_time}" if entity.dimension_exponent_for_time != 0
98
- exponents << "I:#{entity.dimension_exponent_for_electric_current}" if entity.dimension_exponent_for_electric_current != 0
99
- exponents << "Θ:#{entity.dimension_exponent_for_thermodynamic_temperature}" if entity.dimension_exponent_for_thermodynamic_temperature != 0
100
- exponents << "N:#{entity.dimension_exponent_for_amount_of_substance}" if entity.dimension_exponent_for_amount_of_substance != 0
101
- exponents << "J:#{entity.dimension_exponent_for_luminous_intensity}" if entity.dimension_exponent_for_luminous_intensity != 0
102
- details += "\n Exponents: #{exponents.join(', ')}" unless exponents.empty?
103
- end
93
+ exponents = []
94
+ exponents << "L:#{entity.dimension_exponent_for_length}" if entity.dimension_exponent_for_length != 0
95
+ exponents << "M:#{entity.dimension_exponent_for_mass}" if entity.dimension_exponent_for_mass != 0
96
+ exponents << "T:#{entity.dimension_exponent_for_time}" if entity.dimension_exponent_for_time != 0
97
+ exponents << "I:#{entity.dimension_exponent_for_electric_current}" if entity.dimension_exponent_for_electric_current != 0
98
+ exponents << "Θ:#{entity.dimension_exponent_for_thermodynamic_temperature}" if entity.dimension_exponent_for_thermodynamic_temperature != 0
99
+ exponents << "N:#{entity.dimension_exponent_for_amount_of_substance}" if entity.dimension_exponent_for_amount_of_substance != 0
100
+ exponents << "J:#{entity.dimension_exponent_for_luminous_intensity}" if entity.dimension_exponent_for_luminous_intensity != 0
101
+ details += "\n Exponents: #{exponents.join(', ')}" unless exponents.empty?
104
102
  details
105
103
  when Unitsdb::QudtSystemOfUnits
106
104
  details = "SYSTEM OF UNITS: #{entity.label || 'No label'}"
@@ -157,26 +155,17 @@ unmatched_qudt)
157
155
 
158
156
  # Helper to get db entity id
159
157
  def get_db_entity_id(entity)
160
- if entity.respond_to?(:identifiers) && entity.identifiers && !entity.identifiers.empty?
161
- entity.identifiers.first.id
162
- elsif entity.respond_to?(:id)
163
- entity.id
164
- else
165
- "unknown-id"
166
- end
158
+ return entity.identifiers.first.id unless entity.identifiers.empty?
159
+
160
+ entity.short || "unknown-id"
167
161
  end
168
162
 
169
163
  # Helper to get db entity name
170
164
  def get_db_entity_name(entity)
171
- if entity.respond_to?(:names) && entity.names && !entity.names.empty?
172
- entity.names.first.value
173
- elsif entity.respond_to?(:short) && entity.short
174
- entity.short
175
- elsif entity.respond_to?(:name)
176
- entity.name
177
- else
178
- "unknown-name"
179
- end
165
+ return entity.names.first.value unless entity.names.empty?
166
+ return entity.short if entity.short
167
+
168
+ "unknown-name"
180
169
  end
181
170
 
182
171
  # Helper to get qudt entity name
@@ -70,14 +70,14 @@ module Unitsdb
70
70
 
71
71
  # Check if a UnitsDB entity already has a QUDT reference
72
72
  def has_qudt_reference?(entity)
73
- return false unless entity.respond_to?(:references) && entity.references
73
+ return false unless entity.references
74
74
 
75
75
  entity.references.any? { |ref| ref.authority == "qudt" }
76
76
  end
77
77
 
78
78
  # Find the referenced QUDT entity based on the reference URI
79
79
  def find_referenced_qudt_entity(db_entity, qudt_entities)
80
- return nil unless db_entity.respond_to?(:references) && db_entity.references
80
+ return nil unless db_entity.references
81
81
 
82
82
  qudt_ref = db_entity.references.find { |ref| ref.authority == "qudt" }
83
83
  return nil unless qudt_ref
@@ -87,8 +87,8 @@ module Unitsdb
87
87
  end
88
88
 
89
89
  # Get the ID of a UnitsDB entity
90
- def get_entity_id(entity)
91
- entity.respond_to?(:id) ? entity.id : nil
90
+ def get_entity_id(_entity)
91
+ nil
92
92
  end
93
93
 
94
94
  # Find a matching UnitsDB entity for a QUDT entity
@@ -520,7 +520,7 @@ module Unitsdb
520
520
 
521
521
  # Check if QUDT dimension vector matches UnitsDB dimension
522
522
  def dimensions_match?(qudt_dimension, db_dimension)
523
- return false unless qudt_dimension.respond_to?(:dimension_exponent_for_length)
523
+ return false unless qudt_dimension.is_a?(Unitsdb::QudtDimensionVector)
524
524
 
525
525
  # Map QUDT dimension exponents to UnitsDB dimension structure
526
526
  qudt_exponents = {
@@ -552,14 +552,14 @@ module Unitsdb
552
552
  qudt_exponents == db_exponents
553
553
  end
554
554
 
555
- # Get dimension power from UnitsDB dimension entity
555
+ # Get dimension power from UnitsDB dimension entity.
556
+ # Dimension declares all seven dimension-type attrs as
557
+ # DimensionDetails; DimensionDetails always has `power`.
556
558
  def get_dimension_power(db_dimension, dimension_type)
557
- return 0 unless db_dimension.respond_to?(dimension_type)
559
+ property = db_dimension.public_send(dimension_type)
560
+ return 0 unless property
558
561
 
559
- dimension_property = db_dimension.send(dimension_type)
560
- return 0 unless dimension_property.respond_to?(:power)
561
-
562
- dimension_property.power || 0
562
+ property.power || 0
563
563
  end
564
564
 
565
565
  # Normalize names by removing common variations and punctuation
@@ -585,7 +585,7 @@ module Unitsdb
585
585
 
586
586
  # Look for a UnitsDB unit that has an SI reference with this identifier
587
587
  db_units.find do |db_unit|
588
- next unless db_unit.respond_to?(:references) && db_unit.references
588
+ next unless db_unit.references
589
589
 
590
590
  db_unit.references.any? do |ref|
591
591
  ref.authority == "si" && (
@@ -603,7 +603,7 @@ module Unitsdb
603
603
  # PRIORITY 1: Try UCUM code match first (most reliable for prefixes)
604
604
  if qudt_prefix.ucum_code
605
605
  ucum_match = db_prefixes.find do |db_prefix|
606
- db_prefix.respond_to?(:references) && db_prefix.references&.any? do |ref|
606
+ (db_prefix.references || [])&.any? do |ref|
607
607
  ref.authority == "ucum" && ref.uri&.include?(qudt_prefix.ucum_code)
608
608
  end
609
609
  end
@@ -644,17 +644,7 @@ module Unitsdb
644
644
  end
645
645
 
646
646
  # PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
647
- if qudt_prefix.prefix_multiplier
648
- multiplier_match = db_prefixes.find do |db_prefix|
649
- db_prefix.respond_to?(:factor) &&
650
- (db_prefix.factor - qudt_prefix.prefix_multiplier).abs < 1e-10
651
- end
652
-
653
- if multiplier_match
654
- result[:match] = multiplier_match
655
- return result
656
- end
657
- end
647
+ # Skipped: Unitsdb::Prefix has no `factor` attribute in 2.0.
658
648
 
659
649
  # PRIORITY 5: Try normalized name matching
660
650
  if qudt_prefix.label
@@ -720,7 +710,7 @@ module Unitsdb
720
710
  end
721
711
 
722
712
  # PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
723
- if db_prefix.respond_to?(:factor) && db_prefix.factor
713
+ if false
724
714
  multiplier_match = qudt_prefixes.find do |qudt_prefix|
725
715
  qudt_prefix.prefix_multiplier &&
726
716
  (qudt_prefix.prefix_multiplier - db_prefix.factor).abs < 1e-10
@@ -734,10 +724,10 @@ module Unitsdb
734
724
 
735
725
  # Check if an entity has been manually verified (has a special flag)
736
726
  def manually_verified?(entity)
737
- return false unless entity.respond_to?(:references) && entity.references
727
+ return false unless entity.references
738
728
 
739
- entity.references.any? do |ref|
740
- ref.authority == "qudt" && ref.respond_to?(:verified) && ref.verified
729
+ entity.references.any? do |_ref|
730
+ false
741
731
  end
742
732
  end
743
733
  end
@@ -168,20 +168,17 @@ include_potential = false)
168
168
 
169
169
  # Get entity ID (either from identifiers array or directly)
170
170
  def get_entity_id(entity)
171
- if entity.respond_to?(:identifiers) && entity.identifiers && !entity.identifiers.empty?
172
- entity.identifiers.first.id
173
- elsif entity.respond_to?(:id)
174
- entity.id
175
- end
171
+ return entity.identifiers.first.id unless entity.identifiers.empty?
172
+
173
+ entity.short
176
174
  end
177
175
 
178
176
  # Check if an entity has been manually verified (has a special flag)
179
- def manually_verified?(entity)
180
- return false unless entity.respond_to?(:references) && entity.references
181
-
182
- entity.references.any? do |ref|
183
- ref.authority == QUDT_AUTHORITY && ref.respond_to?(:verified) && ref.verified
184
- end
177
+ # Unitsdb::ExternalReference carries no `verified` flag in the
178
+ # 2.0 schema, so nothing is ever manually verified. Kept as a
179
+ # stub for callers; returns false unconditionally.
180
+ def manually_verified?(_entity)
181
+ false
185
182
  end
186
183
  end
187
184
  end
@@ -12,11 +12,7 @@ module Unitsdb
12
12
  autoload :Updater, "unitsdb/commands/qudt/updater"
13
13
  end
14
14
 
15
- class QudtCommand < Thor
16
- # Inherit trace option from parent CLI
17
- class_option :trace, type: :boolean, default: false,
18
- desc: "Show full backtrace on error"
19
-
15
+ class QudtCommand < Unitsdb::Commands::Thor
20
16
  desc "check", "Check QUDT references in UnitsDB"
21
17
  option :entity_type, type: :string, aliases: "-e",
22
18
  desc: "Entity type to check (units, quantities, dimensions, unit_systems). If not specified, all types are checked"
@@ -48,35 +44,6 @@ module Unitsdb
48
44
  def update
49
45
  run_command(Qudt::Update, options)
50
46
  end
51
-
52
- private
53
-
54
- def run_command(command_class, options)
55
- command = command_class.new(options)
56
- command.run
57
- rescue Unitsdb::Errors::CLIRuntimeError => e
58
- handle_cli_error(e)
59
- rescue StandardError => e
60
- handle_error(e)
61
- end
62
-
63
- def handle_cli_error(error)
64
- if options[:trace]
65
- raise error
66
- else
67
- warn "Error: #{error.message}"
68
- exit 1
69
- end
70
- end
71
-
72
- def handle_error(error)
73
- if options[:trace]
74
- raise error
75
- else
76
- warn "Error: #{error.message}"
77
- exit 1
78
- end
79
- end
80
47
  end
81
48
  end
82
49
  end