unitsdb 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fda421d6dfc06976fad5da00dd85f0fb1dbb3dc4865e2904a28b237530ace05
4
- data.tar.gz: 9e4fdd8395fab543936c4d4b415f05c468b788d287545d3ebfd774a53a9f766c
3
+ metadata.gz: e2982ead6dc990098c687109bd98560cd35945c6272e01a88bcd4f1270ffdffa
4
+ data.tar.gz: f89db123f11036b7963fd5fc60a1e37476cd7dac43664be26c95776089479844
5
5
  SHA512:
6
- metadata.gz: 8453d7f411242d4fbf035b73cee6d968505c60e884606b872317a1fe53dd93b3e603a0497c1869b1768649dbf2c23a6fdcbe233dccf4eee95f482f1d440f2163
7
- data.tar.gz: 5a7d1579b935b9afb7bb5e4c0ab8c25e943be6b525d401411bf97d8b3101061a0b211631af0740dcd3476fb012c2c3048dadc0399ec75f91ed425e8416bbd59e
6
+ metadata.gz: 811a621748d4936a1668e7f6969e5090f4da626b7ca0122bbce24ea1d3b217a533d2ea0e5759a812c22faa4d097941538e9273db4c2f84beb908ee301c0ef51a
7
+ data.tar.gz: 23456a3351a981a001f57476bba3815b95c93ce65008189bf1334ae87cf6c0aa57201f897301c8579e0cc9866af10dc2989eb9a58af1aad2c7e63c15d6f05e42
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "canon"
9
- gem "lutaml-model", github: "lutaml/lutaml-model", branch: "main"
9
+ gem "lutaml-model", github: "lutaml/lutaml-model", branch: "fix/global-context-register-lookup-fallback"
10
10
  gem "nokogiri"
11
11
  gem "rake"
12
12
  gem "rspec"
@@ -2,17 +2,129 @@
2
2
 
3
3
  module Unitsdb
4
4
  class Config
5
+ CONTEXT_ID = :unitsdb_v2
6
+
5
7
  class << self
8
+ def context_id
9
+ @context_id ||= CONTEXT_ID
10
+ end
11
+
12
+ def register_model(klass, id:)
13
+ registered_models[id.to_sym] = klass
14
+ klass
15
+ end
16
+
17
+ def registered_models
18
+ @registered_models ||= {}
19
+ end
20
+
6
21
  def models
7
22
  @models ||= {}
8
23
  end
9
24
 
10
25
  def models=(user_models)
11
- models.merge!(user_models)
26
+ normalized_models = user_models.each_with_object({}) do |(id, klass), result|
27
+ model_id = id.to_sym
28
+ result[model_id] = register_model(klass, id: model_id)
29
+ end
30
+
31
+ models.merge!(normalized_models)
12
32
  end
13
33
 
14
34
  def model_for(model_name)
15
- models[model_name]
35
+ model_id = model_name.to_sym
36
+ models[model_id] || registered_models[model_id]
37
+ end
38
+
39
+ def register(id = context_id)
40
+ explicit_registers[id.to_sym]
41
+ end
42
+
43
+ def populate_register(id: context_id, fallback_to: [:default], substitutions: [])
44
+ register_id = id.to_sym
45
+ context(register_id)
46
+
47
+ model_register = Lutaml::Model::Register.new(register_id, fallback: fallback_to)
48
+ resolve_substitutions(
49
+ substitutions,
50
+ registry: build_registry,
51
+ fallback_to: fallback_to,
52
+ id: "#{register_id}_register",
53
+ ).each do |substitution|
54
+ model_register.register_global_type_substitution(**substitution)
55
+ end
56
+
57
+ explicit_registers[register_id] = Lutaml::Model::GlobalRegister.register(model_register)
58
+ end
59
+
60
+ def find_context(id)
61
+ Lutaml::Model::GlobalContext.context(id.to_sym)
62
+ end
63
+
64
+ def resolve_type(type_name, context: context_id)
65
+ Lutaml::Model::GlobalContext.resolve_type(type_name, context.to_sym)
66
+ end
67
+
68
+ def context(id = context_id, force_populate: false)
69
+ existing = find_context(id)
70
+ return existing if existing && !force_populate && populated?(id)
71
+
72
+ populate_context(id: id)
73
+ end
74
+
75
+ def populate_context(id: context_id, fallback_to: [:default], substitutions: [])
76
+ Lutaml::Model::GlobalContext.unregister_context(id) if find_context(id)
77
+
78
+ opts = { registry: build_registry, fallback_to: fallback_to, id: id }
79
+ context = Lutaml::Model::GlobalContext.create_context(
80
+ substitutions: resolve_substitutions(substitutions, **opts),
81
+ **opts,
82
+ )
83
+ mark_populated!(id)
84
+ context
85
+ end
86
+
87
+ def resolve_substitutions(substitutions, registry:, fallback_to:, id:)
88
+ resolution_context = Lutaml::Model::TypeContext.derived(
89
+ id: "#{id}_substitution_resolution",
90
+ registry: registry,
91
+ fallback_to: fallback_to,
92
+ )
93
+
94
+ Array(substitutions).map do |substitution|
95
+ from_key = substitution[:from_type] || substitution[:from]
96
+ to_key = substitution[:to_type] || substitution[:to]
97
+
98
+ {
99
+ from_type: resolve_substitution_type(from_key, resolution_context),
100
+ to_type: resolve_substitution_type(to_key, resolution_context),
101
+ }
102
+ end
103
+ end
104
+
105
+ def resolve_substitution_type(value, resolution_context)
106
+ return value if value.is_a?(Class)
107
+
108
+ Lutaml::Model::TypeResolver.resolve(value, resolution_context)
109
+ end
110
+
111
+ def build_registry
112
+ registry = Lutaml::Model::TypeRegistry.new
113
+ registered_models.each { |model_id, klass| registry.register(model_id, klass) }
114
+ registry
115
+ end
116
+
117
+ def populated?(context_id)
118
+ @populated_for&.[](context_id.to_sym)
119
+ end
120
+
121
+ def mark_populated!(context_id)
122
+ @populated_for ||= {}
123
+ @populated_for[context_id.to_sym] = true
124
+ end
125
+
126
+ def explicit_registers
127
+ @explicit_registers ||= {}
16
128
  end
17
129
  end
18
130
  end
@@ -4,6 +4,15 @@ module Unitsdb
4
4
  class Database < Lutaml::Model::Serializable
5
5
  # model Config.model_for(:units)
6
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
+
7
16
  attribute :schema_version, :string
8
17
  attribute :version, :string
9
18
  attribute :units, Unit, collection: true
@@ -290,25 +299,21 @@ module Unitsdb
290
299
  invalid_refs
291
300
  end
292
301
 
293
- def self.from_db(dir_path)
294
- # If dir_path is a relative path, make it relative to the current working directory
295
- db_path = dir_path
296
- puts "Database directory path: #{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
297
308
 
298
- # Check if the directory exists
309
+ db_path = File.expand_path(dir_path.to_s)
299
310
  unless Dir.exist?(db_path)
300
311
  raise Errors::DatabaseNotFoundError,
301
312
  "Database directory not found: #{db_path}"
302
313
  end
303
314
 
304
- # Define required files
305
- required_files = %w[prefixes.yaml dimensions.yaml units.yaml
306
- quantities.yaml unit_systems.yaml]
307
- yaml_files = required_files.map { |file| File.join(dir_path, file) }
308
-
309
- # Check if all required files exist
310
- missing_files = required_files.reject do |file|
311
- File.exist?(File.join(dir_path, file))
315
+ missing_files = DATABASE_FILES.values.reject do |filename|
316
+ File.exist?(File.join(db_path, filename))
312
317
  end
313
318
 
314
319
  if missing_files.any?
@@ -316,99 +321,92 @@ module Unitsdb
316
321
  "Missing required database files: #{missing_files.join(', ')}"
317
322
  end
318
323
 
319
- # Ensure we have path properly joined with filenames
320
- prefixes_yaml = yaml_files[0]
321
- dimensions_yaml = yaml_files[1]
322
- units_yaml = yaml_files[2]
323
- quantities_yaml = yaml_files[3]
324
- unit_systems_yaml = yaml_files[4]
325
-
326
- # Debug paths
327
- if ENV["DEBUG"]
328
- puts "[UnitsDB] Loading YAML files from directory: #{dir_path}"
329
- puts " - #{prefixes_yaml}"
330
- puts " - #{dimensions_yaml}"
331
- puts " - #{units_yaml}"
332
- puts " - #{quantities_yaml}"
333
- 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
334
334
  end
335
+ end
335
336
 
336
- # Load YAML files with better error handling
337
- begin
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)
343
- rescue Errno::ENOENT => e
344
- raise Errors::DatabaseFileNotFoundError,
345
- "Failed to read database file: #{e.message}"
346
- rescue Psych::SyntaxError => e
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)
347
349
  raise Errors::DatabaseFileInvalidError,
348
- "Invalid YAML in database file: #{e.message}"
349
- rescue StandardError => e
350
- raise Errors::DatabaseLoadError, "Error loading database: #{e.message}"
350
+ "Invalid YAML structure in #{filename}: expected a mapping"
351
351
  end
352
352
 
353
- # Verify all files have schema_version field
354
- missing_schema = []
355
- missing_schema << "prefixes.yaml" unless prefixes_hash.key?("schema_version")
356
- missing_schema << "dimensions.yaml" unless dimensions_hash.key?("schema_version")
357
- missing_schema << "units.yaml" unless units_hash.key?("schema_version")
358
- missing_schema << "quantities.yaml" unless quantities_hash.key?("schema_version")
359
- missing_schema << "unit_systems.yaml" unless unit_systems_hash.key?("schema_version")
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
360
367
 
361
- if missing_schema.any?
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
362
373
  raise Errors::DatabaseFileInvalidError,
363
- "Missing schema_version in files: #{missing_schema.join(', ')}"
374
+ "Missing schema_version in #{filename}"
364
375
  end
365
376
 
366
- # Extract versions from each file
367
- prefixes_version = prefixes_hash["schema_version"]
368
- dimensions_version = dimensions_hash["schema_version"]
369
- units_version = units_hash["schema_version"]
370
- quantities_version = quantities_hash["schema_version"]
371
- unit_systems_version = unit_systems_hash["schema_version"]
372
-
373
- # Check if all versions match
374
- versions = [
375
- prefixes_version,
376
- dimensions_version,
377
- units_version,
378
- quantities_version,
379
- unit_systems_version,
380
- ]
381
-
382
- unless versions.uniq.size == 1
383
- version_info = {
384
- "prefixes.yaml" => prefixes_version,
385
- "dimensions.yaml" => dimensions_version,
386
- "units.yaml" => units_version,
387
- "quantities.yaml" => quantities_version,
388
- "unit_systems.yaml" => unit_systems_version,
389
- }
377
+ unless versions.values.uniq.size == 1
390
378
  raise Errors::VersionMismatchError,
391
- "Version mismatch in database files: #{version_info.inspect}"
379
+ "Version mismatch in database files: #{versions.inspect}"
392
380
  end
393
381
 
394
- # Check if the version is supported
395
- version = versions.first
396
- unless version == "2.0.0"
382
+ version = versions.values.first
383
+ unless version == SUPPORTED_SCHEMA_VERSION
397
384
  raise Errors::UnsupportedVersionError,
398
- "Unsupported database version: #{version}. Only version 2.0.0 is supported."
385
+ "Unsupported database version: #{version}. Only version #{SUPPORTED_SCHEMA_VERSION} is supported."
399
386
  end
400
387
 
401
- combined_yaml = {
402
- "schema_version" => prefixes_version,
403
- "prefixes" => prefixes_hash["prefixes"],
404
- "dimensions" => dimensions_hash["dimensions"],
405
- "units" => units_hash["units"],
406
- "quantities" => quantities_hash["quantities"],
407
- "unit_systems" => unit_systems_hash["unit_systems"],
408
- }.to_yaml
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
409
401
 
410
- from_yaml(combined_yaml)
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)}"
411
407
  end
408
+ private_class_method :validate_schema_versions!, :build_database_hash,
409
+ :fetch_collection!
412
410
 
413
411
  private
414
412
 
@@ -616,8 +614,7 @@ module Unitsdb
616
614
  end
617
615
  end
618
616
 
619
- def validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs,
620
- file_type)
617
+ def validate_reference(ref_id, ref_type, ref_path, registry, invalid_refs, file_type)
621
618
  # Handle references that are objects with id and type (could be a hash or an object)
622
619
  if ref_id.respond_to?(:id) && ref_id.respond_to?(:type)
623
620
  id = ref_id.id
@@ -697,4 +694,6 @@ file_type)
697
694
  end
698
695
  end
699
696
  end
697
+
698
+ Config.register_model(Database, id: :database)
700
699
  end
@@ -43,4 +43,6 @@ module Unitsdb
43
43
  attribute :names, LocalizedString, collection: true
44
44
  attribute :references, ExternalReference, collection: true
45
45
  end
46
+
47
+ Config.register_model(Dimension, id: :dimension)
46
48
  end
@@ -16,4 +16,6 @@ module Unitsdb
16
16
  attribute :symbol, :string
17
17
  attribute :symbols, SymbolPresentations, collection: true
18
18
  end
19
+
20
+ Config.register_model(DimensionDetails, id: :dimension_details)
19
21
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(DimensionReference, id: :dimension_reference)
8
10
  end
@@ -8,4 +8,6 @@ module Unitsdb
8
8
  attribute :version, :string
9
9
  attribute :dimensions, Dimension, collection: true
10
10
  end
11
+
12
+ Config.register_model(Dimensions, id: :dimensions)
11
13
  end
@@ -11,4 +11,6 @@ module Unitsdb
11
11
  attribute :type, :string, values: %w[normative informative]
12
12
  attribute :authority, :string
13
13
  end
14
+
15
+ Config.register_model(ExternalReference, id: :external_reference)
14
16
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(Identifier, id: :identifier)
8
10
  end
@@ -14,4 +14,6 @@ module Unitsdb
14
14
  value&.downcase
15
15
  end
16
16
  end
17
+
18
+ Config.register_model(LocalizedString, id: :localized_string)
17
19
  end
@@ -23,4 +23,6 @@ module Unitsdb
23
23
  attribute :power, :integer
24
24
  attribute :references, ExternalReference, collection: true
25
25
  end
26
+
27
+ Config.register_model(Prefix, id: :prefix)
26
28
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(PrefixReference, id: :prefix_reference)
8
10
  end
@@ -19,4 +19,6 @@ module Unitsdb
19
19
  attribute :version, :string
20
20
  attribute :prefixes, Prefix, collection: true
21
21
  end
22
+
23
+ Config.register_model(Prefixes, id: :prefixes)
22
24
  end
@@ -7,4 +7,6 @@ module Unitsdb
7
7
  attribute :version, :string
8
8
  attribute :quantities, Quantity, collection: true
9
9
  end
10
+
11
+ Config.register_model(Quantities, id: :quantities)
10
12
  end
@@ -12,4 +12,6 @@ module Unitsdb
12
12
  attribute :dimension_reference, DimensionReference
13
13
  attribute :references, ExternalReference, collection: true
14
14
  end
15
+
16
+ Config.register_model(Quantity, id: :quantity)
15
17
  end
@@ -7,4 +7,6 @@ module Unitsdb
7
7
  attribute :id, :string
8
8
  attribute :type, :string
9
9
  end
10
+
11
+ Config.register_model(QuantityReference, id: :quantity_reference)
10
12
  end
data/lib/unitsdb/qudt.rb CHANGED
@@ -18,6 +18,7 @@ module Unitsdb
18
18
  "qudt:unit:#{uri}"
19
19
  end
20
20
  end
21
+ Config.register_model(QudtUnit, id: :qudt_unit)
21
22
 
22
23
  # QUDT QuantityKind from quantitykinds vocabulary
23
24
  # Example: http://qudt.org/vocab/quantitykind/Length
@@ -33,6 +34,7 @@ module Unitsdb
33
34
  "qudt:quantitykind:#{uri}"
34
35
  end
35
36
  end
37
+ Config.register_model(QudtQuantityKind, id: :qudt_quantity_kind)
36
38
 
37
39
  # QUDT DimensionVector from dimensionvectors vocabulary
38
40
  # Example: http://qudt.org/vocab/dimensionvector/A0E0L1I0M0H0T0D0
@@ -52,6 +54,7 @@ module Unitsdb
52
54
  "qudt:dimensionvector:#{uri}"
53
55
  end
54
56
  end
57
+ Config.register_model(QudtDimensionVector, id: :qudt_dimension_vector)
55
58
 
56
59
  # QUDT SystemOfUnits from sou vocabulary
57
60
  # Example: http://qudt.org/vocab/sou/SI
@@ -65,6 +68,7 @@ module Unitsdb
65
68
  "qudt:sou:#{uri}"
66
69
  end
67
70
  end
71
+ Config.register_model(QudtSystemOfUnits, id: :qudt_system_of_units)
68
72
 
69
73
  # QUDT Prefix from prefixes vocabulary
70
74
  # Example: http://qudt.org/vocab/prefix/Kilo
@@ -83,6 +87,7 @@ module Unitsdb
83
87
  "qudt:prefix:#{uri}"
84
88
  end
85
89
  end
90
+ Config.register_model(QudtPrefix, id: :qudt_prefix)
86
91
 
87
92
  # Container for all QUDT vocabularies
88
93
  class QudtVocabularies
@@ -8,4 +8,6 @@ module Unitsdb
8
8
  attribute :unit_reference, UnitReference
9
9
  attribute :prefix_reference, PrefixReference
10
10
  end
11
+
12
+ Config.register_model(RootUnitReference, id: :root_unit_reference)
11
13
  end
data/lib/unitsdb/scale.rb CHANGED
@@ -10,4 +10,6 @@ module Unitsdb
10
10
  attribute :short, :string
11
11
  attribute :properties, ScaleProperties
12
12
  end
13
+
14
+ Config.register_model(Scale, id: :scale)
13
15
  end
@@ -9,4 +9,6 @@ module Unitsdb
9
9
  attribute :interval, :boolean
10
10
  attribute :ratio, :boolean
11
11
  end
12
+
13
+ Config.register_model(ScaleProperties, id: :scale_properties)
12
14
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(ScaleReference, id: :scale_reference)
8
10
  end
@@ -7,4 +7,6 @@ module Unitsdb
7
7
  attribute :version, :string
8
8
  attribute :scales, Scale, collection: true
9
9
  end
10
+
11
+ Config.register_model(Scales, id: :scales)
10
12
  end
@@ -14,4 +14,6 @@ module Unitsdb
14
14
  class SiDerivedBase < RootUnitReference
15
15
  # model Config.model_for(:si_derived_base)
16
16
  end
17
+
18
+ Config.register_model(SiDerivedBase, id: :si_derived_base)
17
19
  end
@@ -11,4 +11,6 @@ module Unitsdb
11
11
  attribute :mathml, :string
12
12
  attribute :unicode, :string
13
13
  end
14
+
15
+ Config.register_model(SymbolPresentations, id: :symbol_presentations)
14
16
  end
data/lib/unitsdb/ucum.rb CHANGED
@@ -28,6 +28,7 @@ module Unitsdb
28
28
  "ucum:base-unit:code:#{code_sensitive}"
29
29
  end
30
30
  end
31
+ Config.register_model(UcumBaseUnit, id: :ucum_base_unit)
31
32
 
32
33
  # <prefix Code="Y" CODE="YA">
33
34
  # <name>yotta</name>
@@ -46,6 +47,7 @@ module Unitsdb
46
47
  map_content to: :content
47
48
  end
48
49
  end
50
+ Config.register_model(UcumPrefixValue, id: :ucum_prefix_value)
49
51
 
50
52
  class UcumPrefix < Lutaml::Model::Serializable
51
53
  attribute :code_sensitive, :string
@@ -67,6 +69,7 @@ module Unitsdb
67
69
  "ucum:prefix:code:#{code_sensitive}"
68
70
  end
69
71
  end
72
+ Config.register_model(UcumPrefix, id: :ucum_prefix)
70
73
 
71
74
  # <unit Code="10*" CODE="10*" isMetric="no" class="dimless">
72
75
  # <name>the number ten for arbitrary powers</name>
@@ -114,6 +117,7 @@ module Unitsdb
114
117
  map_attribute "Unit", to: :unit_sensitive
115
118
  end
116
119
  end
120
+ Config.register_model(UcumUnitValueFunction, id: :ucum_unit_value_function)
117
121
 
118
122
  class UcumUnitValue < Lutaml::Model::Serializable
119
123
  attribute :unit_sensitive, :string
@@ -131,6 +135,7 @@ module Unitsdb
131
135
  map_content to: :content
132
136
  end
133
137
  end
138
+ Config.register_model(UcumUnitValue, id: :ucum_unit_value)
134
139
 
135
140
  class UcumUnit < Lutaml::Model::Serializable
136
141
  attribute :code_sensitive, :string
@@ -165,6 +170,7 @@ module Unitsdb
165
170
  "ucum:unit:#{k}:code:#{code_sensitive}"
166
171
  end
167
172
  end
173
+ Config.register_model(UcumUnit, id: :ucum_unit)
168
174
 
169
175
  class UcumNamespace < Lutaml::Xml::Namespace
170
176
  uri "http://unitsofmeasure.org/ucum-essence"
@@ -199,4 +205,5 @@ module Unitsdb
199
205
 
200
206
  # No adapter registration needed
201
207
  end
208
+ Config.register_model(UcumFile, id: :ucum_file)
202
209
  end
data/lib/unitsdb/unit.rb CHANGED
@@ -50,4 +50,6 @@ module Unitsdb
50
50
  attribute :references, ExternalReference, collection: true
51
51
  attribute :scale_reference, ScaleReference
52
52
  end
53
+
54
+ Config.register_model(Unit, id: :unit)
53
55
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(UnitReference, id: :unit_reference)
8
10
  end
@@ -10,4 +10,6 @@ module Unitsdb
10
10
  attribute :acceptable, :boolean
11
11
  attribute :references, ExternalReference, collection: true
12
12
  end
13
+
14
+ Config.register_model(UnitSystem, id: :unit_system)
13
15
  end
@@ -5,4 +5,6 @@ module Unitsdb
5
5
  attribute :id, :string
6
6
  attribute :type, :string
7
7
  end
8
+
9
+ Config.register_model(UnitSystemReference, id: :unit_system_reference)
8
10
  end
@@ -8,4 +8,6 @@ module Unitsdb
8
8
  attribute :version, :string
9
9
  attribute :unit_systems, UnitSystem, collection: true
10
10
  end
11
+
12
+ Config.register_model(UnitSystems, id: :unit_systems)
11
13
  end
data/lib/unitsdb/units.rb CHANGED
@@ -8,4 +8,6 @@ module Unitsdb
8
8
  attribute :version, :string
9
9
  attribute :units, Unit, collection: true
10
10
  end
11
+
12
+ Config.register_model(Units, id: :units)
11
13
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unitsdb
4
- VERSION = "2.2.1"
4
+ VERSION = "2.2.2"
5
5
 
6
6
  # The version of the bundled UnitsDB data (from the data/ submodule).
7
7
  # This version corresponds to a tag/commit in https://github.com/unitsml/unitsdb.
data/lib/unitsdb.rb CHANGED
@@ -1,52 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "lutaml/model"
4
+ require "unitsdb/config"
5
+ require "unitsdb/identifier"
6
+ require "unitsdb/localized_string"
7
+ require "unitsdb/symbol_presentations"
8
+ require "unitsdb/scale_properties"
9
+ require "unitsdb/unit_reference"
10
+ require "unitsdb/prefix_reference"
11
+ require "unitsdb/quantity_reference"
12
+ require "unitsdb/dimension_reference"
13
+ require "unitsdb/unit_system_reference"
14
+ require "unitsdb/scale_reference"
15
+ require "unitsdb/external_reference"
16
+ require "unitsdb/root_unit_reference"
17
+ require "unitsdb/si_derived_base"
18
+ require "unitsdb/dimension_details"
19
+ require "unitsdb/dimension"
20
+ require "unitsdb/prefix"
21
+ require "unitsdb/unit_system"
22
+ require "unitsdb/quantity"
23
+ require "unitsdb/scale"
24
+ require "unitsdb/unit"
25
+ require "unitsdb/dimensions"
26
+ require "unitsdb/prefixes"
27
+ require "unitsdb/quantities"
28
+ require "unitsdb/scales"
29
+ require "unitsdb/unit_systems"
30
+ require "unitsdb/units"
31
+ require "unitsdb/database"
32
+ require "unitsdb/qudt"
33
+ require "unitsdb/ucum"
4
34
 
5
35
  module Unitsdb
6
- autoload :Cli, "unitsdb/cli"
7
- autoload :Config, "unitsdb/config"
8
- autoload :Commands, "unitsdb/commands"
9
- autoload :Database, "unitsdb/database"
10
- autoload :Dimension, "unitsdb/dimension"
11
- autoload :DimensionDetails, "unitsdb/dimension_details"
12
- autoload :DimensionReference, "unitsdb/dimension_reference"
13
- autoload :Dimensions, "unitsdb/dimensions"
36
+ # Core models are eagerly loaded so type registrations are complete before
37
+ # any context or database loading happens.
38
+ unless RUBY_ENGINE == "opal"
39
+ autoload :Cli, "unitsdb/cli"
40
+ autoload :Commands, "unitsdb/commands"
41
+ end
14
42
  autoload :Errors, "unitsdb/errors"
15
- autoload :ExternalReference, "unitsdb/external_reference"
16
- autoload :Identifier, "unitsdb/identifier"
17
- autoload :LocalizedString, "unitsdb/localized_string"
18
- autoload :Prefix, "unitsdb/prefix"
19
- autoload :PrefixReference, "unitsdb/prefix_reference"
20
- autoload :Prefixes, "unitsdb/prefixes"
21
- autoload :Quantities, "unitsdb/quantities"
22
- autoload :Quantity, "unitsdb/quantity"
23
- autoload :QuantityReference, "unitsdb/quantity_reference"
24
- autoload :QudtUnit, "unitsdb/qudt"
25
- autoload :QudtQuantityKind, "unitsdb/qudt"
26
- autoload :QudtDimensionVector, "unitsdb/qudt"
27
- autoload :QudtSystemOfUnits, "unitsdb/qudt"
28
- autoload :QudtPrefix, "unitsdb/qudt"
29
- autoload :QudtVocabularies, "unitsdb/qudt"
30
- autoload :RootUnitReference, "unitsdb/root_unit_reference"
31
- autoload :Scale, "unitsdb/scale"
32
- autoload :ScaleProperties, "unitsdb/scale_properties"
33
- autoload :ScaleReference, "unitsdb/scale_reference"
34
- autoload :Scales, "unitsdb/scales"
35
- autoload :SiDerivedBase, "unitsdb/si_derived_base"
36
- autoload :SymbolPresentations, "unitsdb/symbol_presentations"
37
- autoload :UcumBaseUnit, "unitsdb/ucum"
38
- autoload :UcumPrefixValue, "unitsdb/ucum"
39
- autoload :UcumPrefix, "unitsdb/ucum"
40
- autoload :UcumUnitValueFunction, "unitsdb/ucum"
41
- autoload :UcumUnitValue, "unitsdb/ucum"
42
- autoload :UcumUnit, "unitsdb/ucum"
43
- autoload :UcumFile, "unitsdb/ucum"
44
- autoload :Unit, "unitsdb/unit"
45
- autoload :UnitReference, "unitsdb/unit_reference"
46
- autoload :UnitSystem, "unitsdb/unit_system"
47
- autoload :UnitSystemReference, "unitsdb/unit_system_reference"
48
- autoload :UnitSystems, "unitsdb/unit_systems"
49
- autoload :Units, "unitsdb/units"
50
43
  autoload :Utils, "unitsdb/utils"
51
44
 
52
45
  class << self
@@ -56,12 +49,19 @@ module Unitsdb
56
49
  end
57
50
 
58
51
  # Returns a pre-loaded Database instance from the bundled data
59
- def database
60
- @database ||= Database.from_db(data_dir)
52
+ def database(context: Config.context_id)
53
+ context_id = context.to_sym
54
+ Config.context(context_id) if context_id == Config.context_id && Config.find_context(context_id).nil?
55
+ klass = Config.resolve_type(:database, context: context_id)
56
+ databases[context_id] ||= klass.from_db(data_dir, context: context_id)
61
57
  end
62
58
 
63
59
  private
64
60
 
61
+ def databases
62
+ @databases ||= {}
63
+ end
64
+
65
65
  def gem_dir
66
66
  @gem_dir ||= File.dirname(__dir__)
67
67
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unitsdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-03 00:00:00.000000000 Z
11
+ date: 2026-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fuzzy_match