unitsdb 2.1.1 → 2.2.1

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +8 -1
  3. data/.gitignore +2 -0
  4. data/.gitmodules +4 -3
  5. data/.rubocop.yml +13 -8
  6. data/.rubocop_todo.yml +217 -100
  7. data/CLAUDE.md +55 -0
  8. data/Gemfile +4 -1
  9. data/README.adoc +283 -16
  10. data/data/dimensions.yaml +1864 -0
  11. data/data/prefixes.yaml +874 -0
  12. data/data/quantities.yaml +3715 -0
  13. data/data/scales.yaml +97 -0
  14. data/data/schemas/dimensions-schema.yaml +153 -0
  15. data/data/schemas/prefixes-schema.yaml +155 -0
  16. data/data/schemas/quantities-schema.yaml +117 -0
  17. data/data/schemas/scales-schema.yaml +106 -0
  18. data/data/schemas/unit_systems-schema.yaml +116 -0
  19. data/data/schemas/units-schema.yaml +215 -0
  20. data/data/unit_systems.yaml +78 -0
  21. data/data/units.yaml +14052 -0
  22. data/exe/unitsdb +7 -1
  23. data/lib/unitsdb/cli.rb +42 -15
  24. data/lib/unitsdb/commands/_modify.rb +40 -4
  25. data/lib/unitsdb/commands/base.rb +6 -2
  26. data/lib/unitsdb/commands/check_si/si_formatter.rb +488 -0
  27. data/lib/unitsdb/commands/check_si/si_matcher.rb +487 -0
  28. data/lib/unitsdb/commands/check_si/si_ttl_parser.rb +103 -0
  29. data/lib/unitsdb/commands/check_si/si_updater.rb +254 -0
  30. data/lib/unitsdb/commands/check_si.rb +54 -35
  31. data/lib/unitsdb/commands/get.rb +11 -10
  32. data/lib/unitsdb/commands/normalize.rb +21 -7
  33. data/lib/unitsdb/commands/qudt/check.rb +150 -0
  34. data/lib/unitsdb/commands/qudt/formatter.rb +194 -0
  35. data/lib/unitsdb/commands/qudt/matcher.rb +746 -0
  36. data/lib/unitsdb/commands/qudt/ttl_parser.rb +403 -0
  37. data/lib/unitsdb/commands/qudt/update.rb +126 -0
  38. data/lib/unitsdb/commands/qudt/updater.rb +189 -0
  39. data/lib/unitsdb/commands/qudt.rb +82 -0
  40. data/lib/unitsdb/commands/release.rb +12 -9
  41. data/lib/unitsdb/commands/search.rb +12 -11
  42. data/lib/unitsdb/commands/ucum/check.rb +42 -29
  43. data/lib/unitsdb/commands/ucum/formatter.rb +2 -1
  44. data/lib/unitsdb/commands/ucum/matcher.rb +23 -9
  45. data/lib/unitsdb/commands/ucum/update.rb +14 -13
  46. data/lib/unitsdb/commands/ucum/updater.rb +40 -6
  47. data/lib/unitsdb/commands/ucum/xml_parser.rb +0 -2
  48. data/lib/unitsdb/commands/ucum.rb +44 -4
  49. data/lib/unitsdb/commands/validate/identifiers.rb +2 -4
  50. data/lib/unitsdb/commands/validate/qudt_references.rb +111 -0
  51. data/lib/unitsdb/commands/validate/references.rb +36 -19
  52. data/lib/unitsdb/commands/validate/si_references.rb +3 -5
  53. data/lib/unitsdb/commands/validate/ucum_references.rb +105 -0
  54. data/lib/unitsdb/commands/validate.rb +67 -11
  55. data/lib/unitsdb/commands.rb +20 -0
  56. data/lib/unitsdb/database.rb +90 -52
  57. data/lib/unitsdb/dimension.rb +1 -4
  58. data/lib/unitsdb/dimension_details.rb +0 -1
  59. data/lib/unitsdb/dimensions.rb +0 -2
  60. data/lib/unitsdb/errors.rb +7 -0
  61. data/lib/unitsdb/prefix.rb +0 -4
  62. data/lib/unitsdb/prefix_reference.rb +0 -2
  63. data/lib/unitsdb/prefixes.rb +0 -1
  64. data/lib/unitsdb/quantities.rb +0 -2
  65. data/lib/unitsdb/quantity.rb +0 -6
  66. data/lib/unitsdb/qudt.rb +100 -0
  67. data/lib/unitsdb/root_unit_reference.rb +0 -3
  68. data/lib/unitsdb/scale.rb +0 -4
  69. data/lib/unitsdb/scale_reference.rb +0 -2
  70. data/lib/unitsdb/scales.rb +0 -2
  71. data/lib/unitsdb/si_derived_base.rb +0 -2
  72. data/lib/unitsdb/ucum.rb +14 -10
  73. data/lib/unitsdb/unit.rb +0 -10
  74. data/lib/unitsdb/unit_reference.rb +0 -2
  75. data/lib/unitsdb/unit_system.rb +1 -3
  76. data/lib/unitsdb/unit_system_reference.rb +0 -2
  77. data/lib/unitsdb/unit_systems.rb +0 -2
  78. data/lib/unitsdb/units.rb +0 -2
  79. data/lib/unitsdb/utils.rb +32 -21
  80. data/lib/unitsdb/version.rb +5 -1
  81. data/lib/unitsdb.rb +62 -14
  82. data/unitsdb.gemspec +6 -3
  83. metadata +52 -13
  84. data/lib/unitsdb/commands/si_formatter.rb +0 -485
  85. data/lib/unitsdb/commands/si_matcher.rb +0 -470
  86. data/lib/unitsdb/commands/si_ttl_parser.rb +0 -100
  87. data/lib/unitsdb/commands/si_updater.rb +0 -212
@@ -4,16 +4,28 @@ require "thor"
4
4
 
5
5
  module Unitsdb
6
6
  module Commands
7
+ module Validate
8
+ autoload :Identifiers, "unitsdb/commands/validate/identifiers"
9
+ autoload :QudtReferences, "unitsdb/commands/validate/qudt_references"
10
+ autoload :References, "unitsdb/commands/validate/references"
11
+ autoload :SiReferences, "unitsdb/commands/validate/si_references"
12
+ autoload :UcumReferences, "unitsdb/commands/validate/ucum_references"
13
+ end
14
+
7
15
  class ValidateCommand < Thor
16
+ # Inherit trace option from parent CLI
17
+ class_option :trace, type: :boolean, default: false,
18
+ desc: "Show full backtrace on error"
19
+
8
20
  desc "references", "Validate that all references exist"
9
- option :debug_registry, type: :boolean, desc: "Show registry contents for debugging"
21
+ option :debug_registry, type: :boolean,
22
+ desc: "Show registry contents for debugging"
10
23
  option :database, type: :string, required: true, aliases: "-d",
11
24
  desc: "Path to UnitsDB database (required)"
12
- option :print_valid, type: :boolean, default: false, desc: "Print valid references too"
25
+ option :print_valid, type: :boolean, default: false,
26
+ desc: "Print valid references too"
13
27
  def references
14
- require_relative "validate/references"
15
-
16
- Commands::Validate::References.new(options).run
28
+ run_command(Commands::Validate::References, options)
17
29
  end
18
30
 
19
31
  desc "identifiers", "Check for uniqueness of identifier fields"
@@ -21,19 +33,63 @@ module Unitsdb
21
33
  desc: "Path to UnitsDB database (required)"
22
34
 
23
35
  def identifiers
24
- require_relative "validate/identifiers"
25
-
26
- Commands::Validate::Identifiers.new(options).run
36
+ run_command(Commands::Validate::Identifiers, options)
27
37
  end
28
38
 
29
- desc "si_references", "Validate that each SI digital framework reference is unique per entity type"
39
+ desc "si_references",
40
+ "Validate that each SI digital framework reference is unique per entity type"
30
41
  option :database, type: :string, required: true, aliases: "-d",
31
42
  desc: "Path to UnitsDB database (required)"
32
43
 
33
44
  def si_references
34
- require_relative "validate/si_references"
45
+ run_command(Commands::Validate::SiReferences, options)
46
+ end
47
+
48
+ desc "qudt_references",
49
+ "Validate that each QUDT reference is unique per entity type"
50
+ option :database, type: :string, required: true, aliases: "-d",
51
+ desc: "Path to UnitsDB database (required)"
52
+
53
+ def qudt_references
54
+ run_command(Commands::Validate::QudtReferences, options)
55
+ end
56
+
57
+ desc "ucum_references",
58
+ "Validate that each UCUM reference is unique per entity type"
59
+ option :database, type: :string, required: true, aliases: "-d",
60
+ desc: "Path to UnitsDB database (required)"
61
+
62
+ def ucum_references
63
+ run_command(Commands::Validate::UcumReferences, options)
64
+ end
65
+
66
+ private
67
+
68
+ def run_command(command_class, options)
69
+ command = command_class.new(options)
70
+ command.run
71
+ rescue Unitsdb::Errors::CLIRuntimeError => e
72
+ handle_cli_error(e)
73
+ rescue StandardError => e
74
+ handle_error(e)
75
+ end
76
+
77
+ def handle_cli_error(error)
78
+ if options[:trace]
79
+ raise error
80
+ else
81
+ warn "Error: #{error.message}"
82
+ exit 1
83
+ end
84
+ end
35
85
 
36
- Commands::Validate::SiReferences.new(options).run
86
+ def handle_error(error)
87
+ if options[:trace]
88
+ raise error
89
+ else
90
+ warn "Error: #{error.message}"
91
+ exit 1
92
+ end
37
93
  end
38
94
  end
39
95
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ module Commands
5
+ autoload :ModifyCommand, "unitsdb/commands/_modify"
6
+ autoload :Base, "unitsdb/commands/base"
7
+ autoload :CheckSi, "unitsdb/commands/check_si"
8
+ autoload :CheckSiCommand, "unitsdb/commands/check_si"
9
+ autoload :Get, "unitsdb/commands/get"
10
+ autoload :Normalize, "unitsdb/commands/normalize"
11
+ autoload :Qudt, "unitsdb/commands/qudt"
12
+ autoload :QudtCommand, "unitsdb/commands/qudt"
13
+ autoload :Release, "unitsdb/commands/release"
14
+ autoload :Search, "unitsdb/commands/search"
15
+ autoload :Ucum, "unitsdb/commands/ucum"
16
+ autoload :UcumCommand, "unitsdb/commands/ucum"
17
+ autoload :Validate, "unitsdb/commands/validate"
18
+ autoload :ValidateCommand, "unitsdb/commands/validate"
19
+ end
20
+ end
@@ -1,12 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "unit"
4
- require_relative "prefix"
5
- require_relative "quantity"
6
- require_relative "dimension"
7
- require_relative "unit_system"
8
- require_relative "errors"
9
-
10
3
  module Unitsdb
11
4
  class Database < Lutaml::Model::Serializable
12
5
  # model Config.model_for(:units)
@@ -25,7 +18,11 @@ module Unitsdb
25
18
  # @return [Object, nil] the first entity with matching identifier or nil if not found
26
19
  def find_by_type(id:, type:)
27
20
  collection = send(type.to_s)
28
- collection.find { |entity| entity.identifiers&.any? { |identifier| identifier.id == id } }
21
+ collection.find do |entity|
22
+ entity.identifiers&.any? do |identifier|
23
+ identifier.id == id
24
+ end
25
+ end
29
26
  end
30
27
 
31
28
  # Find an entity by its identifier id across all entity types
@@ -33,7 +30,8 @@ module Unitsdb
33
30
  # @param type [String, nil] optional identifier type to match
34
31
  # @return [Object, nil] the first entity with matching identifier or nil if not found
35
32
  def get_by_id(id:, type: nil)
36
- %w[units prefixes quantities dimensions unit_systems].each do |collection_name|
33
+ %w[units prefixes quantities dimensions
34
+ unit_systems].each do |collection_name|
37
35
  next unless respond_to?(collection_name)
38
36
 
39
37
  collection = send(collection_name)
@@ -63,7 +61,12 @@ module Unitsdb
63
61
  results = []
64
62
 
65
63
  # Define which collections to search based on type parameter
66
- collections = type ? [type.to_s] : %w[units prefixes quantities dimensions unit_systems]
64
+ collections = if type
65
+ [type.to_s]
66
+ else
67
+ %w[units prefixes quantities
68
+ dimensions unit_systems]
69
+ end
67
70
 
68
71
  collections.each do |collection_name|
69
72
  next unless respond_to?(collection_name)
@@ -71,7 +74,9 @@ module Unitsdb
71
74
  collection = send(collection_name)
72
75
  collection.each do |entity|
73
76
  # Search in identifiers
74
- if entity.identifiers&.any? { |identifier| identifier.id.to_s.downcase.include?(text.downcase) }
77
+ if entity.identifiers&.any? do |identifier|
78
+ identifier.id.to_s.downcase.include?(text.downcase)
79
+ end
75
80
  results << entity
76
81
  next
77
82
  end
@@ -86,14 +91,14 @@ module Unitsdb
86
91
 
87
92
  # Search in short description
88
93
  if entity.respond_to?(:short) && entity.short &&
89
- entity.short.to_s.downcase.include?(text.downcase)
94
+ entity.short.to_s.downcase.include?(text.downcase)
90
95
  results << entity
91
96
  next
92
97
  end
93
98
 
94
99
  # Special case for prefix name (prefixes don't have names array)
95
100
  next unless collection_name == "prefixes" && entity.respond_to?(:name) &&
96
- entity.name.to_s.downcase.include?(text.downcase)
101
+ entity.name.to_s.downcase.include?(text.downcase)
97
102
 
98
103
  results << entity
99
104
  next
@@ -116,7 +121,8 @@ module Unitsdb
116
121
  collections = entity_type ? [entity_type.to_s] : %w[units prefixes]
117
122
 
118
123
  collections.each do |collection_name|
119
- next unless respond_to?(collection_name) && %w[units prefixes].include?(collection_name)
124
+ next unless respond_to?(collection_name) && %w[units
125
+ prefixes].include?(collection_name)
120
126
 
121
127
  collection = send(collection_name)
122
128
  collection.each do |entity|
@@ -158,11 +164,16 @@ module Unitsdb
158
164
 
159
165
  result = {
160
166
  exact: [],
161
- symbol_match: []
167
+ symbol_match: [],
162
168
  }
163
169
 
164
170
  # Define collections to search based on entity_type parameter
165
- collections = entity_type ? [entity_type.to_s] : %w[units prefixes quantities dimensions unit_systems]
171
+ collections = if entity_type
172
+ [entity_type.to_s]
173
+ else
174
+ %w[units prefixes
175
+ quantities dimensions unit_systems]
176
+ end
166
177
 
167
178
  collections.each do |collection_name|
168
179
  next unless respond_to?(collection_name)
@@ -174,23 +185,25 @@ module Unitsdb
174
185
  if %w[exact all].include?(match_type)
175
186
  # Match by short
176
187
  if entity.respond_to?(:short) && entity.short &&
177
- entity.short.downcase == value.downcase
188
+ entity.short.downcase == value.downcase
178
189
  result[:exact] << {
179
190
  entity: entity,
180
191
  match_desc: "short_to_name",
181
- details: "UnitsDB short '#{entity.short}' matches '#{value}'"
192
+ details: "UnitsDB short '#{entity.short}' matches '#{value}'",
182
193
  }
183
194
  next
184
195
  end
185
196
 
186
197
  # Match by names
187
198
  if entity.respond_to?(:names) && entity.names
188
- matching_name = entity.names.find { |name| name.value.to_s.downcase == value.downcase }
199
+ matching_name = entity.names.find do |name|
200
+ name.value.to_s.downcase == value.downcase
201
+ end
189
202
  if matching_name
190
203
  result[:exact] << {
191
204
  entity: entity,
192
205
  match_desc: "name_to_name",
193
- details: "UnitsDB name '#{matching_name.value}' (#{matching_name.lang}) matches '#{value}'"
206
+ details: "UnitsDB name '#{matching_name.value}' (#{matching_name.lang}) matches '#{value}'",
194
207
  }
195
208
  next
196
209
  end
@@ -199,7 +212,7 @@ module Unitsdb
199
212
 
200
213
  # For symbol matches - only applicable to units and prefixes
201
214
  if %w[symbol all].include?(match_type) &&
202
- %w[units prefixes].include?(collection_name)
215
+ %w[units prefixes].include?(collection_name)
203
216
  if collection_name == "units" && entity.respond_to?(:symbols) && entity.symbols
204
217
  # Units can have multiple symbols
205
218
  matching_symbol = entity.symbols.find do |sym|
@@ -211,7 +224,7 @@ module Unitsdb
211
224
  result[:symbol_match] << {
212
225
  entity: entity,
213
226
  match_desc: "symbol_match",
214
- details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'"
227
+ details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'",
215
228
  }
216
229
  end
217
230
  elsif collection_name == "prefixes" && entity.respond_to?(:symbols) && entity.symbols
@@ -225,7 +238,7 @@ module Unitsdb
225
238
  result[:symbol_match] << {
226
239
  entity: entity,
227
240
  match_desc: "symbol_match",
228
- details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'"
241
+ details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'",
229
242
  }
230
243
  end
231
244
  end
@@ -243,7 +256,7 @@ module Unitsdb
243
256
  def validate_uniqueness
244
257
  results = {
245
258
  short: {},
246
- id: {}
259
+ id: {},
247
260
  }
248
261
 
249
262
  # Validate short names for applicable collections
@@ -283,18 +296,24 @@ module Unitsdb
283
296
  puts "Database directory path: #{db_path}"
284
297
 
285
298
  # Check if the directory exists
286
- raise Errors::DatabaseNotFoundError, "Database directory not found: #{db_path}" unless Dir.exist?(db_path)
299
+ unless Dir.exist?(db_path)
300
+ raise Errors::DatabaseNotFoundError,
301
+ "Database directory not found: #{db_path}"
302
+ end
287
303
 
288
304
  # Define required files
289
- required_files = %w[prefixes.yaml dimensions.yaml units.yaml quantities.yaml unit_systems.yaml]
305
+ required_files = %w[prefixes.yaml dimensions.yaml units.yaml
306
+ quantities.yaml unit_systems.yaml]
290
307
  yaml_files = required_files.map { |file| File.join(dir_path, file) }
291
308
 
292
309
  # Check if all required files exist
293
- missing_files = required_files.reject { |file| File.exist?(File.join(dir_path, file)) }
310
+ missing_files = required_files.reject do |file|
311
+ File.exist?(File.join(dir_path, file))
312
+ end
294
313
 
295
314
  if missing_files.any?
296
315
  raise Errors::DatabaseFileNotFoundError,
297
- "Missing required database files: #{missing_files.join(", ")}"
316
+ "Missing required database files: #{missing_files.join(', ')}"
298
317
  end
299
318
 
300
319
  # Ensure we have path properly joined with filenames
@@ -316,15 +335,17 @@ module Unitsdb
316
335
 
317
336
  # Load YAML files with better error handling
318
337
  begin
319
- prefixes_hash = YAML.safe_load(File.read(prefixes_yaml))
320
- dimensions_hash = YAML.safe_load(File.read(dimensions_yaml))
321
- units_hash = YAML.safe_load(File.read(units_yaml))
322
- quantities_hash = YAML.safe_load(File.read(quantities_yaml))
323
- unit_systems_hash = YAML.safe_load(File.read(unit_systems_yaml))
338
+ prefixes_hash = YAML.safe_load_file(prefixes_yaml)
339
+ dimensions_hash = YAML.safe_load_file(dimensions_yaml)
340
+ units_hash = YAML.safe_load_file(units_yaml)
341
+ quantities_hash = YAML.safe_load_file(quantities_yaml)
342
+ unit_systems_hash = YAML.safe_load_file(unit_systems_yaml)
324
343
  rescue Errno::ENOENT => e
325
- raise Errors::DatabaseFileNotFoundError, "Failed to read database file: #{e.message}"
344
+ raise Errors::DatabaseFileNotFoundError,
345
+ "Failed to read database file: #{e.message}"
326
346
  rescue Psych::SyntaxError => e
327
- raise Errors::DatabaseFileInvalidError, "Invalid YAML in database file: #{e.message}"
347
+ raise Errors::DatabaseFileInvalidError,
348
+ "Invalid YAML in database file: #{e.message}"
328
349
  rescue StandardError => e
329
350
  raise Errors::DatabaseLoadError, "Error loading database: #{e.message}"
330
351
  end
@@ -339,7 +360,7 @@ module Unitsdb
339
360
 
340
361
  if missing_schema.any?
341
362
  raise Errors::DatabaseFileInvalidError,
342
- "Missing schema_version in files: #{missing_schema.join(", ")}"
363
+ "Missing schema_version in files: #{missing_schema.join(', ')}"
343
364
  end
344
365
 
345
366
  # Extract versions from each file
@@ -355,7 +376,7 @@ module Unitsdb
355
376
  dimensions_version,
356
377
  units_version,
357
378
  quantities_version,
358
- unit_systems_version
379
+ unit_systems_version,
359
380
  ]
360
381
 
361
382
  unless versions.uniq.size == 1
@@ -364,9 +385,10 @@ module Unitsdb
364
385
  "dimensions.yaml" => dimensions_version,
365
386
  "units.yaml" => units_version,
366
387
  "quantities.yaml" => quantities_version,
367
- "unit_systems.yaml" => unit_systems_version
388
+ "unit_systems.yaml" => unit_systems_version,
368
389
  }
369
- raise Errors::VersionMismatchError, "Version mismatch in database files: #{version_info.inspect}"
390
+ raise Errors::VersionMismatchError,
391
+ "Version mismatch in database files: #{version_info.inspect}"
370
392
  end
371
393
 
372
394
  # Check if the version is supported
@@ -382,7 +404,7 @@ module Unitsdb
382
404
  "dimensions" => dimensions_hash["dimensions"],
383
405
  "units" => units_hash["units"],
384
406
  "quantities" => quantities_hash["quantities"],
385
- "unit_systems" => unit_systems_hash["unit_systems"]
407
+ "unit_systems" => unit_systems_hash["unit_systems"],
386
408
  }.to_yaml
387
409
 
388
410
  from_yaml(combined_yaml)
@@ -533,7 +555,8 @@ module Unitsdb
533
555
  ref_type = "dimensions"
534
556
  ref_path = "dimensions:index:#{index}:dimension_reference"
535
557
 
536
- validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, "dimensions")
558
+ validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs,
559
+ "dimensions")
537
560
  end
538
561
  end
539
562
 
@@ -545,7 +568,8 @@ module Unitsdb
545
568
  ref_type = "unit_systems"
546
569
  ref_path = "units:index:#{index}:unit_system_reference[#{idx}]"
547
570
 
548
- validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, "units")
571
+ validate_reference(ref_id, ref_type, ref_path, registry,
572
+ invalid_refs, "units")
549
573
  end
550
574
  end
551
575
  end
@@ -558,7 +582,8 @@ module Unitsdb
558
582
  ref_type = "quantities"
559
583
  ref_path = "units:index:#{index}:quantity_references[#{idx}]"
560
584
 
561
- validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, "units")
585
+ validate_reference(ref_id, ref_type, ref_path, registry,
586
+ invalid_refs, "units")
562
587
  end
563
588
  end
564
589
  end
@@ -575,7 +600,8 @@ module Unitsdb
575
600
  ref_type = "units"
576
601
  ref_path = "units:index:#{index}:root_units.#{idx}.unit_reference"
577
602
 
578
- validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, "units")
603
+ validate_reference(ref_id, ref_type, ref_path, registry,
604
+ invalid_refs, "units")
579
605
 
580
606
  # Check prefix reference if present
581
607
  next unless root_unit.respond_to?(:prefix_reference) && root_unit.prefix_reference
@@ -584,12 +610,14 @@ module Unitsdb
584
610
  ref_type = "prefixes"
585
611
  ref_path = "units:index:#{index}:root_units.#{idx}.prefix_reference"
586
612
 
587
- validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, "units")
613
+ validate_reference(ref_id, ref_type, ref_path, registry,
614
+ invalid_refs, "units")
588
615
  end
589
616
  end
590
617
  end
591
618
 
592
- def validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, file_type)
619
+ def validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs,
620
+ file_type)
593
621
  # Handle references that are objects with id and type (could be a hash or an object)
594
622
  if ref_id.respond_to?(:id) && ref_id.respond_to?(:type)
595
623
  id = ref_id.id
@@ -608,8 +636,12 @@ module Unitsdb
608
636
  # 3. Try alternate ID formats for unit systems (e.g., SI_base vs si-base)
609
637
  if !valid && type == "unitsml" && ref_type == "unit_systems" && registry.key?(ref_type) && (
610
638
  registry[ref_type].keys.any? { |k| k.end_with?(":#{id}") } ||
611
- registry[ref_type].keys.any? { |k| k.end_with?(":SI_#{id.sub("si-", "")}") } ||
612
- registry[ref_type].keys.any? { |k| k.end_with?(":non-SI_#{id.sub("nonsi-", "")}") }
639
+ registry[ref_type].keys.any? do |k|
640
+ k.end_with?(":SI_#{id.sub('si-', '')}")
641
+ end ||
642
+ registry[ref_type].keys.any? do |k|
643
+ k.end_with?(":non-SI_#{id.sub('nonsi-', '')}")
644
+ end
613
645
  )
614
646
  # Special handling for unit_systems between unitsml and nist types
615
647
  valid = true
@@ -617,7 +649,8 @@ module Unitsdb
617
649
 
618
650
  unless valid
619
651
  invalid_refs[file_type] ||= {}
620
- invalid_refs[file_type][ref_path] = { id: id, type: type, ref_type: ref_type }
652
+ invalid_refs[file_type][ref_path] =
653
+ { id: id, type: type, ref_type: ref_type }
621
654
  end
622
655
  # Handle references that are objects with id and type in a hash
623
656
  elsif ref_id.is_a?(Hash) && ref_id.key?("id") && ref_id.key?("type")
@@ -637,8 +670,12 @@ module Unitsdb
637
670
  # 3. Try alternate ID formats for unit systems (e.g., SI_base vs si-base)
638
671
  if !valid && type == "unitsml" && ref_type == "unit_systems" && registry.key?(ref_type) && (
639
672
  registry[ref_type].keys.any? { |k| k.end_with?(":#{id}") } ||
640
- registry[ref_type].keys.any? { |k| k.end_with?(":SI_#{id.sub("si-", "")}") } ||
641
- registry[ref_type].keys.any? { |k| k.end_with?(":non-SI_#{id.sub("nonsi-", "")}") }
673
+ registry[ref_type].keys.any? do |k|
674
+ k.end_with?(":SI_#{id.sub('si-', '')}")
675
+ end ||
676
+ registry[ref_type].keys.any? do |k|
677
+ k.end_with?(":non-SI_#{id.sub('nonsi-', '')}")
678
+ end
642
679
  )
643
680
  # Special handling for unit_systems between unitsml and nist types
644
681
  valid = true
@@ -646,7 +683,8 @@ module Unitsdb
646
683
 
647
684
  unless valid
648
685
  invalid_refs[file_type] ||= {}
649
- invalid_refs[file_type][ref_path] = { id: id, type: type, ref_type: ref_type }
686
+ invalid_refs[file_type][ref_path] =
687
+ { id: id, type: type, ref_type: ref_type }
650
688
  end
651
689
  else
652
690
  # Handle plain string references (legacy format)
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
- require_relative "dimension_details"
5
- require_relative "quantity"
6
- require_relative "localized_string"
7
3
  # NISTd1:
8
4
  # length:
9
5
  # power: 1
@@ -45,5 +41,6 @@ module Unitsdb
45
41
  attribute :plane_angle, DimensionDetails
46
42
  attribute :short, :string
47
43
  attribute :names, LocalizedString, collection: true
44
+ attribute :references, ExternalReference, collection: true
48
45
  end
49
46
  end
@@ -10,7 +10,6 @@
10
10
  # mathml: "<mi mathvariant='sans-serif'>M</mi>"
11
11
  # unicode: "\U0001D5AC"
12
12
 
13
- require_relative "symbol_presentations"
14
13
  module Unitsdb
15
14
  class DimensionDetails < Lutaml::Model::Serializable
16
15
  attribute :power, :integer
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "dimension"
4
-
5
3
  module Unitsdb
6
4
  class Dimensions < Lutaml::Model::Serializable
7
5
  # model Config.model_for(:dimensions)
@@ -9,5 +9,12 @@ module Unitsdb
9
9
  class DatabaseLoadError < DatabaseError; end
10
10
  class VersionMismatchError < DatabaseError; end
11
11
  class UnsupportedVersionError < DatabaseError; end
12
+
13
+ # CLI-specific errors
14
+ class CLIRuntimeError < StandardError; end
15
+ class InvalidParameterError < CLIRuntimeError; end
16
+ class FileNotFoundError < CLIRuntimeError; end
17
+ class ValidationError < CLIRuntimeError; end
18
+ class InvalidFormatError < CLIRuntimeError; end
12
19
  end
13
20
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
- require_relative "symbol_presentations"
5
- require_relative "external_reference"
6
- require_relative "localized_string"
7
3
  # ---
8
4
  # NISTp10_30:
9
5
  # name: quetta
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
-
5
3
  module Unitsdb
6
4
  class PrefixReference < Identifier
7
5
  attribute :id, :string
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "prefix"
4
3
  # ---
5
4
  # NISTp10_30:
6
5
  # name: quetta
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "quantity"
4
-
5
3
  module Unitsdb
6
4
  class Quantities < Lutaml::Model::Serializable
7
5
  # model Config.model_for(:quantities)
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
- require_relative "unit_reference"
5
- require_relative "dimension_reference"
6
- require_relative "external_reference"
7
- require_relative "localized_string"
8
-
9
3
  module Unitsdb
10
4
  class Quantity < Lutaml::Model::Serializable
11
5
  # model Config.model_for(:quantity)