asciimath2unitsml 0.3.0 → 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: dfcf63b9b9f9f447f63f744608bb19423025756a5f174a123acb5fbecb2143a4
4
- data.tar.gz: a45ba18eb0b8090ba886453bedf91ed18f531afc31061a90e9f33a6bc6e0085b
3
+ metadata.gz: b4d619489e5063d9e3616163d69c6c1f4796615412ee40f0a92f356603f0e366
4
+ data.tar.gz: 0465ac8a99f8929d1d4f8f2db152821e4d1fae7ac66af1a8a3e2feb6092e0c3a
5
5
  SHA512:
6
- metadata.gz: 61c26594d8ab5b4ab07439085ce23de798b8f4e38c0272790a60d64a247f10a19778e4d0cbdb37b9a3a79d6994a6a14ebf97c0dd031551366019ebe2905c5612
7
- data.tar.gz: e60ff3e91ff37a31ac3d5ac0beccb30c5f05c9c9590e1cc0dd01915ff1c9b57520af1d11b14c1b718173d7258a41b318f67db4a509ccd3ed3b4af43501b50d87
6
+ metadata.gz: 3de256a40d7eb24439409664a8b7bb14f1893403a4cfc762b70bd9693a15c0304766a7d20491de4094571fd5b117695350a5ad56100cf67bde1e7c61c4e99004
7
+ data.tar.gz: 4f053e85ff192f040856d0f63ff2d1ffb7a49eb72735f668785a3396e82ff145b8d678d754b8a26b26deee4c3072de4f8af8686f7ee60cb9e339dfe3f7be08c3
@@ -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' ]
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/.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 CHANGED
@@ -1,14 +1,10 @@
1
- # This project follows the Ribose OSS style guide.
2
- # https://github.com/riboseinc/oss-guides
3
- # All project-specific additions and overrides should be specified in this file.
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
4
3
  inherit_from:
5
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
6
5
 
7
6
  # local repo-specific modifications
7
+ # ...
8
8
 
9
9
  AllCops:
10
- DisplayCopNames: false
11
- StyleGuideCopsOnly: false
12
- TargetRubyVersion: 2.4
13
- Rails:
14
- Enabled: true
10
+ TargetRubyVersion: 2.5
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
@@ -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>"\
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
 
@@ -22,32 +22,30 @@ 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$'`
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
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
-
@@ -3,10 +3,13 @@ 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"
9
11
  require_relative "unit"
12
+ require_relative "validate"
10
13
 
11
14
  module Asciimath2UnitsML
12
15
  MATHML_NS = "http://www.w3.org/1998/Math/MathML".freeze
@@ -14,120 +17,86 @@ module Asciimath2UnitsML
14
17
 
15
18
  class Conv
16
19
  def initialize(options = {})
17
- @dimensions_id = read_yaml("../unitsdb/dimensions.yaml").
18
- each_with_object({}) do |(k, v), m|
20
+ @dimensions_id = read_yaml("../unitsdb/dimensions.yaml")
21
+ .each_with_object({}) do |(k, v), m|
19
22
  m[k.to_s] = UnitsDB::Dimension.new(k, v)
20
23
  end
21
- @prefixes_id = read_yaml("../unitsdb/prefixes.yaml").
22
- each_with_object({}) do |(k, v), m|
24
+ @dimensions = flip_name_and_symbols(@dimensions_id)
25
+ @prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
26
+ .each_with_object({}) do |(k, v), m|
23
27
  m[k] = UnitsDB::Prefix.new(k, v)
24
28
  end
25
29
  @prefixes = flip_name_and_symbol(@prefixes_id)
26
- @quantities = read_yaml("../unitsdb/quantities.yaml").
27
- each_with_object({}) do |(k, v), m|
30
+ @quantities = read_yaml("../unitsdb/quantities.yaml")
31
+ .each_with_object({}) do |(k, v), m|
28
32
  m[k.to_s] = UnitsDB::Quantity.new(k, v)
29
33
  end
30
- @units_id = read_yaml("../unitsdb/units.yaml").
31
- each_with_object({}) do |(k, v), m|
34
+ @units_id = read_yaml("../unitsdb/units.yaml")
35
+ .each_with_object({}) do |(k, v), m|
32
36
  m[k.to_s] = UnitsDB::Unit.new(k.to_s, v)
33
37
  end
34
38
  @units = flip_name_and_symbols(@units_id)
35
- @symbols = @units.each_with_object({}) do |(k, v), m|
39
+ @symbols = @units.merge(@dimensions).each_with_object({}) do |(_k, v), m|
36
40
  v.symbolids.each { |x| m[x] = v.symbols_hash[x] }
37
41
  end
38
- @parser = parser
39
- @multiplier = multiplier(options[:multiplier] || "\u00b7")
42
+ @parser, @dim_parser = parsers
43
+ @multiplier = multiplier(options[:multiplier] || "\u22c5")
40
44
  end
41
45
 
42
- def float_to_display(f)
43
- ret = f.to_f.round(1).to_s.sub(/\.0$/, "")
46
+ def float_to_display(float)
47
+ float.to_f.round(1).to_s.sub(/\.0$/, "")
44
48
  end
45
49
 
46
50
  def prefix(units)
47
- units.map { |u| u[:prefix] }.reject { |u| u.nil? }.uniq.map do |p|
48
- <<~END
49
- <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
50
- prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
51
- <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
52
- <PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol>
53
- <PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol>
54
- <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
55
- <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
56
- </Prefix>
57
- END
51
+ units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p|
52
+ <<~XML
53
+ <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
54
+ prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
55
+ <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
56
+ <PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol>
57
+ <PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol>
58
+ <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
59
+ <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
60
+ </Prefix>
61
+ XML
58
62
  end.join("\n")
59
63
  end
60
64
 
61
- def dimension_components(dims)
62
- return if dims.nil? || dims.empty?
63
- <<~END
64
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
65
- #{dims.map { |u| dimension1(u) }.join("\n") }
66
- </Dimension>
67
- END
68
- end
69
-
70
- U2D = {
71
- "m" => { dimension: "Length", order: 1, symbol: "L" },
72
- "g" => { dimension: "Mass", order: 2, symbol: "M" },
73
- "kg" => { dimension: "Mass", order: 2, symbol: "M" },
74
- "s" => { dimension: "Time", order: 3, symbol: "T" },
75
- "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
76
- "K" => { dimension: "ThermodynamicTemperature", order: 5,
77
- symbol: "Theta" },
78
- "degK" => { dimension: "ThermodynamicTemperature", order: 5,
79
- symbol: "Theta" },
80
- "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
81
- "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
82
- "deg" => { dimension: "PlaneAngle", order: 8, symbol: "Phi" },
83
- }.freeze
84
-
85
- def units2dimensions(units)
86
- norm = decompose_units(units)
87
- return if norm.any? do |u|
88
- u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
89
- end
90
- norm.map do |u|
91
- { dimension: U2D[u[:unit]][:dimension],
92
- unit: u[:unit],
93
- exponent: u[:exponent] || 1,
94
- symbol: U2D[u[:unit]][:symbol] }
95
- end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
96
- end
97
-
98
- def dimension1(u)
99
- %(<#{u[:dimension]} symbol="#{u[:symbol]}"
100
- powerNumerator="#{float_to_display(u[:exponent])}"/>)
101
- end
102
-
103
- def dim_id(dims)
104
- return nil if dims.nil? || dims.empty?
105
- dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
106
- dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
107
- AmountOfSubstance LuminousIntensity PlaneAngle)
108
- .map { |h| dimhash.dig(h, :exponent) }.join(":")
109
- id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }&.
110
- first&.id and return id.to_s
111
- "D_" + dims.map do |d|
112
- U2D[d[:unit]][:symbol] +
113
- (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
114
- end.join("")
115
- end
116
-
117
65
  def decompose_units(units)
118
66
  gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
119
67
  end
120
68
 
121
69
  def gather_units(units)
122
- units.sort { |a, b| a[:unit] <=> b[:unit] }.each_with_object([]) do |k, m|
70
+ if units[0][:dim] then gather_dimensions(units)
71
+ else gather_units1(units)
72
+ end
73
+ end
74
+
75
+ def gather_units1(units)
76
+ units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m|
123
77
  if m.empty? || m[-1][:unit] != k[:unit] then m << k
124
78
  else
125
79
  m[-1] = {
126
80
  prefix: combine_prefixes(
127
- @prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]),
81
+ @prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]
82
+ ),
128
83
  unit: m[-1][:unit],
129
84
  exponent: (k[:exponent]&.to_f || 1) +
130
- (m[-1][:exponent]&.to_f || 1) }
85
+ (m[-1][:exponent]&.to_f || 1),
86
+ }
87
+ end
88
+ end
89
+ end
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
+ }
131
100
  end
132
101
  end
133
102
  end
@@ -135,16 +104,18 @@ module Asciimath2UnitsML
135
104
  # treat g not kg as base unit: we have stripped the prefix k in parsing
136
105
  # reduce units down to basic units
137
106
  def decompose_unit(u)
138
- if u[:unit].nil? then u
139
- elsif u[:unit] == "g" then u
140
- 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
141
109
  elsif !@units[u[:unit]].si_derived_bases
142
110
  { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
143
111
  else
144
112
  @units[u[:unit]].si_derived_bases.each_with_object([]) do |k, m|
145
- prefix = !k[:prefix].nil? && !k[:prefix].empty? ?
146
- combine_prefixes(@prefixes_id[k[:prefix]], @prefixes[u[:prefix]]) :
147
- u[:prefix]
113
+ prefix = if !k[:prefix].nil? && !k[:prefix].empty?
114
+ combine_prefixes(@prefixes_id[k[:prefix]],
115
+ @prefixes[u[:prefix]])
116
+ else
117
+ u[:prefix]
118
+ end
148
119
  m << { prefix: prefix,
149
120
  unit: @units_id[k[:id]].symbolid,
150
121
  exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_f || 1) }
@@ -157,6 +128,7 @@ module Asciimath2UnitsML
157
128
  return p1.symbolid if p2.nil?
158
129
  return p2.symbolid if p1.nil?
159
130
  return "unknown" if p1.base != p2.base
131
+
160
132
  @prefixes.each do |_, p|
161
133
  return p.symbolid if p.base == p1.base && p.power == p1.power + p2.power
162
134
  end
@@ -174,43 +146,26 @@ module Asciimath2UnitsML
174
146
  def quantity(normtext, quantity)
175
147
  return unless @units[normtext] && @units[normtext].quantities.size == 1 ||
176
148
  @quantities[quantity]
149
+
177
150
  id = quantity || @units[normtext].quantities.first
178
151
  @units[normtext]&.dimension and
179
152
  dim = %( dimensionURL="##{@units[normtext].dimension}")
180
- <<~END
181
- <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
182
- #{quantityname(id)}
183
- </Quantity>
184
- END
185
- end
186
-
187
- def dimid2dimensions(normtext)
188
- @dimensions_id[normtext].keys.map do |k|
189
- { dimension: k,
190
- symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
191
- exponent: @dimensions_id[normtext].exponent(k) }
192
- end
193
- end
194
-
195
- def dimension(normtext)
196
- return unless @units[normtext]&.dimension
197
- dims = dimid2dimensions(@units[normtext]&.dimension)
198
- <<~END
199
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
200
- #{dims.map { |u| dimension1(u) }.join("\n") }
201
- </Dimension>
202
- END
153
+ <<~XML
154
+ <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
155
+ #{quantityname(id)}
156
+ </Quantity>
157
+ XML
203
158
  end
204
159
 
205
160
  def unitsml(units, origtext, normtext, quantity, name)
206
161
  dims = units2dimensions(units)
207
- <<~END
208
- #{unit(units, origtext, normtext, dims, name)}
209
- #{prefix(units)}
210
- #{dimension(normtext)}
211
- #{dimension_components(dims)}
212
- #{quantity(normtext, quantity)}
213
- END
162
+ <<~XML
163
+ #{unit(units, origtext, normtext, dims, name)}
164
+ #{prefix(units)}
165
+ #{dimension(normtext)}
166
+ #{dimension_components(dims)}
167
+ #{quantity(normtext, quantity)}
168
+ XML
214
169
  end
215
170
  end
216
171
  end