asciimath2unitsml 0.2.4 → 0.3.3

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: a2279898112af9b3602b0f7ed1a713adc4130015a3f616767d364952fb87b8ff
4
- data.tar.gz: 2bf900fe40159a836fed5bbbcdc7f76c7911083242e12962949b269fafe2e92d
3
+ metadata.gz: 829d573c90a88f5d26b2310d69f5ea575084df208cd3f441342435b0a6a3d353
4
+ data.tar.gz: 534c2ea7485b1de1c126de112a1ad8c9b10683797034e99313fda199c5f7e572
5
5
  SHA512:
6
- metadata.gz: 8d3c8c4ca3db1208f5764ddd0cf2ab221548dceb3ac99d69a14778bd05dc4aec07a54064ae408908aacf27f5dbdd456fbca6eb42f29cc626527d518f03ae831f
7
- data.tar.gz: 3b1d4a11f5db9225b20802ab261ba67099f977a66af680a1aaa19ffe2fdb6f6bbf78f0088f5473fe7b1e23083a72a32f9e130a9fe71abe240f9f306610bdef64
6
+ metadata.gz: c6eec2cb24fff7931d236a9a14a6d4ae1a938fe348d1e1d02a4d2f9be8e7f72e124e633ef0ef4b0f1e476ee8a2dee900210e60010600e0b082eb95237d2c70d2
7
+ data.tar.gz: e6943596be90a3bd1e6336b7bfa395cee4aa41e88ab6e5b2d003216a2271fc72249a018218d65c4ef446f4d246412e2b9fa0ac0d9721095abd4d9baa95515389
@@ -16,21 +16,11 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '3.0', '2.7', '2.6', '2.5', '2.4' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
- include:
23
- - ruby: '3.0'
24
- os: 'ubuntu-latest'
25
- experimental: true
26
- - ruby: '3.0'
27
- os: 'windows-latest'
28
- experimental: true
29
- - ruby: '3.0'
30
- os: 'macos-latest'
31
- experimental: true
32
22
  steps:
33
- - uses: actions/checkout@master
23
+ - uses: actions/checkout@v2
34
24
  with:
35
25
  submodules: true
36
26
 
@@ -40,14 +30,3 @@ jobs:
40
30
  bundler-cache: true
41
31
 
42
32
  - run: bundle exec rake
43
-
44
- tests-passed:
45
- needs: rake
46
- runs-on: ubuntu-latest
47
- steps:
48
- - uses: peter-evans/repository-dispatch@v1
49
- with:
50
- token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
51
- repository: ${{ github.repository }}
52
- event-type: notify
53
- client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .rubocop-https--*
data/.hound.yml ADDED
@@ -0,0 +1,5 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ ruby:
4
+ enabled: true
5
+ config_file: .rubocop.yml
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ inherit_from:
4
+ - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
5
+
6
+ # local repo-specific modifications
7
+ # ...
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.4
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "https://rubygems.org"
2
-
2
+
3
3
  # Specify your gem's dependencies in ruby-vobject.gemspec
4
4
  gemspec
data/README.adoc CHANGED
@@ -53,6 +53,8 @@ from UnitsDB. For example, `unitsml(cal_th/cm^2, name: langley)`.
53
53
  The unit-string gives the canonical representation of the unit, but SYMBOL is what will be rendered.
54
54
  For example, `unitsml(cal_th/cm^2, name: langley, symbol: La)`, or `unitsml(mm*s^-2, symbol: mm cdot s^-2)`.
55
55
  (All variables in SYMBOL are rendered upright, as is the default for units.)
56
+ * `unitsml(unit-string, multiplier: SYMBOL)` provides an alternate symbol for the multiliper of
57
+ units. The options are an XML entity, or the values `space` or `nospace` (for which see discussion under _Usage_).
56
58
 
57
59
  Standalone prefixes can be recognised by replacing the unit with hyphen; so `unitsml(p-)` corresponds
58
60
  to the standalone prefix "pico" (and is rendered as "p").
@@ -230,7 +232,7 @@ This table can be generated (in Asciidoc format) through `Asciimath2UnitsML::Con
230
232
  | ton | ton of TNT (energy equivalent): `ton_TNT` | ton of refrigeration (12 000 Btu_IT/h): `ton_refrigeration` | | | |
231
233
  | tsp | teaspoon: `tsp` | teaspoon (FDA): `tsp_label` | | | |
232
234
  | yd | yard: `yd` | yard (based on US survey foot): `yd_US_survey` | | | |
233
- | º | degree (degree of arc): `deg` | | | | |
235
+ | ° | degree (degree of arc): `deg` | | | | |
234
236
  | γ | gamma: `gamma` | | | | |
235
237
  | μ | micron: `micron` | | | | |
236
238
  | Ω | ohm: `Ohm` | | | | |
@@ -258,3 +260,4 @@ This table can be generated (in Asciidoc format) through `Asciimath2UnitsML::Con
258
260
  | °R | degree Rankine: `degR` | | | | |
259
261
  | ƛ~C~ | natural unit of length: `lambda-bar_C` | | | | |
260
262
  |===
263
+
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "asciimath2unitsml/version"
6
6
 
@@ -29,25 +29,23 @@ Gem::Specification.new do |spec|
29
29
  .split("\n")
30
30
  .map { |kv_str| kv_str.split(" ") }
31
31
  .each do |(_, submodule_path)|
32
+ # for each submodule, change working directory to that submodule
33
+ Dir.chdir(submodule_path) do
34
+ # issue git ls-files in submodule's directory
35
+ submodule_files = `git ls-files | grep -i '.yaml$'`.split($\)
32
36
 
33
- # for each submodule, change working directory to that submodule
34
- Dir.chdir(submodule_path) do
35
-
36
- # issue git ls-files in submodule's directory
37
- submodule_files = `git ls-files | grep -i '.yaml$'`.split($\)
38
-
39
- submodule_files_paths = submodule_files.map do |filename|
40
- File.join submodule_path, filename
41
- end
42
-
43
- # add relative paths to gem.files
44
- spec.files += submodule_files_paths
37
+ submodule_files_paths = submodule_files.map do |filename|
38
+ File.join submodule_path, filename
45
39
  end
40
+
41
+ # add relative paths to gem.files
42
+ spec.files += submodule_files_paths
43
+ end
46
44
  end
47
45
 
48
46
  spec.add_dependency "asciimath"
49
47
  spec.add_dependency "htmlentities"
50
- spec.add_dependency "nokogiri", "~> 1.10.4"
48
+ spec.add_dependency "nokogiri", "~> 1.11"
51
49
  spec.add_dependency "rsec", "~> 1.0.0"
52
50
 
53
51
  spec.add_development_dependency "bundler"
@@ -56,10 +54,9 @@ Gem::Specification.new do |spec|
56
54
  spec.add_development_dependency "guard", "~> 2.14"
57
55
  spec.add_development_dependency "guard-rspec", "~> 4.7"
58
56
  spec.add_development_dependency "rake", "~> 12.0"
57
+ spec.add_development_dependency "rexml"
59
58
  spec.add_development_dependency "rspec", "~> 3.6"
60
- spec.add_development_dependency "rubocop", "= 0.54.0"
59
+ spec.add_development_dependency "rubocop", "~> 1.5.2"
61
60
  spec.add_development_dependency "simplecov", "~> 0.15"
62
61
  spec.add_development_dependency "timecop", "~> 0.9"
63
- spec.add_development_dependency "rexml"
64
62
  end
65
-
data/bin/rspec CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
-
2
+
3
3
  # This file was generated by Bundler.
4
4
  #
5
5
  # The application 'rspec' is installed as part of a gem, and
@@ -15,4 +15,3 @@ require "rubygems"
15
15
  require "bundler/setup"
16
16
 
17
17
  load Gem.bin_path("rspec-core", "rspec")
18
-
@@ -1,4 +1,3 @@
1
1
  require_relative "asciimath2unitsml/version"
2
2
  require_relative "asciimath2unitsml/conv"
3
3
  require_relative "unitsdb_ruby/unitsdb"
4
-
@@ -7,70 +7,78 @@ require_relative "string"
7
7
  require_relative "parse"
8
8
  require_relative "render"
9
9
  require_relative "unit"
10
+ require_relative "validate"
10
11
 
11
12
  module Asciimath2UnitsML
12
13
  MATHML_NS = "http://www.w3.org/1998/Math/MathML".freeze
13
- UNITSML_NS = "http://unitsml.nist.gov/2005".freeze
14
+ UNITSML_NS = "https://schema.unitsml.org/unitsml/1.0".freeze
14
15
 
15
16
  class Conv
16
17
  def initialize(options = {})
17
- @dimensions_id = read_yaml("../unitsdb/dimensions.yaml").each_with_object({}) do |(k, v), m|
18
+ @dimensions_id = read_yaml("../unitsdb/dimensions.yaml")
19
+ .each_with_object({}) do |(k, v), m|
18
20
  m[k.to_s] = UnitsDB::Dimension.new(k, v)
19
21
  end
20
- @prefixes_id = read_yaml("../unitsdb/prefixes.yaml").each_with_object({}) do |(k, v), m|
22
+ @prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
23
+ .each_with_object({}) do |(k, v), m|
21
24
  m[k] = UnitsDB::Prefix.new(k, v)
22
25
  end
23
26
  @prefixes = flip_name_and_symbol(@prefixes_id)
24
- @quantities = read_yaml("../unitsdb/quantities.yaml").each_with_object({}) do |(k, v), m|
27
+ @quantities = read_yaml("../unitsdb/quantities.yaml")
28
+ .each_with_object({}) do |(k, v), m|
25
29
  m[k.to_s] = UnitsDB::Quantity.new(k, v)
26
30
  end
27
- @units_id = read_yaml("../unitsdb/units.yaml").each_with_object({}) do |(k, v), m|
31
+ @units_id = read_yaml("../unitsdb/units.yaml")
32
+ .each_with_object({}) do |(k, v), m|
28
33
  m[k.to_s] = UnitsDB::Unit.new(k.to_s, v)
29
34
  end
30
35
  @units = flip_name_and_symbols(@units_id)
31
- @symbols = @units.each_with_object({}) do |(k, v), m|
36
+ @symbols = @units.each_with_object({}) do |(_k, v), m|
32
37
  v.symbolids.each { |x| m[x] = v.symbols_hash[x] }
33
38
  end
34
39
  @parser = parser
35
- @multiplier = multiplier(options[:multiplier] || "\u00b7")
40
+ @multiplier = multiplier(options[:multiplier] || "\u22c5")
36
41
  end
37
42
 
38
- def float_to_display(f)
39
- ret = f.to_f.round(1).to_s.sub(/\.0$/, "")
43
+ def float_to_display(float)
44
+ float.to_f.round(1).to_s.sub(/\.0$/, "")
40
45
  end
41
46
 
42
47
  def prefix(units)
43
- units.map { |u| u[:prefix] }.reject { |u| u.nil? }.uniq.map do |p|
44
- <<~END
45
- <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
46
- prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
47
- <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
48
- <PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol>
49
- <PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol>
50
- <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
51
- <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
52
- </Prefix>
53
- END
48
+ units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p|
49
+ <<~XML
50
+ <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
51
+ prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
52
+ <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
53
+ <PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol>
54
+ <PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol>
55
+ <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
56
+ <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
57
+ </Prefix>
58
+ XML
54
59
  end.join("\n")
55
60
  end
56
61
 
57
62
  def dimension_components(dims)
58
63
  return if dims.nil? || dims.empty?
59
- <<~END
60
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
61
- #{dims.map { |u| dimension1(u) }.join("\n") }
62
- </Dimension>
63
- END
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
64
70
  end
65
71
 
66
- U2D = {
72
+ U2D = {
67
73
  "m" => { dimension: "Length", order: 1, symbol: "L" },
68
74
  "g" => { dimension: "Mass", order: 2, symbol: "M" },
69
75
  "kg" => { dimension: "Mass", order: 2, symbol: "M" },
70
76
  "s" => { dimension: "Time", order: 3, symbol: "T" },
71
77
  "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
72
- "K" => { dimension: "ThermodynamicTemperature", order: 5, symbol: "Theta" },
73
- "degK" => { dimension: "ThermodynamicTemperature", order: 5, symbol: "Theta" },
78
+ "K" => { dimension: "ThermodynamicTemperature", order: 5,
79
+ symbol: "Theta" },
80
+ "degK" => { dimension: "ThermodynamicTemperature", order: 5,
81
+ symbol: "Theta" },
74
82
  "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
75
83
  "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
76
84
  "deg" => { dimension: "PlaneAngle", order: 8, symbol: "Phi" },
@@ -78,28 +86,35 @@ module Asciimath2UnitsML
78
86
 
79
87
  def units2dimensions(units)
80
88
  norm = decompose_units(units)
81
- return if norm.any? { |u| u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil? }
89
+ return if norm.any? do |u|
90
+ u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
91
+ end
92
+
82
93
  norm.map do |u|
83
94
  { dimension: U2D[u[:unit]][:dimension],
84
95
  unit: u[:unit],
85
96
  exponent: u[:exponent] || 1,
86
- symbol: U2D[u[:unit]][:symbol] }
97
+ symbol: U2D[u[:unit]][:symbol] }
87
98
  end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
88
99
  end
89
100
 
90
- def dimension1(u)
91
- %(<#{u[:dimension]} symbol="#{u[:symbol]}" powerNumerator="#{float_to_display(u[:exponent])}"/>)
101
+ def dimension1(dim)
102
+ %(<#{dim[:dimension]} symbol="#{dim[:symbol]}"
103
+ powerNumerator="#{float_to_display(dim[:exponent])}"/>)
92
104
  end
93
105
 
94
106
  def dim_id(dims)
95
107
  return nil if dims.nil? || dims.empty?
108
+
96
109
  dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
97
- dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
110
+ dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
98
111
  AmountOfSubstance LuminousIntensity PlaneAngle)
99
112
  .map { |h| dimhash.dig(h, :exponent) }.join(":")
100
- id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }&.first&.id and return id.to_s
113
+ id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
114
+ &.first&.id and return id.to_s
101
115
  "D_" + dims.map do |d|
102
- U2D[d[:unit]][:symbol] + (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
116
+ U2D[d[:unit]][:symbol] +
117
+ (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
103
118
  end.join("")
104
119
  end
105
120
 
@@ -108,12 +123,17 @@ module Asciimath2UnitsML
108
123
  end
109
124
 
110
125
  def gather_units(units)
111
- units.sort { |a, b| a[:unit] <=> b[:unit] }.each_with_object([]) do |k, m|
126
+ units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m|
112
127
  if m.empty? || m[-1][:unit] != k[:unit] then m << k
113
128
  else
114
- m[-1] = { prefix: combine_prefixes(@prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]),
115
- unit: m[-1][:unit],
116
- exponent: (k[:exponent]&.to_f || 1) + (m[-1][:exponent]&.to_f || 1) }
129
+ m[-1] = {
130
+ prefix: combine_prefixes(
131
+ @prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]
132
+ ),
133
+ unit: m[-1][:unit],
134
+ exponent: (k[:exponent]&.to_f || 1) +
135
+ (m[-1][:exponent]&.to_f || 1),
136
+ }
117
137
  end
118
138
  end
119
139
  end
@@ -128,8 +148,13 @@ module Asciimath2UnitsML
128
148
  { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
129
149
  else
130
150
  @units[u[:unit]].si_derived_bases.each_with_object([]) do |k, m|
131
- m << { prefix: !k[:prefix].nil? && !k[:prefix].empty? ?
132
- combine_prefixes(@prefixes_id[k[:prefix]], @prefixes[u[:prefix]]) : u[:prefix],
151
+ prefix = if !k[:prefix].nil? && !k[:prefix].empty?
152
+ combine_prefixes(@prefixes_id[k[:prefix]],
153
+ @prefixes[u[:prefix]])
154
+ else
155
+ u[:prefix]
156
+ end
157
+ m << { prefix: prefix,
133
158
  unit: @units_id[k[:id]].symbolid,
134
159
  exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_f || 1) }
135
160
  end
@@ -141,6 +166,7 @@ module Asciimath2UnitsML
141
166
  return p1.symbolid if p2.nil?
142
167
  return p2.symbolid if p1.nil?
143
168
  return "unknown" if p1.base != p2.base
169
+
144
170
  @prefixes.each do |_, p|
145
171
  return p.symbolid if p.base == p1.base && p.power == p1.power + p2.power
146
172
  end
@@ -156,14 +182,17 @@ module Asciimath2UnitsML
156
182
  end
157
183
 
158
184
  def quantity(normtext, quantity)
159
- return unless @units[normtext] && @units[normtext].quantities.size == 1 || @quantities[quantity]
185
+ return unless @units[normtext] && @units[normtext].quantities.size == 1 ||
186
+ @quantities[quantity]
187
+
160
188
  id = quantity || @units[normtext].quantities.first
161
- dim = %( dimensionURL="##{@units[normtext].dimension}") if @units[normtext]&.dimension
162
- <<~END
163
- <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
164
- #{quantityname(id)}
165
- </Quantity>
166
- END
189
+ @units[normtext]&.dimension and
190
+ dim = %( dimensionURL="##{@units[normtext].dimension}")
191
+ <<~XML
192
+ <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
193
+ #{quantityname(id)}
194
+ </Quantity>
195
+ XML
167
196
  end
168
197
 
169
198
  def dimid2dimensions(normtext)
@@ -175,24 +204,25 @@ module Asciimath2UnitsML
175
204
  end
176
205
 
177
206
  def dimension(normtext)
178
- return unless @units[normtext]&.dimension
207
+ return unless @units[normtext]&.dimension
208
+
179
209
  dims = dimid2dimensions(@units[normtext]&.dimension)
180
- <<~END
181
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
182
- #{dims.map { |u| dimension1(u) }.join("\n") }
183
- </Dimension>
184
- END
210
+ <<~XML
211
+ <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
212
+ #{dims.map { |u| dimension1(u) }.join("\n")}
213
+ </Dimension>
214
+ XML
185
215
  end
186
216
 
187
217
  def unitsml(units, origtext, normtext, quantity, name)
188
218
  dims = units2dimensions(units)
189
- <<~END
190
- #{unit(units, origtext, normtext, dims, name)}
191
- #{prefix(units)}
192
- #{dimension(normtext)}
193
- #{dimension_components(dims)}
194
- #{quantity(normtext, quantity)}
195
- END
219
+ <<~XML
220
+ #{unit(units, origtext, normtext, dims, name)}
221
+ #{prefix(units)}
222
+ #{dimension(normtext)}
223
+ #{dimension_components(dims)}
224
+ #{quantity(normtext, quantity)}
225
+ XML
196
226
  end
197
227
  end
198
228
  end
@@ -3,71 +3,29 @@ module Asciimath2UnitsML
3
3
  include Rsec::Helpers
4
4
 
5
5
  def read_yaml(path)
6
- validate_yaml(symbolize_keys(YAML.load_file(File.join(File.join(File.dirname(__FILE__), path)))), path)
6
+ validate_yaml(symbolize_keys(YAML
7
+ .load_file(File.join(File.join(File.dirname(__FILE__), path)))), path)
7
8
  end
8
9
 
9
10
  def flip_name_and_symbol(hash)
10
- hash.each_with_object({}) do |(k, v), m|
11
+ hash.each_with_object({}) do |(_k, v), m|
11
12
  next if v.name.nil? || v.name.empty?
13
+
12
14
  m[v.symbolid] = v
13
15
  end
14
16
  end
15
17
 
16
18
  def flip_name_and_symbols(hash)
17
- hash.each_with_object({}) do |(k, v), m|
19
+ hash.each_with_object({}) do |(_k, v), m|
18
20
  next if v.name.nil? || v.name.empty?
19
- v.symbolids.each { |s| m[s] = v }
20
- end
21
- end
22
-
23
- def validate_yaml(hash, path)
24
- return hash if path == "../unitsdb/quantities.yaml"
25
- return hash if path == "../unitsdb/dimensions.yaml"
26
- hash.each_with_object({}) do |(k, v), m|
27
- path == "../unitsdb/units.yaml" and validate_unit(v)
28
- m = validate_symbols(m, v)
29
- v[:unit_symbols]&.each { |s| validate_unit_symbol_cardinality(s, k) }
30
- end
31
- hash
32
- end
33
-
34
- def validate_unit(v)
35
- if v[:quantity_reference]
36
- v[:quantity_reference].is_a?(Array) or
37
- raise StandardError.new "No quantity_reference array provided for unit: #{v}"
38
- end
39
- if v[:unit_name]
40
- v[:unit_name].is_a?(Array) or raise StandardError.new "No unit_name array provided for unit: #{v}"
41
- end
42
- end
43
21
 
44
- def validate_symbols(m, v)
45
- symbol = symbol_key(v)
46
- !symbol.nil? or raise StandardError.new "No symbol provided for unit: #{v}"
47
- Array(symbol)&.each do |s|
48
- m[s] && s != "1" and
49
- raise StandardError.new "symbol #{s} is not unique in #{v}: already used for #{m[s]}"
50
- m[s] = v
22
+ v.symbolids.each { |s| m[s] = v }
51
23
  end
52
- m
53
- end
54
-
55
- def validate_unit_symbol_cardinality(us, k)
56
- return true if us.nil?
57
- !us[:id].nil? && !us[:ascii].nil? && !us[:html].nil? && !us[:mathml].nil? && !us[:latex].nil? &&
58
- !us[:unicode].nil? and return true
59
- raise StandardError.new "malformed unit_symbol for #{k}: #{us}"
60
- end
61
-
62
- def symbol_key(v)
63
- symbol = v[:unit_symbols]&.each_with_object([]) { |s, m| m << (s["id"] || s[:id]) } ||
64
- v.dig(:symbol, :ascii) || v[:symbol] #|| v[:short]
65
- symbol = [symbol] if !symbol.nil? && v[:unit_symbols] && !symbol.is_a?(Array)
66
- symbol
67
24
  end
68
25
 
69
26
  def symbolize_keys(hash)
70
27
  return hash if hash.is_a? String
28
+
71
29
  hash.inject({}) do |result, (key, value)|
72
30
  new_key = case key
73
31
  when String then key.to_sym
@@ -97,46 +55,58 @@ module Asciimath2UnitsML
97
55
  seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } |
98
56
  seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
99
57
  seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
100
- seq(unit1, exponent._? & multiplier) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0] )} } |
101
- seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0] )} } |
102
- seq(prefix1, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0] ) } } |
103
- seq(prefix2, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0] ) } } |
104
- "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
58
+ seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
59
+ 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]) } } |
62
+ "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
63
+ units1 = "(".r >> lazy{units} << ")" | unit
105
64
  units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
106
65
  seq(prefix1, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
107
- unit.join(multiplier)
66
+ units1.join(multiplier)
108
67
  parser = units.eof
109
68
  end
110
69
 
111
- def parse(x)
112
- text = Array(x.split(/,\s*/))
70
+ def parse(expr)
71
+ text = Array(expr.split(/,\s*/))
113
72
  units = @parser.parse!(text[0])
114
73
  if !units || Rsec::INVALID[units]
115
74
  raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
116
75
  end
76
+
117
77
  Rsec::Fail.reset
118
78
  postprocess(units, text)
119
79
  end
120
80
 
121
81
  def postprocess(units, text)
122
- units = postprocess1(units)
123
- quantity = text[1..-1]&.select { |x| /^quantity:/.match(x) }&.first&.sub(/^quantity:\s*/, "")
124
- name = text[1..-1]&.select { |x| /^name:/.match(x) }&.first&.sub(/^name:\s*/, "")
125
- symbol = text[1..-1]&.select { |x| /^symbol:/.match(x) }&.first&.sub(/^symbol:\s*/, "")
82
+ 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*/, "")
126
95
  normtext = units_only(units).each.map do |u|
127
96
  exp = u[:exponent] && u[:exponent] != "1" ? "^#{u[:exponent]}" : ""
128
97
  "#{u[:prefix]}#{u[:unit]}#{exp}"
129
98
  end.join("*")
130
- [units, text[0], normtext, quantity, name, symbol]
99
+ [units, text[0], normtext, quantity, name, symbol, multiplier]
131
100
  end
132
101
 
133
102
  def postprocess1(units)
134
103
  inverse = false
135
- units.each_with_object([]) do |u, m|
104
+ units.each_with_object([]) do |u, m|
136
105
  if u[:multiplier]
137
- inverse = (u[:multiplier] == "/")
106
+ inverse = !inverse if u[:multiplier] == "/"
138
107
  else
139
- u[:exponent] = inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent]
108
+ u[:exponent] =
109
+ inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent]
140
110
  u[:exponent] = u[:exponent]&.sub(/^--+/, "")
141
111
  end
142
112
  m << u
@@ -148,32 +118,48 @@ module Asciimath2UnitsML
148
118
  MathML2UnitsML(xml).to_xml
149
119
  end
150
120
 
151
- # https://www.w3.org/TR/mathml-units/ section 2: delimit number Invisible-Times unit
121
+ # https://www.w3.org/TR/mathml-units/ section 2:
122
+ # delimit number Invisible-Times unit
152
123
  def MathML2UnitsML(xml)
153
124
  xml.is_a? String and xml = Nokogiri::XML(xml)
154
125
  xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x|
155
- next unless %r{^unitsml\(.+\)$}.match(x.text)
126
+ next unless %r{^unitsml\(.+\)$}.match?(x.text)
127
+
156
128
  text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
157
- units, origtext, normtext, quantity, name, symbol = parse(text)
158
- rendering = symbol ? embeddedmathml(asciimath2mathml(symbol)) : mathmlsymbol(units, false)
159
- x.replace("#{delimspace(rendering, x)}<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
129
+ units, origtext, normtext, quantity, name, symbol, multiplier =
130
+ parse(text)
131
+ rendering = symbol ? embeddedmathml(asciimath2mathml(symbol)) :
132
+ mathmlsymbol(units, false, multiplier)
133
+ x.replace("#{delimspace(rendering, x)}"\
134
+ "<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
160
135
  "#{unitsml(units, origtext, normtext, quantity, name)}")
161
136
  end
162
137
  dedup_ids(xml)
163
138
  end
164
139
 
140
+ # if previous sibling's last descendent non-whitespace is MathML and
141
+ # mn or mi, no space
165
142
  def delimspace(rendering, elem)
166
- return "" if elem&.previous_element && elem&.previous_element.name != "mn"
167
- text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>").text.strip)
143
+ prec_text_elem =
144
+ elem.xpath("./preceding-sibling::*[namespace-uri() = '#{MATHML_NS}']/"\
145
+ "descendant::text()[normalize-space()!='']"\
146
+ "[last()]/parent::*").last
147
+ return "" if prec_text_elem.nil? ||
148
+ !%w(mn mi).include?(prec_text_elem&.name)
149
+
150
+ text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>")
151
+ .text.strip)
168
152
  /\p{L}|\p{N}/.match(text) ?
169
153
  "<mo rspace='thickmathspace'>&#x2062;</mo>" : "<mo>&#x2062;</mo>"
170
154
  end
171
155
 
172
156
  def dedup_ids(xml)
173
157
  %w(Unit Dimension Prefix Quantity).each do |t|
174
- xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map { |a| a.text }.uniq.each do |v|
158
+ xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map(&:text)
159
+ .uniq.each do |v|
175
160
  xml.xpath(".//*[@xml:id = '#{v}']").each_with_index do |n, i|
176
- next if i == 0
161
+ next if i.zero?
162
+
177
163
  n.remove
178
164
  end
179
165
  end
@@ -183,44 +169,47 @@ module Asciimath2UnitsML
183
169
 
184
170
  def asciimath2mathml(expression)
185
171
  AsciiMath::MathMLBuilder.new(:msword => true).append_expression(
186
- AsciiMath.parse(HTMLEntities.new.decode(expression)).ast).to_s.
187
- gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
172
+ AsciiMath.parse(HTMLEntities.new.decode(expression)).ast
173
+ ).to_s.gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
188
174
  end
189
175
 
190
176
  def embeddedmathml(mathml)
191
177
  x = Nokogiri::XML(mathml)
192
- x.xpath(".//m:mi", "m" => MATHML_NS).each { |mi| mi["mathvariant"] = "normal" }
178
+ x.xpath(".//m:mi", "m" => MATHML_NS)
179
+ .each { |mi| mi["mathvariant"] = "normal" }
193
180
  x.children.to_xml
194
181
  end
195
182
 
196
183
  def ambig_units
197
- u = @units_id.each_with_object({}) do |(k, v), m|
184
+ u = @units_id.each_with_object({}) do |(_k, v), m|
198
185
  v.symbolids.each do |x|
199
186
  next if %r{[*/^]}.match(x)
200
187
  next unless v.symbols_hash[x][:html] != x
188
+
201
189
  m[v.symbols_hash[x][:html]] ||= []
202
190
  m[v.symbols_hash[x][:html]] << x
203
191
  end
204
192
  end
205
- u.keys.each { |k| u[k] = u[k].unshift(k) if @symbols.dig(k, :html) == k }
193
+ u.each_key { |k| u[k] = u[k].unshift(k) if @symbols.dig(k, :html) == k }
206
194
  render_ambig_units(u)
207
195
  end
208
196
 
209
197
  def render_ambig_units(u)
210
198
  maxcols = 0
211
199
  u.each { |_, v| maxcols = v.size if maxcols < v.size }
212
- puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{"| " * (maxcols - 1)}\n)
200
+ puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{'| ' * (maxcols - 1)}\n)
213
201
  puts "\n\n"
214
- u.keys.sort_by { |a| [-u[a].size, a.gsub(%r{\&[^;]+;}, "").gsub(/[^A-Za-z]/, "").downcase] }.each do |k|
202
+ u.keys.sort_by { |a| [-u[a].size, a.gsub(%r{\&[^;]+;}, "")
203
+ .gsub(/[^A-Za-z]/, "").downcase] }.each do |k|
215
204
  print "| #{html2adoc(k)} "
216
- u[k].sort_by { |v1| v1.size }.each { |v1| print "| #{@units[v1].name}: `#{v1}` " }
217
- puts "#{"| " * (maxcols - u[k].size) }\n"
205
+ u[k].sort_by(&:size).each { |v1| print "| #{@units[v1].name}: `#{v1}` " }
206
+ puts "#{'| ' * (maxcols - u[k].size)}\n"
218
207
  end
219
208
  puts "|===\n"
220
209
  end
221
210
 
222
- def html2adoc(k)
223
- k.gsub(%r{<i>}, "__").gsub(%r{</i>}, "__")
211
+ def html2adoc(elem)
212
+ elem.gsub(%r{<i>}, "__").gsub(%r{</i>}, "__")
224
213
  .gsub(%r{<sup>}, "^").gsub(%r{</sup>}, "^")
225
214
  .gsub(%r{<sub>}, "~").gsub(%r{</sub>}, "~")
226
215
  end