asciimath2unitsml 0.3.3 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 829d573c90a88f5d26b2310d69f5ea575084df208cd3f441342435b0a6a3d353
4
- data.tar.gz: 534c2ea7485b1de1c126de112a1ad8c9b10683797034e99313fda199c5f7e572
3
+ metadata.gz: b4d619489e5063d9e3616163d69c6c1f4796615412ee40f0a92f356603f0e366
4
+ data.tar.gz: 0465ac8a99f8929d1d4f8f2db152821e4d1fae7ac66af1a8a3e2feb6092e0c3a
5
5
  SHA512:
6
- metadata.gz: c6eec2cb24fff7931d236a9a14a6d4ae1a938fe348d1e1d02a4d2f9be8e7f72e124e633ef0ef4b0f1e476ee8a2dee900210e60010600e0b082eb95237d2c70d2
7
- data.tar.gz: e6943596be90a3bd1e6336b7bfa395cee4aa41e88ab6e5b2d003216a2271fc72249a018218d65c4ef446f4d246412e2b9fa0ac0d9721095abd4d9baa95515389
6
+ metadata.gz: 3de256a40d7eb24439409664a8b7bb14f1893403a4cfc762b70bd9693a15c0304766a7d20491de4094571fd5b117695350a5ad56100cf67bde1e7c61c4e99004
7
+ data.tar.gz: 4f053e85ff192f040856d0f63ff2d1ffb7a49eb72735f668785a3396e82ff145b8d678d754b8a26b26deee4c3072de4f8af8686f7ee60cb9e339dfe3f7be08c3
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '3.0', '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '3.0', '2.7', '2.6', '2.5' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
22
  steps:
data/.rubocop.yml CHANGED
@@ -7,4 +7,4 @@ inherit_from:
7
7
  # ...
8
8
 
9
9
  AllCops:
10
- TargetRubyVersion: 2.4
10
+ TargetRubyVersion: 2.5
data/README.adoc CHANGED
@@ -59,6 +59,24 @@ units. The options are an XML entity, or the values `space` or `nospace` (for wh
59
59
  Standalone prefixes can be recognised by replacing the unit with hyphen; so `unitsml(p-)` corresponds
60
60
  to the standalone prefix "pico" (and is rendered as "p").
61
61
 
62
+ The gem also supports fundamental units, e.g. `unitsml(e)` for the atomic unit of charge, _e_,
63
+ and symbols for dimensions. The latter are entered as `dim_XXX`, where `XXX` is their established symbol:
64
+
65
+ |===
66
+ |Symbol | Dimension
67
+
68
+ |dim_L | Length
69
+ |dim_M | Mass
70
+ |dim_T | Time
71
+ |dim_I | Electric Current
72
+ |dim_Theta | Thermodynamic Temperature
73
+ |dim_N | Amount of Substance
74
+ |dim_J | Luminous Intensity
75
+ |dim_phi | Plane Angle (dimensionless)
76
+ |===
77
+
78
+ e.g. `unitsml(dim_I)` for the dimension of electric current, 𝖨.
79
+
62
80
  == Rendering
63
81
 
64
82
  The output of the gem is MathML, with MathML unit expressions (expressed as `<mi>`,
@@ -141,7 +159,7 @@ The converter is run as:
141
159
  [source,ruby]
142
160
  ----
143
161
  c = Asciimath2UnitsML::Conv.new()
144
- c.Asciimath2UnitsML(1 "unitsml(mm*s^-2)") # AsciiMath string containing UnitsML
162
+ c.Asciimath2UnitsML('1 "unitsml(mm*s^-2)"') # AsciiMath string containing UnitsML
145
163
  c.MathML2UnitsML("<math xmlns='http://www.w3.org/1998/Math/MathML'><mn>7</mn>"\
146
164
  "<mtext>unitsml(kg^-2)</mtext></math>") # AsciiMath string containing <mtext>unitsml()</mtext>
147
165
  c.MathML2UnitsML(Nokogiri::XML("<math xmlns='http://www.w3.org/1998/Math/MathML'><mn>7</mn>"\
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.require_paths = ["lib"]
23
23
  spec.files = `git ls-files`.split("\n")
24
24
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
25
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
25
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
26
26
 
27
27
  # get an array of submodule dirs relatively to root repo
28
28
  `git config --file .gitmodules --get-regexp '\\.path$'`
@@ -3,6 +3,8 @@ require "nokogiri"
3
3
  require "htmlentities"
4
4
  require "yaml"
5
5
  require "rsec"
6
+ require_relative "read"
7
+ require_relative "dimensions"
6
8
  require_relative "string"
7
9
  require_relative "parse"
8
10
  require_relative "render"
@@ -19,6 +21,7 @@ module Asciimath2UnitsML
19
21
  .each_with_object({}) do |(k, v), m|
20
22
  m[k.to_s] = UnitsDB::Dimension.new(k, v)
21
23
  end
24
+ @dimensions = flip_name_and_symbols(@dimensions_id)
22
25
  @prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
23
26
  .each_with_object({}) do |(k, v), m|
24
27
  m[k] = UnitsDB::Prefix.new(k, v)
@@ -33,10 +36,10 @@ module Asciimath2UnitsML
33
36
  m[k.to_s] = UnitsDB::Unit.new(k.to_s, v)
34
37
  end
35
38
  @units = flip_name_and_symbols(@units_id)
36
- @symbols = @units.each_with_object({}) do |(_k, v), m|
39
+ @symbols = @units.merge(@dimensions).each_with_object({}) do |(_k, v), m|
37
40
  v.symbolids.each { |x| m[x] = v.symbols_hash[x] }
38
41
  end
39
- @parser = parser
42
+ @parser, @dim_parser = parsers
40
43
  @multiplier = multiplier(options[:multiplier] || "\u22c5")
41
44
  end
42
45
 
@@ -59,70 +62,17 @@ module Asciimath2UnitsML
59
62
  end.join("\n")
60
63
  end
61
64
 
62
- def dimension_components(dims)
63
- return if dims.nil? || dims.empty?
64
-
65
- <<~XML
66
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
67
- #{dims.map { |u| dimension1(u) }.join("\n")}
68
- </Dimension>
69
- XML
70
- end
71
-
72
- U2D = {
73
- "m" => { dimension: "Length", order: 1, symbol: "L" },
74
- "g" => { dimension: "Mass", order: 2, symbol: "M" },
75
- "kg" => { dimension: "Mass", order: 2, symbol: "M" },
76
- "s" => { dimension: "Time", order: 3, symbol: "T" },
77
- "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
78
- "K" => { dimension: "ThermodynamicTemperature", order: 5,
79
- symbol: "Theta" },
80
- "degK" => { dimension: "ThermodynamicTemperature", order: 5,
81
- symbol: "Theta" },
82
- "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
83
- "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
84
- "deg" => { dimension: "PlaneAngle", order: 8, symbol: "Phi" },
85
- }.freeze
86
-
87
- def units2dimensions(units)
88
- norm = decompose_units(units)
89
- return if norm.any? do |u|
90
- u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
91
- end
92
-
93
- norm.map do |u|
94
- { dimension: U2D[u[:unit]][:dimension],
95
- unit: u[:unit],
96
- exponent: u[:exponent] || 1,
97
- symbol: U2D[u[:unit]][:symbol] }
98
- end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
99
- end
100
-
101
- def dimension1(dim)
102
- %(<#{dim[:dimension]} symbol="#{dim[:symbol]}"
103
- powerNumerator="#{float_to_display(dim[:exponent])}"/>)
104
- end
105
-
106
- def dim_id(dims)
107
- return nil if dims.nil? || dims.empty?
108
-
109
- dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
110
- dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
111
- AmountOfSubstance LuminousIntensity PlaneAngle)
112
- .map { |h| dimhash.dig(h, :exponent) }.join(":")
113
- id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
114
- &.first&.id and return id.to_s
115
- "D_" + dims.map do |d|
116
- U2D[d[:unit]][:symbol] +
117
- (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
118
- end.join("")
119
- end
120
-
121
65
  def decompose_units(units)
122
66
  gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
123
67
  end
124
68
 
125
69
  def gather_units(units)
70
+ if units[0][:dim] then gather_dimensions(units)
71
+ else gather_units1(units)
72
+ end
73
+ end
74
+
75
+ def gather_units1(units)
126
76
  units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m|
127
77
  if m.empty? || m[-1][:unit] != k[:unit] then m << k
128
78
  else
@@ -138,12 +88,24 @@ module Asciimath2UnitsML
138
88
  end
139
89
  end
140
90
 
91
+ def gather_dimensions(units)
92
+ units.sort_by { |a| a[:dim] }.each_with_object([]) do |k, m|
93
+ if m.empty? || m[-1][:dim] != k[:dim] then m << k
94
+ else
95
+ m[-1] = {
96
+ dim: m[-1][:dim],
97
+ exponent: (k[:exponent]&.to_f || 1) +
98
+ (m[-1][:exponent]&.to_f || 1),
99
+ }
100
+ end
101
+ end
102
+ end
103
+
141
104
  # treat g not kg as base unit: we have stripped the prefix k in parsing
142
105
  # reduce units down to basic units
143
106
  def decompose_unit(u)
144
- if u[:unit].nil? then u
145
- elsif u[:unit] == "g" then u
146
- elsif @units[u[:unit]].system_type == "SI_base" then u
107
+ if u[:unit].nil? || u[:unit] == "g" ||
108
+ @units[u[:unit]].system_type == "SI_base" then u
147
109
  elsif !@units[u[:unit]].si_derived_bases
148
110
  { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
149
111
  else
@@ -195,25 +157,6 @@ module Asciimath2UnitsML
195
157
  XML
196
158
  end
197
159
 
198
- def dimid2dimensions(normtext)
199
- @dimensions_id[normtext].keys.map do |k|
200
- { dimension: k,
201
- symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
202
- exponent: @dimensions_id[normtext].exponent(k) }
203
- end
204
- end
205
-
206
- def dimension(normtext)
207
- return unless @units[normtext]&.dimension
208
-
209
- dims = dimid2dimensions(@units[normtext]&.dimension)
210
- <<~XML
211
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
212
- #{dims.map { |u| dimension1(u) }.join("\n")}
213
- </Dimension>
214
- XML
215
- end
216
-
217
160
  def unitsml(units, origtext, normtext, quantity, name)
218
161
  dims = units2dimensions(units)
219
162
  <<~XML
@@ -0,0 +1,117 @@
1
+ module Asciimath2UnitsML
2
+ class Conv
3
+ def dimension_components(dims)
4
+ return if dims.nil? || dims.empty?
5
+
6
+ <<~XML
7
+ <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
8
+ #{dims.map { |u| dimension1(u) }.join("\n")}
9
+ </Dimension>
10
+ XML
11
+ end
12
+
13
+ U2D = {
14
+ "m" => { dimension: "Length", order: 1, symbol: "L" },
15
+ "g" => { dimension: "Mass", order: 2, symbol: "M" },
16
+ "kg" => { dimension: "Mass", order: 2, symbol: "M" },
17
+ "s" => { dimension: "Time", order: 3, symbol: "T" },
18
+ "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
19
+ "K" => { dimension: "ThermodynamicTemperature", order: 5,
20
+ symbol: "Theta" },
21
+ "degK" => { dimension: "ThermodynamicTemperature", order: 5,
22
+ symbol: "Theta" },
23
+ "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
24
+ "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
25
+ "deg" => { dimension: "PlaneAngle", order: 8, symbol: "phi" },
26
+ }.freeze
27
+
28
+ Dim2D = {
29
+ "dim_L" => U2D["m"],
30
+ "dim_M" => U2D["g"],
31
+ "dim_T" => U2D["s"],
32
+ "dim_I" => U2D["A"],
33
+ "dim_Theta" => U2D["K"],
34
+ "dim_N" => U2D["mol"],
35
+ "dim_J" => U2D["cd"],
36
+ "dim_phi" => U2D["deg"],
37
+ }.freeze
38
+
39
+ def units2dimensions(units)
40
+ norm = decompose_units(units)
41
+ return units2dimensions_dim_input(norm) if norm[0][:dim]
42
+ return if norm.any? do |u|
43
+ u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
44
+ end
45
+
46
+ norm.map do |u|
47
+ { dimension: U2D[u[:unit]][:dimension],
48
+ unit: u[:unit],
49
+ exponent: u[:exponent] || 1,
50
+ symbol: U2D[u[:unit]][:symbol] }
51
+ end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
52
+ end
53
+
54
+ def units2dimensions_dim_input(norm)
55
+ norm.map do |u|
56
+ { dimension: Dim2D[u[:dim]][:dimension],
57
+ exponent: u[:exponent] || 1,
58
+ id: u[:dim],
59
+ symbol: Dim2D[u[:dim]][:symbol] }
60
+ end.sort { |a, b| Dim2D[a[:id]][:order] <=> Dim2D[b[:id]][:order] }
61
+ end
62
+
63
+ def dimension1(dim)
64
+ %(<#{dim[:dimension]} symbol="#{dim[:symbol]}"
65
+ powerNumerator="#{float_to_display(dim[:exponent])}"/>)
66
+ end
67
+
68
+ def dim_id(dims)
69
+ return nil if dims.nil? || dims.empty?
70
+
71
+ dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
72
+ dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
73
+ AmountOfSubstance LuminousIntensity PlaneAngle)
74
+ .map { |h| dimhash.dig(h, :exponent) }.join(":")
75
+ id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
76
+ &.first&.id and return id.to_s
77
+ "D_" + dims.map do |d|
78
+ (U2D.dig(d[:unit], :symbol) || Dim2D.dig(d[:id], :symbol)) +
79
+ (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
80
+ end.join("")
81
+ end
82
+
83
+ def decompose_units(units)
84
+ gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
85
+ end
86
+
87
+ def dimid2dimensions(normtext)
88
+ @dimensions_id[normtext].keys.map do |k|
89
+ { dimension: k,
90
+ symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
91
+ exponent: @dimensions_id[normtext].exponent(k) }
92
+ end
93
+ end
94
+
95
+ def dimension(normtext)
96
+ return unless @units[normtext]&.dimension
97
+
98
+ dims = dimid2dimensions(@units[normtext]&.dimension)
99
+ <<~XML
100
+ <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
101
+ #{dims.map { |u| dimension1(u) }.join("\n")}
102
+ </Dimension>
103
+ XML
104
+ end
105
+
106
+ def unitsml(units, origtext, normtext, quantity, name)
107
+ dims = units2dimensions(units)
108
+ <<~XML
109
+ #{unit(units, origtext, normtext, dims, name)}
110
+ #{prefix(units)}
111
+ #{dimension(normtext)}
112
+ #{dimension_components(dims)}
113
+ #{quantity(normtext, quantity)}
114
+ XML
115
+ end
116
+ end
117
+ end
@@ -1,102 +1,101 @@
1
1
  module Asciimath2UnitsML
2
2
  class Conv
3
3
  include Rsec::Helpers
4
-
5
- def read_yaml(path)
6
- validate_yaml(symbolize_keys(YAML
7
- .load_file(File.join(File.join(File.dirname(__FILE__), path)))), path)
8
- end
9
-
10
- def flip_name_and_symbol(hash)
11
- hash.each_with_object({}) do |(_k, v), m|
12
- next if v.name.nil? || v.name.empty?
13
-
14
- m[v.symbolid] = v
15
- end
16
- end
17
-
18
- def flip_name_and_symbols(hash)
19
- hash.each_with_object({}) do |(_k, v), m|
20
- next if v.name.nil? || v.name.empty?
21
-
22
- v.symbolids.each { |s| m[s] = v }
23
- end
4
+ def parsers
5
+ exponent = /\^\(-?\d+\)/.r.map { |m| m.sub(/\^/, "").gsub(/[()]/, "") } |
6
+ /\^-?\d+/.r.map { |m| m.sub(/\^/, "") }
7
+ multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } }
8
+ units = units_parse(exponent, multiplier)
9
+ dimensions = dimensions_parser(exponent, multiplier)
10
+ [units.eof, dimensions.eof]
24
11
  end
25
12
 
26
- def symbolize_keys(hash)
27
- return hash if hash.is_a? String
28
-
29
- hash.inject({}) do |result, (key, value)|
30
- new_key = case key
31
- when String then key.to_sym
32
- else key
33
- end
34
- new_value = case value
35
- when Hash then symbolize_keys(value)
36
- when Array then value.map { |m| symbolize_keys(m) }
37
- else value
38
- end
39
- result[new_key] = new_value
40
- result
41
- end
13
+ def dimensions_parser(exponent, multiplier)
14
+ dim1 = /#{@dimensions.keys.sort_by(&:length).reverse.join("|")}/.r
15
+ dimension =
16
+ seq("sqrt(", dim1, ")") { |x| { dim: x[1], display_exponent: "0.5" } } |
17
+ seq(dim1, exponent._? & (multiplier | ")".r)) { |x| { dim: x[0], display_exponent: (x[1][0]) } } |
18
+ seq(dim1, exponent._?).eof { |x| { dim: x[0], display_exponent: (x[1][0]) } }
19
+ dimensions1 = "(".r >> lazy { dimensions } << ")" | dimension
20
+ dimensions = dimensions1.join(multiplier) # rubocop:disable Style/RedundantAssignment
21
+ dimensions
42
22
  end
43
23
 
44
- def parser
24
+ def units_parse(exponent, multiplier)
45
25
  prefix2 = /#{@prefixes.keys.select { |x| x.size == 2 }.join("|")}/.r
46
26
  prefix1 = /#{@prefixes.keys.select { |x| x.size == 1 }.join("|")}/.r
47
27
  unit_keys = @units.keys.reject do |k|
48
28
  /\*|\^|\/|^1$/.match(k) || @units[k].prefixed
49
29
  end.map { |k| Regexp.escape(k) }
50
30
  unit1 = /#{unit_keys.sort_by(&:length).reverse.join("|")}/.r
51
- exponent = /\^\(-?\d+\)/.r.map { |m| m.sub(/\^/, "").gsub(/[()]/, "") } |
52
- /\^-?\d+/.r.map { |m| m.sub(/\^/, "") }
53
- multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } }
54
- unit =
31
+
32
+ unit =
55
33
  seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } |
56
34
  seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
57
35
  seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
58
36
  seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
59
37
  seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
60
- seq(prefix1, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
61
- seq(prefix2, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
38
+ seq(prefix1, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
39
+ seq(prefix2, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
62
40
  "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
63
- units1 = "(".r >> lazy{units} << ")" | unit
64
- units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
41
+ units1 = "(".r >> lazy { units } << ")" | unit
42
+ units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } | # rubocop:disable Style/RedundantAssignment
65
43
  seq(prefix1, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
66
44
  units1.join(multiplier)
67
- parser = units.eof
45
+ units
68
46
  end
69
47
 
70
48
  def parse(expr)
71
49
  text = Array(expr.split(/,\s*/))
50
+ if /dim_/.match?(text[0]) then parse_dimensions(text)
51
+ else parse_units(text)
52
+ end
53
+ end
54
+
55
+ def parse_units(text)
72
56
  units = @parser.parse!(text[0])
73
57
  if !units || Rsec::INVALID[units]
74
58
  raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
75
59
  end
76
60
 
77
61
  Rsec::Fail.reset
78
- postprocess(units, text)
62
+ postprocess(units, text, true)
63
+ end
64
+
65
+ def parse_dimensions(text)
66
+ units = @dim_parser.parse!(text[0])
67
+ if !units || Rsec::INVALID[units]
68
+ raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
69
+ end
70
+
71
+ Rsec::Fail.reset
72
+ postprocess(units, text, false)
79
73
  end
80
74
 
81
- def postprocess(units, text)
75
+ def postprocess(units, text, is_units)
82
76
  units = postprocess1(units.flatten)
83
- quantity = text[1..-1]&.select do |x|
84
- /^quantity:/.match(x)
85
- end&.first&.sub(/^quantity:\s*/, "")
86
- name = text[1..-1]&.select do |x|
87
- /^name:/.match(x)
88
- end&.first&.sub(/^name:\s*/, "")
89
- symbol = text[1..-1]&.select do |x|
90
- /^symbol:/.match(x)
91
- end&.first&.sub(/^symbol:\s*/, "")
92
- multiplier = text[1..-1]&.select do |x|
93
- /^multiplier:/.match(x)
94
- end&.first&.sub(/^multiplier:\s*/, "")
95
- normtext = units_only(units).each.map do |u|
96
- exp = u[:exponent] && u[:exponent] != "1" ? "^#{u[:exponent]}" : ""
97
- "#{u[:prefix]}#{u[:unit]}#{exp}"
77
+ normtext = postprocess_normtext(units, is_units)
78
+ [units, text[0], normtext, postprocess_extr(text, "quantity"),
79
+ postprocess_extr(text, "name"), postprocess_extr(text, "symbol"),
80
+ postprocess_extr(text, "multiplier")]
81
+ end
82
+
83
+ def postprocess_normtext(units, is_units)
84
+ units_only(units).each.map do |u|
85
+ if is_units then "#{u[:prefix]}#{u[:unit]}#{display_exp(u)}"
86
+ else "#{u[:dim]}#{display_exp(u)}"
87
+ end
98
88
  end.join("*")
99
- [units, text[0], normtext, quantity, name, symbol, multiplier]
89
+ end
90
+
91
+ def postprocess_extr(text, name)
92
+ text[1..-1]&.select do |x|
93
+ /^#{name}:/.match(x)
94
+ end&.first&.sub(/^#{name}:\s*/, "")
95
+ end
96
+
97
+ def display_exp(unit)
98
+ unit[:exponent] && unit[:exponent] != "1" ? "^#{unit[:exponent]}" : ""
100
99
  end
101
100
 
102
101
  def postprocess1(units)
@@ -128,8 +127,11 @@ module Asciimath2UnitsML
128
127
  text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
129
128
  units, origtext, normtext, quantity, name, symbol, multiplier =
130
129
  parse(text)
131
- rendering = symbol ? embeddedmathml(asciimath2mathml(symbol)) :
132
- mathmlsymbol(units, false, multiplier)
130
+ rendering = if symbol
131
+ embeddedmathml(asciimath2mathml(symbol))
132
+ else
133
+ mathmlsymbol(units, false, multiplier)
134
+ end
133
135
  x.replace("#{delimspace(rendering, x)}"\
134
136
  "<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
135
137
  "#{unitsml(units, origtext, normtext, quantity, name)}")
@@ -149,8 +151,10 @@ module Asciimath2UnitsML
149
151
 
150
152
  text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>")
151
153
  .text.strip)
152
- /\p{L}|\p{N}/.match(text) ?
153
- "<mo rspace='thickmathspace'>&#x2062;</mo>" : "<mo>&#x2062;</mo>"
154
+ if /\p{L}|\p{N}/.match?(text)
155
+ "<mo rspace='thickmathspace'>&#x2062;</mo>"
156
+ else "<mo>&#x2062;</mo>"
157
+ end
154
158
  end
155
159
 
156
160
  def dedup_ids(xml)
@@ -168,8 +172,8 @@ module Asciimath2UnitsML
168
172
  end
169
173
 
170
174
  def asciimath2mathml(expression)
171
- AsciiMath::MathMLBuilder.new(:msword => true).append_expression(
172
- AsciiMath.parse(HTMLEntities.new.decode(expression)).ast
175
+ AsciiMath::MathMLBuilder.new(msword: true).append_expression(
176
+ AsciiMath.parse(HTMLEntities.new.decode(expression)).ast,
173
177
  ).to_s.gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
174
178
  end
175
179
 
@@ -183,7 +187,7 @@ module Asciimath2UnitsML
183
187
  def ambig_units
184
188
  u = @units_id.each_with_object({}) do |(_k, v), m|
185
189
  v.symbolids.each do |x|
186
- next if %r{[*/^]}.match(x)
190
+ next if %r{[*/^]}.match?(x)
187
191
  next unless v.symbols_hash[x][:html] != x
188
192
 
189
193
  m[v.symbols_hash[x][:html]] ||= []
@@ -199,8 +203,10 @@ module Asciimath2UnitsML
199
203
  u.each { |_, v| maxcols = v.size if maxcols < v.size }
200
204
  puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{'| ' * (maxcols - 1)}\n)
201
205
  puts "\n\n"
202
- u.keys.sort_by { |a| [-u[a].size, a.gsub(%r{\&[^;]+;}, "")
203
- .gsub(/[^A-Za-z]/, "").downcase] }.each do |k|
206
+ u.keys.sort_by do |a|
207
+ [-u[a].size, a.gsub(%r{&[^;]+;}, "")
208
+ .gsub(/[^A-Za-z]/, "").downcase]
209
+ end.each do |k|
204
210
  print "| #{html2adoc(k)} "
205
211
  u[k].sort_by(&:size).each { |v1| print "| #{@units[v1].name}: `#{v1}` " }
206
212
  puts "#{'| ' * (maxcols - u[k].size)}\n"