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.
Files changed (95) 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/config.rb +114 -2
  57. data/lib/unitsdb/database.rb +160 -123
  58. data/lib/unitsdb/dimension.rb +3 -4
  59. data/lib/unitsdb/dimension_details.rb +2 -1
  60. data/lib/unitsdb/dimension_reference.rb +2 -0
  61. data/lib/unitsdb/dimensions.rb +2 -2
  62. data/lib/unitsdb/errors.rb +7 -0
  63. data/lib/unitsdb/external_reference.rb +2 -0
  64. data/lib/unitsdb/identifier.rb +2 -0
  65. data/lib/unitsdb/localized_string.rb +2 -0
  66. data/lib/unitsdb/prefix.rb +2 -4
  67. data/lib/unitsdb/prefix_reference.rb +2 -2
  68. data/lib/unitsdb/prefixes.rb +2 -1
  69. data/lib/unitsdb/quantities.rb +2 -2
  70. data/lib/unitsdb/quantity.rb +2 -6
  71. data/lib/unitsdb/quantity_reference.rb +2 -0
  72. data/lib/unitsdb/qudt.rb +105 -0
  73. data/lib/unitsdb/root_unit_reference.rb +2 -3
  74. data/lib/unitsdb/scale.rb +2 -4
  75. data/lib/unitsdb/scale_properties.rb +2 -0
  76. data/lib/unitsdb/scale_reference.rb +2 -2
  77. data/lib/unitsdb/scales.rb +2 -2
  78. data/lib/unitsdb/si_derived_base.rb +2 -2
  79. data/lib/unitsdb/symbol_presentations.rb +2 -0
  80. data/lib/unitsdb/ucum.rb +21 -10
  81. data/lib/unitsdb/unit.rb +2 -10
  82. data/lib/unitsdb/unit_reference.rb +2 -2
  83. data/lib/unitsdb/unit_system.rb +3 -3
  84. data/lib/unitsdb/unit_system_reference.rb +2 -2
  85. data/lib/unitsdb/unit_systems.rb +2 -2
  86. data/lib/unitsdb/units.rb +2 -2
  87. data/lib/unitsdb/utils.rb +32 -21
  88. data/lib/unitsdb/version.rb +5 -1
  89. data/lib/unitsdb.rb +62 -14
  90. data/unitsdb.gemspec +6 -3
  91. metadata +52 -13
  92. data/lib/unitsdb/commands/si_formatter.rb +0 -485
  93. data/lib/unitsdb/commands/si_matcher.rb +0 -470
  94. data/lib/unitsdb/commands/si_ttl_parser.rb +0 -100
  95. data/lib/unitsdb/commands/si_updater.rb +0 -212
@@ -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
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ # QUDT Unit from units vocabulary
5
+ # Example: http://qudt.org/vocab/unit/M (meter)
6
+ class QudtUnit < Lutaml::Model::Serializable
7
+ attribute :uri, :string
8
+ attribute :label, :string
9
+ attribute :symbol, :string
10
+ attribute :has_quantity_kind, :string
11
+ attribute :has_dimension_vector, :string
12
+ attribute :conversion_multiplier, :float
13
+ attribute :conversion_offset, :float
14
+ attribute :description, :string
15
+ attribute :si_exact_match, :string
16
+
17
+ def identifier
18
+ "qudt:unit:#{uri}"
19
+ end
20
+ end
21
+ Config.register_model(QudtUnit, id: :qudt_unit)
22
+
23
+ # QUDT QuantityKind from quantitykinds vocabulary
24
+ # Example: http://qudt.org/vocab/quantitykind/Length
25
+ class QudtQuantityKind < Lutaml::Model::Serializable
26
+ attribute :uri, :string
27
+ attribute :label, :string
28
+ attribute :has_dimension_vector, :string
29
+ attribute :description, :string
30
+ attribute :symbol, :string
31
+ attribute :si_exact_match, :string
32
+
33
+ def identifier
34
+ "qudt:quantitykind:#{uri}"
35
+ end
36
+ end
37
+ Config.register_model(QudtQuantityKind, id: :qudt_quantity_kind)
38
+
39
+ # QUDT DimensionVector from dimensionvectors vocabulary
40
+ # Example: http://qudt.org/vocab/dimensionvector/A0E0L1I0M0H0T0D0
41
+ class QudtDimensionVector < Lutaml::Model::Serializable
42
+ attribute :uri, :string
43
+ attribute :label, :string
44
+ attribute :dimension_exponent_for_length, :integer
45
+ attribute :dimension_exponent_for_mass, :integer
46
+ attribute :dimension_exponent_for_time, :integer
47
+ attribute :dimension_exponent_for_electric_current, :integer
48
+ attribute :dimension_exponent_for_thermodynamic_temperature, :integer
49
+ attribute :dimension_exponent_for_amount_of_substance, :integer
50
+ attribute :dimension_exponent_for_luminous_intensity, :integer
51
+ attribute :description, :string
52
+
53
+ def identifier
54
+ "qudt:dimensionvector:#{uri}"
55
+ end
56
+ end
57
+ Config.register_model(QudtDimensionVector, id: :qudt_dimension_vector)
58
+
59
+ # QUDT SystemOfUnits from sou vocabulary
60
+ # Example: http://qudt.org/vocab/sou/SI
61
+ class QudtSystemOfUnits < Lutaml::Model::Serializable
62
+ attribute :uri, :string
63
+ attribute :label, :string
64
+ attribute :abbreviation, :string
65
+ attribute :description, :string
66
+
67
+ def identifier
68
+ "qudt:sou:#{uri}"
69
+ end
70
+ end
71
+ Config.register_model(QudtSystemOfUnits, id: :qudt_system_of_units)
72
+
73
+ # QUDT Prefix from prefixes vocabulary
74
+ # Example: http://qudt.org/vocab/prefix/Kilo
75
+ class QudtPrefix < Lutaml::Model::Serializable
76
+ attribute :uri, :string
77
+ attribute :label, :string
78
+ attribute :symbol, :string
79
+ attribute :prefix_multiplier, :float
80
+ attribute :prefix_multiplier_sn, :string
81
+ attribute :ucum_code, :string
82
+ attribute :si_exact_match, :string
83
+ attribute :description, :string
84
+ attribute :prefix_type, :string # "DecimalPrefix" or "BinaryPrefix"
85
+
86
+ def identifier
87
+ "qudt:prefix:#{uri}"
88
+ end
89
+ end
90
+ Config.register_model(QudtPrefix, id: :qudt_prefix)
91
+
92
+ # Container for all QUDT vocabularies
93
+ class QudtVocabularies
94
+ attr_accessor :units, :quantity_kinds, :dimension_vectors,
95
+ :systems_of_units, :prefixes
96
+
97
+ def initialize
98
+ @units = []
99
+ @quantity_kinds = []
100
+ @dimension_vectors = []
101
+ @systems_of_units = []
102
+ @prefixes = []
103
+ end
104
+ end
105
+ end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "unit_reference"
4
- require_relative "prefix_reference"
5
-
6
3
  module Unitsdb
7
4
  class RootUnitReference < Lutaml::Model::Serializable
8
5
  # model Config.model_for(:root_unit)
@@ -11,4 +8,6 @@ module Unitsdb
11
8
  attribute :unit_reference, UnitReference
12
9
  attribute :prefix_reference, PrefixReference
13
10
  end
11
+
12
+ Config.register_model(RootUnitReference, id: :root_unit_reference)
14
13
  end
data/lib/unitsdb/scale.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
- require_relative "localized_string"
5
- require_relative "scale_properties"
6
-
7
3
  module Unitsdb
8
4
  class Scale < Lutaml::Model::Serializable
9
5
  # model Config.model_for(:quantity)
@@ -14,4 +10,6 @@ module Unitsdb
14
10
  attribute :short, :string
15
11
  attribute :properties, ScaleProperties
16
12
  end
13
+
14
+ Config.register_model(Scale, id: :scale)
17
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
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
-
5
3
  module Unitsdb
6
4
  class ScaleReference < Identifier
7
5
  attribute :id, :string
8
6
  attribute :type, :string
9
7
  end
8
+
9
+ Config.register_model(ScaleReference, id: :scale_reference)
10
10
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "scale"
4
-
5
3
  module Unitsdb
6
4
  class Scales < Lutaml::Model::Serializable
7
5
  # model Config.model_for(:Scale)
@@ -9,4 +7,6 @@ module Unitsdb
9
7
  attribute :version, :string
10
8
  attribute :scales, Scale, collection: true
11
9
  end
10
+
11
+ Config.register_model(Scales, id: :scales)
12
12
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "root_unit_reference"
4
-
5
3
  # si_derived_bases:
6
4
  # - power: 2
7
5
  # unit_reference:
@@ -16,4 +14,6 @@ module Unitsdb
16
14
  class SiDerivedBase < RootUnitReference
17
15
  # model Config.model_for(:si_derived_base)
18
16
  end
17
+
18
+ Config.register_model(SiDerivedBase, id: :si_derived_base)
19
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
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "lutaml/model"
4
-
5
3
  module Unitsdb
6
4
  # <base-unit Code="s" CODE="S" dim="T">
7
5
  # <name>second</name>
@@ -17,7 +15,7 @@ module Unitsdb
17
15
  attribute :property, :string
18
16
 
19
17
  xml do
20
- root "base-unit"
18
+ element "base-unit"
21
19
  map_attribute "Code", to: :code_sensitive
22
20
  map_attribute "CODE", to: :code
23
21
  map_attribute "dim", to: :dimension
@@ -30,6 +28,7 @@ module Unitsdb
30
28
  "ucum:base-unit:code:#{code_sensitive}"
31
29
  end
32
30
  end
31
+ Config.register_model(UcumBaseUnit, id: :ucum_base_unit)
33
32
 
34
33
  # <prefix Code="Y" CODE="YA">
35
34
  # <name>yotta</name>
@@ -43,11 +42,12 @@ module Unitsdb
43
42
  attribute :content, :string
44
43
 
45
44
  xml do
46
- root "value"
45
+ element "value"
47
46
  map_attribute "value", to: :value
48
47
  map_content to: :content
49
48
  end
50
49
  end
50
+ Config.register_model(UcumPrefixValue, id: :ucum_prefix_value)
51
51
 
52
52
  class UcumPrefix < Lutaml::Model::Serializable
53
53
  attribute :code_sensitive, :string
@@ -57,7 +57,7 @@ module Unitsdb
57
57
  attribute :value, UcumPrefixValue
58
58
 
59
59
  xml do
60
- root "prefix"
60
+ element "prefix"
61
61
  map_attribute "Code", to: :code_sensitive
62
62
  map_attribute "CODE", to: :code
63
63
  map_element "name", to: :name
@@ -69,6 +69,7 @@ module Unitsdb
69
69
  "ucum:prefix:code:#{code_sensitive}"
70
70
  end
71
71
  end
72
+ Config.register_model(UcumPrefix, id: :ucum_prefix)
72
73
 
73
74
  # <unit Code="10*" CODE="10*" isMetric="no" class="dimless">
74
75
  # <name>the number ten for arbitrary powers</name>
@@ -110,12 +111,13 @@ module Unitsdb
110
111
  attribute :unit_sensitive, :string
111
112
 
112
113
  xml do
113
- root "function"
114
+ element "function"
114
115
  map_attribute "name", to: :name
115
116
  map_attribute "value", to: :value
116
117
  map_attribute "Unit", to: :unit_sensitive
117
118
  end
118
119
  end
120
+ Config.register_model(UcumUnitValueFunction, id: :ucum_unit_value_function)
119
121
 
120
122
  class UcumUnitValue < Lutaml::Model::Serializable
121
123
  attribute :unit_sensitive, :string
@@ -125,7 +127,7 @@ module Unitsdb
125
127
  attribute :content, :string
126
128
 
127
129
  xml do
128
- root "value"
130
+ element "value"
129
131
  map_attribute "Unit", to: :unit_sensitive
130
132
  map_attribute "UNIT", to: :unit
131
133
  map_attribute "value", to: :value
@@ -133,6 +135,7 @@ module Unitsdb
133
135
  map_content to: :content
134
136
  end
135
137
  end
138
+ Config.register_model(UcumUnitValue, id: :ucum_unit_value)
136
139
 
137
140
  class UcumUnit < Lutaml::Model::Serializable
138
141
  attribute :code_sensitive, :string
@@ -147,7 +150,7 @@ module Unitsdb
147
150
  attribute :value, UcumUnitValue
148
151
 
149
152
  xml do
150
- root "unit"
153
+ element "unit"
151
154
  map_attribute "Code", to: :code_sensitive
152
155
  map_attribute "CODE", to: :code
153
156
  map_attribute "isMetric", to: :is_metric
@@ -167,6 +170,12 @@ module Unitsdb
167
170
  "ucum:unit:#{k}:code:#{code_sensitive}"
168
171
  end
169
172
  end
173
+ Config.register_model(UcumUnit, id: :ucum_unit)
174
+
175
+ class UcumNamespace < Lutaml::Xml::Namespace
176
+ uri "http://unitsofmeasure.org/ucum-essence"
177
+ prefix_default "ucum"
178
+ end
170
179
 
171
180
  # This is the root element of the UCUM XML "ucum-essence.xml" file.
172
181
  #
@@ -182,8 +191,9 @@ module Unitsdb
182
191
  attribute :units, UcumUnit, collection: true
183
192
 
184
193
  xml do
185
- root "root"
186
- namespace "http://unitsofmeasure.org/ucum-essence"
194
+ element "root"
195
+ namespace UcumNamespace
196
+
187
197
  map_attribute "version", to: :version
188
198
  map_attribute "revision", to: :revision
189
199
  map_attribute "revision-date", to: :revision_date
@@ -195,4 +205,5 @@ module Unitsdb
195
205
 
196
206
  # No adapter registration needed
197
207
  end
208
+ Config.register_model(UcumFile, id: :ucum_file)
198
209
  end
data/lib/unitsdb/unit.rb CHANGED
@@ -1,15 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "symbol_presentations"
4
- require_relative "unit_system_reference"
5
- require_relative "root_unit_reference"
6
- require_relative "si_derived_base"
7
- require_relative "quantity_reference"
8
- require_relative "dimension_reference"
9
- require_relative "external_reference"
10
- require_relative "localized_string"
11
- require_relative "scale_reference"
12
-
13
3
  # "NISTu10":
14
4
  # dimension_url: "#NISTd9"
15
5
  # short: steradian
@@ -60,4 +50,6 @@ module Unitsdb
60
50
  attribute :references, ExternalReference, collection: true
61
51
  attribute :scale_reference, ScaleReference
62
52
  end
53
+
54
+ Config.register_model(Unit, id: :unit)
63
55
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
-
5
3
  module Unitsdb
6
4
  class UnitReference < Identifier
7
5
  attribute :id, :string
8
6
  attribute :type, :string
9
7
  end
8
+
9
+ Config.register_model(UnitReference, id: :unit_reference)
10
10
  end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
- require_relative "localized_string"
5
-
6
3
  module Unitsdb
7
4
  class UnitSystem < Lutaml::Model::Serializable
8
5
  # model Config.model_for(:unit_system)
@@ -11,5 +8,8 @@ module Unitsdb
11
8
  attribute :names, LocalizedString, collection: true
12
9
  attribute :short, :string
13
10
  attribute :acceptable, :boolean
11
+ attribute :references, ExternalReference, collection: true
14
12
  end
13
+
14
+ Config.register_model(UnitSystem, id: :unit_system)
15
15
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "identifier"
4
-
5
3
  module Unitsdb
6
4
  class UnitSystemReference < Identifier
7
5
  attribute :id, :string
8
6
  attribute :type, :string
9
7
  end
8
+
9
+ Config.register_model(UnitSystemReference, id: :unit_system_reference)
10
10
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "unit_system"
4
-
5
3
  module Unitsdb
6
4
  class UnitSystems < Lutaml::Model::Serializable
7
5
  # model Config.model_for(:unit_systems)
@@ -10,4 +8,6 @@ module Unitsdb
10
8
  attribute :version, :string
11
9
  attribute :unit_systems, UnitSystem, collection: true
12
10
  end
11
+
12
+ Config.register_model(UnitSystems, id: :unit_systems)
13
13
  end
data/lib/unitsdb/units.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "unit"
4
-
5
3
  module Unitsdb
6
4
  class Units < Lutaml::Model::Serializable
7
5
  # model Config.model_for(:units)
@@ -10,4 +8,6 @@ module Unitsdb
10
8
  attribute :version, :string
11
9
  attribute :units, Unit, collection: true
12
10
  end
11
+
12
+ Config.register_model(Units, id: :units)
13
13
  end
data/lib/unitsdb/utils.rb CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  module Unitsdb
4
4
  module Utils
5
- DEFAULT_YAML_FILES = %w[dimensions prefixes quantities unit_systems units].map { |f| "#{f}.yaml" }
5
+ DEFAULT_YAML_FILES = %w[dimensions prefixes quantities unit_systems
6
+ units].map do |f|
7
+ "#{f}.yaml"
8
+ end
6
9
 
7
10
  def self.levenshtein_distance(s, t)
8
11
  m = s.length
@@ -32,7 +35,10 @@ module Unitsdb
32
35
  def self.find_similar_ids(id, valid_ids, max_results = 5)
33
36
  # Simple similarity measure based on Levenshtein distance
34
37
  valid_ids
35
- .map { |valid_id| [valid_id, levenshtein_distance(id.to_s, valid_id.to_s)] }
38
+ .map do |valid_id|
39
+ [valid_id,
40
+ levenshtein_distance(id.to_s, valid_id.to_s)]
41
+ end
36
42
  .sort_by { |_, distance| distance }
37
43
  .take(max_results)
38
44
  .select { |_, distance| distance < [id.to_s.length, 10].min }
@@ -44,32 +50,37 @@ module Unitsdb
44
50
  when Hash
45
51
  # Transform values first, then sort keys
46
52
  obj.transform_values { |v| sort_yaml_keys(v) }
47
- .sort_by do |key, _|
48
- key_str = key.to_s
53
+ .sort_by do |key, _|
54
+ key_str = key.to_s
49
55
 
50
- # Handle NIST IDs with proper category-based sorting
51
- case key_str
52
- when /\ANIST([a-z])(\d+)_(-?\d+)\Z/ # Prefixes with power (NISTp2_10)
53
- [0, ::Regexp.last_match(1), ::Regexp.last_match(2).to_i, ::Regexp.last_match(3).to_i]
54
- when /\ANIST([a-z])(\d+)\Z/ # Prefixes without power
55
- [0, ::Regexp.last_match(1), ::Regexp.last_match(2).to_i, 0]
56
- when %r{[/e]} # Composite IDs with '/' or 'e' to the end
57
- [2, key_str]
58
- when /\ANISTu(\d+)\.(.+)\Z/ # Simple unit IDs (NISTu10.1)
59
- [1, "u", ::Regexp.last_match(1).to_i, ::Regexp.last_match(2)]
60
- else
61
- [3, key_str] # Everything else
62
- end
63
- end.to_h
56
+ # Handle NIST IDs with proper category-based sorting
57
+ case key_str
58
+ when /\ANIST([a-z])(\d+)_(-?\d+)\Z/ # Prefixes with power (NISTp2_10)
59
+ [0, ::Regexp.last_match(1), ::Regexp.last_match(2).to_i,
60
+ ::Regexp.last_match(3).to_i]
61
+ when /\ANIST([a-z])(\d+)\Z/ # Prefixes without power
62
+ [0, ::Regexp.last_match(1), ::Regexp.last_match(2).to_i, 0]
63
+ when %r{[/e]} # Composite IDs with '/' or 'e' to the end
64
+ [2, key_str]
65
+ when /\ANISTu(\d+)\.(.+)\Z/ # Simple unit IDs (NISTu10.1)
66
+ [1, "u", ::Regexp.last_match(1).to_i, ::Regexp.last_match(2)]
67
+ else
68
+ [3, key_str] # Everything else
69
+ end
70
+ end.to_h
64
71
  when Array
65
72
  # For arrays in the new structure, sort them if they're arrays of hashes with 'id' or 'short' keys
66
- if !obj.empty? && obj.all? { |item| item.is_a?(Hash) }
73
+ if !obj.empty? && obj.all?(Hash)
67
74
  # Sort by 'id' within identifiers array
68
75
  if obj.first.key?("id") && obj.first.key?("type")
69
- obj.sort_by { |item| item["id"].to_s }.map { |item| sort_yaml_keys(item) }
76
+ obj.sort_by do |item|
77
+ item["id"].to_s
78
+ end.map { |item| sort_yaml_keys(item) }
70
79
  # Sort by 'short' for other arrays (like main unit arrays)
71
80
  elsif obj.first.key?("short")
72
- obj.sort_by { |item| item["short"].to_s }.map { |item| sort_yaml_keys(item) }
81
+ obj.sort_by do |item|
82
+ item["short"].to_s
83
+ end.map { |item| sort_yaml_keys(item) }
73
84
  else
74
85
  obj.map { |item| sort_yaml_keys(item) }
75
86
  end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unitsdb
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.2"
5
+
6
+ # The version of the bundled UnitsDB data (from the data/ submodule).
7
+ # This version corresponds to a tag/commit in https://github.com/unitsml/unitsdb.
8
+ UNITS_DATA_VERSION = "2.0.0"
5
9
  end
data/lib/unitsdb.rb CHANGED
@@ -1,21 +1,69 @@
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
- require_relative "unitsdb/version"
6
- require_relative "unitsdb/config"
7
- require_relative "unitsdb/errors"
8
- require_relative "unitsdb/database"
9
- require_relative "unitsdb/dimensions"
10
- require_relative "unitsdb/prefixes"
11
- require_relative "unitsdb/quantities"
12
- require_relative "unitsdb/unit_systems"
13
- require_relative "unitsdb/scales"
14
- require_relative "unitsdb/units"
15
- require_relative "unitsdb/utils"
35
+ module Unitsdb
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
42
+ autoload :Errors, "unitsdb/errors"
43
+ autoload :Utils, "unitsdb/utils"
16
44
 
17
- # CLI-related requires
18
- require_relative "unitsdb/cli" if defined?(Thor)
45
+ class << self
46
+ # Returns the path to the bundled data directory containing YAML files
47
+ def data_dir
48
+ @data_dir ||= File.join(gem_dir, "data")
49
+ end
19
50
 
20
- module Unitsdb
51
+ # Returns a pre-loaded Database instance from the bundled data
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)
57
+ end
58
+
59
+ private
60
+
61
+ def databases
62
+ @databases ||= {}
63
+ end
64
+
65
+ def gem_dir
66
+ @gem_dir ||= File.dirname(__dir__)
67
+ end
68
+ end
21
69
  end
data/unitsdb.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = spec.homepage
20
20
  spec.metadata["changelog_uri"] = "https://github.com/unitsml/unitsdb-ruby/releases"
21
+ spec.metadata["rubygems_mfa_required"] = "true"
21
22
 
22
23
  # Specify which files should be added to the gem when it is released.
23
24
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -26,15 +27,17 @@ Gem::Specification.new do |spec|
26
27
  f.match(%r{^(test|spec|features)/})
27
28
  end
28
29
  end
30
+ # Include YAML data files in the gem
31
+ spec.files += Dir.glob("data/**/*.yaml")
29
32
  spec.bindir = "exe"
30
33
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.test_files = `git ls-files -- {spec}/*`.split("\n")
32
34
  spec.require_paths = ["lib"]
33
35
 
34
- spec.add_dependency "lutaml-model", "~>0.7"
36
+ spec.add_dependency "fuzzy_match"
37
+ spec.add_dependency "lutaml-model", "~> 0.8.0"
35
38
  spec.add_dependency "rdf", "~> 3.1"
36
39
  spec.add_dependency "rdf-turtle", "~> 3.1"
37
40
  spec.add_dependency "rubyzip", "~> 2.3"
38
- spec.add_dependency "terminal-table"
41
+ spec.add_dependency "table_tennis", "~> 0.0.7"
39
42
  spec.add_dependency "thor", "~> 1.0"
40
43
  end