unitsdb 2.2.1 → 2.2.4
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/opal.yml +36 -0
- data/.gitignore +3 -0
- data/Gemfile +1 -0
- data/Rakefile +3 -1
- data/lib/unitsdb/cli.rb +5 -41
- data/lib/unitsdb/commands/_modify.rb +1 -34
- data/lib/unitsdb/commands/check_si/si_formatter.rb +6 -6
- data/lib/unitsdb/commands/check_si/si_matcher.rb +202 -292
- data/lib/unitsdb/commands/check_si/si_updater.rb +16 -36
- data/lib/unitsdb/commands/entity_presenter.rb +98 -0
- data/lib/unitsdb/commands/get.rb +16 -113
- data/lib/unitsdb/commands/qudt/formatter.rb +16 -27
- data/lib/unitsdb/commands/qudt/matcher.rb +18 -28
- data/lib/unitsdb/commands/qudt/updater.rb +8 -11
- data/lib/unitsdb/commands/qudt.rb +1 -34
- data/lib/unitsdb/commands/search.rb +33 -188
- data/lib/unitsdb/commands/thor.rb +41 -0
- data/lib/unitsdb/commands/ucum/formatter.rb +9 -18
- data/lib/unitsdb/commands/ucum/matcher.rb +4 -4
- data/lib/unitsdb/commands/ucum/updater.rb +3 -5
- data/lib/unitsdb/commands/ucum.rb +1 -34
- data/lib/unitsdb/commands/validate/qudt_references.rb +29 -70
- data/lib/unitsdb/commands/validate/references.rb +5 -303
- data/lib/unitsdb/commands/validate/si_references.rb +30 -66
- data/lib/unitsdb/commands/validate/ucum_references.rb +30 -64
- data/lib/unitsdb/commands/validate.rb +1 -36
- data/lib/unitsdb/commands.rb +2 -0
- data/lib/unitsdb/config.rb +170 -4
- data/lib/unitsdb/database/loader.rb +135 -0
- data/lib/unitsdb/database/reference_validator.rb +227 -0
- data/lib/unitsdb/database/uniqueness_validator.rb +80 -0
- data/lib/unitsdb/database.rb +127 -588
- data/lib/unitsdb/dimension.rb +2 -27
- data/lib/unitsdb/dimension_details.rb +2 -0
- data/lib/unitsdb/dimension_reference.rb +2 -0
- data/lib/unitsdb/dimensions.rb +2 -2
- 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/opal.rb +43 -0
- data/lib/unitsdb/prefix.rb +2 -13
- data/lib/unitsdb/prefix_reference.rb +2 -0
- data/lib/unitsdb/prefixes.rb +2 -2
- data/lib/unitsdb/quantities.rb +2 -1
- data/lib/unitsdb/quantity.rb +2 -2
- data/lib/unitsdb/quantity_reference.rb +2 -2
- data/lib/unitsdb/qudt.rb +5 -0
- data/lib/unitsdb/root_unit_reference.rb +2 -2
- data/lib/unitsdb/scale.rb +2 -2
- data/lib/unitsdb/scale_properties.rb +2 -1
- data/lib/unitsdb/scale_reference.rb +2 -0
- data/lib/unitsdb/scales.rb +2 -1
- data/lib/unitsdb/si_derived_base.rb +2 -1
- data/lib/unitsdb/symbol_presentations.rb +2 -2
- data/lib/unitsdb/ucum.rb +7 -0
- data/lib/unitsdb/unit.rb +2 -34
- data/lib/unitsdb/unit_reference.rb +2 -0
- data/lib/unitsdb/unit_system.rb +2 -2
- data/lib/unitsdb/unit_system_reference.rb +2 -0
- data/lib/unitsdb/unit_systems.rb +2 -2
- data/lib/unitsdb/units.rb +2 -2
- data/lib/unitsdb/version.rb +1 -1
- data/lib/unitsdb.rb +134 -27
- data/unitsdb.gemspec +1 -0
- metadata +23 -2
|
@@ -13,24 +13,9 @@ module Unitsdb
|
|
|
13
13
|
module_function
|
|
14
14
|
|
|
15
15
|
# Update references in YAML file (TTL → DB direction)
|
|
16
|
-
def update_references(entity_type, missing_matches,
|
|
16
|
+
def update_references(entity_type, missing_matches, _db_entities,
|
|
17
17
|
output_file, include_potential = false)
|
|
18
|
-
|
|
19
|
-
original_yaml_file = db_entities.first.send(:yaml_file) if db_entities&.first.respond_to?(
|
|
20
|
-
:yaml_file, true
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
# If we can't get the path from the database object, use the output file path as a fallback
|
|
24
|
-
if original_yaml_file.nil? || !File.exist?(original_yaml_file)
|
|
25
|
-
puts "Warning: Could not determine original YAML file path. Using output file as template."
|
|
26
|
-
original_yaml_file = output_file
|
|
27
|
-
|
|
28
|
-
# Create an empty template if output file doesn't exist
|
|
29
|
-
unless File.exist?(original_yaml_file)
|
|
30
|
-
FileUtils.mkdir_p(File.dirname(original_yaml_file))
|
|
31
|
-
File.write(original_yaml_file, { entity_type => [] }.to_yaml)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
18
|
+
original_yaml_file = resolve_yaml_file(output_file, entity_type)
|
|
34
19
|
|
|
35
20
|
# Load the original YAML file
|
|
36
21
|
yaml_content = File.read(original_yaml_file)
|
|
@@ -111,23 +96,7 @@ module Unitsdb
|
|
|
111
96
|
# Update references in YAML file (DB → TTL direction)
|
|
112
97
|
def update_db_references(entity_type, missing_refs, output_file,
|
|
113
98
|
include_potential = false)
|
|
114
|
-
|
|
115
|
-
first_entity = missing_refs.first&.dig(:db_entity)
|
|
116
|
-
original_yaml_file = first_entity.send(:yaml_file) if first_entity.respond_to?(
|
|
117
|
-
:yaml_file, true
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
# If we can't get the path from the database object, use the output file path as a fallback
|
|
121
|
-
if original_yaml_file.nil? || !File.exist?(original_yaml_file)
|
|
122
|
-
puts "Warning: Could not determine original YAML file path. Using output file as template."
|
|
123
|
-
original_yaml_file = output_file
|
|
124
|
-
|
|
125
|
-
# Create an empty template if output file doesn't exist
|
|
126
|
-
unless File.exist?(original_yaml_file)
|
|
127
|
-
FileUtils.mkdir_p(File.dirname(original_yaml_file))
|
|
128
|
-
File.write(original_yaml_file, { entity_type => [] }.to_yaml)
|
|
129
|
-
end
|
|
130
|
-
end
|
|
99
|
+
original_yaml_file = resolve_yaml_file(output_file, entity_type)
|
|
131
100
|
|
|
132
101
|
# Load the original YAML file
|
|
133
102
|
yaml_content = File.read(original_yaml_file)
|
|
@@ -146,7 +115,7 @@ module Unitsdb
|
|
|
146
115
|
# Check if it's an exact match or if we're including potential matches
|
|
147
116
|
match_type = match_types[ttl_entity[:uri]] || "Exact match" # Default to exact match
|
|
148
117
|
match_pair_key = "#{entity_id}:#{ttl_entity[:uri]}"
|
|
149
|
-
match_details = Unitsdb::Commands::CheckSi::SiMatcher.
|
|
118
|
+
match_details = Unitsdb::Commands::CheckSi::SiMatcher.match_details&.dig(match_pair_key)
|
|
150
119
|
|
|
151
120
|
if match_details && %w[symbol_match
|
|
152
121
|
partial_match].include?(match_details[:match_desc])
|
|
@@ -208,9 +177,20 @@ module Unitsdb
|
|
|
208
177
|
write_yaml_file(output_file, output_data)
|
|
209
178
|
end
|
|
210
179
|
|
|
180
|
+
# Resolve which YAML file to read from. Caller supplies
|
|
181
|
+
# `output_file` as the canonical path; if it doesn't exist
|
|
182
|
+
# yet we seed it with an empty `{entity_type => []}` template.
|
|
183
|
+
def resolve_yaml_file(output_file, entity_type)
|
|
184
|
+
unless File.exist?(output_file)
|
|
185
|
+
FileUtils.mkdir_p(File.dirname(output_file))
|
|
186
|
+
File.write(output_file, { entity_type => [] }.to_yaml)
|
|
187
|
+
end
|
|
188
|
+
output_file
|
|
189
|
+
end
|
|
190
|
+
|
|
211
191
|
# Helper to write YAML file
|
|
192
|
+
# Ensure the output directory exists
|
|
212
193
|
def write_yaml_file(output_file, output_data)
|
|
213
|
-
# Ensure the output directory exists
|
|
214
194
|
output_dir = File.dirname(output_file)
|
|
215
195
|
FileUtils.mkdir_p(output_dir)
|
|
216
196
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Unitsdb
|
|
4
|
+
module Commands
|
|
5
|
+
# Present a single entity as text for the Get/Search CLI commands.
|
|
6
|
+
# Pulls every displayable field off the typed model — no
|
|
7
|
+
# `respond_to?` feature detection. New entity types extend
|
|
8
|
+
# `TYPE_NAME` and `extras`; nothing else changes.
|
|
9
|
+
class EntityPresenter
|
|
10
|
+
TYPE_NAME = {
|
|
11
|
+
Unitsdb::Unit => "Unit",
|
|
12
|
+
Unitsdb::Prefix => "Prefix",
|
|
13
|
+
Unitsdb::Quantity => "Quantity",
|
|
14
|
+
Unitsdb::Dimension => "Dimension",
|
|
15
|
+
Unitsdb::UnitSystem => "UnitSystem",
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
def initialize(entity)
|
|
19
|
+
@entity = entity
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Human-readable type label, e.g. "Unit", "Prefix".
|
|
23
|
+
def type_name
|
|
24
|
+
TYPE_NAME[@entity.class] || @entity.class.name.split("::").last
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Best-effort display name: first localized name value → short → "N/A".
|
|
28
|
+
def display_name
|
|
29
|
+
name = @entity.names.first
|
|
30
|
+
return name.value.to_s if name&.value
|
|
31
|
+
return @entity.short.to_s if @entity.short
|
|
32
|
+
|
|
33
|
+
"N/A"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Multi-line "details" output for `unitsdb get ID`.
|
|
37
|
+
def print_details
|
|
38
|
+
puts "Entity details:"
|
|
39
|
+
puts " - Type: #{type_name}"
|
|
40
|
+
puts " - Name: #{display_name}"
|
|
41
|
+
puts " - Description: #{@entity.short}" if show_short?
|
|
42
|
+
print_identifiers(header: " - Identifiers:", item_indent: " ")
|
|
43
|
+
print_extras
|
|
44
|
+
print_references
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Single-block summary used by `unitsdb search` per result.
|
|
48
|
+
def print_summary
|
|
49
|
+
puts " - #{type_name}: #{display_name}"
|
|
50
|
+
print_identifiers(header: " IDs:", item_indent: " ")
|
|
51
|
+
puts " Description: #{@entity.short}" if show_short?
|
|
52
|
+
puts ""
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def show_short?
|
|
58
|
+
@entity.short && @entity.short != display_name
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def print_identifiers(header:, item_indent:)
|
|
62
|
+
identifiers = @entity.identifiers
|
|
63
|
+
if identifiers.empty?
|
|
64
|
+
puts "#{header} None"
|
|
65
|
+
return
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
puts header
|
|
69
|
+
identifiers.each do |id|
|
|
70
|
+
puts "#{item_indent}- #{id.id} (Type: #{id.type || 'N/A'})"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def print_extras
|
|
75
|
+
case @entity
|
|
76
|
+
when Unitsdb::Unit
|
|
77
|
+
print_unit_symbols
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def print_unit_symbols
|
|
82
|
+
return unless @entity.symbols.any?
|
|
83
|
+
|
|
84
|
+
puts " - Symbols:"
|
|
85
|
+
@entity.symbols.each { |s| puts " - #{s}" }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def print_references
|
|
89
|
+
return unless @entity.references.any?
|
|
90
|
+
|
|
91
|
+
puts " - References:"
|
|
92
|
+
@entity.references.each do |ref|
|
|
93
|
+
puts " - #{ref.type}: #{ref.uri}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/unitsdb/commands/get.rb
CHANGED
|
@@ -1,133 +1,36 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
3
|
module Unitsdb
|
|
6
4
|
module Commands
|
|
7
5
|
class Get < Base
|
|
8
6
|
def get(id)
|
|
9
|
-
# Database path is guaranteed by Thor's global option
|
|
10
7
|
id_type = @options[:id_type]
|
|
11
8
|
format = @options[:format] || "text"
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Search by ID
|
|
17
|
-
entity = database.get_by_id(id: id, type: id_type)
|
|
18
|
-
|
|
19
|
-
unless entity
|
|
20
|
-
puts "No entity found with ID: '#{id}'"
|
|
21
|
-
return
|
|
22
|
-
end
|
|
10
|
+
database = load_database(@options[:database])
|
|
11
|
+
entity = database.get_by_id(id: id, type: id_type)
|
|
23
12
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
puts entity.send("to_#{format.downcase}")
|
|
28
|
-
return
|
|
29
|
-
rescue NoMethodError
|
|
30
|
-
raise Unitsdb::Errors::InvalidFormatError,
|
|
31
|
-
"Unable to convert entity to #{format.upcase} format: output format not supported for this entity type"
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Default text output
|
|
36
|
-
print_entity_details(entity)
|
|
37
|
-
rescue Unitsdb::Errors::DatabaseError => e
|
|
38
|
-
raise Unitsdb::Errors::DatabaseLoadError,
|
|
39
|
-
"Failed to load database: #{e.message}"
|
|
40
|
-
rescue StandardError => e
|
|
41
|
-
raise Unitsdb::Errors::CLIRuntimeError, "Search failed: #{e.message}"
|
|
13
|
+
if entity.nil?
|
|
14
|
+
puts "No entity found with ID: '#{id}'"
|
|
15
|
+
return
|
|
42
16
|
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
def print_entity_details(entity)
|
|
48
|
-
# Determine entity type
|
|
49
|
-
entity_type = get_entity_type(entity)
|
|
50
|
-
|
|
51
|
-
# Get name
|
|
52
|
-
name = get_entity_name(entity)
|
|
53
17
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
puts " - Name: #{name}"
|
|
57
|
-
|
|
58
|
-
# Print description if available
|
|
59
|
-
puts " - Description: #{entity.short}" if entity.respond_to?(:short) && entity.short && entity.short != name
|
|
60
|
-
|
|
61
|
-
# Print all identifiers
|
|
62
|
-
if entity.identifiers&.any?
|
|
63
|
-
puts " - Identifiers:"
|
|
64
|
-
entity.identifiers.each do |id|
|
|
65
|
-
puts " - #{id.id} (Type: #{id.type || 'N/A'})"
|
|
66
|
-
end
|
|
18
|
+
if %w[json yaml].include?(format.downcase)
|
|
19
|
+
print_serialized(entity, format.downcase)
|
|
67
20
|
else
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Print additional properties based on entity type
|
|
72
|
-
case entity
|
|
73
|
-
when Unitsdb::Unit
|
|
74
|
-
puts " - Symbols:" if entity.respond_to?(:symbols) && entity.symbols&.any?
|
|
75
|
-
if entity.respond_to?(:symbols) && entity.symbols&.any?
|
|
76
|
-
entity.symbols.each do |s|
|
|
77
|
-
puts " - #{s}"
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
puts " - Definition: #{entity.definition}" if entity.respond_to?(:definition) && entity.definition
|
|
82
|
-
|
|
83
|
-
if entity.respond_to?(:dimensions) && entity.dimensions&.any?
|
|
84
|
-
puts " - Dimensions:"
|
|
85
|
-
entity.dimensions.each { |d| puts " - #{d}" }
|
|
86
|
-
end
|
|
87
|
-
when Unitsdb::Quantity
|
|
88
|
-
puts " - Dimensions: #{entity.dimension}" if entity.respond_to?(:dimension) && entity.dimension
|
|
89
|
-
when Unitsdb::Prefix
|
|
90
|
-
puts " - Value: #{entity.value}" if entity.respond_to?(:value) && entity.value
|
|
91
|
-
puts " - Symbol: #{entity.symbol}" if entity.respond_to?(:symbol) && entity.symbol
|
|
92
|
-
when Unitsdb::Dimension
|
|
93
|
-
# Any dimension-specific properties
|
|
94
|
-
when Unitsdb::UnitSystem
|
|
95
|
-
puts " - Organization: #{entity.organization}" if entity.respond_to?(:organization) && entity.organization
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Print references if available
|
|
99
|
-
return unless entity.respond_to?(:references) && entity.references&.any?
|
|
100
|
-
|
|
101
|
-
puts " - References:"
|
|
102
|
-
entity.references.each do |ref|
|
|
103
|
-
puts " - #{ref.type}: #{ref.uri}"
|
|
21
|
+
EntityPresenter.new(entity).print_details
|
|
104
22
|
end
|
|
23
|
+
rescue Unitsdb::Errors::DatabaseError => e
|
|
24
|
+
raise Unitsdb::Errors::DatabaseLoadError,
|
|
25
|
+
"Failed to load database: #{e.message}"
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
raise Unitsdb::Errors::CLIRuntimeError, "Get failed: #{e.message}"
|
|
105
28
|
end
|
|
106
29
|
|
|
107
|
-
|
|
108
|
-
case entity
|
|
109
|
-
when Unitsdb::Unit
|
|
110
|
-
"Unit"
|
|
111
|
-
when Unitsdb::Prefix
|
|
112
|
-
"Prefix"
|
|
113
|
-
when Unitsdb::Quantity
|
|
114
|
-
"Quantity"
|
|
115
|
-
when Unitsdb::Dimension
|
|
116
|
-
"Dimension"
|
|
117
|
-
when Unitsdb::UnitSystem
|
|
118
|
-
"UnitSystem"
|
|
119
|
-
else
|
|
120
|
-
"Unknown"
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def get_entity_name(entity)
|
|
125
|
-
# Using early returns is still preferable for simple conditions
|
|
126
|
-
return entity.names.first if entity.respond_to?(:names) && entity.names&.any?
|
|
127
|
-
return entity.name if entity.respond_to?(:name) && entity.name
|
|
128
|
-
return entity.short if entity.respond_to?(:short) && entity.short
|
|
30
|
+
private
|
|
129
31
|
|
|
130
|
-
|
|
32
|
+
def print_serialized(entity, format)
|
|
33
|
+
puts entity.public_send("to_#{format}")
|
|
131
34
|
end
|
|
132
35
|
end
|
|
133
36
|
end
|
|
@@ -90,17 +90,15 @@ unmatched_qudt)
|
|
|
90
90
|
details = "DIMENSION VECTOR: #{entity.label || 'No label'}"
|
|
91
91
|
details += "\n URI: #{entity.uri}"
|
|
92
92
|
details += "\n Description: #{entity.description}" if entity.description
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
details += "\n Exponents: #{exponents.join(', ')}" unless exponents.empty?
|
|
103
|
-
end
|
|
93
|
+
exponents = []
|
|
94
|
+
exponents << "L:#{entity.dimension_exponent_for_length}" if entity.dimension_exponent_for_length != 0
|
|
95
|
+
exponents << "M:#{entity.dimension_exponent_for_mass}" if entity.dimension_exponent_for_mass != 0
|
|
96
|
+
exponents << "T:#{entity.dimension_exponent_for_time}" if entity.dimension_exponent_for_time != 0
|
|
97
|
+
exponents << "I:#{entity.dimension_exponent_for_electric_current}" if entity.dimension_exponent_for_electric_current != 0
|
|
98
|
+
exponents << "Θ:#{entity.dimension_exponent_for_thermodynamic_temperature}" if entity.dimension_exponent_for_thermodynamic_temperature != 0
|
|
99
|
+
exponents << "N:#{entity.dimension_exponent_for_amount_of_substance}" if entity.dimension_exponent_for_amount_of_substance != 0
|
|
100
|
+
exponents << "J:#{entity.dimension_exponent_for_luminous_intensity}" if entity.dimension_exponent_for_luminous_intensity != 0
|
|
101
|
+
details += "\n Exponents: #{exponents.join(', ')}" unless exponents.empty?
|
|
104
102
|
details
|
|
105
103
|
when Unitsdb::QudtSystemOfUnits
|
|
106
104
|
details = "SYSTEM OF UNITS: #{entity.label || 'No label'}"
|
|
@@ -157,26 +155,17 @@ unmatched_qudt)
|
|
|
157
155
|
|
|
158
156
|
# Helper to get db entity id
|
|
159
157
|
def get_db_entity_id(entity)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
entity.id
|
|
164
|
-
else
|
|
165
|
-
"unknown-id"
|
|
166
|
-
end
|
|
158
|
+
return entity.identifiers.first.id unless entity.identifiers.empty?
|
|
159
|
+
|
|
160
|
+
entity.short || "unknown-id"
|
|
167
161
|
end
|
|
168
162
|
|
|
169
163
|
# Helper to get db entity name
|
|
170
164
|
def get_db_entity_name(entity)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
elsif entity.respond_to?(:name)
|
|
176
|
-
entity.name
|
|
177
|
-
else
|
|
178
|
-
"unknown-name"
|
|
179
|
-
end
|
|
165
|
+
return entity.names.first.value unless entity.names.empty?
|
|
166
|
+
return entity.short if entity.short
|
|
167
|
+
|
|
168
|
+
"unknown-name"
|
|
180
169
|
end
|
|
181
170
|
|
|
182
171
|
# Helper to get qudt entity name
|
|
@@ -70,14 +70,14 @@ module Unitsdb
|
|
|
70
70
|
|
|
71
71
|
# Check if a UnitsDB entity already has a QUDT reference
|
|
72
72
|
def has_qudt_reference?(entity)
|
|
73
|
-
return false unless entity.
|
|
73
|
+
return false unless entity.references
|
|
74
74
|
|
|
75
75
|
entity.references.any? { |ref| ref.authority == "qudt" }
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
# Find the referenced QUDT entity based on the reference URI
|
|
79
79
|
def find_referenced_qudt_entity(db_entity, qudt_entities)
|
|
80
|
-
return nil unless db_entity.
|
|
80
|
+
return nil unless db_entity.references
|
|
81
81
|
|
|
82
82
|
qudt_ref = db_entity.references.find { |ref| ref.authority == "qudt" }
|
|
83
83
|
return nil unless qudt_ref
|
|
@@ -87,8 +87,8 @@ module Unitsdb
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
# Get the ID of a UnitsDB entity
|
|
90
|
-
def get_entity_id(
|
|
91
|
-
|
|
90
|
+
def get_entity_id(_entity)
|
|
91
|
+
nil
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
# Find a matching UnitsDB entity for a QUDT entity
|
|
@@ -520,7 +520,7 @@ module Unitsdb
|
|
|
520
520
|
|
|
521
521
|
# Check if QUDT dimension vector matches UnitsDB dimension
|
|
522
522
|
def dimensions_match?(qudt_dimension, db_dimension)
|
|
523
|
-
return false unless qudt_dimension.
|
|
523
|
+
return false unless qudt_dimension.is_a?(Unitsdb::QudtDimensionVector)
|
|
524
524
|
|
|
525
525
|
# Map QUDT dimension exponents to UnitsDB dimension structure
|
|
526
526
|
qudt_exponents = {
|
|
@@ -552,14 +552,14 @@ module Unitsdb
|
|
|
552
552
|
qudt_exponents == db_exponents
|
|
553
553
|
end
|
|
554
554
|
|
|
555
|
-
# Get dimension power from UnitsDB dimension entity
|
|
555
|
+
# Get dimension power from UnitsDB dimension entity.
|
|
556
|
+
# Dimension declares all seven dimension-type attrs as
|
|
557
|
+
# DimensionDetails; DimensionDetails always has `power`.
|
|
556
558
|
def get_dimension_power(db_dimension, dimension_type)
|
|
557
|
-
|
|
559
|
+
property = db_dimension.public_send(dimension_type)
|
|
560
|
+
return 0 unless property
|
|
558
561
|
|
|
559
|
-
|
|
560
|
-
return 0 unless dimension_property.respond_to?(:power)
|
|
561
|
-
|
|
562
|
-
dimension_property.power || 0
|
|
562
|
+
property.power || 0
|
|
563
563
|
end
|
|
564
564
|
|
|
565
565
|
# Normalize names by removing common variations and punctuation
|
|
@@ -585,7 +585,7 @@ module Unitsdb
|
|
|
585
585
|
|
|
586
586
|
# Look for a UnitsDB unit that has an SI reference with this identifier
|
|
587
587
|
db_units.find do |db_unit|
|
|
588
|
-
next unless db_unit.
|
|
588
|
+
next unless db_unit.references
|
|
589
589
|
|
|
590
590
|
db_unit.references.any? do |ref|
|
|
591
591
|
ref.authority == "si" && (
|
|
@@ -603,7 +603,7 @@ module Unitsdb
|
|
|
603
603
|
# PRIORITY 1: Try UCUM code match first (most reliable for prefixes)
|
|
604
604
|
if qudt_prefix.ucum_code
|
|
605
605
|
ucum_match = db_prefixes.find do |db_prefix|
|
|
606
|
-
db_prefix.
|
|
606
|
+
(db_prefix.references || [])&.any? do |ref|
|
|
607
607
|
ref.authority == "ucum" && ref.uri&.include?(qudt_prefix.ucum_code)
|
|
608
608
|
end
|
|
609
609
|
end
|
|
@@ -644,17 +644,7 @@ module Unitsdb
|
|
|
644
644
|
end
|
|
645
645
|
|
|
646
646
|
# PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
|
|
647
|
-
|
|
648
|
-
multiplier_match = db_prefixes.find do |db_prefix|
|
|
649
|
-
db_prefix.respond_to?(:factor) &&
|
|
650
|
-
(db_prefix.factor - qudt_prefix.prefix_multiplier).abs < 1e-10
|
|
651
|
-
end
|
|
652
|
-
|
|
653
|
-
if multiplier_match
|
|
654
|
-
result[:match] = multiplier_match
|
|
655
|
-
return result
|
|
656
|
-
end
|
|
657
|
-
end
|
|
647
|
+
# Skipped: Unitsdb::Prefix has no `factor` attribute in 2.0.
|
|
658
648
|
|
|
659
649
|
# PRIORITY 5: Try normalized name matching
|
|
660
650
|
if qudt_prefix.label
|
|
@@ -720,7 +710,7 @@ module Unitsdb
|
|
|
720
710
|
end
|
|
721
711
|
|
|
722
712
|
# PRIORITY 4: Try multiplier match (for prefixes with same scale factor)
|
|
723
|
-
if
|
|
713
|
+
if false
|
|
724
714
|
multiplier_match = qudt_prefixes.find do |qudt_prefix|
|
|
725
715
|
qudt_prefix.prefix_multiplier &&
|
|
726
716
|
(qudt_prefix.prefix_multiplier - db_prefix.factor).abs < 1e-10
|
|
@@ -734,10 +724,10 @@ module Unitsdb
|
|
|
734
724
|
|
|
735
725
|
# Check if an entity has been manually verified (has a special flag)
|
|
736
726
|
def manually_verified?(entity)
|
|
737
|
-
return false unless entity.
|
|
727
|
+
return false unless entity.references
|
|
738
728
|
|
|
739
|
-
entity.references.any? do |
|
|
740
|
-
|
|
729
|
+
entity.references.any? do |_ref|
|
|
730
|
+
false
|
|
741
731
|
end
|
|
742
732
|
end
|
|
743
733
|
end
|
|
@@ -168,20 +168,17 @@ include_potential = false)
|
|
|
168
168
|
|
|
169
169
|
# Get entity ID (either from identifiers array or directly)
|
|
170
170
|
def get_entity_id(entity)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
entity.id
|
|
175
|
-
end
|
|
171
|
+
return entity.identifiers.first.id unless entity.identifiers.empty?
|
|
172
|
+
|
|
173
|
+
entity.short
|
|
176
174
|
end
|
|
177
175
|
|
|
178
176
|
# Check if an entity has been manually verified (has a special flag)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
end
|
|
177
|
+
# Unitsdb::ExternalReference carries no `verified` flag in the
|
|
178
|
+
# 2.0 schema, so nothing is ever manually verified. Kept as a
|
|
179
|
+
# stub for callers; returns false unconditionally.
|
|
180
|
+
def manually_verified?(_entity)
|
|
181
|
+
false
|
|
185
182
|
end
|
|
186
183
|
end
|
|
187
184
|
end
|
|
@@ -12,11 +12,7 @@ module Unitsdb
|
|
|
12
12
|
autoload :Updater, "unitsdb/commands/qudt/updater"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
class QudtCommand < Thor
|
|
16
|
-
# Inherit trace option from parent CLI
|
|
17
|
-
class_option :trace, type: :boolean, default: false,
|
|
18
|
-
desc: "Show full backtrace on error"
|
|
19
|
-
|
|
15
|
+
class QudtCommand < Unitsdb::Commands::Thor
|
|
20
16
|
desc "check", "Check QUDT references in UnitsDB"
|
|
21
17
|
option :entity_type, type: :string, aliases: "-e",
|
|
22
18
|
desc: "Entity type to check (units, quantities, dimensions, unit_systems). If not specified, all types are checked"
|
|
@@ -48,35 +44,6 @@ module Unitsdb
|
|
|
48
44
|
def update
|
|
49
45
|
run_command(Qudt::Update, options)
|
|
50
46
|
end
|
|
51
|
-
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
def run_command(command_class, options)
|
|
55
|
-
command = command_class.new(options)
|
|
56
|
-
command.run
|
|
57
|
-
rescue Unitsdb::Errors::CLIRuntimeError => e
|
|
58
|
-
handle_cli_error(e)
|
|
59
|
-
rescue StandardError => e
|
|
60
|
-
handle_error(e)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def handle_cli_error(error)
|
|
64
|
-
if options[:trace]
|
|
65
|
-
raise error
|
|
66
|
-
else
|
|
67
|
-
warn "Error: #{error.message}"
|
|
68
|
-
exit 1
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def handle_error(error)
|
|
73
|
-
if options[:trace]
|
|
74
|
-
raise error
|
|
75
|
-
else
|
|
76
|
-
warn "Error: #{error.message}"
|
|
77
|
-
exit 1
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
47
|
end
|
|
81
48
|
end
|
|
82
49
|
end
|