unitsml 0.4.6 → 0.5.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/docs/README.adoc +104 -2
  3. data/lib/unitsml/dimension.rb +1 -1
  4. data/lib/unitsml/fenced.rb +77 -0
  5. data/lib/unitsml/formula.rb +21 -8
  6. data/lib/unitsml/intermediate_exp_rules.rb +35 -0
  7. data/lib/unitsml/parse.rb +16 -25
  8. data/lib/unitsml/parser.rb +19 -4
  9. data/lib/unitsml/prefix.rb +10 -10
  10. data/lib/unitsml/transform.rb +31 -0
  11. data/lib/unitsml/unit.rb +29 -7
  12. data/lib/unitsml/unitsdb/dimension.rb +12 -18
  13. data/lib/unitsml/unitsdb/dimension_quantity.rb +2 -6
  14. data/lib/unitsml/unitsdb/dimensions.rb +4 -8
  15. data/lib/unitsml/unitsdb/prefix_reference.rb +23 -0
  16. data/lib/unitsml/unitsdb/prefixes.rb +19 -5
  17. data/lib/unitsml/unitsdb/quantities.rb +6 -4
  18. data/lib/unitsml/unitsdb/unit.rb +21 -0
  19. data/lib/unitsml/unitsdb/units.rb +20 -17
  20. data/lib/unitsml/unitsdb.rb +8 -4
  21. data/lib/unitsml/utility.rb +36 -44
  22. data/lib/unitsml/version.rb +1 -1
  23. data/lib/unitsml.rb +34 -16
  24. data/unitsdb/LICENSE.md +53 -0
  25. data/unitsdb/README.adoc +1071 -0
  26. data/unitsdb/RELEASE-NOTES.adoc +269 -0
  27. data/unitsdb/dimensions.yaml +1255 -602
  28. data/unitsdb/prefixes.yaml +742 -301
  29. data/unitsdb/quantities.yaml +3104 -2458
  30. data/unitsdb/scales.yaml +97 -0
  31. data/unitsdb/schemas/README.md +159 -0
  32. data/unitsdb/schemas/dimensions-schema.yaml +157 -0
  33. data/unitsdb/schemas/prefixes-schema.yaml +159 -0
  34. data/unitsdb/schemas/quantities-schema.yaml +120 -0
  35. data/unitsdb/schemas/scales-schema.yaml +109 -0
  36. data/unitsdb/schemas/unit_systems-schema.yaml +120 -0
  37. data/unitsdb/schemas/units-schema.yaml +219 -0
  38. data/unitsdb/spec/units_spec.rb +11 -10
  39. data/unitsdb/unit_systems.yaml +73 -15
  40. data/unitsdb/units.yaml +12566 -9974
  41. data/unitsdb/validate_schemas.rb +208 -0
  42. data/unitsml.gemspec +2 -1
  43. metadata +36 -8
  44. data/unitsdb/docs/README.adoc +0 -12
  45. data/unitsdb/docs/navigation.adoc +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa7225e4922a972e29d438320d23fce921f62c550553a9eb24bb6bb501b7eb22
4
- data.tar.gz: f96fd6719ff152b0d853c20e80a7bfa2ce389715d49a90adf282cc0dcb5781c7
3
+ metadata.gz: edaa6904f430d793ab777f84d10c89925006c07654d769932ac17eb34e826e93
4
+ data.tar.gz: d5883a47de366c89c8e3d603aa9bfc99f307e94d73285bddcec426a34f6e963d
5
5
  SHA512:
6
- metadata.gz: 1b5a62abd80dd0c28a2168e5318f0bb80c68a5e894ed90f62097e3a9b9ad742c450c7f4e1815e8171d414cc2795ebba54d444a2929a7207f021da2594f3f232e
7
- data.tar.gz: c73a55849dd8ecf6c3534ccb54d099fbbfd5eb683359f7b4c094df13b9372cdbc60969f7d8ec1bb9829646ee33be564abc45c7b5a924fa97dcb42d29e1747808
6
+ metadata.gz: 46d962a6cb805be3f839125dc3bbab75913e0bac277800f808908f6de81d117c54fbd163418ef35b546834b8d0d9640290664d2ceb9658aea6638c6e86b29a5d
7
+ data.tar.gz: 7d628fe1043c6dfc29b7e03844f1d2fbff50078afe344d0089682417dd441504aac9792dc6ff16cf7f340e4899e5d963375d341d7c553b0681e81d428022648b
data/docs/README.adoc CHANGED
@@ -169,6 +169,104 @@ unit.to_unicode # Unicode representation
169
169
  unit.to_xml # XML (in UnitsML) representation
170
170
  ----
171
171
 
172
+ ==== Explicit parenthesis
173
+
174
+ When converting units to formats like MathML or LaTeX, you can specify whether
175
+ to use explicit parentheses for clarity in complex expressions.
176
+
177
+ A pair of parentheses is typically used for two purposes:
178
+
179
+ . For grouping to indicate operator precedence in mathematical expressions. When
180
+ expressing units, most of the time, parentheses are used to indicate operator
181
+ precedence, parentheses are only kept in cases where it indicates precedence.
182
+ When parentheses are not needed for precedence, such as in the expression
183
+ `(m/s)`, the parentheses can be removed whilch simplifies the expression into
184
+ `m/s`.
185
+
186
+ . For indicating that an expression is a compound unit. These parentheses are
187
+ explicit parentheses that cannot be removed without changing the meaning of the
188
+ expression.
189
+
190
+ UnitsML Ruby provides an option `explicit_parenthesis` to control the inclusion
191
+ of parentheses in the output.
192
+
193
+ In an expression:
194
+
195
+ * `(...)` is considered an implicit parenthesis for grouping and operator
196
+ precedence and can be removed without changing the meaning of the expression.
197
+
198
+ * `((...))` is considered an explicit parenthesis, which indicates that the
199
+ parentheses need to be preserved in the output regardless of operator
200
+ precedence.
201
+
202
+ The `explicit_parenthesis` option allows you to control how parentheses are
203
+ considered in the output formats. It can be set to `true` or `false`.
204
+
205
+ Syntax for using `explicit_parenthesis` is as follows:
206
+
207
+ [source,ruby]
208
+ ----
209
+ unit.to_asciimath(explicit_parenthesis: true) # or false
210
+ unit.to_mathml(explicit_parenthesis: true) # or false
211
+ unit.to_latex(explicit_parenthesis: true) # or false
212
+ ----
213
+
214
+ When `explicit_parenthesis` is set to:
215
+
216
+ `true`:: (default) the usage of `(...)` and `((...))` is differentiated as
217
+ implicit and explicit parentheses, respectively.
218
+
219
+ `false`:: all parentheses are treated as grouping parentheses, there is no
220
+ difference between `(...)` and `((...))`.
221
+
222
+
223
+ .By default `explicit_parenthesis` is `true` and double parentheses are considered explicit parentheses
224
+ [example]
225
+ ====
226
+ [source, ruby]
227
+ ----
228
+ Unitsml.parse("((m/s))").to_asciimath
229
+ > "(m/s^-1)" # Only one of the two pairs of parentheses are included in the output
230
+ ----
231
+ ====
232
+
233
+ If an extra pair of parentheses is included, it will be considered as grouping
234
+ parentheses and will not be included in the Unitsml::Formula or the output.
235
+
236
+ .By default `explicit_parenthesis` is `true` and double parentheses are considered explicit parentheses
237
+ [example]
238
+ ====
239
+ [source, ruby]
240
+ ----
241
+ Unitsml.parse("(((m/s)))").to_asciimath
242
+ > "(m/s^-1)" # the third pair of parentheses are ignored as grouping parentheses
243
+ Unitsml.parse("(((((m/s)))))").to_asciimath
244
+ > "((m/s^-1))" # the fifth pair of parentheses are ignored as grouping parentheses
245
+ ----
246
+
247
+ [source,ruby]
248
+ ----
249
+ unit = Unitsml.parse("((m/s))")
250
+ unit.to_asciimath # equivalent to (explicit_parenthesis: true) => "(m/s^-1)"
251
+ unit = Unitsml.parse("((m/s))*((m/s))")
252
+ unit.to_asciimath(explicit_parenthesis: true) # "(m/s^-1)*(m/s^-1)"
253
+ ----
254
+ ====
255
+
256
+ When `explicit_parenthesis` is `false`, all parentheses are treated as grouping parentheses
257
+ and therefore will be reduced to only the necessary parentheses for operator precedence.
258
+
259
+ .When `explicit_parenthesis` is `false`, all parentheses are treated as grouping parentheses
260
+ [example]
261
+ ====
262
+ [source,ruby]
263
+ ----
264
+ unit = Unitsml.parse("(m/s)")
265
+ unit.to_asciimath(explicit_parenthesis: false) # => "m/s"
266
+ unit = Unitsml.parse("((m/s))*((m/s))")
267
+ unit.to_asciimath(explicit_parenthesis: false) # "m/s^-1*m/s^-1"
268
+ ----
269
+ ====
172
270
 
173
271
 
174
272
  == Installation
@@ -196,7 +294,9 @@ $ gem install unitsml
196
294
 
197
295
  == Usage
198
296
 
199
- *UnitsML* Ruby provides functionality to represent and convert units between different formats including *MathML*, *LaTeX*, *AsciiMath*, *HTML*, *Unicode*, and *XML*(*Unitsml* schema based elements).
297
+ *UnitsML* Ruby provides functionality to represent and convert units between
298
+ different formats including *MathML*, *LaTeX*, *AsciiMath*, *HTML*, *Unicode*,
299
+ and *XML*(*Unitsml* schema based elements).
200
300
 
201
301
  === Basic Usage
202
302
 
@@ -275,7 +375,9 @@ repository.
275
375
 
276
376
  == Development
277
377
 
278
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
378
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
379
+ `bundle exec spec` to run the tests. You can also run `bin/console` for an
380
+ interactive prompt that will allow you to experiment.
279
381
 
280
382
  === Submodules
281
383
 
@@ -20,7 +20,7 @@ module Unitsml
20
20
  end
21
21
 
22
22
  def dim_symbols
23
- dim_instance.send(@dim.processed_keys.last).dim_symbols.first
23
+ dim_instance.send(@dim.processed_keys.last).symbols.first
24
24
  end
25
25
 
26
26
  def to_mathml(_)
@@ -0,0 +1,77 @@
1
+ module Unitsml
2
+ class Fenced
3
+ attr_reader :open_paren, :value, :close_paren
4
+
5
+ def initialize(open_paren, value, close_paren)
6
+ @open_paren = open_paren
7
+ @value = value
8
+ @close_paren = close_paren
9
+ end
10
+
11
+ def ==(object)
12
+ self.class == object.class &&
13
+ open_paren == object&.open_paren &&
14
+ value == object&.value &&
15
+ close_paren == object&.close_paren
16
+ end
17
+
18
+ def to_asciimath(options = {})
19
+ fenced_conversion_for(lang: :asciimath, options: options)
20
+ end
21
+
22
+ def to_latex(options = {})
23
+ fenced_conversion_for(lang: :latex, options: options)
24
+ end
25
+
26
+ def to_mathml(options = {})
27
+ mathml = value.to_mathml(options)
28
+ return mathml unless options[:explicit_parenthesis]
29
+
30
+ fenced = ::Mml::Mrow.new(mo_value: [::Mml::Mo.new(value: open_paren)])
31
+ fenced.ordered = true
32
+ fenced.element_order ||= [xml_order_element("mo")]
33
+ [mathml].flatten.each { |record| add_math_element(fenced, record) }
34
+ fenced.mo_value << ::Mml::Mo.new(value: close_paren)
35
+ fenced.element_order << xml_order_element("mo")
36
+ { method_name: :mrow, value: fenced }
37
+ end
38
+
39
+ def to_html(options = {})
40
+ fenced_conversion_for(lang: :html, options: options)
41
+ end
42
+
43
+ def to_unicode(options = {})
44
+ fenced_conversion_for(lang: :unicode, options: options)
45
+ end
46
+
47
+ def dimensions_extraction
48
+ case value
49
+ when Dimension
50
+ value
51
+ when Formula, Fenced
52
+ value.dimensions_extraction
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def add_math_element(instance, child_hash)
59
+ method_name = child_hash[:method_name]
60
+ method_value = instance.public_send(:"#{method_name}_value") || []
61
+ method_value += Array(child_hash[:value])
62
+ instance.public_send(:"#{method_name}_value=", method_value)
63
+ instance.element_order << xml_order_element(method_name.to_s)
64
+ end
65
+
66
+ def xml_order_element(tag_name)
67
+ Lutaml::Model::Xml::Element.new("Element", tag_name)
68
+ end
69
+
70
+ def fenced_conversion_for(lang:, options:)
71
+ lang_value = value.send(:"to_#{lang}", options)
72
+ return lang_value unless options[:explicit_parenthesis]
73
+
74
+ "#{open_paren}#{lang_value}#{close_paren}"
75
+ end
76
+ end
77
+ end
@@ -29,7 +29,7 @@ module Unitsml
29
29
 
30
30
  def to_mathml(options = {})
31
31
  if root
32
- update_options(options)
32
+ options = update_options(options)
33
33
  nullify_mml_models if plurimath_available?
34
34
  math = ::Mml::MathWithNamespace.new(display: "block")
35
35
  math.ordered = true
@@ -61,7 +61,7 @@ module Unitsml
61
61
  end
62
62
 
63
63
  def to_xml(options = {})
64
- update_options(options)
64
+ options = update_options(options)
65
65
  if (dimensions_array = extract_dimensions(value)).any?
66
66
  dimensions(sort_dims(dimensions_array), options)
67
67
  elsif @orig_text.match(/-$/)
@@ -79,18 +79,28 @@ module Unitsml
79
79
  Plurimath::Math.parse(to_mathml(options), :mathml)
80
80
  end
81
81
 
82
+ def dimensions_extraction
83
+ extract_dimensions(value)
84
+ end
85
+
82
86
  private
83
87
 
84
88
  def extract_dimensions(formula)
85
89
  formula.each_with_object([]) do |term, dimensions|
86
90
  if term.is_a?(Dimension)
87
91
  dimensions << term
88
- elsif term.is_a?(Sqrt) && term.value.is_a?(Dimension)
89
- sqrt_term = term.value.dup
90
- sqrt_term.power_numerator = "0.5"
91
- dimensions << sqrt_term
92
+ elsif term.is_a?(Sqrt)
93
+ if term.value.is_a?(Dimension)
94
+ sqrt_term = term.value.dup
95
+ sqrt_term.power_numerator = "0.5"
96
+ dimensions << sqrt_term
97
+ elsif term.value.is_a?(Fenced)
98
+ dimensions.concat(Array(term.value.dimensions_extraction))
99
+ end
92
100
  elsif term.is_a?(Formula)
93
101
  dimensions.concat(extract_dimensions(term.value))
102
+ elsif term.is_a?(Fenced)
103
+ dimensions.concat(Array(term.dimensions_extraction))
94
104
  end
95
105
  end
96
106
  end
@@ -106,13 +116,15 @@ module Unitsml
106
116
  next unless term.value.is_a?(Unit)
107
117
 
108
118
  units_arr << term.value
119
+ when Fenced
120
+ units_arr.concat(extract_units([term.value]))
109
121
  end
110
122
  end
111
123
  end
112
124
 
113
125
  def units(options)
114
126
  all_units = extract_units(value)
115
- norm_text = Utility.postprocess_normtext(all_units)
127
+ norm_text = all_units.map(&:xml_postprocess_name).join("*")
116
128
  dims = Utility.units2dimensions(extract_units(value))
117
129
  [
118
130
  Utility.unit(all_units, self, dims, norm_text, explicit_value&.dig(:name), options),
@@ -196,7 +208,8 @@ module Unitsml
196
208
  return options unless root
197
209
 
198
210
  multiplier = options[:multiplier] || explicit_value&.dig(:multiplier)
199
- options.merge(multiplier: multiplier).compact
211
+ explicit_parenthesis = options.key?(:explicit_parenthesis) ? options[:explicit_parenthesis] : true
212
+ options.merge(multiplier: multiplier, explicit_parenthesis: explicit_parenthesis).compact
200
213
  end
201
214
  end
202
215
  end
@@ -0,0 +1,35 @@
1
+ module Unitsml
2
+ module IntermediateExpRules
3
+ include Parslet
4
+
5
+ # Rules for slashed number
6
+ rule(:slashed_number_int_exp) { slashed_number | (str("(") >> slashed_number >> str(")")) }
7
+
8
+ # Rules for prefixes_units
9
+ rule(:prefixes_units_int_exp) { prefixes_units | (str("(") >> prefixes_units_named_exp.as(:intermediate_exp) >> str(")") >> extended_prefixed_units.maybe) }
10
+ rule(:extended_prefixed_units) { extender >> prefixes_units_int_exp.as(:sequence) }
11
+ rule(:prefixes_units_named_exp) do
12
+ prefixes_units |
13
+ ((str("(").as(:open_parenthesis) >> prefixes_units_int_exp.as(:int_exp) >> str(")").as(:close_parenthesis)).as(:intermediate_exp) >> extended_prefixed_units.maybe)
14
+ end
15
+
16
+ # Rules for dimension_rules
17
+ rule(:dimension_rules_int_exp) { dimension_rules | (str("(") >> dimension_rules_named_exp.as(:intermediate_exp) >> str(")") >> extended_dimension_rules.maybe) }
18
+ rule(:extended_dimension_rules) { extender >> dimension_rules_int_exp.as(:sequence) }
19
+ rule(:dimension_rules_named_exp) do
20
+ dimension_rules |
21
+ ((str("(").as(:open_parenthesis) >> dimension_rules_int_exp.as(:int_exp) >> str(")").as(:close_parenthesis)).as(:intermediate_exp) >> extended_dimension_rules.maybe)
22
+ end
23
+
24
+ # Rules for dimensions
25
+ rule(:sqrt_dimensions) { str("sqrt(") >> dimensions_int_exp.as(:sqrt) >> str(")") }
26
+ rule(:powered_dimensions) { dimensions >> power.maybe }
27
+ rule(:dimensions_int_exp) { powered_dimensions | (str("(") >> dimensions_named_exp.as(:intermediate_exp) >> str(")")) }
28
+ rule(:dimensions_named_exp) { powered_dimensions | (str("(").as(:open_parenthesis) >> dimensions_int_exp.as(:int_exp) >> str(")").as(:close_parenthesis)) }
29
+
30
+ # Rules for sequence
31
+ rule(:sqrt_sequence) { str("sqrt(") >> sequence_int_exp.as(:sqrt) >> str(")") }
32
+ rule(:sequence_int_exp) { sequence | (str("(") >> sequence_named_exp.as(:intermediate_exp)>> str(")")) }
33
+ rule(:sequence_named_exp) { sequence | (str("(").as(:open_parenthesis) >> sequence_int_exp.as(:int_exp) >> str(")").as(:close_parenthesis)) }
34
+ end
35
+ end
data/lib/unitsml/parse.rb CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  require "parslet"
4
4
  require "unitsml/unitsdb"
5
+ require_relative "intermediate_exp_rules"
5
6
  module Unitsml
6
7
  class Parse < Parslet::Parser
7
- rule(:power) { str("^") >> intermediate_exp(slashed_number) }
8
+ include IntermediateExpRules
9
+
10
+ rule(:power) { str("^") >> slashed_number_int_exp }
8
11
  rule(:hyphen) { str("-") }
9
12
  rule(:number) { hyphen.maybe >> match(/[0-9]/).repeat(1) }
10
13
 
@@ -32,24 +35,24 @@ module Unitsml
32
35
  end
33
36
 
34
37
  rule(:prefixes_units) do
35
- (sqrt(sequence) >> extend_exp(prefixes_units)) |
36
- (str("1").as(:units) >> extend_exp(prefixes_units)) |
37
- (unit_and_power >> extender >> intermediate_exp(prefixes_units).as(:sequence)) |
38
- unit_and_power |
39
- (single_letter_prefixes >> unit_and_power >> extender >> intermediate_exp(prefixes_units).as(:sequence)) |
40
- (single_letter_prefixes >> unit_and_power) |
41
- (double_letter_prefixes >> unit_and_power >> extender >> intermediate_exp(prefixes_units).as(:sequence)) |
42
- (double_letter_prefixes >> unit_and_power)
38
+ (sqrt_sequence >> extended_prefixed_units.maybe) |
39
+ (str("1").as(:units) >> extended_prefixed_units.maybe) |
40
+ (unit_and_power >> extended_prefixed_units) |
41
+ unit_and_power >> (str(")").present? | any.absent?) |
42
+ (double_letter_prefixes >> unit_and_power >> extended_prefixed_units) |
43
+ (double_letter_prefixes >> unit_and_power) |
44
+ (single_letter_prefixes >> unit_and_power >> extended_prefixed_units) |
45
+ (single_letter_prefixes >> unit_and_power)
43
46
  end
44
47
 
45
48
  rule(:dimension_rules) do
46
- (sqrt(intermediate_exp(dimensions >> power.maybe)) >> extend_exp(dimension_rules)) |
47
- (dimensions >> power.maybe >> extend_exp(dimension_rules))
49
+ (sqrt_dimensions >> extended_dimension_rules.maybe) |
50
+ (powered_dimensions >> extended_dimension_rules.maybe)
48
51
  end
49
52
 
50
53
  rule(:expression) do
51
- intermediate_exp(prefixes_units) |
52
- intermediate_exp(dimension_rules) |
54
+ prefixes_units_int_exp |
55
+ dimension_rules_int_exp |
53
56
  single_letter_prefixes >> hyphen |
54
57
  double_letter_prefixes >> hyphen
55
58
  end
@@ -63,17 +66,5 @@ module Unitsml
63
66
  expression | str(expr_string).as(file_name.to_sym)
64
67
  end
65
68
  end
66
-
67
- def sqrt(rule)
68
- str("sqrt(") >> rule.as(:sqrt) >> str(")")
69
- end
70
-
71
- def extend_exp(rule)
72
- (extender >> intermediate_exp(rule).as(:sequence)).maybe
73
- end
74
-
75
- def intermediate_exp(rule)
76
- rule | (str("(") >> rule >> str(")"))
77
- end
78
69
  end
79
70
  end
@@ -6,7 +6,7 @@ module Unitsml
6
6
 
7
7
  def initialize(text)
8
8
  @regexp = %r{(quantity|name|symbol|multiplier):\s*}
9
- @text = text&.match(/unitsml\((.*)\)/) ? Regexp.last_match[1] : text
9
+ @text = extract_equation(text)
10
10
  @orig_text = @text
11
11
  @text = @text.gsub("−", "-")
12
12
  post_extras
@@ -15,7 +15,7 @@ module Unitsml
15
15
  def parse
16
16
  nodes = Parse.new.parse(text)
17
17
  transformed = Transform.new.apply(nodes)
18
- formula_value = transformed.is_a?(Formula) ? transformed.value : Array(transformed)
18
+ formula_value = transformed.is_a?(Formula) ? transformed.value : [transformed].flatten
19
19
  formula = Formula.new(
20
20
  formula_value,
21
21
  explicit_value: @extras_hash,
@@ -28,21 +28,28 @@ module Unitsml
28
28
  formula
29
29
  end
30
30
 
31
- def update_units_exponents(array, inverse)
31
+ def update_units_exponents(array, inverse, sqrt = false)
32
32
  array.each do |object|
33
33
  if object.is_a?(Sqrt)
34
34
  object = object.value
35
- object.power_numerator = "0.5"
35
+ if object.respond_to?(:power_numerator)
36
+ object.power_numerator = "0.5"
37
+ else
38
+ update_units_exponents([object], inverse, true)
39
+ end
36
40
  end
37
41
 
38
42
  case object
39
43
  when Unit
44
+ next object.power_numerator = "0.5" if sqrt
40
45
  next unless inverse
41
46
 
42
47
  exponent = inverse ? "-#{object&.power_numerator || '1'}" : object.power_numerator
43
48
  object.power_numerator = exponent&.sub(/^--+/, "")
49
+ when Dimension then object.power_numerator = "0.5" if sqrt
44
50
  when Extender then inverse = !inverse if ["/", "//"].any?(object.symbol)
45
51
  when Formula then update_units_exponents(object.value, inverse)
52
+ when Fenced then update_units_exponents([object.value], inverse, sqrt)
46
53
  end
47
54
  end
48
55
  end
@@ -62,5 +69,13 @@ module Unitsml
62
69
  key, _, value = text&.partition(":")
63
70
  @extras_hash[key&.to_sym] ||= value&.strip
64
71
  end
72
+
73
+ private
74
+
75
+ def extract_equation(text)
76
+ return text unless text&.start_with?("unitsml(")
77
+
78
+ text.delete_prefix("unitsml(").delete_suffix(")")
79
+ end
65
80
  end
66
81
  end
@@ -20,21 +20,21 @@ module Unitsml
20
20
  end
21
21
 
22
22
  def id
23
- @prefix.id
23
+ @id ||= prefix_instance.identifiers.find { |prefix| prefix.type == "nist" }&.id
24
24
  end
25
25
 
26
26
  def name
27
- prefix_instance.name
27
+ @name ||= prefix_instance.names.find { |name| name.lang == "en" }.value
28
28
  end
29
29
 
30
- def prefixes_symbols
31
- prefix_instance.symbol
30
+ def prefix_symbols
31
+ prefix_instance.symbols.last
32
32
  end
33
33
 
34
34
  def to_mathml(_)
35
35
  symbol = Utility.string_to_html_entity(
36
36
  Utility.html_entity_to_unicode(
37
- prefixes_symbols.html
37
+ prefix_symbols.html
38
38
  ),
39
39
  )
40
40
  return symbol unless only_instance
@@ -43,23 +43,23 @@ module Unitsml
43
43
  end
44
44
 
45
45
  def to_latex(_)
46
- prefixes_symbols.latex
46
+ prefix_symbols.latex
47
47
  end
48
48
 
49
49
  def to_asciimath(_)
50
- prefixes_symbols.ascii
50
+ prefix_symbols.ascii
51
51
  end
52
52
 
53
53
  def to_html(_)
54
- prefixes_symbols.html
54
+ prefix_symbols.html
55
55
  end
56
56
 
57
57
  def to_unicode(_)
58
- prefixes_symbols.unicode
58
+ prefix_symbols.unicode
59
59
  end
60
60
 
61
61
  def symbolid
62
- prefixes_symbols.ascii if prefixes_symbols
62
+ prefix_symbols.ascii if prefix_symbols
63
63
  end
64
64
 
65
65
  def base
@@ -7,6 +7,7 @@ module Unitsml
7
7
  rule(units: simple(:unit)) { Unit.new(unit.to_s) }
8
8
  rule(prefixes: simple(:prefix)) { Prefix.new(prefix.to_s) }
9
9
  rule(dimensions: simple(:dimension)) { Dimension.new(dimension.to_s) }
10
+ rule(intermediate_exp: simple(:int_exp)) { int_exp }
10
11
 
11
12
  rule(units: simple(:unit),
12
13
  integer: simple(:integer)) do
@@ -30,6 +31,36 @@ module Unitsml
30
31
  Unit.new(unit.to_s, integer.to_s, prefix: prefix_obj)
31
32
  end
32
33
 
34
+ rule(open_parenthesis: simple(:open_paren),
35
+ int_exp: simple(:exp),
36
+ close_parenthesis: simple(:close_paren)) do
37
+ Fenced.new(open_paren.to_s, exp, close_paren.to_s)
38
+ end
39
+
40
+ rule(open_parenthesis: simple(:open_paren),
41
+ int_exp: simple(:exp),
42
+ close_parenthesis: simple(:close_paren),
43
+ sequence: sequence(:sequence)) do
44
+ Formula.new(
45
+ [
46
+ Fenced.new(open_paren.to_s, exp, close_paren.to_s),
47
+ sequence,
48
+ ],
49
+ )
50
+ end
51
+
52
+ rule(intermediate_exp: simple(:intermediate_exp),
53
+ extender: simple(:extender),
54
+ sequence: simple(:sequence)) do
55
+ Formula.new(
56
+ [
57
+ intermediate_exp,
58
+ Extender.new(extender.to_s),
59
+ sequence,
60
+ ],
61
+ )
62
+ end
63
+
33
64
  rule(prefixes: simple(:prefix),
34
65
  units: simple(:unit),
35
66
  integer: simple(:integer),
data/lib/unitsml/unit.rb CHANGED
@@ -4,6 +4,8 @@ module Unitsml
4
4
  class Unit
5
5
  attr_accessor :unit_name, :power_numerator, :prefix
6
6
 
7
+ SI_UNIT_SYSTEM = %w[si_base si_derived_special si_derived_non_special].freeze
8
+
7
9
  def initialize(unit_name,
8
10
  power_numerator = nil,
9
11
  prefix: nil)
@@ -24,7 +26,7 @@ module Unitsml
24
26
  end
25
27
 
26
28
  def unit_symbols
27
- unit_instance.unit_symbols.find { |symbol| symbol.id == unit_name }
29
+ unit_instance.symbols.find { |symbol| symbol.id == unit_name }
28
30
  end
29
31
 
30
32
  def numerator_value(mathml = true)
@@ -89,7 +91,7 @@ module Unitsml
89
91
  end
90
92
 
91
93
  def enumerated_name
92
- unit_instance&.unit_name&.first
94
+ unit_instance.names.find { |name| name.lang == "en" }&.value
93
95
  end
94
96
 
95
97
  def prefix_name
@@ -97,15 +99,35 @@ module Unitsml
97
99
  end
98
100
 
99
101
  def system_type
100
- unit_instance.unit_system.type
101
- end
102
-
103
- def system_name
104
- unit_instance.unit_system.name
102
+ system_reference&.first&.id
105
103
  end
106
104
 
107
105
  def si_derived_bases
108
106
  unit_instance.si_derived_bases
109
107
  end
108
+
109
+ def xml_postprocess_name
110
+ "#{prefix_name}#{unit_name}#{display_exp}"
111
+ end
112
+
113
+ def si_system_type?
114
+ SI_UNIT_SYSTEM.include?(downcase_system_type)
115
+ end
116
+
117
+ def downcase_system_type
118
+ Lutaml::Model::Utils.snake_case(system_type)
119
+ end
120
+
121
+ private
122
+
123
+ def display_exp
124
+ return unless power_numerator
125
+
126
+ "^#{power_numerator}" if power_numerator != "1"
127
+ end
128
+
129
+ def system_reference
130
+ unit_instance.unit_system_reference
131
+ end
110
132
  end
111
133
  end