unitsdb 2.1.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release.yml +8 -1
  3. data/.gitignore +2 -0
  4. data/.gitmodules +4 -3
  5. data/.rubocop.yml +13 -8
  6. data/.rubocop_todo.yml +217 -100
  7. data/CLAUDE.md +55 -0
  8. data/Gemfile +4 -1
  9. data/README.adoc +283 -16
  10. data/data/dimensions.yaml +1864 -0
  11. data/data/prefixes.yaml +874 -0
  12. data/data/quantities.yaml +3715 -0
  13. data/data/scales.yaml +97 -0
  14. data/data/schemas/dimensions-schema.yaml +153 -0
  15. data/data/schemas/prefixes-schema.yaml +155 -0
  16. data/data/schemas/quantities-schema.yaml +117 -0
  17. data/data/schemas/scales-schema.yaml +106 -0
  18. data/data/schemas/unit_systems-schema.yaml +116 -0
  19. data/data/schemas/units-schema.yaml +215 -0
  20. data/data/unit_systems.yaml +78 -0
  21. data/data/units.yaml +14052 -0
  22. data/exe/unitsdb +7 -1
  23. data/lib/unitsdb/cli.rb +42 -15
  24. data/lib/unitsdb/commands/_modify.rb +40 -4
  25. data/lib/unitsdb/commands/base.rb +6 -2
  26. data/lib/unitsdb/commands/check_si/si_formatter.rb +488 -0
  27. data/lib/unitsdb/commands/check_si/si_matcher.rb +487 -0
  28. data/lib/unitsdb/commands/check_si/si_ttl_parser.rb +103 -0
  29. data/lib/unitsdb/commands/check_si/si_updater.rb +254 -0
  30. data/lib/unitsdb/commands/check_si.rb +54 -35
  31. data/lib/unitsdb/commands/get.rb +11 -10
  32. data/lib/unitsdb/commands/normalize.rb +21 -7
  33. data/lib/unitsdb/commands/qudt/check.rb +150 -0
  34. data/lib/unitsdb/commands/qudt/formatter.rb +194 -0
  35. data/lib/unitsdb/commands/qudt/matcher.rb +746 -0
  36. data/lib/unitsdb/commands/qudt/ttl_parser.rb +403 -0
  37. data/lib/unitsdb/commands/qudt/update.rb +126 -0
  38. data/lib/unitsdb/commands/qudt/updater.rb +189 -0
  39. data/lib/unitsdb/commands/qudt.rb +82 -0
  40. data/lib/unitsdb/commands/release.rb +12 -9
  41. data/lib/unitsdb/commands/search.rb +12 -11
  42. data/lib/unitsdb/commands/ucum/check.rb +42 -29
  43. data/lib/unitsdb/commands/ucum/formatter.rb +2 -1
  44. data/lib/unitsdb/commands/ucum/matcher.rb +23 -9
  45. data/lib/unitsdb/commands/ucum/update.rb +14 -13
  46. data/lib/unitsdb/commands/ucum/updater.rb +40 -6
  47. data/lib/unitsdb/commands/ucum/xml_parser.rb +0 -2
  48. data/lib/unitsdb/commands/ucum.rb +44 -4
  49. data/lib/unitsdb/commands/validate/identifiers.rb +2 -4
  50. data/lib/unitsdb/commands/validate/qudt_references.rb +111 -0
  51. data/lib/unitsdb/commands/validate/references.rb +36 -19
  52. data/lib/unitsdb/commands/validate/si_references.rb +3 -5
  53. data/lib/unitsdb/commands/validate/ucum_references.rb +105 -0
  54. data/lib/unitsdb/commands/validate.rb +67 -11
  55. data/lib/unitsdb/commands.rb +20 -0
  56. data/lib/unitsdb/database.rb +90 -52
  57. data/lib/unitsdb/dimension.rb +1 -4
  58. data/lib/unitsdb/dimension_details.rb +0 -1
  59. data/lib/unitsdb/dimensions.rb +0 -2
  60. data/lib/unitsdb/errors.rb +7 -0
  61. data/lib/unitsdb/prefix.rb +0 -4
  62. data/lib/unitsdb/prefix_reference.rb +0 -2
  63. data/lib/unitsdb/prefixes.rb +0 -1
  64. data/lib/unitsdb/quantities.rb +0 -2
  65. data/lib/unitsdb/quantity.rb +0 -6
  66. data/lib/unitsdb/qudt.rb +100 -0
  67. data/lib/unitsdb/root_unit_reference.rb +0 -3
  68. data/lib/unitsdb/scale.rb +0 -4
  69. data/lib/unitsdb/scale_reference.rb +0 -2
  70. data/lib/unitsdb/scales.rb +0 -2
  71. data/lib/unitsdb/si_derived_base.rb +0 -2
  72. data/lib/unitsdb/ucum.rb +14 -10
  73. data/lib/unitsdb/unit.rb +0 -10
  74. data/lib/unitsdb/unit_reference.rb +0 -2
  75. data/lib/unitsdb/unit_system.rb +1 -3
  76. data/lib/unitsdb/unit_system_reference.rb +0 -2
  77. data/lib/unitsdb/unit_systems.rb +0 -2
  78. data/lib/unitsdb/units.rb +0 -2
  79. data/lib/unitsdb/utils.rb +32 -21
  80. data/lib/unitsdb/version.rb +5 -1
  81. data/lib/unitsdb.rb +62 -14
  82. data/unitsdb.gemspec +6 -3
  83. metadata +52 -13
  84. data/lib/unitsdb/commands/si_formatter.rb +0 -485
  85. data/lib/unitsdb/commands/si_matcher.rb +0 -470
  86. data/lib/unitsdb/commands/si_ttl_parser.rb +0 -100
  87. data/lib/unitsdb/commands/si_updater.rb +0 -212
@@ -1,212 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "yaml"
4
- require "fileutils"
5
-
6
- module Unitsdb
7
- module Commands
8
- # Updater for SI references in YAML
9
- module SiUpdater
10
- SI_AUTHORITY = "si-digital-framework"
11
-
12
- module_function
13
-
14
- # Update references in YAML file (TTL → DB direction)
15
- def update_references(entity_type, missing_matches, db_entities, output_file, include_potential = false)
16
- # Use the database objects to access the data directly
17
- original_yaml_file = db_entities.first.send(:yaml_file) if db_entities&.first.respond_to?(:yaml_file, true)
18
-
19
- # If we can't get the path from the database object, use the output file path as a fallback
20
- if original_yaml_file.nil? || !File.exist?(original_yaml_file)
21
- puts "Warning: Could not determine original YAML file path. Using output file as template."
22
- original_yaml_file = output_file
23
-
24
- # Create an empty template if output file doesn't exist
25
- unless File.exist?(original_yaml_file)
26
- FileUtils.mkdir_p(File.dirname(original_yaml_file))
27
- File.write(original_yaml_file, { entity_type => [] }.to_yaml)
28
- end
29
- end
30
-
31
- # Load the original YAML file
32
- yaml_content = File.read(original_yaml_file)
33
- output_data = YAML.safe_load(yaml_content)
34
-
35
- # Group by entity ID to avoid duplicates
36
- grouped_matches = missing_matches.group_by { |match| match[:entity_id] }
37
-
38
- # Process each entity that needs updating
39
- grouped_matches.each do |entity_id, matches|
40
- # Filter matches based on include_potential parameter
41
- filtered_matches = matches.select do |match|
42
- # Check if it's an exact match or if we're including potential matches
43
- match_details = match[:match_details]
44
- if match_details&.dig(:exact) == false || %w[symbol_match
45
- partial_match].include?(match_details&.dig(:match_desc) || "")
46
- include_potential
47
- else
48
- true
49
- end
50
- end
51
-
52
- # Skip if no matches after filtering
53
- next if filtered_matches.empty?
54
-
55
- # Find the entity in the array under the entity_type key
56
- entity_index = output_data[entity_type].find_index do |e|
57
- # Find entity with matching identifier
58
- e["identifiers"]&.any? { |id| id["id"] == entity_id }
59
- end
60
-
61
- next unless entity_index
62
-
63
- # Get the entity
64
- entity = output_data[entity_type][entity_index]
65
-
66
- # Initialize references array if it doesn't exist
67
- entity["references"] ||= []
68
-
69
- # Add new references
70
- filtered_matches.each do |match|
71
- # If this match has multiple SI references, add them all
72
- if match[:multiple_si]
73
- match[:multiple_si].each do |si_data|
74
- # Check if reference already exists
75
- next if entity["references"].any? do |ref|
76
- ref["uri"] == si_data[:uri] && ref["authority"] == SI_AUTHORITY
77
- end
78
-
79
- # Add new reference
80
- entity["references"] << {
81
- "uri" => si_data[:uri],
82
- "type" => "normative",
83
- "authority" => SI_AUTHORITY
84
- }
85
- end
86
- else
87
- # Check if reference already exists
88
- next if entity["references"].any? do |ref|
89
- ref["uri"] == match[:si_uri] && ref["authority"] == SI_AUTHORITY
90
- end
91
-
92
- # Add new reference
93
- entity["references"] << {
94
- "uri" => match[:si_uri],
95
- "type" => "normative",
96
- "authority" => SI_AUTHORITY
97
- }
98
- end
99
- end
100
- end
101
-
102
- write_yaml_file(output_file, output_data)
103
- end
104
-
105
- # Update references in YAML file (DB → TTL direction)
106
- def update_db_references(entity_type, missing_refs, output_file, include_potential = false)
107
- # Try to get the original YAML file from the first entity
108
- first_entity = missing_refs.first&.dig(:db_entity)
109
- original_yaml_file = first_entity.send(:yaml_file) if first_entity.respond_to?(:yaml_file, true)
110
-
111
- # If we can't get the path from the database object, use the output file path as a fallback
112
- if original_yaml_file.nil? || !File.exist?(original_yaml_file)
113
- puts "Warning: Could not determine original YAML file path. Using output file as template."
114
- original_yaml_file = output_file
115
-
116
- # Create an empty template if output file doesn't exist
117
- unless File.exist?(original_yaml_file)
118
- FileUtils.mkdir_p(File.dirname(original_yaml_file))
119
- File.write(original_yaml_file, { entity_type => [] }.to_yaml)
120
- end
121
- end
122
-
123
- # Load the original YAML file
124
- yaml_content = File.read(original_yaml_file)
125
- output_data = YAML.safe_load(yaml_content)
126
-
127
- # Group by entity ID to avoid duplicates
128
- missing_refs_by_id = {}
129
-
130
- missing_refs.each do |match|
131
- entity_id = match[:entity_id] || match[:db_entity].short
132
- ttl_entities = match[:ttl_entities]
133
- match_types = match[:match_types] || {}
134
-
135
- # Filter TTL entities based on include_potential parameter
136
- filtered_ttl_entities = ttl_entities.select do |ttl_entity|
137
- # Check if it's an exact match or if we're including potential matches
138
- match_type = match_types[ttl_entity[:uri]] || "Exact match" # Default to exact match
139
- match_pair_key = "#{entity_id}:#{ttl_entity[:uri]}"
140
- match_details = Unitsdb::Commands::SiMatcher.instance_variable_get(:@match_details)&.dig(match_pair_key)
141
-
142
- if match_details && %w[symbol_match partial_match].include?(match_details[:match_desc])
143
- include_potential
144
- else
145
- match_type == "Exact match" || include_potential
146
- end
147
- end
148
-
149
- # Skip if no entities after filtering
150
- next if filtered_ttl_entities.empty?
151
-
152
- missing_refs_by_id[entity_id] ||= []
153
-
154
- # Add filtered matching TTL entities for this DB entity
155
- filtered_ttl_entities.each do |ttl_entity|
156
- missing_refs_by_id[entity_id] << {
157
- uri: ttl_entity[:uri],
158
- type: "normative",
159
- authority: SI_AUTHORITY
160
- }
161
- end
162
- end
163
-
164
- # Update the YAML content
165
- output_data[entity_type].each do |entity_yaml|
166
- # Find entity by ID or short
167
- entity_id = if entity_yaml["identifiers"]
168
- begin
169
- entity_yaml["identifiers"].first["id"]
170
- rescue StandardError
171
- nil
172
- end
173
- elsif entity_yaml["id"]
174
- entity_yaml["id"]
175
- end
176
-
177
- next unless entity_id && missing_refs_by_id.key?(entity_id)
178
-
179
- # Add references
180
- entity_yaml["references"] ||= []
181
-
182
- missing_refs_by_id[entity_id].each do |ref|
183
- # Check if this reference already exists
184
- next if entity_yaml["references"].any? do |existing_ref|
185
- existing_ref["uri"] == ref[:uri] &&
186
- existing_ref["authority"] == ref[:authority]
187
- end
188
-
189
- # Add the reference
190
- entity_yaml["references"] << {
191
- "uri" => ref[:uri],
192
- "type" => ref[:type],
193
- "authority" => ref[:authority]
194
- }
195
- end
196
- end
197
-
198
- write_yaml_file(output_file, output_data)
199
- end
200
-
201
- # Helper to write YAML file
202
- def write_yaml_file(output_file, output_data)
203
- # Ensure the output directory exists
204
- output_dir = File.dirname(output_file)
205
- FileUtils.mkdir_p(output_dir) unless Dir.exist?(output_dir)
206
-
207
- # Write to YAML file
208
- File.write(output_file, output_data.to_yaml)
209
- end
210
- end
211
- end
212
- end