plurimath 0.10.7 → 0.11.0
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 +4 -4
- data/.github/workflows/release.yml +3 -2
- data/README.adoc +343 -44
- data/lib/plurimath/asciimath/parse.rb +6 -2
- data/lib/plurimath/configuration.rb +17 -0
- data/lib/plurimath/deprecation.rb +81 -0
- data/lib/plurimath/errors/configuration_error.rb +27 -0
- data/lib/plurimath/errors/deprecation_error.rb +33 -0
- data/lib/plurimath/errors/error.rb +6 -0
- data/lib/plurimath/errors/formatter/unsupported_base.rb +1 -1
- data/lib/plurimath/errors/formatter/unsupported_locale.rb +18 -0
- data/lib/plurimath/errors/omml/unsupported_node_error.rb +1 -1
- data/lib/plurimath/errors/parse_error.rb +1 -1
- data/lib/plurimath/errors/parse_option_error.rb +34 -0
- data/lib/plurimath/formatter/numbers/base.rb +18 -8
- data/lib/plurimath/formatter/numbers/base_notation.rb +67 -0
- data/lib/plurimath/formatter/numbers/digit_sequence.rb +96 -0
- data/lib/plurimath/formatter/numbers/format_options.rb +141 -0
- data/lib/plurimath/formatter/numbers/fraction.rb +50 -93
- data/lib/plurimath/formatter/numbers/integer.rb +30 -6
- data/lib/plurimath/formatter/numbers/notation_renderer.rb +128 -0
- data/lib/plurimath/formatter/numbers/number_renderer.rb +66 -0
- data/lib/plurimath/formatter/numbers/parts.rb +69 -0
- data/lib/plurimath/formatter/numbers/parts_renderer.rb +30 -0
- data/lib/plurimath/formatter/numbers/precision_resolver.rb +54 -0
- data/lib/plurimath/formatter/numbers/sign_renderer.rb +28 -0
- data/lib/plurimath/formatter/numbers/significant.rb +77 -103
- data/lib/plurimath/formatter/numbers/source.rb +120 -0
- data/lib/plurimath/formatter/numbers/symbol_resolver.rb +55 -0
- data/lib/plurimath/formatter/numbers.rb +11 -0
- data/lib/plurimath/formatter/standard.rb +32 -42
- data/lib/plurimath/formatter/supported_locales.rb +27 -0
- data/lib/plurimath/formatter.rb +1 -2
- data/lib/plurimath/html/constants.rb +2 -0
- data/lib/plurimath/html/parse.rb +77 -14
- data/lib/plurimath/html/parser.rb +15 -3
- data/lib/plurimath/html/transform.rb +193 -91
- data/lib/plurimath/html/transform_utility.rb +61 -0
- data/lib/plurimath/html.rb +1 -0
- data/lib/plurimath/latex/parse.rb +7 -1
- data/lib/plurimath/latex/transform.rb +5 -5
- data/lib/plurimath/math/function/lim.rb +6 -0
- data/lib/plurimath/math/number.rb +8 -2
- data/lib/plurimath/math/symbols/cdot.rb +1 -1
- data/lib/plurimath/math/symbols/exclam.rb +1 -1
- data/lib/plurimath/math/symbols/minus.rb +1 -1
- data/lib/plurimath/math/symbols/percent.rb +1 -1
- data/lib/plurimath/math/symbols/pi.rb +1 -1
- data/lib/plurimath/math/symbols/slash.rb +1 -1
- data/lib/plurimath/math.rb +56 -8
- data/lib/plurimath/number_formatter.rb +57 -27
- data/lib/plurimath/unicode_math/parse.rb +7 -1
- data/lib/plurimath/unicode_math/transform.rb +2 -2
- data/lib/plurimath/version.rb +1 -1
- data/lib/plurimath.rb +23 -1
- metadata +21 -4
- data/lib/plurimath/formatter/number_formatter.rb +0 -115
- data/lib/plurimath/formatter/numeric_formatter.rb +0 -187
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Plurimath
|
|
4
|
-
module Formatter
|
|
5
|
-
class NumericFormatter
|
|
6
|
-
attr_accessor :locale, :localize_number, :localizer_symbols,
|
|
7
|
-
:twitter_cldr_reader
|
|
8
|
-
|
|
9
|
-
LOCALIZE_NUMBER_REGEX = %r{(?<group>[^#])?(?<groupdigits>#+0)(?<decimal>.)(?<fractdigits>#+)(?<fractgroup>[^#])?}
|
|
10
|
-
SUPPORTED_NOTATIONS = %i[e scientific engineering].freeze
|
|
11
|
-
|
|
12
|
-
def initialize(locale, localize_number:, localizer_symbols:)
|
|
13
|
-
@locale = locale
|
|
14
|
-
@localize_number = localize_number
|
|
15
|
-
@localizer_symbols = localizer_symbols
|
|
16
|
-
@twitter_cldr_reader = twitter_cldr_reader_lookup
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def localized_number(number_string, locale:, precision:, format:)
|
|
20
|
-
options_instance_variables(number_string, format, precision)
|
|
21
|
-
@twitter_cldr_reader.merge!(format)
|
|
22
|
-
if SUPPORTED_NOTATIONS.include?(@notation&.to_sym)
|
|
23
|
-
return send("#{@notation}_format",
|
|
24
|
-
number_string)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
localize_number(number_string)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
def twitter_cldr_reader_lookup
|
|
33
|
-
symbols = Formatter::SupportedLocales::LOCALES[locale.to_sym]
|
|
34
|
-
symbols
|
|
35
|
-
.merge!(@localizer_symbols)
|
|
36
|
-
.merge!(parse_localize_number)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def parse_localize_number
|
|
40
|
-
@localize_number or return {}
|
|
41
|
-
m = LOCALIZE_NUMBER_REGEX.match(@localize_number) or return {}
|
|
42
|
-
{
|
|
43
|
-
decimal: m[:decimal],
|
|
44
|
-
group_digits: m[:groupdigits].size,
|
|
45
|
-
fraction_group_digits: m[:fractdigits].size,
|
|
46
|
-
group: m[:group] == " " ? "\u00A0" : (m[:group] || ""),
|
|
47
|
-
fraction_group: m[:fractgroup] == " " ? "\u00A0" : (m[:fractgroup] || ""),
|
|
48
|
-
}.compact
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def localize_number(num)
|
|
52
|
-
Formatter::NumberFormatter.new(
|
|
53
|
-
BigDecimal(num),
|
|
54
|
-
@twitter_cldr_reader,
|
|
55
|
-
).format(
|
|
56
|
-
precision: @precision,
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def e_format(num_str)
|
|
61
|
-
notations_formatting(num_str).join(@e.to_s)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def scientific_format(num_str)
|
|
65
|
-
notations_formatting(num_str).join(" #{@times} 10^")
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def engineering_format(num_str)
|
|
69
|
-
@precision = num_str.length - 1 unless @precision.positive?
|
|
70
|
-
|
|
71
|
-
chars = notation_chars(num_str)
|
|
72
|
-
update_string_index(chars, chars.last.to_i % 3)
|
|
73
|
-
chars[0] = localize_number(chars[0])
|
|
74
|
-
chars.join(" #{@times} 10^")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def update_exponent_value(number_str)
|
|
78
|
-
exponent_number = BigDecimal(number_str) - 1
|
|
79
|
-
return exponent_number.to_i if exponent_number.negative? || @exponent_sign.to_s != "plus"
|
|
80
|
-
|
|
81
|
-
"+#{exponent_number.to_i}"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def notation_chars(num_str)
|
|
85
|
-
bd = BigDecimal(num_str)
|
|
86
|
-
return [num_str, 0] if bd.zero?
|
|
87
|
-
|
|
88
|
-
notation_array = bd.to_s("e").split("e")
|
|
89
|
-
notation_array[1] = update_exponent_value(notation_array[1])
|
|
90
|
-
number_str = notation_array[0]
|
|
91
|
-
number_str = number_str.gsub(/0\.(\d)/, '\1.')
|
|
92
|
-
number_str = number_str.sub(".", "") if number_str.start_with?(".")
|
|
93
|
-
notation_array[0] =
|
|
94
|
-
number_str.end_with?(".") ? number_str[0..-2] : number_str
|
|
95
|
-
notation_array
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def notations_formatting(num_str)
|
|
99
|
-
chars = notation_chars(num_str)
|
|
100
|
-
chars[0] = localize_number(chars[0])
|
|
101
|
-
chars << "0" if chars.length == 1
|
|
102
|
-
chars
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def options_instance_variables(string, format, precision)
|
|
106
|
-
@e = format[:e]&.to_sym || :e
|
|
107
|
-
@times = format[:times]&.to_sym || "\u{d7}"
|
|
108
|
-
@notation = format[:notation]&.to_sym || nil
|
|
109
|
-
@precision = update_precision(string, precision, format)
|
|
110
|
-
@exponent_sign = format[:exponent_sign]&.to_sym || nil
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def update_precision(num, precision, format)
|
|
114
|
-
return precision if precision
|
|
115
|
-
|
|
116
|
-
significant_precision = significant_base_precision(num, format)
|
|
117
|
-
return significant_precision if significant_precision
|
|
118
|
-
|
|
119
|
-
if SUPPORTED_NOTATIONS.include?(@notation&.to_sym)
|
|
120
|
-
return num.sub(".",
|
|
121
|
-
"").size - 1
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
num.include?(".") ? num.sub(/^.*\./, "").size : 0
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# When precision is omitted, infer the target-base fractional digits
|
|
128
|
-
# needed to satisfy :significant. Cap the count to the source significant
|
|
129
|
-
# digits so base conversion does not invent precision for values like 0.1.
|
|
130
|
-
# Add one extra digit when the source has more significant digits so
|
|
131
|
-
# Significant can still perform the final rounding pass.
|
|
132
|
-
def significant_base_precision(num, format)
|
|
133
|
-
base = format[:base] || Formatter::NumberFormatter::DEFAULT_BASE
|
|
134
|
-
return unless target_base?(base)
|
|
135
|
-
|
|
136
|
-
significant = format[:significant].to_i
|
|
137
|
-
return if significant.zero?
|
|
138
|
-
|
|
139
|
-
return 0 unless source_fractional?(num)
|
|
140
|
-
|
|
141
|
-
source_significant = source_significant_digits(num)
|
|
142
|
-
effective_significant = [significant, source_significant].min
|
|
143
|
-
target_precision = [
|
|
144
|
-
effective_significant - target_base_integer_length(num, base),
|
|
145
|
-
0,
|
|
146
|
-
].max
|
|
147
|
-
|
|
148
|
-
target_precision += 1 if source_significant > effective_significant
|
|
149
|
-
target_precision
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
def target_base?(base)
|
|
153
|
-
Formatter::NumberFormatter::DEFAULT_BASE_PREFIXES.key?(base) &&
|
|
154
|
-
base != Formatter::NumberFormatter::DEFAULT_BASE
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def source_fractional?(num)
|
|
158
|
-
mantissa, exponent = num.to_s.downcase.split("e", 2)
|
|
159
|
-
fraction_length = mantissa.split(".", 2)[1].to_s.length
|
|
160
|
-
|
|
161
|
-
fraction_length > exponent.to_i
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def source_significant_digits(num)
|
|
165
|
-
mantissa = num.to_s.downcase.split("e", 2).first
|
|
166
|
-
mantissa.sub(/\A[-+]/, "").delete(".").sub(/\A0+/, "").length
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def target_base_integer_length(num, base)
|
|
170
|
-
integer = BigDecimal(num).abs.to_i
|
|
171
|
-
return 0 if integer.zero?
|
|
172
|
-
|
|
173
|
-
integer.to_s(base).length
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def update_string_index(chars, index)
|
|
177
|
-
return if index.zero?
|
|
178
|
-
|
|
179
|
-
chars.first.delete!(".")
|
|
180
|
-
chars.first.insert(index + 1, ".") unless chars.first[index + 2].nil?
|
|
181
|
-
exponent = chars[-1]
|
|
182
|
-
chars[-1] =
|
|
183
|
-
"#{'+' if exponent.to_s.start_with?('+')}#{exponent.to_i - index}"
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|