plurimath 0.8.2 → 0.8.3

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: f961f580d6f46c943b805f8c2f2a77281151ddcb76eab4a7e7adabbfe61b2b6b
4
- data.tar.gz: fbe6a5651b11576a161fe0620780aa359151688d97fac674874679d138c8c34d
3
+ metadata.gz: def00e41e6010e06ea7df51573e342c4ed8b815e079bcbad3a7776cc5d625e02
4
+ data.tar.gz: d46595b7a57d2a391e849d58a6b23f7e449e042e891797967f13cee0364c32df
5
5
  SHA512:
6
- metadata.gz: badfd5bd7eb9f2b84ef7604c21ab4f82fa93de5c52df760ee2fcc7ade85cd6900dbc527d41faf2c2521ae6dfbeb2cf79f8af0028927c6a1049bd921836fdec41
7
- data.tar.gz: 886be496741ca30633f2ca6d25a5d39f1e5986065adb07cbc961a08ebb6fc04f4d060037afaafec59fb4fbcc5510c968aa1b06bfec366388d7bab1eaad2add99
6
+ metadata.gz: 5e5c0c02a41fcd2fdbebbd11ca103228ec5c9a2b4e68e98a364c39d988540ebfa844ad06785ced1538186ae7a0583978fe8c1a548c1da135d243d633557cc298
7
+ data.tar.gz: 15463a536fac275fe0935b360dd754ed787a202d4d77b4ef3f4934359e45ec4393e0c95bd6a7ce7f02a9e655f21eeeec312f932462354965a287e08e92b55e89
@@ -0,0 +1,114 @@
1
+ require "twitter_cldr"
2
+ require_relative "twitter_cldr_rb/integer"
3
+ require_relative "twitter_cldr_rb/fraction"
4
+ require_relative "twitter_cldr_rb/number_formatter"
5
+
6
+ module Plurimath
7
+ module Formatter
8
+ class NumberFormatter
9
+ attr_accessor :locale, :localize_number, :localizer_symbols
10
+
11
+ LOCALIZE_NUMBER_REGEX = %r{(?<group>[^#])?(?<groupdigits>#+0)(?<decimal>.)(?<fractdigits>#+)(?<fractgroup>[^#])?}
12
+ SUPPORTED_NOTATIONS = %i[e scientific engineering].freeze
13
+
14
+ def initialize(locale, localize_number:, localizer_symbols:)
15
+ @locale = locale
16
+ @localize_number = localize_number
17
+ @localizer_symbols = localizer_symbols
18
+ @twitter_cldr_reader = twitter_cldr_reader(locale)
19
+ end
20
+
21
+ def localized_number(number_string, locale:, precision:, format:)
22
+ options_instance_variables(number_string, format, precision)
23
+ @twitter_cldr_reader.merge!(format)
24
+ return send("#{@notation}_format", number_string) if SUPPORTED_NOTATIONS.include?(@notation&.to_sym)
25
+
26
+ localize_number(number_string)
27
+ end
28
+
29
+ private
30
+
31
+ def twitter_cldr_reader(locale)
32
+ num = TwitterCldr::DataReaders::NumberDataReader.new(locale)
33
+ num.symbols
34
+ .merge!(@localizer_symbols)
35
+ .merge!(parse_localize_number)
36
+ end
37
+
38
+ def parse_localize_number
39
+ @localize_number or return {}
40
+ m = LOCALIZE_NUMBER_REGEX.match(@localize_number) or return {}
41
+ ret = {
42
+ decimal: m[:decimal],
43
+ group_digits: m[:groupdigits].size,
44
+ fraction_group_digits: m[:fractdigits].size,
45
+ group: m[:group] == " " ? "\u00A0" : (m[:group] || ""),
46
+ fraction_group: m[:fractgroup] == " " ? "\u00A0" : (m[:fractgroup] || "")
47
+ }.compact
48
+ end
49
+
50
+ def localize_number(num)
51
+ num = num.match?(/\./) ? num.to_f : num.to_i
52
+ localized = BigDecimal(num.to_s).localize(@locale)
53
+ return localized.to_s if @precision.zero?
54
+
55
+ localized.to_decimal.to_s(precision: @precision)
56
+ end
57
+
58
+ def e_format(num_str)
59
+ notations_formatting(num_str).join(@e.to_s)
60
+ end
61
+
62
+ def scientific_format(num_str)
63
+ notations_formatting(num_str).join(" #{@times} 10^")
64
+ end
65
+
66
+ def engineering_format(num_str)
67
+ @precision = num_str.length - 1 unless @precision > 0
68
+ chars = notation_chars(num_str)
69
+ update_string_index(chars, chars.last.to_i % 3)
70
+ chars[0] = localize_number(chars[0])
71
+ chars.join(" #{@times} 10^")
72
+ end
73
+
74
+ def update_exponent_sign(str)
75
+ str.gsub!("e", "e+") if @exponent_sign == :plus
76
+ end
77
+
78
+ def notation_chars(num_str)
79
+ notation_number = ("%.#{@precision}e" %num_str)
80
+ update_exponent_sign(notation_number.gsub!("+0", ""))
81
+ notation_number.split("e")
82
+ end
83
+
84
+ def notations_formatting(num_str)
85
+ chars = notation_chars(num_str)
86
+ chars[0] = localize_number(chars[0])
87
+ chars
88
+ end
89
+
90
+ def options_instance_variables(string, format, precision)
91
+ @e = format.delete(:e)&.to_sym || :e
92
+ @times = format.delete(:times)&.to_sym || "\u{d7}"
93
+ @notation = format.delete(:notation)&.to_sym || nil
94
+ @precision = update_precision(string, precision)
95
+ @exponent_sign = format.delete(:exponent_sign)&.to_sym || nil
96
+ end
97
+
98
+ def update_precision(num, precision)
99
+ return precision if precision
100
+ return num.sub(/\./, "").size - 1 if SUPPORTED_NOTATIONS.include?(@notation&.to_sym)
101
+
102
+ /\./.match?(num) ? num.sub(/^.*\./, "").size : 0
103
+ end
104
+
105
+ def update_string_index(chars, index)
106
+ return if index.zero?
107
+
108
+ chars.first.delete!(".")
109
+ chars.first.insert(index + 1, ".")
110
+ chars[-1] = (chars[-1].to_i - index).to_s
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwitterCldr
4
+ module Formatters
5
+ module Numbers
6
+ class Fraction
7
+ attr_reader :format, :decimal, :precision, :separator, :group
8
+
9
+ def initialize(token, symbols = {})
10
+ @format = token ? token.value.split('.').pop : ''
11
+ @decimal = symbols[:decimal] || '.'
12
+ @separator = symbols[:fraction_group] || " "
13
+ @group = symbols[:fraction_group_digits] || 3
14
+ @digit_count = symbols[:digit_count] || nil
15
+ @precision = @format.length
16
+ end
17
+
18
+ def apply(fraction, options = {}, int = "")
19
+ precision = options[:precision] || self.precision
20
+ return "" unless precision > 0
21
+
22
+ number = interpolate(format(options), fraction, :left)
23
+ number = digit_count_format(int, fraction, number) if @digit_count
24
+ decimal + change_format(precision, number)
25
+ end
26
+
27
+ def format(options)
28
+ precision = options[:precision] || self.precision
29
+ precision ? '0' * precision : @format
30
+ end
31
+
32
+ protected
33
+
34
+ def change_format(precision, string)
35
+ tokens = []
36
+ tokens << string&.slice!(0, group) until string&.empty?
37
+ tokens.compact.join(separator)
38
+ end
39
+
40
+ def digit_count_format(int, fraction, number)
41
+ integer = int + "." + fraction
42
+ float = integer.to_f
43
+ int_length = integer.length - 1
44
+ @digit_count ||= int_length
45
+ if int_length > @digit_count
46
+ float.round(@digit_count - int.length).to_s.split(".").last
47
+ elsif int_length < @digit_count
48
+ number += "0" * (@digit_count - int_length)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwitterCldr
4
+ module Formatters
5
+ module Numbers
6
+ class Integer
7
+ def initialize(token, symbols = {})
8
+ format = token.value.split('.')[0]
9
+ @format = prepare_format(format, symbols)
10
+ @groups = Array(symbols[:group_digits] || parse_groups(format))
11
+ @separator = symbols[:group] || ','
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TwitterCldr
4
+ module Formatters
5
+ class NumberFormatter
6
+ def format(tokens, number, options = {})
7
+ options[:precision] ||= precision_from(number)
8
+ options[:type] ||= :decimal
9
+
10
+ prefix, suffix, integer_format, fraction_format = *partition_tokens(tokens)
11
+ number = truncate_number(number, integer_format.format.length)
12
+
13
+ int, fraction = parse_number(number, options)
14
+ result = integer_format.apply(int, options)
15
+ result << fraction_format.apply(fraction, options, int) if fraction
16
+
17
+ number_system.transliterate(
18
+ "#{prefix.to_s}#{result}#{suffix.to_s}"
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,6 +7,7 @@ require_relative "mathml"
7
7
  require_relative "html"
8
8
  require_relative "latex"
9
9
  require_relative "unitsml"
10
+ require_relative "number_formatter"
10
11
  require_relative "math/core"
11
12
  require_relative "math/number"
12
13
  require_relative "math/symbol"
@@ -0,0 +1,32 @@
1
+ require "plurimath/formatter/number_formatter"
2
+
3
+ module Plurimath
4
+ class NumberFormatter
5
+ attr_accessor :locale, :localize_number, :localizer_symbols
6
+
7
+ def initialize(locale = "en", localize_number: nil, localizer_symbols: {})
8
+ @locale = supported_locale(locale)
9
+ @localize_number = localize_number
10
+ @localizer_symbols = localizer_symbols
11
+ end
12
+
13
+ def localized_number(number_string, locale: @locale, precision: nil, format: {})
14
+ Formatter::NumberFormatter.new(
15
+ supported_locale(locale),
16
+ localize_number: localize_number,
17
+ localizer_symbols: localizer_symbols,
18
+ ).localized_number(
19
+ number_string,
20
+ locale: supported_locale(locale),
21
+ precision: precision,
22
+ format: format,
23
+ )
24
+ end
25
+
26
+ private
27
+
28
+ def supported_locale(locale)
29
+ TwitterCldr.supported_locale?(locale.to_sym) ? locale.to_sym : :en
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plurimath
4
- VERSION = "0.8.2"
4
+ VERSION = "0.8.3"
5
5
  end
data/plurimath.gemspec CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.bindir = "exe"
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
+ spec.add_dependency 'twitter_cldr'
27
28
  spec.add_dependency 'parslet'
28
29
  spec.add_dependency 'ox'
29
30
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plurimath
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-16 00:00:00.000000000 Z
11
+ date: 2024-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: twitter_cldr
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: parslet
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -70,6 +84,10 @@ files:
70
84
  - lib/plurimath/asciimath/parse.rb
71
85
  - lib/plurimath/asciimath/parser.rb
72
86
  - lib/plurimath/asciimath/transform.rb
87
+ - lib/plurimath/formatter/number_formatter.rb
88
+ - lib/plurimath/formatter/twitter_cldr_rb/fraction.rb
89
+ - lib/plurimath/formatter/twitter_cldr_rb/integer.rb
90
+ - lib/plurimath/formatter/twitter_cldr_rb/number_formatter.rb
73
91
  - lib/plurimath/html.rb
74
92
  - lib/plurimath/html/constants.rb
75
93
  - lib/plurimath/html/parse.rb
@@ -214,6 +232,7 @@ files:
214
232
  - lib/plurimath/mathml/constants.rb
215
233
  - lib/plurimath/mathml/parser.rb
216
234
  - lib/plurimath/mathml/transform.rb
235
+ - lib/plurimath/number_formatter.rb
217
236
  - lib/plurimath/omml.rb
218
237
  - lib/plurimath/omml/parser.rb
219
238
  - lib/plurimath/omml/transform.rb
@@ -259,7 +278,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
278
  - !ruby/object:Gem::Version
260
279
  version: '0'
261
280
  requirements: []
262
- rubygems_version: 3.3.26
281
+ rubygems_version: 3.3.27
263
282
  signing_key:
264
283
  specification_version: 4
265
284
  summary: Converts LaTeX math into MathML.