unitsdb 1.0.0 → 2.1.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/.rspec +2 -1
  4. data/.rubocop_todo.yml +88 -12
  5. data/Gemfile +2 -2
  6. data/README.adoc +697 -1
  7. data/exe/unitsdb +7 -0
  8. data/lib/unitsdb/cli.rb +81 -0
  9. data/lib/unitsdb/commands/_modify.rb +22 -0
  10. data/lib/unitsdb/commands/base.rb +52 -0
  11. data/lib/unitsdb/commands/check_si.rb +124 -0
  12. data/lib/unitsdb/commands/get.rb +133 -0
  13. data/lib/unitsdb/commands/normalize.rb +81 -0
  14. data/lib/unitsdb/commands/release.rb +112 -0
  15. data/lib/unitsdb/commands/search.rb +219 -0
  16. data/lib/unitsdb/commands/si_formatter.rb +485 -0
  17. data/lib/unitsdb/commands/si_matcher.rb +470 -0
  18. data/lib/unitsdb/commands/si_ttl_parser.rb +100 -0
  19. data/lib/unitsdb/commands/si_updater.rb +212 -0
  20. data/lib/unitsdb/commands/validate/identifiers.rb +40 -0
  21. data/lib/unitsdb/commands/validate/references.rb +316 -0
  22. data/lib/unitsdb/commands/validate/si_references.rb +115 -0
  23. data/lib/unitsdb/commands/validate.rb +40 -0
  24. data/lib/unitsdb/database.rb +661 -0
  25. data/lib/unitsdb/dimension.rb +49 -0
  26. data/lib/unitsdb/dimension_details.rb +20 -0
  27. data/lib/unitsdb/dimension_reference.rb +8 -0
  28. data/lib/unitsdb/dimensions.rb +4 -10
  29. data/lib/unitsdb/errors.rb +13 -0
  30. data/lib/unitsdb/external_reference.rb +14 -0
  31. data/lib/unitsdb/identifier.rb +8 -0
  32. data/lib/unitsdb/localized_string.rb +17 -0
  33. data/lib/unitsdb/prefix.rb +30 -0
  34. data/lib/unitsdb/prefix_reference.rb +10 -0
  35. data/lib/unitsdb/prefixes.rb +4 -11
  36. data/lib/unitsdb/quantities.rb +4 -31
  37. data/lib/unitsdb/quantity.rb +21 -0
  38. data/lib/unitsdb/quantity_reference.rb +10 -0
  39. data/lib/unitsdb/root_unit_reference.rb +14 -0
  40. data/lib/unitsdb/scale.rb +17 -0
  41. data/lib/unitsdb/scale_properties.rb +12 -0
  42. data/lib/unitsdb/scale_reference.rb +10 -0
  43. data/lib/unitsdb/scales.rb +11 -0
  44. data/lib/unitsdb/si_derived_base.rb +19 -0
  45. data/lib/unitsdb/symbol_presentations.rb +3 -8
  46. data/lib/unitsdb/unit.rb +63 -0
  47. data/lib/unitsdb/unit_reference.rb +10 -0
  48. data/lib/unitsdb/unit_system.rb +15 -0
  49. data/lib/unitsdb/unit_system_reference.rb +10 -0
  50. data/lib/unitsdb/unit_systems.rb +4 -10
  51. data/lib/unitsdb/units.rb +4 -10
  52. data/lib/unitsdb/utils.rb +84 -0
  53. data/lib/unitsdb/version.rb +1 -1
  54. data/lib/unitsdb.rb +12 -2
  55. data/unitsdb.gemspec +6 -1
  56. metadata +116 -20
  57. data/lib/unitsdb/dimensions/dimension.rb +0 -59
  58. data/lib/unitsdb/dimensions/quantity.rb +0 -32
  59. data/lib/unitsdb/dimensions/symbol.rb +0 -26
  60. data/lib/unitsdb/prefixes/prefix.rb +0 -35
  61. data/lib/unitsdb/prefixes/symbol.rb +0 -17
  62. data/lib/unitsdb/quantities/quantity.rb +0 -37
  63. data/lib/unitsdb/quantities/unit_reference.rb +0 -15
  64. data/lib/unitsdb/unit_systems/unit_system.rb +0 -19
  65. data/lib/unitsdb/units/quantity_reference.rb +0 -17
  66. data/lib/unitsdb/units/root_unit.rb +0 -21
  67. data/lib/unitsdb/units/root_units.rb +0 -18
  68. data/lib/unitsdb/units/si_derived_base.rb +0 -26
  69. data/lib/unitsdb/units/symbol.rb +0 -19
  70. data/lib/unitsdb/units/system.rb +0 -17
  71. data/lib/unitsdb/units/unit.rb +0 -73
  72. data/lib/unitsdb/unitsdb.rb +0 -6
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+ require_relative "dimension_details"
5
+ require_relative "quantity"
6
+ require_relative "localized_string"
7
+ # NISTd1:
8
+ # length:
9
+ # power: 1
10
+ # symbol: L
11
+ # dim_symbols:
12
+ # - id: "dim_L"
13
+ # ascii: "L"
14
+ # html: "𝖫"
15
+ # mathml: "<mi mathvariant='sans-serif'>L</mi>"
16
+ # latex: \ensuremath{\mathsf{L}}
17
+ # unicode: "𝖫"
18
+
19
+ # NISTd9:
20
+ # -dimensionless: true
21
+ # -plane_angle:
22
+ # - dim_symbols:
23
+ # - - ascii: phi
24
+ # - html: "&#x1D785;"
25
+ # - id: dim_phi
26
+ # - latex: "\\ensuremath{\\mathsf{\\phi}}"
27
+ # - mathml: "<mi mathvariant='sans-serif'>&#x3c6;</mi>"
28
+ # - unicode: "\U0001D785"
29
+ # - power: 1
30
+ # - symbol: phi
31
+
32
+ module Unitsdb
33
+ class Dimension < Lutaml::Model::Serializable
34
+ # model Config.model_for(:dimension)
35
+
36
+ attribute :identifiers, Identifier, collection: true
37
+ attribute :dimensionless, :boolean
38
+ attribute :length, DimensionDetails
39
+ attribute :mass, DimensionDetails
40
+ attribute :time, DimensionDetails
41
+ attribute :electric_current, DimensionDetails
42
+ attribute :thermodynamic_temperature, DimensionDetails
43
+ attribute :amount_of_substance, DimensionDetails
44
+ attribute :luminous_intensity, DimensionDetails
45
+ attribute :plane_angle, DimensionDetails
46
+ attribute :short, :string
47
+ attribute :names, LocalizedString, collection: true
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # power: 1
4
+ # symbol: M
5
+ # symbols:
6
+ # - ascii: M
7
+ # html: "&#x1D5AC;"
8
+ # id: dim_M
9
+ # latex: "\\ensuremath{\\mathsf{M}}"
10
+ # mathml: "<mi mathvariant='sans-serif'>M</mi>"
11
+ # unicode: "\U0001D5AC"
12
+
13
+ require_relative "symbol_presentations"
14
+ module Unitsdb
15
+ class DimensionDetails < Lutaml::Model::Serializable
16
+ attribute :power, :integer
17
+ attribute :symbol, :string
18
+ attribute :symbols, SymbolPresentations, collection: true
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ class DimensionReference < Identifier
5
+ attribute :id, :string
6
+ attribute :type, :string
7
+ end
8
+ end
@@ -1,18 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "dimensions/dimension"
3
+ require_relative "dimension"
4
4
 
5
5
  module Unitsdb
6
- class Dimensions
7
- include Lutaml::Model::Serialize
8
- model Config.model_for(:dimensions)
6
+ class Dimensions < Lutaml::Model::Serializable
7
+ # model Config.model_for(:dimensions)
9
8
 
9
+ attribute :schema_version, :string
10
10
  attribute :dimensions, Dimension, collection: true
11
-
12
- key_value do
13
- map to: :dimensions, root_mappings: {
14
- id: :key
15
- }
16
- end
17
11
  end
18
12
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ module Errors
5
+ class DatabaseError < StandardError; end
6
+ class DatabaseNotFoundError < DatabaseError; end
7
+ class DatabaseFileNotFoundError < DatabaseError; end
8
+ class DatabaseFileInvalidError < DatabaseError; end
9
+ class DatabaseLoadError < DatabaseError; end
10
+ class VersionMismatchError < DatabaseError; end
11
+ class UnsupportedVersionError < DatabaseError; end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # references:
4
+ # - uri: http://si-digital-framework.org/quantities/LENG
5
+ # type: normative
6
+ # authority: si-digital-framework
7
+
8
+ module Unitsdb
9
+ class ExternalReference < Identifier
10
+ attribute :uri, :string
11
+ attribute :type, :string, values: %w[normative informative]
12
+ attribute :authority, :string
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ class Identifier < Lutaml::Model::Serializable
5
+ attribute :id, :string
6
+ attribute :type, :string
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ # Represents a localized string with a language tag
5
+ class LocalizedString < Lutaml::Model::Serializable
6
+ attribute :value, :string
7
+ attribute :lang, :string
8
+
9
+ def to_s
10
+ "#{value} (#{lang})"
11
+ end
12
+
13
+ def downcase
14
+ value&.downcase
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+ require_relative "symbol_presentations"
5
+ require_relative "external_reference"
6
+ require_relative "localized_string"
7
+ # ---
8
+ # NISTp10_30:
9
+ # name: quetta
10
+ # symbol:
11
+ # ascii: Q
12
+ # html: Q
13
+ # latex: Q
14
+ # unicode: Q
15
+ # base: 10
16
+ # power: 30
17
+
18
+ module Unitsdb
19
+ class Prefix < Lutaml::Model::Serializable
20
+ # model Config.model_for(:prefix)
21
+
22
+ attribute :identifiers, Identifier, collection: true
23
+ attribute :names, LocalizedString, collection: true
24
+ attribute :short, :string
25
+ attribute :symbols, SymbolPresentations, collection: true
26
+ attribute :base, :integer
27
+ attribute :power, :integer
28
+ attribute :references, ExternalReference, collection: true
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+
5
+ module Unitsdb
6
+ class PrefixReference < Identifier
7
+ attribute :id, :string
8
+ attribute :type, :string
9
+ end
10
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "prefixes/prefix"
3
+ require_relative "prefix"
4
4
  # ---
5
5
  # NISTp10_30:
6
6
  # name: quetta
@@ -13,17 +13,10 @@ require_relative "prefixes/prefix"
13
13
  # power: 30
14
14
 
15
15
  module Unitsdb
16
- class Prefixes
17
- include Lutaml::Model::Serialize
18
-
19
- model Config.model_for(:prefixes)
16
+ class Prefixes < Lutaml::Model::Serializable
17
+ # model Config.model_for(:prefixes)
20
18
 
19
+ attribute :schema_version, :string
21
20
  attribute :prefixes, Prefix, collection: true
22
-
23
- key_value do
24
- map to: :prefixes, root_mappings: {
25
- id: :key
26
- }
27
- end
28
21
  end
29
22
  end
@@ -1,38 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # # Quantities
4
- # NISTq156:
5
- # dimension_url: "#NISTd68"
6
- # quantity_type: derived
7
- # quantity_name:
8
- # - linear expansion coefficient
9
- # unit_reference:
10
- # - name: kelvin to the power minus one
11
- # url: "#NISTu5e-1/1"
12
-
13
- # NISTq155:
14
- # dimension_url: "#NISTd57"
15
- # quantity_type: derived
16
- # quantity_name:
17
- # - area moment of inertia
18
- # - second moment of area
19
- # unit_reference:
20
- # - name: inch to the fourth power
21
- # url: "#NISTu208"
22
-
23
- require_relative "quantities/quantity"
3
+ require_relative "quantity"
24
4
 
25
5
  module Unitsdb
26
- class Quantities
27
- include Lutaml::Model::Serialize
28
- model Config.model_for(:quantities)
29
-
6
+ class Quantities < Lutaml::Model::Serializable
7
+ # model Config.model_for(:quantities)
8
+ attribute :schema_version, :string
30
9
  attribute :quantities, Quantity, collection: true
31
-
32
- key_value do
33
- map to: :quantities, root_mappings: {
34
- id: :key
35
- }
36
- end
37
10
  end
38
11
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
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
+ module Unitsdb
10
+ class Quantity < Lutaml::Model::Serializable
11
+ # model Config.model_for(:quantity)
12
+
13
+ attribute :identifiers, Identifier, collection: true
14
+ attribute :quantity_type, :string
15
+ attribute :names, LocalizedString, collection: true
16
+ attribute :short, :string
17
+ attribute :unit_references, UnitReference, collection: true
18
+ attribute :dimension_reference, DimensionReference
19
+ attribute :references, ExternalReference, collection: true
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ class QuantityReference < Identifier
5
+ # model Config.model_for(:quantity_reference)
6
+
7
+ attribute :id, :string
8
+ attribute :type, :string
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "unit_reference"
4
+ require_relative "prefix_reference"
5
+
6
+ module Unitsdb
7
+ class RootUnitReference < Lutaml::Model::Serializable
8
+ # model Config.model_for(:root_unit)
9
+
10
+ attribute :power, :integer
11
+ attribute :unit_reference, UnitReference
12
+ attribute :prefix_reference, PrefixReference
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+ require_relative "localized_string"
5
+ require_relative "scale_properties"
6
+
7
+ module Unitsdb
8
+ class Scale < Lutaml::Model::Serializable
9
+ # model Config.model_for(:quantity)
10
+
11
+ attribute :identifiers, Identifier, collection: true
12
+ attribute :names, LocalizedString, collection: true
13
+ attribute :description, LocalizedString, collection: true
14
+ attribute :short, :string
15
+ attribute :properties, ScaleProperties
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ class ScaleProperties < Lutaml::Model::Serializable
5
+ # model Config.model_for(:quantity)
6
+ attribute :continuous, :boolean
7
+ attribute :ordered, :boolean
8
+ attribute :logarithmic, :boolean
9
+ attribute :interval, :boolean
10
+ attribute :ratio, :boolean
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+
5
+ module Unitsdb
6
+ class ScaleReference < Identifier
7
+ attribute :id, :string
8
+ attribute :type, :string
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "scale"
4
+
5
+ module Unitsdb
6
+ class Scales < Lutaml::Model::Serializable
7
+ # model Config.model_for(:Scale)
8
+ attribute :schema_version, :string
9
+ attribute :scales, Scale, collection: true
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "root_unit_reference"
4
+
5
+ # si_derived_bases:
6
+ # - power: 2
7
+ # unit_reference:
8
+ # id: NISTu1
9
+ # type: nist
10
+ # - power: -2
11
+ # unit_reference:
12
+ # id: NISTu1
13
+ # type: nist
14
+
15
+ module Unitsdb
16
+ class SiDerivedBase < RootUnitReference
17
+ # model Config.model_for(:si_derived_base)
18
+ end
19
+ end
@@ -2,18 +2,13 @@
2
2
 
3
3
  module Unitsdb
4
4
  class SymbolPresentations < Lutaml::Model::Serializable
5
- model Config.model_for(:symbol_presentations)
5
+ # model Config.model_for(:symbol_presentations)
6
6
 
7
+ attribute :id, :string
7
8
  attribute :ascii, :string
8
9
  attribute :html, :string
9
10
  attribute :latex, :string
11
+ attribute :mathml, :string
10
12
  attribute :unicode, :string
11
-
12
- key_value do
13
- map :ascii, to: :ascii
14
- map :html, to: :html
15
- map :latex, to: :latex
16
- map :unicode, to: :unicode
17
- end
18
13
  end
19
14
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
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
+ # "NISTu10":
14
+ # dimension_url: "#NISTd9"
15
+ # short: steradian
16
+ # root: true
17
+ # unit_system:
18
+ # type: "SI_derived_special"
19
+ # name: "SI"
20
+ # names:
21
+ # - "steradian"
22
+ # unit_symbols:
23
+ # - id: "sr"
24
+ # ascii: "sr"
25
+ # html: "sr"
26
+ # mathml: "<mi mathvariant='normal'>sr</mi>"
27
+ # latex: \ensuremath{\mathrm{sr}}
28
+ # unicode: "sr"
29
+ # root_units:
30
+ # enumerated_root_units:
31
+ # - unit: "steradian"
32
+ # power_denominator: 1
33
+ # power: 1
34
+ # quantity_reference:
35
+ # - name: "solid angle"
36
+ # url: "#NISTq11"
37
+ # si_derived_bases:
38
+ # - id: NISTu1
39
+ # prefix:
40
+ # power: 1
41
+ # - id: NISTu1
42
+ # prefix:
43
+ # power: -1
44
+
45
+ module Unitsdb
46
+ class Unit < Lutaml::Model::Serializable
47
+ # model Config.model_for(:unit)
48
+
49
+ attribute :identifiers, Identifier, collection: true
50
+ attribute :short, :string
51
+ attribute :root, :boolean
52
+ attribute :prefixed, :boolean
53
+ attribute :dimension_reference, DimensionReference
54
+ attribute :unit_system_reference, UnitSystemReference, collection: true
55
+ attribute :names, LocalizedString, collection: true
56
+ attribute :symbols, SymbolPresentations, collection: true
57
+ attribute :quantity_references, QuantityReference, collection: true
58
+ attribute :si_derived_bases, SiDerivedBase, collection: true
59
+ attribute :root_units, RootUnitReference, collection: true
60
+ attribute :references, ExternalReference, collection: true
61
+ attribute :scale_reference, ScaleReference
62
+ end
63
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+
5
+ module Unitsdb
6
+ class UnitReference < Identifier
7
+ attribute :id, :string
8
+ attribute :type, :string
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+ require_relative "localized_string"
5
+
6
+ module Unitsdb
7
+ class UnitSystem < Lutaml::Model::Serializable
8
+ # model Config.model_for(:unit_system)
9
+
10
+ attribute :identifiers, Identifier, collection: true
11
+ attribute :names, LocalizedString, collection: true
12
+ attribute :short, :string
13
+ attribute :acceptable, :boolean
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "identifier"
4
+
5
+ module Unitsdb
6
+ class UnitSystemReference < Identifier
7
+ attribute :id, :string
8
+ attribute :type, :string
9
+ end
10
+ end
@@ -1,18 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "unit_systems/unit_system"
3
+ require_relative "unit_system"
4
4
 
5
5
  module Unitsdb
6
- class UnitSystems
7
- include Lutaml::Model::Serialize
8
- model Config.model_for(:unit_systems)
6
+ class UnitSystems < Lutaml::Model::Serializable
7
+ # model Config.model_for(:unit_systems)
9
8
 
9
+ attribute :schema_version, :string
10
10
  attribute :unit_systems, UnitSystem, collection: true
11
-
12
- key_value do
13
- map to: :unit_systems, root_mappings: {
14
- id: :key
15
- }
16
- end
17
11
  end
18
12
  end
data/lib/unitsdb/units.rb CHANGED
@@ -1,18 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "unitsdb/units/unit"
3
+ require_relative "unit"
4
4
 
5
5
  module Unitsdb
6
- class Units
7
- include Lutaml::Model::Serialize
8
- model Config.model_for(:units)
6
+ class Units < Lutaml::Model::Serializable
7
+ # model Config.model_for(:units)
9
8
 
9
+ attribute :schema_version, :string
10
10
  attribute :units, Unit, collection: true
11
-
12
- key_value do
13
- map to: :units, root_mappings: {
14
- id: :key,
15
- }
16
- end
17
11
  end
18
12
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unitsdb
4
+ module Utils
5
+ DEFAULT_YAML_FILES = %w[dimensions prefixes quantities unit_systems units].map { |f| "#{f}.yaml" }
6
+
7
+ def self.levenshtein_distance(s, t)
8
+ m = s.length
9
+ n = t.length
10
+
11
+ return m if n.zero?
12
+ return n if m.zero?
13
+
14
+ d = Array.new(m + 1) { Array.new(n + 1) }
15
+
16
+ (0..m).each { |i| d[i][0] = i }
17
+ (0..n).each { |j| d[0][j] = j }
18
+
19
+ (1..n).each do |j|
20
+ (1..m).each do |i|
21
+ d[i][j] = if s[i - 1] == t[j - 1]
22
+ d[i - 1][j - 1]
23
+ else
24
+ [d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + 1].min
25
+ end
26
+ end
27
+ end
28
+
29
+ d[m][n]
30
+ end
31
+
32
+ def self.find_similar_ids(id, valid_ids, max_results = 5)
33
+ # Simple similarity measure based on Levenshtein distance
34
+ valid_ids
35
+ .map { |valid_id| [valid_id, levenshtein_distance(id.to_s, valid_id.to_s)] }
36
+ .sort_by { |_, distance| distance }
37
+ .take(max_results)
38
+ .select { |_, distance| distance < [id.to_s.length, 10].min }
39
+ .map { |valid_id, _| valid_id }
40
+ end
41
+
42
+ def self.sort_yaml_keys(obj)
43
+ case obj
44
+ when Hash
45
+ # Transform values first, then sort keys
46
+ obj.transform_values { |v| sort_yaml_keys(v) }
47
+ .sort_by do |key, _|
48
+ key_str = key.to_s
49
+
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
64
+ when Array
65
+ # 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) }
67
+ # Sort by 'id' within identifiers array
68
+ if obj.first.key?("id") && obj.first.key?("type")
69
+ obj.sort_by { |item| item["id"].to_s }.map { |item| sort_yaml_keys(item) }
70
+ # Sort by 'short' for other arrays (like main unit arrays)
71
+ elsif obj.first.key?("short")
72
+ obj.sort_by { |item| item["short"].to_s }.map { |item| sort_yaml_keys(item) }
73
+ else
74
+ obj.map { |item| sort_yaml_keys(item) }
75
+ end
76
+ else
77
+ obj.map { |item| sort_yaml_keys(item) }
78
+ end
79
+ else
80
+ obj
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Unitsdb
4
- VERSION = "1.0.0"
4
+ VERSION = "2.1.0"
5
5
  end