asciimath2unitsml 0.3.2 → 0.4.2

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: f51b82e234fddaf66252f77a276a3acf68dae4356502a3c900253f5d4d4dffcf
4
- data.tar.gz: 59dd18f009952329c1c07af2132ec06123c06dd3caea4ee7f22f17c0f4ec1cbc
3
+ metadata.gz: 25adab652658a50b2747ff9087cffa7c1c2fa864a701b253e393359ad3091ff0
4
+ data.tar.gz: 20d02312fcef3908ef823a59d18c45e6e03bc0c9d7c33b221c680048add583ca
5
5
  SHA512:
6
- metadata.gz: 9a925e3db85d3086d676c07c101609e87674d620394f5fa0a536ab3652f3aa9c0cc6a74507d79264e0154bf51ea4121d47b7275a94212bc934b822b0392a9970
7
- data.tar.gz: 59d98ebd629a20e8f03dc32a1870474e5808b9d38f51a87feec5eae9f0746535bed9dcf38b1faf3939319bb3989b1d926088e8d834388e48f045070e3749312a
6
+ metadata.gz: f82a936470d1e3ade5b48da9ea7a14825e7e0c82aaf14082b6c5dc44e7f09a04bede324875ed94879e2eeb2f483fc78aee4920075ced0ee528cf143a71424c5e
7
+ data.tar.gz: e3c5e9b073e51c4c8ae860c5c43cc6d2c39333f5b87f9eb6df8b10b77a293a910c6e46b5b7f260468be8be6b4ce8677e9cd49cd19e05eae34e5158d272ab0352
@@ -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,44 +22,41 @@ 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.12"
51
49
  spec.add_dependency "rsec", "~> 1.0.0"
52
50
 
53
51
  spec.add_development_dependency "bundler"
54
- spec.add_development_dependency "byebug", "~> 9.1"
52
+ spec.add_development_dependency "debug"
55
53
  spec.add_development_dependency "equivalent-xml", "~> 0.6"
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
-
@@ -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
 
@@ -46,7 +49,7 @@ module Asciimath2UnitsML
46
49
 
47
50
  def prefix(units)
48
51
  units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p|
49
- <<~END
52
+ <<~XML
50
53
  <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
51
54
  prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
52
55
  <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
@@ -55,74 +58,21 @@ module Asciimath2UnitsML
55
58
  <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
56
59
  <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
57
60
  </Prefix>
58
- END
61
+ XML
59
62
  end.join("\n")
60
63
  end
61
64
 
62
- def dimension_components(dims)
63
- return if dims.nil? || dims.empty?
64
-
65
- <<~END
66
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
67
- #{dims.map { |u| dimension1(u) }.join("\n")}
68
- </Dimension>
69
- END
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(u)
102
- %(<#{u[:dimension]} symbol="#{u[:symbol]}"
103
- powerNumerator="#{float_to_display(u[: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
@@ -188,41 +150,22 @@ module Asciimath2UnitsML
188
150
  id = quantity || @units[normtext].quantities.first
189
151
  @units[normtext]&.dimension and
190
152
  dim = %( dimensionURL="##{@units[normtext].dimension}")
191
- <<~END
153
+ <<~XML
192
154
  <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
193
155
  #{quantityname(id)}
194
156
  </Quantity>
195
- END
196
- end
197
-
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
- <<~END
211
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
212
- #{dims.map { |u| dimension1(u) }.join("\n")}
213
- </Dimension>
214
- END
157
+ XML
215
158
  end
216
159
 
217
160
  def unitsml(units, origtext, normtext, quantity, name)
218
161
  dims = units2dimensions(units)
219
- <<~END
162
+ <<~XML
220
163
  #{unit(units, origtext, normtext, dims, name)}
221
164
  #{prefix(units)}
222
165
  #{dimension(normtext)}
223
166
  #{dimension_components(dims)}
224
167
  #{quantity(normtext, quantity)}
225
- END
168
+ XML
226
169
  end
227
170
  end
228
171
  end
@@ -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