unitsdb 2.1.1 → 2.2.2
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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +8 -1
- data/.gitignore +2 -0
- data/.gitmodules +4 -3
- data/.rubocop.yml +13 -8
- data/.rubocop_todo.yml +217 -100
- data/CLAUDE.md +55 -0
- data/Gemfile +4 -1
- data/README.adoc +283 -16
- data/data/dimensions.yaml +1864 -0
- data/data/prefixes.yaml +874 -0
- data/data/quantities.yaml +3715 -0
- data/data/scales.yaml +97 -0
- data/data/schemas/dimensions-schema.yaml +153 -0
- data/data/schemas/prefixes-schema.yaml +155 -0
- data/data/schemas/quantities-schema.yaml +117 -0
- data/data/schemas/scales-schema.yaml +106 -0
- data/data/schemas/unit_systems-schema.yaml +116 -0
- data/data/schemas/units-schema.yaml +215 -0
- data/data/unit_systems.yaml +78 -0
- data/data/units.yaml +14052 -0
- data/exe/unitsdb +7 -1
- data/lib/unitsdb/cli.rb +42 -15
- data/lib/unitsdb/commands/_modify.rb +40 -4
- data/lib/unitsdb/commands/base.rb +6 -2
- data/lib/unitsdb/commands/check_si/si_formatter.rb +488 -0
- data/lib/unitsdb/commands/check_si/si_matcher.rb +487 -0
- data/lib/unitsdb/commands/check_si/si_ttl_parser.rb +103 -0
- data/lib/unitsdb/commands/check_si/si_updater.rb +254 -0
- data/lib/unitsdb/commands/check_si.rb +54 -35
- data/lib/unitsdb/commands/get.rb +11 -10
- data/lib/unitsdb/commands/normalize.rb +21 -7
- data/lib/unitsdb/commands/qudt/check.rb +150 -0
- data/lib/unitsdb/commands/qudt/formatter.rb +194 -0
- data/lib/unitsdb/commands/qudt/matcher.rb +746 -0
- data/lib/unitsdb/commands/qudt/ttl_parser.rb +403 -0
- data/lib/unitsdb/commands/qudt/update.rb +126 -0
- data/lib/unitsdb/commands/qudt/updater.rb +189 -0
- data/lib/unitsdb/commands/qudt.rb +82 -0
- data/lib/unitsdb/commands/release.rb +12 -9
- data/lib/unitsdb/commands/search.rb +12 -11
- data/lib/unitsdb/commands/ucum/check.rb +42 -29
- data/lib/unitsdb/commands/ucum/formatter.rb +2 -1
- data/lib/unitsdb/commands/ucum/matcher.rb +23 -9
- data/lib/unitsdb/commands/ucum/update.rb +14 -13
- data/lib/unitsdb/commands/ucum/updater.rb +40 -6
- data/lib/unitsdb/commands/ucum/xml_parser.rb +0 -2
- data/lib/unitsdb/commands/ucum.rb +44 -4
- data/lib/unitsdb/commands/validate/identifiers.rb +2 -4
- data/lib/unitsdb/commands/validate/qudt_references.rb +111 -0
- data/lib/unitsdb/commands/validate/references.rb +36 -19
- data/lib/unitsdb/commands/validate/si_references.rb +3 -5
- data/lib/unitsdb/commands/validate/ucum_references.rb +105 -0
- data/lib/unitsdb/commands/validate.rb +67 -11
- data/lib/unitsdb/commands.rb +20 -0
- data/lib/unitsdb/config.rb +114 -2
- data/lib/unitsdb/database.rb +160 -123
- data/lib/unitsdb/dimension.rb +3 -4
- data/lib/unitsdb/dimension_details.rb +2 -1
- data/lib/unitsdb/dimension_reference.rb +2 -0
- data/lib/unitsdb/dimensions.rb +2 -2
- data/lib/unitsdb/errors.rb +7 -0
- data/lib/unitsdb/external_reference.rb +2 -0
- data/lib/unitsdb/identifier.rb +2 -0
- data/lib/unitsdb/localized_string.rb +2 -0
- data/lib/unitsdb/prefix.rb +2 -4
- data/lib/unitsdb/prefix_reference.rb +2 -2
- data/lib/unitsdb/prefixes.rb +2 -1
- data/lib/unitsdb/quantities.rb +2 -2
- data/lib/unitsdb/quantity.rb +2 -6
- data/lib/unitsdb/quantity_reference.rb +2 -0
- data/lib/unitsdb/qudt.rb +105 -0
- data/lib/unitsdb/root_unit_reference.rb +2 -3
- data/lib/unitsdb/scale.rb +2 -4
- data/lib/unitsdb/scale_properties.rb +2 -0
- data/lib/unitsdb/scale_reference.rb +2 -2
- data/lib/unitsdb/scales.rb +2 -2
- data/lib/unitsdb/si_derived_base.rb +2 -2
- data/lib/unitsdb/symbol_presentations.rb +2 -0
- data/lib/unitsdb/ucum.rb +21 -10
- data/lib/unitsdb/unit.rb +2 -10
- data/lib/unitsdb/unit_reference.rb +2 -2
- data/lib/unitsdb/unit_system.rb +3 -3
- data/lib/unitsdb/unit_system_reference.rb +2 -2
- data/lib/unitsdb/unit_systems.rb +2 -2
- data/lib/unitsdb/units.rb +2 -2
- data/lib/unitsdb/utils.rb +32 -21
- data/lib/unitsdb/version.rb +5 -1
- data/lib/unitsdb.rb +62 -14
- data/unitsdb.gemspec +6 -3
- metadata +52 -13
- data/lib/unitsdb/commands/si_formatter.rb +0 -485
- data/lib/unitsdb/commands/si_matcher.rb +0 -470
- data/lib/unitsdb/commands/si_ttl_parser.rb +0 -100
- data/lib/unitsdb/commands/si_updater.rb +0 -212
data/lib/unitsdb/database.rb
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
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)
|
|
13
6
|
|
|
7
|
+
DATABASE_FILES = {
|
|
8
|
+
"prefixes" => "prefixes.yaml",
|
|
9
|
+
"dimensions" => "dimensions.yaml",
|
|
10
|
+
"units" => "units.yaml",
|
|
11
|
+
"quantities" => "quantities.yaml",
|
|
12
|
+
"unit_systems" => "unit_systems.yaml",
|
|
13
|
+
}.freeze
|
|
14
|
+
SUPPORTED_SCHEMA_VERSION = "2.0.0"
|
|
15
|
+
|
|
14
16
|
attribute :schema_version, :string
|
|
15
17
|
attribute :version, :string
|
|
16
18
|
attribute :units, Unit, collection: true
|
|
@@ -25,7 +27,11 @@ module Unitsdb
|
|
|
25
27
|
# @return [Object, nil] the first entity with matching identifier or nil if not found
|
|
26
28
|
def find_by_type(id:, type:)
|
|
27
29
|
collection = send(type.to_s)
|
|
28
|
-
collection.find
|
|
30
|
+
collection.find do |entity|
|
|
31
|
+
entity.identifiers&.any? do |identifier|
|
|
32
|
+
identifier.id == id
|
|
33
|
+
end
|
|
34
|
+
end
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
# Find an entity by its identifier id across all entity types
|
|
@@ -33,7 +39,8 @@ module Unitsdb
|
|
|
33
39
|
# @param type [String, nil] optional identifier type to match
|
|
34
40
|
# @return [Object, nil] the first entity with matching identifier or nil if not found
|
|
35
41
|
def get_by_id(id:, type: nil)
|
|
36
|
-
%w[units prefixes quantities dimensions
|
|
42
|
+
%w[units prefixes quantities dimensions
|
|
43
|
+
unit_systems].each do |collection_name|
|
|
37
44
|
next unless respond_to?(collection_name)
|
|
38
45
|
|
|
39
46
|
collection = send(collection_name)
|
|
@@ -63,7 +70,12 @@ module Unitsdb
|
|
|
63
70
|
results = []
|
|
64
71
|
|
|
65
72
|
# Define which collections to search based on type parameter
|
|
66
|
-
collections =
|
|
73
|
+
collections = if type
|
|
74
|
+
[type.to_s]
|
|
75
|
+
else
|
|
76
|
+
%w[units prefixes quantities
|
|
77
|
+
dimensions unit_systems]
|
|
78
|
+
end
|
|
67
79
|
|
|
68
80
|
collections.each do |collection_name|
|
|
69
81
|
next unless respond_to?(collection_name)
|
|
@@ -71,7 +83,9 @@ module Unitsdb
|
|
|
71
83
|
collection = send(collection_name)
|
|
72
84
|
collection.each do |entity|
|
|
73
85
|
# Search in identifiers
|
|
74
|
-
if entity.identifiers&.any?
|
|
86
|
+
if entity.identifiers&.any? do |identifier|
|
|
87
|
+
identifier.id.to_s.downcase.include?(text.downcase)
|
|
88
|
+
end
|
|
75
89
|
results << entity
|
|
76
90
|
next
|
|
77
91
|
end
|
|
@@ -86,14 +100,14 @@ module Unitsdb
|
|
|
86
100
|
|
|
87
101
|
# Search in short description
|
|
88
102
|
if entity.respond_to?(:short) && entity.short &&
|
|
89
|
-
|
|
103
|
+
entity.short.to_s.downcase.include?(text.downcase)
|
|
90
104
|
results << entity
|
|
91
105
|
next
|
|
92
106
|
end
|
|
93
107
|
|
|
94
108
|
# Special case for prefix name (prefixes don't have names array)
|
|
95
109
|
next unless collection_name == "prefixes" && entity.respond_to?(:name) &&
|
|
96
|
-
|
|
110
|
+
entity.name.to_s.downcase.include?(text.downcase)
|
|
97
111
|
|
|
98
112
|
results << entity
|
|
99
113
|
next
|
|
@@ -116,7 +130,8 @@ module Unitsdb
|
|
|
116
130
|
collections = entity_type ? [entity_type.to_s] : %w[units prefixes]
|
|
117
131
|
|
|
118
132
|
collections.each do |collection_name|
|
|
119
|
-
next unless respond_to?(collection_name) && %w[units
|
|
133
|
+
next unless respond_to?(collection_name) && %w[units
|
|
134
|
+
prefixes].include?(collection_name)
|
|
120
135
|
|
|
121
136
|
collection = send(collection_name)
|
|
122
137
|
collection.each do |entity|
|
|
@@ -158,11 +173,16 @@ module Unitsdb
|
|
|
158
173
|
|
|
159
174
|
result = {
|
|
160
175
|
exact: [],
|
|
161
|
-
symbol_match: []
|
|
176
|
+
symbol_match: [],
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
# Define collections to search based on entity_type parameter
|
|
165
|
-
collections =
|
|
180
|
+
collections = if entity_type
|
|
181
|
+
[entity_type.to_s]
|
|
182
|
+
else
|
|
183
|
+
%w[units prefixes
|
|
184
|
+
quantities dimensions unit_systems]
|
|
185
|
+
end
|
|
166
186
|
|
|
167
187
|
collections.each do |collection_name|
|
|
168
188
|
next unless respond_to?(collection_name)
|
|
@@ -174,23 +194,25 @@ module Unitsdb
|
|
|
174
194
|
if %w[exact all].include?(match_type)
|
|
175
195
|
# Match by short
|
|
176
196
|
if entity.respond_to?(:short) && entity.short &&
|
|
177
|
-
|
|
197
|
+
entity.short.downcase == value.downcase
|
|
178
198
|
result[:exact] << {
|
|
179
199
|
entity: entity,
|
|
180
200
|
match_desc: "short_to_name",
|
|
181
|
-
details: "UnitsDB short '#{entity.short}' matches '#{value}'"
|
|
201
|
+
details: "UnitsDB short '#{entity.short}' matches '#{value}'",
|
|
182
202
|
}
|
|
183
203
|
next
|
|
184
204
|
end
|
|
185
205
|
|
|
186
206
|
# Match by names
|
|
187
207
|
if entity.respond_to?(:names) && entity.names
|
|
188
|
-
matching_name = entity.names.find
|
|
208
|
+
matching_name = entity.names.find do |name|
|
|
209
|
+
name.value.to_s.downcase == value.downcase
|
|
210
|
+
end
|
|
189
211
|
if matching_name
|
|
190
212
|
result[:exact] << {
|
|
191
213
|
entity: entity,
|
|
192
214
|
match_desc: "name_to_name",
|
|
193
|
-
details: "UnitsDB name '#{matching_name.value}' (#{matching_name.lang}) matches '#{value}'"
|
|
215
|
+
details: "UnitsDB name '#{matching_name.value}' (#{matching_name.lang}) matches '#{value}'",
|
|
194
216
|
}
|
|
195
217
|
next
|
|
196
218
|
end
|
|
@@ -199,7 +221,7 @@ module Unitsdb
|
|
|
199
221
|
|
|
200
222
|
# For symbol matches - only applicable to units and prefixes
|
|
201
223
|
if %w[symbol all].include?(match_type) &&
|
|
202
|
-
|
|
224
|
+
%w[units prefixes].include?(collection_name)
|
|
203
225
|
if collection_name == "units" && entity.respond_to?(:symbols) && entity.symbols
|
|
204
226
|
# Units can have multiple symbols
|
|
205
227
|
matching_symbol = entity.symbols.find do |sym|
|
|
@@ -211,7 +233,7 @@ module Unitsdb
|
|
|
211
233
|
result[:symbol_match] << {
|
|
212
234
|
entity: entity,
|
|
213
235
|
match_desc: "symbol_match",
|
|
214
|
-
details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'"
|
|
236
|
+
details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'",
|
|
215
237
|
}
|
|
216
238
|
end
|
|
217
239
|
elsif collection_name == "prefixes" && entity.respond_to?(:symbols) && entity.symbols
|
|
@@ -225,7 +247,7 @@ module Unitsdb
|
|
|
225
247
|
result[:symbol_match] << {
|
|
226
248
|
entity: entity,
|
|
227
249
|
match_desc: "symbol_match",
|
|
228
|
-
details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'"
|
|
250
|
+
details: "UnitsDB symbol '#{matching_symbol.ascii}' matches '#{value}'",
|
|
229
251
|
}
|
|
230
252
|
end
|
|
231
253
|
end
|
|
@@ -243,7 +265,7 @@ module Unitsdb
|
|
|
243
265
|
def validate_uniqueness
|
|
244
266
|
results = {
|
|
245
267
|
short: {},
|
|
246
|
-
id: {}
|
|
268
|
+
id: {},
|
|
247
269
|
}
|
|
248
270
|
|
|
249
271
|
# Validate short names for applicable collections
|
|
@@ -277,116 +299,114 @@ module Unitsdb
|
|
|
277
299
|
invalid_refs
|
|
278
300
|
end
|
|
279
301
|
|
|
280
|
-
def self.from_db(dir_path)
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
raise Errors::DatabaseNotFoundError, "Database directory not found: #{db_path}" unless Dir.exist?(db_path)
|
|
302
|
+
def self.from_db(dir_path, context: Unitsdb::Config.context_id)
|
|
303
|
+
context_id = context.to_sym
|
|
304
|
+
if context_id == Unitsdb::Config.context_id &&
|
|
305
|
+
Unitsdb::Config.find_context(context_id).nil?
|
|
306
|
+
Unitsdb::Config.context(context_id)
|
|
307
|
+
end
|
|
287
308
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
309
|
+
db_path = File.expand_path(dir_path.to_s)
|
|
310
|
+
unless Dir.exist?(db_path)
|
|
311
|
+
raise Errors::DatabaseNotFoundError,
|
|
312
|
+
"Database directory not found: #{db_path}"
|
|
313
|
+
end
|
|
291
314
|
|
|
292
|
-
|
|
293
|
-
|
|
315
|
+
missing_files = DATABASE_FILES.values.reject do |filename|
|
|
316
|
+
File.exist?(File.join(db_path, filename))
|
|
317
|
+
end
|
|
294
318
|
|
|
295
319
|
if missing_files.any?
|
|
296
320
|
raise Errors::DatabaseFileNotFoundError,
|
|
297
|
-
"Missing required database files: #{missing_files.join(
|
|
321
|
+
"Missing required database files: #{missing_files.join(', ')}"
|
|
298
322
|
end
|
|
299
323
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
puts " - #{prefixes_yaml}"
|
|
311
|
-
puts " - #{dimensions_yaml}"
|
|
312
|
-
puts " - #{units_yaml}"
|
|
313
|
-
puts " - #{quantities_yaml}"
|
|
314
|
-
puts " - #{unit_systems_yaml}"
|
|
324
|
+
documents = load_database_documents(db_path)
|
|
325
|
+
schema_version = validate_schema_versions!(documents)
|
|
326
|
+
combined_hash = build_database_hash(documents, schema_version)
|
|
327
|
+
|
|
328
|
+
Lutaml::Model::GlobalContext.with_context(context_id) do
|
|
329
|
+
if Unitsdb::Config.register(context_id)
|
|
330
|
+
from_hash(combined_hash, register: context_id)
|
|
331
|
+
else
|
|
332
|
+
from_hash(combined_hash)
|
|
333
|
+
end
|
|
315
334
|
end
|
|
335
|
+
end
|
|
316
336
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
raise Errors::
|
|
337
|
+
def self.load_database_documents(db_path)
|
|
338
|
+
puts "[UnitsDB] Loading YAML files from directory: #{db_path}" if ENV["UNITSDB_DEBUG"]
|
|
339
|
+
DATABASE_FILES.transform_values do |filename|
|
|
340
|
+
puts " - #{File.join(db_path, filename)}" if ENV["UNITSDB_DEBUG"]
|
|
341
|
+
load_database_yaml(File.join(db_path, filename), filename)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def self.load_database_yaml(path, filename)
|
|
346
|
+
document = YAML.safe_load_file(path)
|
|
347
|
+
|
|
348
|
+
unless document.is_a?(Hash)
|
|
349
|
+
raise Errors::DatabaseFileInvalidError,
|
|
350
|
+
"Invalid YAML structure in #{filename}: expected a mapping"
|
|
330
351
|
end
|
|
331
352
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
353
|
+
document
|
|
354
|
+
rescue Errno::ENOENT => e
|
|
355
|
+
raise Errors::DatabaseFileNotFoundError,
|
|
356
|
+
"Failed to read database file: #{e.message}"
|
|
357
|
+
rescue Psych::SyntaxError => e
|
|
358
|
+
raise Errors::DatabaseFileInvalidError,
|
|
359
|
+
"Invalid YAML in database file: #{e.message}"
|
|
360
|
+
rescue Errors::DatabaseError
|
|
361
|
+
raise
|
|
362
|
+
rescue StandardError => e
|
|
363
|
+
raise Errors::DatabaseLoadError,
|
|
364
|
+
"Error loading database file #{filename}: #{e.message}"
|
|
365
|
+
end
|
|
366
|
+
private_class_method :load_database_documents, :load_database_yaml
|
|
339
367
|
|
|
340
|
-
|
|
368
|
+
def self.validate_schema_versions!(documents)
|
|
369
|
+
versions = DATABASE_FILES.each_with_object({}) do |(collection_key, filename), result|
|
|
370
|
+
document = documents.fetch(collection_key)
|
|
371
|
+
result[filename] = document.fetch("schema_version")
|
|
372
|
+
rescue KeyError
|
|
341
373
|
raise Errors::DatabaseFileInvalidError,
|
|
342
|
-
"Missing schema_version in
|
|
374
|
+
"Missing schema_version in #{filename}"
|
|
343
375
|
end
|
|
344
376
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
units_version = units_hash["schema_version"]
|
|
349
|
-
quantities_version = quantities_hash["schema_version"]
|
|
350
|
-
unit_systems_version = unit_systems_hash["schema_version"]
|
|
351
|
-
|
|
352
|
-
# Check if all versions match
|
|
353
|
-
versions = [
|
|
354
|
-
prefixes_version,
|
|
355
|
-
dimensions_version,
|
|
356
|
-
units_version,
|
|
357
|
-
quantities_version,
|
|
358
|
-
unit_systems_version
|
|
359
|
-
]
|
|
360
|
-
|
|
361
|
-
unless versions.uniq.size == 1
|
|
362
|
-
version_info = {
|
|
363
|
-
"prefixes.yaml" => prefixes_version,
|
|
364
|
-
"dimensions.yaml" => dimensions_version,
|
|
365
|
-
"units.yaml" => units_version,
|
|
366
|
-
"quantities.yaml" => quantities_version,
|
|
367
|
-
"unit_systems.yaml" => unit_systems_version
|
|
368
|
-
}
|
|
369
|
-
raise Errors::VersionMismatchError, "Version mismatch in database files: #{version_info.inspect}"
|
|
377
|
+
unless versions.values.uniq.size == 1
|
|
378
|
+
raise Errors::VersionMismatchError,
|
|
379
|
+
"Version mismatch in database files: #{versions.inspect}"
|
|
370
380
|
end
|
|
371
381
|
|
|
372
|
-
|
|
373
|
-
version
|
|
374
|
-
unless version == "2.0.0"
|
|
382
|
+
version = versions.values.first
|
|
383
|
+
unless version == SUPPORTED_SCHEMA_VERSION
|
|
375
384
|
raise Errors::UnsupportedVersionError,
|
|
376
|
-
"Unsupported database version: #{version}. Only version
|
|
385
|
+
"Unsupported database version: #{version}. Only version #{SUPPORTED_SCHEMA_VERSION} is supported."
|
|
377
386
|
end
|
|
378
387
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
"
|
|
385
|
-
|
|
386
|
-
|
|
388
|
+
version
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def self.build_database_hash(documents, schema_version)
|
|
392
|
+
{
|
|
393
|
+
"schema_version" => schema_version,
|
|
394
|
+
}.merge(
|
|
395
|
+
DATABASE_FILES.keys.to_h do |collection_key|
|
|
396
|
+
document = documents.fetch(collection_key)
|
|
397
|
+
[collection_key, fetch_collection!(document, collection_key)]
|
|
398
|
+
end,
|
|
399
|
+
)
|
|
400
|
+
end
|
|
387
401
|
|
|
388
|
-
|
|
402
|
+
def self.fetch_collection!(document, collection_key)
|
|
403
|
+
document.fetch(collection_key)
|
|
404
|
+
rescue KeyError
|
|
405
|
+
raise Errors::DatabaseFileInvalidError,
|
|
406
|
+
"Missing #{collection_key} collection in #{DATABASE_FILES.fetch(collection_key)}"
|
|
389
407
|
end
|
|
408
|
+
private_class_method :validate_schema_versions!, :build_database_hash,
|
|
409
|
+
:fetch_collection!
|
|
390
410
|
|
|
391
411
|
private
|
|
392
412
|
|
|
@@ -533,7 +553,8 @@ module Unitsdb
|
|
|
533
553
|
ref_type = "dimensions"
|
|
534
554
|
ref_path = "dimensions:index:#{index}:dimension_reference"
|
|
535
555
|
|
|
536
|
-
validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs,
|
|
556
|
+
validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs,
|
|
557
|
+
"dimensions")
|
|
537
558
|
end
|
|
538
559
|
end
|
|
539
560
|
|
|
@@ -545,7 +566,8 @@ module Unitsdb
|
|
|
545
566
|
ref_type = "unit_systems"
|
|
546
567
|
ref_path = "units:index:#{index}:unit_system_reference[#{idx}]"
|
|
547
568
|
|
|
548
|
-
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
569
|
+
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
570
|
+
invalid_refs, "units")
|
|
549
571
|
end
|
|
550
572
|
end
|
|
551
573
|
end
|
|
@@ -558,7 +580,8 @@ module Unitsdb
|
|
|
558
580
|
ref_type = "quantities"
|
|
559
581
|
ref_path = "units:index:#{index}:quantity_references[#{idx}]"
|
|
560
582
|
|
|
561
|
-
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
583
|
+
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
584
|
+
invalid_refs, "units")
|
|
562
585
|
end
|
|
563
586
|
end
|
|
564
587
|
end
|
|
@@ -575,7 +598,8 @@ module Unitsdb
|
|
|
575
598
|
ref_type = "units"
|
|
576
599
|
ref_path = "units:index:#{index}:root_units.#{idx}.unit_reference"
|
|
577
600
|
|
|
578
|
-
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
601
|
+
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
602
|
+
invalid_refs, "units")
|
|
579
603
|
|
|
580
604
|
# Check prefix reference if present
|
|
581
605
|
next unless root_unit.respond_to?(:prefix_reference) && root_unit.prefix_reference
|
|
@@ -584,7 +608,8 @@ module Unitsdb
|
|
|
584
608
|
ref_type = "prefixes"
|
|
585
609
|
ref_path = "units:index:#{index}:root_units.#{idx}.prefix_reference"
|
|
586
610
|
|
|
587
|
-
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
611
|
+
validate_reference(ref_id, ref_type, ref_path, registry,
|
|
612
|
+
invalid_refs, "units")
|
|
588
613
|
end
|
|
589
614
|
end
|
|
590
615
|
end
|
|
@@ -608,8 +633,12 @@ module Unitsdb
|
|
|
608
633
|
# 3. Try alternate ID formats for unit systems (e.g., SI_base vs si-base)
|
|
609
634
|
if !valid && type == "unitsml" && ref_type == "unit_systems" && registry.key?(ref_type) && (
|
|
610
635
|
registry[ref_type].keys.any? { |k| k.end_with?(":#{id}") } ||
|
|
611
|
-
registry[ref_type].keys.any?
|
|
612
|
-
|
|
636
|
+
registry[ref_type].keys.any? do |k|
|
|
637
|
+
k.end_with?(":SI_#{id.sub('si-', '')}")
|
|
638
|
+
end ||
|
|
639
|
+
registry[ref_type].keys.any? do |k|
|
|
640
|
+
k.end_with?(":non-SI_#{id.sub('nonsi-', '')}")
|
|
641
|
+
end
|
|
613
642
|
)
|
|
614
643
|
# Special handling for unit_systems between unitsml and nist types
|
|
615
644
|
valid = true
|
|
@@ -617,7 +646,8 @@ module Unitsdb
|
|
|
617
646
|
|
|
618
647
|
unless valid
|
|
619
648
|
invalid_refs[file_type] ||= {}
|
|
620
|
-
invalid_refs[file_type][ref_path] =
|
|
649
|
+
invalid_refs[file_type][ref_path] =
|
|
650
|
+
{ id: id, type: type, ref_type: ref_type }
|
|
621
651
|
end
|
|
622
652
|
# Handle references that are objects with id and type in a hash
|
|
623
653
|
elsif ref_id.is_a?(Hash) && ref_id.key?("id") && ref_id.key?("type")
|
|
@@ -637,8 +667,12 @@ module Unitsdb
|
|
|
637
667
|
# 3. Try alternate ID formats for unit systems (e.g., SI_base vs si-base)
|
|
638
668
|
if !valid && type == "unitsml" && ref_type == "unit_systems" && registry.key?(ref_type) && (
|
|
639
669
|
registry[ref_type].keys.any? { |k| k.end_with?(":#{id}") } ||
|
|
640
|
-
registry[ref_type].keys.any?
|
|
641
|
-
|
|
670
|
+
registry[ref_type].keys.any? do |k|
|
|
671
|
+
k.end_with?(":SI_#{id.sub('si-', '')}")
|
|
672
|
+
end ||
|
|
673
|
+
registry[ref_type].keys.any? do |k|
|
|
674
|
+
k.end_with?(":non-SI_#{id.sub('nonsi-', '')}")
|
|
675
|
+
end
|
|
642
676
|
)
|
|
643
677
|
# Special handling for unit_systems between unitsml and nist types
|
|
644
678
|
valid = true
|
|
@@ -646,7 +680,8 @@ module Unitsdb
|
|
|
646
680
|
|
|
647
681
|
unless valid
|
|
648
682
|
invalid_refs[file_type] ||= {}
|
|
649
|
-
invalid_refs[file_type][ref_path] =
|
|
683
|
+
invalid_refs[file_type][ref_path] =
|
|
684
|
+
{ id: id, type: type, ref_type: ref_type }
|
|
650
685
|
end
|
|
651
686
|
else
|
|
652
687
|
# Handle plain string references (legacy format)
|
|
@@ -659,4 +694,6 @@ module Unitsdb
|
|
|
659
694
|
end
|
|
660
695
|
end
|
|
661
696
|
end
|
|
697
|
+
|
|
698
|
+
Config.register_model(Database, id: :database)
|
|
662
699
|
end
|
data/lib/unitsdb/dimension.rb
CHANGED
|
@@ -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,8 @@ 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
|
|
46
|
+
|
|
47
|
+
Config.register_model(Dimension, id: :dimension)
|
|
49
48
|
end
|
|
@@ -10,11 +10,12 @@
|
|
|
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
|
|
17
16
|
attribute :symbol, :string
|
|
18
17
|
attribute :symbols, SymbolPresentations, collection: true
|
|
19
18
|
end
|
|
19
|
+
|
|
20
|
+
Config.register_model(DimensionDetails, id: :dimension_details)
|
|
20
21
|
end
|
data/lib/unitsdb/dimensions.rb
CHANGED
|
@@ -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)
|
|
@@ -10,4 +8,6 @@ module Unitsdb
|
|
|
10
8
|
attribute :version, :string
|
|
11
9
|
attribute :dimensions, Dimension, collection: true
|
|
12
10
|
end
|
|
11
|
+
|
|
12
|
+
Config.register_model(Dimensions, id: :dimensions)
|
|
13
13
|
end
|
data/lib/unitsdb/errors.rb
CHANGED
|
@@ -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
|
data/lib/unitsdb/identifier.rb
CHANGED
data/lib/unitsdb/prefix.rb
CHANGED
|
@@ -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
|
|
@@ -27,4 +23,6 @@ module Unitsdb
|
|
|
27
23
|
attribute :power, :integer
|
|
28
24
|
attribute :references, ExternalReference, collection: true
|
|
29
25
|
end
|
|
26
|
+
|
|
27
|
+
Config.register_model(Prefix, id: :prefix)
|
|
30
28
|
end
|
data/lib/unitsdb/prefixes.rb
CHANGED
|
@@ -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
|
|
@@ -20,4 +19,6 @@ module Unitsdb
|
|
|
20
19
|
attribute :version, :string
|
|
21
20
|
attribute :prefixes, Prefix, collection: true
|
|
22
21
|
end
|
|
22
|
+
|
|
23
|
+
Config.register_model(Prefixes, id: :prefixes)
|
|
23
24
|
end
|
data/lib/unitsdb/quantities.rb
CHANGED
|
@@ -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)
|
|
@@ -9,4 +7,6 @@ module Unitsdb
|
|
|
9
7
|
attribute :version, :string
|
|
10
8
|
attribute :quantities, Quantity, collection: true
|
|
11
9
|
end
|
|
10
|
+
|
|
11
|
+
Config.register_model(Quantities, id: :quantities)
|
|
12
12
|
end
|
data/lib/unitsdb/quantity.rb
CHANGED
|
@@ -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)
|
|
@@ -18,4 +12,6 @@ module Unitsdb
|
|
|
18
12
|
attribute :dimension_reference, DimensionReference
|
|
19
13
|
attribute :references, ExternalReference, collection: true
|
|
20
14
|
end
|
|
15
|
+
|
|
16
|
+
Config.register_model(Quantity, id: :quantity)
|
|
21
17
|
end
|