unitsml 0.6.5 → 0.6.7
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 +42 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +79 -21
- data/Gemfile +3 -2
- data/Rakefile +10 -0
- data/lib/unitsml/configuration.rb +15 -5
- data/lib/unitsml/dimension.rb +1 -1
- data/lib/unitsml/errors/invalid_model_error.rb +24 -0
- data/lib/unitsml/errors/unsupported_payload_type_error.rb +13 -0
- data/lib/unitsml/errors.rb +3 -0
- data/lib/unitsml/fenced.rb +1 -1
- data/lib/unitsml/formula.rb +2 -1
- data/lib/unitsml/mathml_helper.rb +1 -1
- data/lib/unitsml/model/dimension_quantities.rb +9 -9
- data/lib/unitsml/model/prefixes.rb +2 -2
- data/lib/unitsml/model/quantities.rb +1 -1
- data/lib/unitsml/model.rb +8 -9
- data/lib/unitsml/opal/database_payload.rb +7 -0
- data/lib/unitsml/opal/payload_generator.rb +95 -0
- data/lib/unitsml/opal.rb +102 -0
- data/lib/unitsml/parser.rb +1 -1
- data/lib/unitsml/prefix_adapter.rb +82 -0
- data/lib/unitsml/unitsdb/database.rb +17 -4
- data/lib/unitsml/unitsdb/dimension.rb +25 -37
- data/lib/unitsml/unitsdb/dimensions.rb +4 -8
- data/lib/unitsml/unitsdb/finders.rb +27 -0
- data/lib/unitsml/unitsdb/prefixes.rb +5 -12
- data/lib/unitsml/unitsdb/unit.rb +4 -2
- data/lib/unitsml/unitsdb/units.rb +4 -12
- data/lib/unitsml/unitsdb.rb +32 -44
- data/lib/unitsml/utility.rb +59 -88
- data/lib/unitsml/version.rb +1 -1
- data/lib/unitsml/xml/formatter.rb +63 -0
- data/lib/unitsml/xml.rb +7 -0
- data/lib/unitsml.rb +2 -0
- data/unitsml.gemspec +2 -2
- metadata +27 -17
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "unitsdb"
|
|
4
|
+
|
|
5
|
+
module Unitsml
|
|
6
|
+
module Opal
|
|
7
|
+
class PayloadGenerator
|
|
8
|
+
DEFAULT_OUTPUT_PATH =
|
|
9
|
+
File.expand_path("database_payload.rb", __dir__).freeze
|
|
10
|
+
|
|
11
|
+
RECEIVER = "Unitsml::Unitsdb::Database"
|
|
12
|
+
METHOD = "load_opal_payload"
|
|
13
|
+
|
|
14
|
+
# Maps a scalar value's class to the serializer that emits its
|
|
15
|
+
# Ruby source representation. Kept as a constant so adding a new
|
|
16
|
+
# scalar type is a one-line change (OCP).
|
|
17
|
+
SCALAR_SERIALIZERS = {
|
|
18
|
+
String => :inspect.to_proc,
|
|
19
|
+
Symbol => ->(v) { ":#{v}" },
|
|
20
|
+
Integer => :to_s.to_proc,
|
|
21
|
+
Float => :to_s.to_proc,
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
def initialize(unitsdb_data_dir: default_data_dir)
|
|
25
|
+
@unitsdb_data_dir = unitsdb_data_dir
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def call
|
|
29
|
+
"#{header}#{body}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def write_to(path = DEFAULT_OUTPUT_PATH)
|
|
33
|
+
File.write(path, call)
|
|
34
|
+
path
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
attr_reader :unitsdb_data_dir
|
|
40
|
+
|
|
41
|
+
def header
|
|
42
|
+
<<~RUBY
|
|
43
|
+
# frozen_string_literal: true
|
|
44
|
+
|
|
45
|
+
# AUTO-GENERATED by `bundle exec rake unitsml:generate_opal_payload`.
|
|
46
|
+
# Do not edit by hand. Edit the YAML in unitsdb-ruby/data/ and
|
|
47
|
+
# regenerate. This file is loaded by lib/unitsml/opal.rb under Opal
|
|
48
|
+
# to satisfy Unitsml::Unitsdb::Database.from_db without a filesystem.
|
|
49
|
+
RUBY
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def body
|
|
53
|
+
"#{RECEIVER}.#{METHOD}(#{serialize(database_hash)}.freeze)\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def database_hash
|
|
57
|
+
::Unitsdb::Database.from_db(unitsdb_data_dir).to_hash
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Custom serializer rather than Hash#inspect so the output is
|
|
61
|
+
# byte-identical across Ruby versions (3.3 vs 3.4 changed Hash#inspect
|
|
62
|
+
# to add spaces around "=>"). String#inspect is itself stable for
|
|
63
|
+
# UTF-8 clean data.
|
|
64
|
+
def serialize(value)
|
|
65
|
+
case value
|
|
66
|
+
when Hash then serialize_hash(value)
|
|
67
|
+
when Array then serialize_array(value)
|
|
68
|
+
when true then "true"
|
|
69
|
+
when false then "false"
|
|
70
|
+
when nil then "nil"
|
|
71
|
+
else serialize_scalar(value)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def serialize_hash(value)
|
|
76
|
+
"{#{value.map { |k, v| "#{serialize(k)}=>#{serialize(v)}" }.join(',')}}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def serialize_array(value)
|
|
80
|
+
"[#{value.map { |v| serialize(v) }.join(',')}]"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def serialize_scalar(value)
|
|
84
|
+
serializer = SCALAR_SERIALIZERS[value.class]
|
|
85
|
+
return serializer.call(value) if serializer
|
|
86
|
+
|
|
87
|
+
raise Unitsml::Errors::UnsupportedPayloadTypeError, value.class
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def default_data_dir
|
|
91
|
+
::Unitsdb.data_dir
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/unitsml/opal.rb
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Opal entry point for unitsml.
|
|
4
|
+
#
|
|
5
|
+
# Under MRI, lib/unitsml.rb uses autoload for lazy loading. Under Opal,
|
|
6
|
+
# autoload does not lazy-execute, so this boot file eager-requires every
|
|
7
|
+
# entry point. Consumers (e.g. plurimath-js) add `-r unitsml/opal` to
|
|
8
|
+
# their Opal compile command.
|
|
9
|
+
#
|
|
10
|
+
# Load order rationale:
|
|
11
|
+
# 1. Upstream boot files first — unitsml depends on lutaml-model,
|
|
12
|
+
# unitsdb, mml (and transitively omml via plurimath-js consumers).
|
|
13
|
+
# 2. unitsml.rb next — sets up top-level autoloads and Configuration.
|
|
14
|
+
# 3. Errors before everything else (low-level, no deps).
|
|
15
|
+
# 4. The Opal payload — defines Unitsml::Unitsdb::Database::DATABASE
|
|
16
|
+
# so Unitsml::Unitsdb::Database.from_db can satisfy without a
|
|
17
|
+
# filesystem under Opal.
|
|
18
|
+
# 5. Unitsdb sub-files — define classes that subclass ::Unitsdb::*
|
|
19
|
+
# and call Configuration.register_model side-effects.
|
|
20
|
+
# 6. Model tree — declares the Unitsml XML model classes. Each parent
|
|
21
|
+
# module (Prefixes, Quantities, DimensionQuantities, Units) is
|
|
22
|
+
# required first to set up its own autoloads, then its leaves.
|
|
23
|
+
# 7. Parser/Transform/Prefix/Unit/Dimension etc. — top-level domain
|
|
24
|
+
# classes that reference Model and Unitsdb.
|
|
25
|
+
|
|
26
|
+
require "lutaml/model"
|
|
27
|
+
require "unitsdb/opal"
|
|
28
|
+
require "mml/opal"
|
|
29
|
+
require "omml/opal"
|
|
30
|
+
|
|
31
|
+
require "unitsml"
|
|
32
|
+
|
|
33
|
+
require "unitsml/version"
|
|
34
|
+
require "unitsml/errors"
|
|
35
|
+
require "unitsml/errors/base_error"
|
|
36
|
+
require "unitsml/errors/invalid_model_error"
|
|
37
|
+
require "unitsml/errors/opal_payload_not_bundled_error"
|
|
38
|
+
require "unitsml/errors/plurimath_load_error"
|
|
39
|
+
require "unitsml/errors/unsupported_payload_type_error"
|
|
40
|
+
|
|
41
|
+
require "unitsml/opal/database_payload"
|
|
42
|
+
|
|
43
|
+
require "unitsml/configuration"
|
|
44
|
+
require "unitsml/namespace"
|
|
45
|
+
|
|
46
|
+
require "unitsml/unitsdb"
|
|
47
|
+
require "unitsml/unitsdb/database"
|
|
48
|
+
require "unitsml/unitsdb/dimension_details"
|
|
49
|
+
require "unitsml/unitsdb/finders"
|
|
50
|
+
require "unitsml/unitsdb/prefix_reference"
|
|
51
|
+
require "unitsml/unitsdb/dimension"
|
|
52
|
+
require "unitsml/unitsdb/dimensions"
|
|
53
|
+
require "unitsml/unitsdb/unit"
|
|
54
|
+
require "unitsml/unitsdb/units"
|
|
55
|
+
require "unitsml/unitsdb/prefixes"
|
|
56
|
+
require "unitsml/unitsdb/quantities"
|
|
57
|
+
|
|
58
|
+
require "unitsml/model"
|
|
59
|
+
require "unitsml/model/dimension"
|
|
60
|
+
require "unitsml/model/dimension_quantities"
|
|
61
|
+
require "unitsml/model/dimension_quantities/amount_of_substance"
|
|
62
|
+
require "unitsml/model/dimension_quantities/electric_current"
|
|
63
|
+
require "unitsml/model/dimension_quantities/length"
|
|
64
|
+
require "unitsml/model/dimension_quantities/luminous_intensity"
|
|
65
|
+
require "unitsml/model/dimension_quantities/mass"
|
|
66
|
+
require "unitsml/model/dimension_quantities/plane_angle"
|
|
67
|
+
require "unitsml/model/dimension_quantities/quantity"
|
|
68
|
+
require "unitsml/model/dimension_quantities/thermodynamic_temperature"
|
|
69
|
+
require "unitsml/model/dimension_quantities/time"
|
|
70
|
+
require "unitsml/model/prefix"
|
|
71
|
+
require "unitsml/model/prefixes"
|
|
72
|
+
require "unitsml/model/prefixes/name"
|
|
73
|
+
require "unitsml/model/prefixes/symbol"
|
|
74
|
+
require "unitsml/model/quantities"
|
|
75
|
+
require "unitsml/model/quantities/name"
|
|
76
|
+
require "unitsml/model/quantity"
|
|
77
|
+
require "unitsml/model/unit"
|
|
78
|
+
require "unitsml/model/units"
|
|
79
|
+
require "unitsml/model/units/enumerated_root_unit"
|
|
80
|
+
require "unitsml/model/units/name"
|
|
81
|
+
require "unitsml/model/units/root_units"
|
|
82
|
+
require "unitsml/model/units/symbol"
|
|
83
|
+
require "unitsml/model/units/system"
|
|
84
|
+
|
|
85
|
+
require "unitsml/dimension"
|
|
86
|
+
require "unitsml/extender"
|
|
87
|
+
require "unitsml/fenced"
|
|
88
|
+
require "unitsml/fenced_numeric"
|
|
89
|
+
require "unitsml/formula"
|
|
90
|
+
require "unitsml/intermediate_exp_rules"
|
|
91
|
+
require "unitsml/mathml_helper"
|
|
92
|
+
require "unitsml/number"
|
|
93
|
+
require "unitsml/parse"
|
|
94
|
+
require "unitsml/parser"
|
|
95
|
+
require "unitsml/prefix"
|
|
96
|
+
require "unitsml/prefix_adapter"
|
|
97
|
+
require "unitsml/sqrt"
|
|
98
|
+
require "unitsml/transform"
|
|
99
|
+
require "unitsml/unit"
|
|
100
|
+
require "unitsml/utility"
|
|
101
|
+
require "unitsml/xml"
|
|
102
|
+
require "unitsml/xml/formatter"
|
data/lib/unitsml/parser.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Unitsml
|
|
|
32
32
|
array.each do |object|
|
|
33
33
|
if object.is_a?(Sqrt)
|
|
34
34
|
object = object.value
|
|
35
|
-
if object.
|
|
35
|
+
if object.is_a?(Unit)
|
|
36
36
|
object.power_numerator = Number.new("0.5")
|
|
37
37
|
else
|
|
38
38
|
update_units_exponents([object], inverse, true)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Unitsml
|
|
4
|
+
# Value object that adapts the various "prefix-shaped" inputs flowing
|
|
5
|
+
# through Unitsml::Utility to a single, type-explicit interface.
|
|
6
|
+
#
|
|
7
|
+
# Dispatch is by `is_a?` / `case/when`, so type errors surface at the
|
|
8
|
+
# boundary instead of silently falling through.
|
|
9
|
+
#
|
|
10
|
+
# Recognized inputs:
|
|
11
|
+
# - `Unitsml::Prefix` — already adapted, has full API
|
|
12
|
+
# - `::Unitsdb::Prefix` — upstream record, has `symbols`
|
|
13
|
+
# - `Unitsml::Unitsdb::PrefixReference` — UnitsML reference, has `symbolid`
|
|
14
|
+
# - `::Unitsdb::PrefixReference` — bare id/type, needs lookup
|
|
15
|
+
# - `String` — prefix name, looked up
|
|
16
|
+
# - `nil` — null adapter
|
|
17
|
+
class PrefixAdapter
|
|
18
|
+
attr_reader :raw
|
|
19
|
+
|
|
20
|
+
def initialize(raw)
|
|
21
|
+
@raw = raw
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.wrap(prefix)
|
|
25
|
+
return new(nil) if prefix.nil?
|
|
26
|
+
return prefix if prefix.is_a?(PrefixAdapter)
|
|
27
|
+
|
|
28
|
+
case prefix
|
|
29
|
+
when Unitsml::Prefix, ::Unitsdb::Prefix,
|
|
30
|
+
Unitsml::Unitsdb::PrefixReference
|
|
31
|
+
new(prefix)
|
|
32
|
+
when ::Unitsdb::PrefixReference
|
|
33
|
+
from_id(prefix.id)
|
|
34
|
+
when String
|
|
35
|
+
from_name(prefix)
|
|
36
|
+
else
|
|
37
|
+
new(nil)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.from_name(name)
|
|
42
|
+
return new(nil) unless Unitsml::Unitsdb.prefixes_array.include?(name)
|
|
43
|
+
|
|
44
|
+
new(Unitsml::Prefix.new(name))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.from_id(id)
|
|
48
|
+
new(Unitsml::Unitsdb.prefixes.find_by_id(id))
|
|
49
|
+
end
|
|
50
|
+
private_class_method :from_id
|
|
51
|
+
|
|
52
|
+
def null?
|
|
53
|
+
@raw.nil?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def base
|
|
57
|
+
@raw&.base
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def power
|
|
61
|
+
@raw&.power
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def symbolid
|
|
65
|
+
case @raw
|
|
66
|
+
when Unitsml::Prefix, Unitsml::Unitsdb::PrefixReference
|
|
67
|
+
@raw.symbolid
|
|
68
|
+
when ::Unitsdb::Prefix
|
|
69
|
+
@raw.symbols.first&.ascii
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def prefix_name
|
|
74
|
+
case @raw
|
|
75
|
+
when Unitsml::Prefix
|
|
76
|
+
@raw.prefix_name
|
|
77
|
+
when ::Unitsdb::Prefix, Unitsml::Unitsdb::PrefixReference
|
|
78
|
+
symbolid
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -3,18 +3,31 @@
|
|
|
3
3
|
module Unitsml
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Database < ::Unitsdb::Database
|
|
6
|
-
DATABASE = nil
|
|
7
|
-
|
|
8
6
|
def self.from_db(dir_path, context: Unitsml::Configuration.context.id)
|
|
9
7
|
return super unless RUBY_ENGINE == "opal"
|
|
10
8
|
|
|
11
9
|
context_id = context.to_sym
|
|
12
|
-
raise Unitsml::Errors::OpalPayloadNotBundledError unless
|
|
10
|
+
raise Unitsml::Errors::OpalPayloadNotBundledError unless opal_payload
|
|
13
11
|
|
|
14
12
|
Unitsml::Configuration.context
|
|
15
13
|
|
|
16
|
-
from_hash(
|
|
14
|
+
from_hash(opal_payload, register: context_id)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.load_opal_payload(payload)
|
|
18
|
+
@opal_payload = payload
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.reset_opal_payload
|
|
22
|
+
return unless instance_variable_defined?(:@opal_payload)
|
|
23
|
+
|
|
24
|
+
remove_instance_variable(:@opal_payload)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.opal_payload
|
|
28
|
+
@opal_payload
|
|
17
29
|
end
|
|
30
|
+
private_class_method :opal_payload
|
|
18
31
|
|
|
19
32
|
Configuration.register_model(self, id: :database)
|
|
20
33
|
end
|
|
@@ -3,48 +3,38 @@
|
|
|
3
3
|
module Unitsml
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Dimension < ::Unitsdb::Dimension
|
|
6
|
+
QUANTITY_KEYS = %i[
|
|
7
|
+
length
|
|
8
|
+
mass
|
|
9
|
+
time
|
|
10
|
+
thermodynamic_temperature
|
|
11
|
+
amount_of_substance
|
|
12
|
+
luminous_intensity
|
|
13
|
+
plane_angle
|
|
14
|
+
electric_current
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
6
17
|
attr_reader :parsables,
|
|
7
18
|
:parsable,
|
|
8
19
|
:processed_keys,
|
|
9
20
|
:vector
|
|
10
21
|
|
|
11
22
|
def initialize(attrs)
|
|
23
|
+
@quantities = {}
|
|
12
24
|
@parsables = {}
|
|
13
25
|
@processed_keys = []
|
|
14
26
|
@parsable = false
|
|
15
27
|
super
|
|
16
28
|
end
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def mass=(value)
|
|
23
|
-
quantities_common_code(:mass, value)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def time=(value)
|
|
27
|
-
quantities_common_code(:time, value)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def thermodynamic_temperature=(value)
|
|
31
|
-
quantities_common_code(:thermodynamic_temperature, value)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def amount_of_substance=(value)
|
|
35
|
-
quantities_common_code(:amount_of_substance, value)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def luminous_intensity=(value)
|
|
39
|
-
quantities_common_code(:luminous_intensity, value)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def plane_angle=(value)
|
|
43
|
-
quantities_common_code(:plane_angle, value)
|
|
44
|
-
end
|
|
30
|
+
QUANTITY_KEYS.each do |key|
|
|
31
|
+
define_method("#{key}=") do |value|
|
|
32
|
+
register_quantity(key, value)
|
|
33
|
+
end
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
define_method(key) do
|
|
36
|
+
@quantities[key]
|
|
37
|
+
end
|
|
48
38
|
end
|
|
49
39
|
|
|
50
40
|
def dim_symbols
|
|
@@ -69,11 +59,11 @@ module Unitsml
|
|
|
69
59
|
|
|
70
60
|
private
|
|
71
61
|
|
|
72
|
-
def
|
|
62
|
+
def register_quantity(key, value)
|
|
73
63
|
return if value.nil?
|
|
74
64
|
|
|
75
|
-
|
|
76
|
-
@processed_keys <<
|
|
65
|
+
@quantities[key] = value
|
|
66
|
+
@processed_keys << key.to_s
|
|
77
67
|
dim_symbols = dimension_symbols_for(value)
|
|
78
68
|
return if Lutaml::Model::Utils.empty?(dim_symbols)
|
|
79
69
|
|
|
@@ -83,12 +73,10 @@ module Unitsml
|
|
|
83
73
|
|
|
84
74
|
def dimension_symbols_for(value)
|
|
85
75
|
return [] if value.nil?
|
|
76
|
+
return Array(value.dim_symbols) if value.is_a?(::Unitsdb::Dimension)
|
|
77
|
+
return Array(value.symbols) if value.is_a?(::Unitsdb::DimensionDetails)
|
|
86
78
|
|
|
87
|
-
|
|
88
|
-
Array(value.dim_symbols)
|
|
89
|
-
else
|
|
90
|
-
Array(value.symbols)
|
|
91
|
-
end
|
|
79
|
+
[]
|
|
92
80
|
end
|
|
93
81
|
end
|
|
94
82
|
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module Unitsml
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Dimensions < ::Unitsdb::Dimensions
|
|
6
|
+
include Unitsml::Unitsdb::Finders
|
|
7
|
+
|
|
6
8
|
def dimensions=(value)
|
|
7
9
|
super(value.map { |d| Dimension.new(d.to_hash) })
|
|
8
10
|
end
|
|
@@ -13,11 +15,11 @@ module Unitsml
|
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def find_by_id(d_id)
|
|
16
|
-
|
|
18
|
+
find_first_in(dimensions, field: :id, value: d_id)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def find_parsables_by_id(d_id)
|
|
20
|
-
|
|
22
|
+
find_first_in(dimensions, field: :id, value: parsables[d_id])
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def parsables
|
|
@@ -25,12 +27,6 @@ module Unitsml
|
|
|
25
27
|
object.merge!(dimension.parsables)
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def find(field, matching_data)
|
|
32
|
-
dimensions.find { |dim| dim.send(field) == matching_data }
|
|
33
|
-
end
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
Configuration.register_model(Dimensions, id: :dimensions)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Unitsml
|
|
4
|
+
module Unitsdb
|
|
5
|
+
# Shared lookup helpers for Unitsml collection wrappers. Each host
|
|
6
|
+
# collection (Units, Prefixes, Dimensions) keeps its own public
|
|
7
|
+
# find_by_* API; this module owns the two scanning shapes that the
|
|
8
|
+
# host implementations previously duplicated.
|
|
9
|
+
module Finders
|
|
10
|
+
# Find the first item in `collection` where `item.<field> == value`.
|
|
11
|
+
def find_first_in(collection, field:, value:)
|
|
12
|
+
collection.find { |item| item.public_send(field) == value }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Find the first item in `collection` where `item.<via>` contains
|
|
16
|
+
# an element whose `<field>` equals `value`. Used for collections
|
|
17
|
+
# of items that expose a nested list of identifiers or symbols.
|
|
18
|
+
def find_first_through(collection, via:, field:, value:)
|
|
19
|
+
collection.find do |item|
|
|
20
|
+
item.public_send(via).any? do |inner|
|
|
21
|
+
inner.public_send(field) == value
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
module Unitsml
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Prefixes < ::Unitsdb::Prefixes
|
|
6
|
+
include Unitsml::Unitsdb::Finders
|
|
7
|
+
|
|
6
8
|
def find_by_id(p_id)
|
|
7
|
-
|
|
9
|
+
find_first_through(prefixes, via: :identifiers, field: :id, value: p_id)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def find_by_symbol_name(ascii_sym)
|
|
11
|
-
|
|
13
|
+
find_first_through(prefixes, via: :symbols, field: :ascii,
|
|
14
|
+
value: ascii_sym)
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def ascii_symbols
|
|
@@ -19,16 +22,6 @@ module Unitsml
|
|
|
19
22
|
names_array.concat(symbol)
|
|
20
23
|
end
|
|
21
24
|
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
def find(matching_data, field, prefix_method)
|
|
26
|
-
prefixes.find do |prefix|
|
|
27
|
-
prefix.public_send(prefix_method.to_sym).find do |object|
|
|
28
|
-
object.public_send(field) == matching_data
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
25
|
end
|
|
33
26
|
|
|
34
27
|
Configuration.register_model(Prefixes, id: :prefixes)
|
data/lib/unitsml/unitsdb/unit.rb
CHANGED
|
@@ -4,9 +4,11 @@ module Unitsml
|
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Unit < ::Unitsdb::Unit
|
|
6
6
|
def dimension_url
|
|
7
|
-
quantity_id = quantity_references
|
|
7
|
+
quantity_id = quantity_references.first&.id
|
|
8
|
+
return unless quantity_id
|
|
9
|
+
|
|
8
10
|
quantity = Unitsml::Unitsdb.quantities.find_by_id(quantity_id)
|
|
9
|
-
quantity
|
|
11
|
+
quantity&.dimension_reference&.id
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def en_name
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
module Unitsml
|
|
4
4
|
module Unitsdb
|
|
5
5
|
class Units < ::Unitsdb::Units
|
|
6
|
+
include Unitsml::Unitsdb::Finders
|
|
7
|
+
|
|
6
8
|
def find_by_id(u_id)
|
|
7
|
-
|
|
9
|
+
find_first_through(units, via: :identifiers, field: :id, value: u_id)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def find_by_name(u_name)
|
|
11
|
-
|
|
13
|
+
find_first_through(units, via: :symbols, field: :id, value: u_name)
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def filtered
|
|
@@ -30,16 +32,6 @@ module Unitsml
|
|
|
30
32
|
unit.symbols&.each { |unit_sym| object[unit_sym.id] = unit }
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def find(matching_data, field, unit_method)
|
|
37
|
-
units.find do |unit|
|
|
38
|
-
unit.public_send(unit_method.to_sym).find do |id|
|
|
39
|
-
id.public_send(field) == matching_data
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
35
|
end
|
|
44
36
|
|
|
45
37
|
Configuration.register_model(Units, id: :units)
|
data/lib/unitsml/unitsdb.rb
CHANGED
|
@@ -2,24 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
require "unitsdb"
|
|
4
4
|
|
|
5
|
-
require_relative "unitsdb/database"
|
|
6
|
-
require_relative "unitsdb/dimension_details"
|
|
7
|
-
require_relative "unitsdb/prefix_reference"
|
|
8
|
-
require_relative "unitsdb/dimension"
|
|
9
|
-
require_relative "unitsdb/dimensions"
|
|
10
|
-
require_relative "unitsdb/unit"
|
|
11
|
-
require_relative "unitsdb/units"
|
|
12
|
-
require_relative "unitsdb/prefixes"
|
|
13
|
-
require_relative "unitsdb/quantities"
|
|
14
5
|
module Unitsml
|
|
15
6
|
module Unitsdb
|
|
7
|
+
autoload :Database, "unitsml/unitsdb/database"
|
|
8
|
+
autoload :DimensionDetails, "unitsml/unitsdb/dimension_details"
|
|
9
|
+
autoload :Finders, "unitsml/unitsdb/finders"
|
|
10
|
+
autoload :PrefixReference, "unitsml/unitsdb/prefix_reference"
|
|
11
|
+
autoload :Dimension, "unitsml/unitsdb/dimension"
|
|
12
|
+
autoload :Dimensions, "unitsml/unitsdb/dimensions"
|
|
13
|
+
autoload :Unit, "unitsml/unitsdb/unit"
|
|
14
|
+
autoload :Units, "unitsml/unitsdb/units"
|
|
15
|
+
autoload :Prefixes, "unitsml/unitsdb/prefixes"
|
|
16
|
+
autoload :Quantities, "unitsml/unitsdb/quantities"
|
|
17
|
+
|
|
16
18
|
class << self
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
quantities
|
|
22
|
-
|
|
19
|
+
CACHE_INSTANCE_VARIABLES = %i[
|
|
20
|
+
@units
|
|
21
|
+
@prefixes
|
|
22
|
+
@dimensions
|
|
23
|
+
@quantities
|
|
24
|
+
@prefixes_array
|
|
25
|
+
@sized_prefixes
|
|
26
|
+
@database
|
|
23
27
|
].freeze
|
|
24
28
|
|
|
25
29
|
def units
|
|
@@ -65,19 +69,23 @@ module Unitsml
|
|
|
65
69
|
@database ||= load_database
|
|
66
70
|
end
|
|
67
71
|
|
|
72
|
+
def reset_caches
|
|
73
|
+
CACHE_INSTANCE_VARIABLES.each do |ivar|
|
|
74
|
+
remove_instance_variable(ivar) if instance_variable_defined?(ivar)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
68
78
|
private
|
|
69
79
|
|
|
80
|
+
# Delegates to the upstream loader, falling back to the UnitsML
|
|
81
|
+
# Database subclass when the upstream cannot satisfy the request
|
|
82
|
+
# (e.g. context substitution not yet wired up). Both paths load
|
|
83
|
+
# from `Unitsdb.data_dir` — the upstream `Unitsdb.database` calls
|
|
84
|
+
# `Database.from_db(data_dir, ...)` internally, and so does the
|
|
85
|
+
# fallback.
|
|
70
86
|
def load_database
|
|
71
87
|
context_id = Configuration.context.id
|
|
72
88
|
|
|
73
|
-
if ::Unitsdb.respond_to?(:database)
|
|
74
|
-
return load_unitsdb_database(context_id)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
Database.from_db(database_path, context: context_id)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def load_unitsdb_database(context_id)
|
|
81
89
|
::Unitsdb.database(context: context_id)
|
|
82
90
|
rescue ::Unitsdb::Errors::DatabaseNotFoundError,
|
|
83
91
|
::Unitsdb::Errors::DatabaseFileNotFoundError
|
|
@@ -85,27 +93,7 @@ module Unitsml
|
|
|
85
93
|
end
|
|
86
94
|
|
|
87
95
|
def database_path
|
|
88
|
-
|
|
89
|
-
database_files_present?(path)
|
|
90
|
-
end ||
|
|
91
|
-
File.join(unitsdb_gem_path, "vendor", "unitsdb")
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def candidate_database_paths
|
|
95
|
-
[
|
|
96
|
-
File.join(unitsdb_gem_path, "data"),
|
|
97
|
-
File.join(unitsdb_gem_path, "vendor", "unitsdb"),
|
|
98
|
-
]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def database_files_present?(dir_path)
|
|
102
|
-
REQUIRED_DATABASE_FILES.all? do |file_name|
|
|
103
|
-
File.exist?(File.join(dir_path, file_name))
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def unitsdb_gem_path
|
|
108
|
-
Gem.loaded_specs.fetch("unitsdb").full_gem_path
|
|
96
|
+
::Unitsdb.data_dir
|
|
109
97
|
end
|
|
110
98
|
end
|
|
111
99
|
end
|