asciimath2unitsml 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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"