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
|
@@ -5,7 +5,7 @@ module Plurimath
|
|
|
5
5
|
class Transform < Parslet::Transform
|
|
6
6
|
rule(base: simple(:base)) { base }
|
|
7
7
|
rule(over: simple(:over)) { over }
|
|
8
|
-
rule(number: simple(:num)) { Math::Number.new(num) }
|
|
8
|
+
rule(number: simple(:num)) { Math::Number.new(Utility.html_entity_to_unicode(num.to_s)) }
|
|
9
9
|
rule(power: simple(:power)) { power }
|
|
10
10
|
rule(unary: simple(:unary)) { Utility.get_class(unary).new }
|
|
11
11
|
rule(space: simple(:space)) { Math::Function::Text.new(" ") }
|
|
@@ -188,7 +188,7 @@ module Plurimath
|
|
|
188
188
|
number: simple(:number)) do
|
|
189
189
|
Math::Function::Power.new(
|
|
190
190
|
power,
|
|
191
|
-
Math::Number.new(number),
|
|
191
|
+
Math::Number.new(Utility.html_entity_to_unicode(number.to_s)),
|
|
192
192
|
)
|
|
193
193
|
end
|
|
194
194
|
|
|
@@ -428,7 +428,7 @@ module Plurimath
|
|
|
428
428
|
rule(number: simple(:number),
|
|
429
429
|
subscript: simple(:subscript)) do
|
|
430
430
|
Math::Function::Base.new(
|
|
431
|
-
Math::Number.new(number),
|
|
431
|
+
Math::Number.new(Utility.html_entity_to_unicode(number.to_s)),
|
|
432
432
|
subscript,
|
|
433
433
|
)
|
|
434
434
|
end
|
|
@@ -436,7 +436,7 @@ module Plurimath
|
|
|
436
436
|
rule(number: simple(:number),
|
|
437
437
|
supscript: simple(:supscript)) do
|
|
438
438
|
Math::Function::Power.new(
|
|
439
|
-
Math::Number.new(number),
|
|
439
|
+
Math::Number.new(Utility.html_entity_to_unicode(number.to_s)),
|
|
440
440
|
supscript,
|
|
441
441
|
)
|
|
442
442
|
end
|
|
@@ -445,7 +445,7 @@ module Plurimath
|
|
|
445
445
|
subscript: simple(:subscript),
|
|
446
446
|
supscript: simple(:supscript)) do
|
|
447
447
|
Math::Function::PowerBase.new(
|
|
448
|
-
Math::Number.new(number),
|
|
448
|
+
Math::Number.new(Utility.html_entity_to_unicode(number.to_s)),
|
|
449
449
|
subscript,
|
|
450
450
|
supscript,
|
|
451
451
|
)
|
|
@@ -28,6 +28,12 @@ module Plurimath
|
|
|
28
28
|
"\\#{class_name}#{first_value}#{second_value}"
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
def to_html(options:)
|
|
32
|
+
first_value = "<i>#{parameter_one.to_html(options: options)}</i>" if parameter_one
|
|
33
|
+
second_value = "<i>#{parameter_two.to_html(options: options)}</i>" if parameter_two
|
|
34
|
+
"<i>lim</i>#{first_value}#{second_value}"
|
|
35
|
+
end
|
|
36
|
+
|
|
31
37
|
def to_mathml_without_math_tag(intent, options:)
|
|
32
38
|
first_value = Utility.ox_element("mo") << "lim"
|
|
33
39
|
return first_value unless any_value_exist?
|
|
@@ -93,8 +93,14 @@ module Plurimath
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def format_value_with_options(options)
|
|
96
|
-
formatter = options
|
|
97
|
-
|
|
96
|
+
formatter = options.fetch(:formatter) do
|
|
97
|
+
Plurimath.configuration.number_formatter
|
|
98
|
+
end
|
|
99
|
+
return value unless formatter
|
|
100
|
+
|
|
101
|
+
if formatter.respond_to?(:format_number)
|
|
102
|
+
formatter.format_number(options[:formula], self)
|
|
103
|
+
elsif formatter.respond_to?(:format)
|
|
98
104
|
formatter.format(options[:formula], self)
|
|
99
105
|
elsif formatter.respond_to?(:localized_number)
|
|
100
106
|
formatter.localized_number(value.to_s)
|
data/lib/plurimath/math.rb
CHANGED
|
@@ -7,6 +7,7 @@ module Plurimath
|
|
|
7
7
|
autoload :Function, "#{__dir__}/math/function"
|
|
8
8
|
autoload :InvalidTypeError, "#{__dir__}/errors/invalid_type_error"
|
|
9
9
|
autoload :Number, "#{__dir__}/math/number"
|
|
10
|
+
autoload :ParseOptionError, "#{__dir__}/errors/parse_option_error"
|
|
10
11
|
autoload :ParseError, "#{__dir__}/errors/parse_error"
|
|
11
12
|
autoload :Symbols, "#{__dir__}/math/symbols"
|
|
12
13
|
|
|
@@ -19,15 +20,23 @@ module Plurimath
|
|
|
19
20
|
unicode: UnicodeMath,
|
|
20
21
|
asciimath: Asciimath,
|
|
21
22
|
}.freeze
|
|
23
|
+
SUPPORTED_PARSE_OPTIONS = %i[locale].freeze
|
|
24
|
+
LOCALIZED_PARSE_TYPES = %i[asciimath html latex unicode].freeze
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
def parse(text, type, **options)
|
|
24
29
|
raise InvalidTypeError.new unless valid_type?(type)
|
|
25
30
|
|
|
31
|
+
type = type.to_sym
|
|
32
|
+
unknown_options = options.keys - SUPPORTED_PARSE_OPTIONS
|
|
33
|
+
raise_unknown_parse_options!(unknown_options) unless unknown_options.empty?
|
|
34
|
+
|
|
35
|
+
raise_unsupported_parse_option!(type, :locale) if options.key?(:locale) && !localized_parse_type?(type)
|
|
36
|
+
options = normalize_parse_options(options)
|
|
37
|
+
|
|
26
38
|
begin
|
|
27
|
-
|
|
28
|
-
formula = klass.new(text).to_formula
|
|
29
|
-
formula.input_string = text
|
|
30
|
-
formula
|
|
39
|
+
parse_with_configuration(text, type, options)
|
|
31
40
|
rescue ParseError
|
|
32
41
|
# Re-raise ParseError from lower layers unchanged to preserve specialized error types
|
|
33
42
|
raise
|
|
@@ -36,17 +45,56 @@ module Plurimath
|
|
|
36
45
|
end
|
|
37
46
|
end
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
def parse_with_configuration(text, type, options)
|
|
49
|
+
return parse_formula(text, type) unless options.key?(:locale)
|
|
50
|
+
|
|
51
|
+
Plurimath.with_configuration do |config|
|
|
52
|
+
config.locale = options.fetch(:locale)
|
|
53
|
+
parse_formula(text, type)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def parse_formula(text, type)
|
|
58
|
+
klass = klass_from_type(type)
|
|
59
|
+
formula = klass.new(text).to_formula
|
|
60
|
+
formula.input_string = text
|
|
61
|
+
formula
|
|
62
|
+
end
|
|
40
63
|
|
|
41
64
|
def klass_from_type(type_string_or_sym)
|
|
42
65
|
VALID_TYPES[type_string_or_sym.to_sym]
|
|
43
66
|
end
|
|
44
67
|
|
|
68
|
+
def normalize_parse_options(options)
|
|
69
|
+
return options unless options.key?(:locale)
|
|
70
|
+
|
|
71
|
+
options.merge(
|
|
72
|
+
locale: Formatter::SupportedLocales.key_for!(options.fetch(:locale)),
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def localized_parse_type?(type)
|
|
77
|
+
LOCALIZED_PARSE_TYPES.include?(type)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def raise_unknown_parse_options!(options)
|
|
81
|
+
raise ParseOptionError.unknown_options(
|
|
82
|
+
options,
|
|
83
|
+
supported_options: SUPPORTED_PARSE_OPTIONS,
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def raise_unsupported_parse_option!(type, option)
|
|
88
|
+
raise ParseOptionError.unsupported_options(
|
|
89
|
+
type,
|
|
90
|
+
[option],
|
|
91
|
+
supported_types: LOCALIZED_PARSE_TYPES,
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
45
95
|
def valid_type?(type)
|
|
46
96
|
(type.is_a?(::Symbol) || type.is_a?(String)) &&
|
|
47
97
|
VALID_TYPES.key?(type.to_sym)
|
|
48
98
|
end
|
|
49
|
-
|
|
50
|
-
module_function :parse, :klass_from_type, :valid_type?
|
|
51
99
|
end
|
|
52
100
|
end
|
|
@@ -1,52 +1,82 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "bigdecimal"
|
|
4
|
-
|
|
5
3
|
module Plurimath
|
|
6
4
|
class NumberFormatter
|
|
7
5
|
attr_accessor :locale, :localize_number, :localizer_symbols, :precision
|
|
8
6
|
|
|
9
|
-
def initialize(
|
|
10
|
-
|
|
7
|
+
def initialize(
|
|
8
|
+
locale = "en",
|
|
9
|
+
localize_number: nil,
|
|
10
|
+
localizer_symbols: {},
|
|
11
|
+
precision: nil
|
|
12
|
+
)
|
|
11
13
|
@locale = supported_locale(locale)
|
|
12
14
|
@localize_number = localize_number
|
|
13
15
|
@localizer_symbols = localizer_symbols
|
|
14
16
|
@precision = precision
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def localized_number(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
def localized_number(
|
|
20
|
+
number_string,
|
|
21
|
+
locale: @locale,
|
|
22
|
+
precision: @precision,
|
|
23
|
+
format: {}
|
|
24
|
+
)
|
|
25
|
+
locale = supported_locale(locale)
|
|
26
|
+
source = Formatter::Numbers::Source.new(number_string)
|
|
27
|
+
options = format_options(source, locale, precision, format)
|
|
28
|
+
|
|
29
|
+
if options.notation_supported?
|
|
30
|
+
return notation_renderer(options).render(source, options.notation)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
render_localized_number(source, options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def twitter_cldr_reader(locale: @locale)
|
|
37
|
+
symbols_for(supported_locale(locale), {})
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def format_options(source, locale, precision, format)
|
|
43
|
+
Formatter::Numbers::FormatOptions.new(
|
|
44
|
+
source,
|
|
45
|
+
symbols: symbols_for(locale, format),
|
|
27
46
|
precision: precision,
|
|
28
|
-
|
|
47
|
+
precision_resolver: precision_resolver,
|
|
29
48
|
)
|
|
30
|
-
ensure
|
|
31
|
-
symbols(locale.to_sym).replace(prev_symbols)
|
|
32
49
|
end
|
|
33
50
|
|
|
34
|
-
def
|
|
35
|
-
Formatter::
|
|
36
|
-
|
|
37
|
-
|
|
51
|
+
def notation_renderer(options)
|
|
52
|
+
Formatter::Numbers::NotationRenderer.new(options)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def precision_resolver
|
|
56
|
+
@precision_resolver ||= Formatter::Numbers::PrecisionResolver.new
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def render_localized_number(source, options)
|
|
60
|
+
Formatter::Numbers::NumberRenderer.new(
|
|
61
|
+
source,
|
|
62
|
+
options,
|
|
63
|
+
).format
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def symbol_resolver(locale)
|
|
67
|
+
Formatter::Numbers::SymbolResolver.new(
|
|
68
|
+
locale,
|
|
38
69
|
localizer_symbols: localizer_symbols,
|
|
39
|
-
|
|
70
|
+
localize_number: localize_number,
|
|
71
|
+
)
|
|
40
72
|
end
|
|
41
73
|
|
|
42
|
-
|
|
74
|
+
def symbols_for(locale, format)
|
|
75
|
+
symbol_resolver(locale).resolve.merge(format)
|
|
76
|
+
end
|
|
43
77
|
|
|
44
78
|
def supported_locale(locale)
|
|
45
79
|
Formatter::SupportedLocales::LOCALES.key?(locale.to_sym) ? locale.to_sym : :en
|
|
46
80
|
end
|
|
47
|
-
|
|
48
|
-
def symbols(locale)
|
|
49
|
-
Formatter::SupportedLocales::LOCALES[locale]
|
|
50
|
-
end
|
|
51
81
|
end
|
|
52
82
|
end
|
|
@@ -35,7 +35,7 @@ module Plurimath
|
|
|
35
35
|
rule(:op_opener) { open_paren | op_open_unicode | op_open_paren | op_open }
|
|
36
36
|
rule(:op_closer) { op_close_unicode | close_paren | op_close_paren | op_close }
|
|
37
37
|
|
|
38
|
-
rule(:op_decimal) { str(",") | str(".") }
|
|
38
|
+
rule(:op_decimal) { decimal_marker | str(",") | str(".") }
|
|
39
39
|
rule(:diacritics) { (char.as(:char) >> diacritics.as(:diacritics)) | char.as(:char) }
|
|
40
40
|
rule(:open_paren) { (op_masked_open >> (op_closer | op_opener)).as(:open_paren) | op_masked_open }
|
|
41
41
|
|
|
@@ -242,6 +242,12 @@ module Plurimath
|
|
|
242
242
|
end
|
|
243
243
|
|
|
244
244
|
root :expression
|
|
245
|
+
|
|
246
|
+
def decimal_marker
|
|
247
|
+
# UnicodeMath::Parser entity-encodes input before Parslet sees it, so
|
|
248
|
+
# non-ASCII locale markers must match that encoded parser input.
|
|
249
|
+
str(Utility.string_to_html_entity(Plurimath.configuration.decimal))
|
|
250
|
+
end
|
|
245
251
|
end
|
|
246
252
|
end
|
|
247
253
|
end
|
|
@@ -185,7 +185,7 @@ module Plurimath
|
|
|
185
185
|
|
|
186
186
|
rule(decimal: simple(:decimal),
|
|
187
187
|
whole: simple(:whole)) do
|
|
188
|
-
Math::Number.new("#{decimal}#{whole.value}")
|
|
188
|
+
Math::Number.new(Utility.html_entity_to_unicode("#{decimal}#{whole.value}"))
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
rule(positive: simple(:positive),
|
|
@@ -2222,7 +2222,7 @@ module Plurimath
|
|
|
2222
2222
|
rule(whole: simple(:whole),
|
|
2223
2223
|
decimal: simple(:decimal),
|
|
2224
2224
|
fractional: simple(:fractional)) do
|
|
2225
|
-
Math::Number.new("#{whole.value}#{decimal}#{fractional.value}")
|
|
2225
|
+
Math::Number.new(Utility.html_entity_to_unicode("#{whole.value}#{decimal}#{fractional.value}"))
|
|
2226
2226
|
end
|
|
2227
2227
|
|
|
2228
2228
|
rule(factor: simple(:factor),
|
data/lib/plurimath/version.rb
CHANGED
data/lib/plurimath.rb
CHANGED
|
@@ -8,6 +8,11 @@ require "plurimath/xml_engine"
|
|
|
8
8
|
module Plurimath
|
|
9
9
|
autoload :Asciimath, "plurimath/asciimath"
|
|
10
10
|
autoload :Cli, "plurimath/cli" unless RUBY_ENGINE == "opal"
|
|
11
|
+
autoload :Configuration, "plurimath/configuration"
|
|
12
|
+
autoload :Deprecation, "plurimath/deprecation"
|
|
13
|
+
autoload :Error, "plurimath/errors/error"
|
|
14
|
+
autoload :ConfigurationError, "plurimath/errors/configuration_error"
|
|
15
|
+
autoload :DeprecationError, "plurimath/errors/deprecation_error"
|
|
11
16
|
autoload :Formatter, "plurimath/formatter"
|
|
12
17
|
autoload :Html, "plurimath/html"
|
|
13
18
|
autoload :Latex, "plurimath/latex"
|
|
@@ -28,7 +33,24 @@ module Plurimath
|
|
|
28
33
|
Mml::V4::Configuration.adapter = adapter unless Mml::V4::Configuration.adapter
|
|
29
34
|
end
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
def configuration
|
|
37
|
+
@configuration ||= Configuration.new
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def configure
|
|
41
|
+
yield(configuration)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def with_configuration
|
|
45
|
+
# Swap the global config to an isolated copy so block mutations are scoped.
|
|
46
|
+
previous_configuration = configuration
|
|
47
|
+
@configuration = previous_configuration.dup
|
|
48
|
+
yield(configuration)
|
|
49
|
+
ensure
|
|
50
|
+
@configuration = previous_configuration
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module_function :mml_adapter, :configuration, :configure, :with_configuration
|
|
32
54
|
end
|
|
33
55
|
|
|
34
56
|
default_adapter =
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plurimath
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bigdecimal
|
|
@@ -193,19 +193,35 @@ files:
|
|
|
193
193
|
- lib/plurimath/asciimath/parser.rb
|
|
194
194
|
- lib/plurimath/asciimath/transform.rb
|
|
195
195
|
- lib/plurimath/cli.rb
|
|
196
|
+
- lib/plurimath/configuration.rb
|
|
197
|
+
- lib/plurimath/deprecation.rb
|
|
196
198
|
- lib/plurimath/errors.rb
|
|
199
|
+
- lib/plurimath/errors/configuration_error.rb
|
|
200
|
+
- lib/plurimath/errors/deprecation_error.rb
|
|
201
|
+
- lib/plurimath/errors/error.rb
|
|
197
202
|
- lib/plurimath/errors/formatter/unsupported_base.rb
|
|
203
|
+
- lib/plurimath/errors/formatter/unsupported_locale.rb
|
|
198
204
|
- lib/plurimath/errors/invalid_type_error.rb
|
|
199
205
|
- lib/plurimath/errors/omml/unsupported_node_error.rb
|
|
200
206
|
- lib/plurimath/errors/parse_error.rb
|
|
207
|
+
- lib/plurimath/errors/parse_option_error.rb
|
|
201
208
|
- lib/plurimath/formatter.rb
|
|
202
|
-
- lib/plurimath/formatter/number_formatter.rb
|
|
203
209
|
- lib/plurimath/formatter/numbers.rb
|
|
204
210
|
- lib/plurimath/formatter/numbers/base.rb
|
|
211
|
+
- lib/plurimath/formatter/numbers/base_notation.rb
|
|
212
|
+
- lib/plurimath/formatter/numbers/digit_sequence.rb
|
|
213
|
+
- lib/plurimath/formatter/numbers/format_options.rb
|
|
205
214
|
- lib/plurimath/formatter/numbers/fraction.rb
|
|
206
215
|
- lib/plurimath/formatter/numbers/integer.rb
|
|
216
|
+
- lib/plurimath/formatter/numbers/notation_renderer.rb
|
|
217
|
+
- lib/plurimath/formatter/numbers/number_renderer.rb
|
|
218
|
+
- lib/plurimath/formatter/numbers/parts.rb
|
|
219
|
+
- lib/plurimath/formatter/numbers/parts_renderer.rb
|
|
220
|
+
- lib/plurimath/formatter/numbers/precision_resolver.rb
|
|
221
|
+
- lib/plurimath/formatter/numbers/sign_renderer.rb
|
|
207
222
|
- lib/plurimath/formatter/numbers/significant.rb
|
|
208
|
-
- lib/plurimath/formatter/
|
|
223
|
+
- lib/plurimath/formatter/numbers/source.rb
|
|
224
|
+
- lib/plurimath/formatter/numbers/symbol_resolver.rb
|
|
209
225
|
- lib/plurimath/formatter/standard.rb
|
|
210
226
|
- lib/plurimath/formatter/supported_locales.rb
|
|
211
227
|
- lib/plurimath/html.rb
|
|
@@ -213,6 +229,7 @@ files:
|
|
|
213
229
|
- lib/plurimath/html/parse.rb
|
|
214
230
|
- lib/plurimath/html/parser.rb
|
|
215
231
|
- lib/plurimath/html/transform.rb
|
|
232
|
+
- lib/plurimath/html/transform_utility.rb
|
|
216
233
|
- lib/plurimath/latex.rb
|
|
217
234
|
- lib/plurimath/latex/constants.rb
|
|
218
235
|
- lib/plurimath/latex/parse.rb
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Plurimath
|
|
4
|
-
module Formatter
|
|
5
|
-
class NumberFormatter
|
|
6
|
-
attr_reader :number, :data_reader
|
|
7
|
-
|
|
8
|
-
DEFAULT_BASE = Numbers::Base::DEFAULT_BASE
|
|
9
|
-
HEX_ALPHABETS = "abcdef"
|
|
10
|
-
STRING_SYMBOLS = {
|
|
11
|
-
dot: ".",
|
|
12
|
-
f: "F",
|
|
13
|
-
}.freeze
|
|
14
|
-
DEFAULT_BASE_PREFIXES = {
|
|
15
|
-
2 => "0b",
|
|
16
|
-
8 => "0o",
|
|
17
|
-
10 => "",
|
|
18
|
-
16 => "0x",
|
|
19
|
-
}.freeze
|
|
20
|
-
|
|
21
|
-
def initialize(number, data_reader = {})
|
|
22
|
-
@number = number
|
|
23
|
-
@data_reader = data_reader
|
|
24
|
-
@base = data_reader[:base] || DEFAULT_BASE
|
|
25
|
-
unless DEFAULT_BASE_PREFIXES.key?(@base)
|
|
26
|
-
raise UnsupportedBase.new(@base,
|
|
27
|
-
DEFAULT_BASE_PREFIXES)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Handle base_prefix: if explicitly provided (even as nil), use it; otherwise use default
|
|
31
|
-
@base_prefix = if data_reader.key?(:base_prefix)
|
|
32
|
-
data_reader[:base_prefix].to_s
|
|
33
|
-
else
|
|
34
|
-
DEFAULT_BASE_PREFIXES[@base]
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def format(precision: nil)
|
|
39
|
-
data_reader[:precision] = precision || precision_from(number)
|
|
40
|
-
int, frac, integer_format, fraction_format, signif_format = *partition_tokens(number)
|
|
41
|
-
# FIX FOR:
|
|
42
|
-
# NotImplementedError: String#<< not supported. Mutable String methods are not supported in Opal.
|
|
43
|
-
result = []
|
|
44
|
-
result << integer_format.apply(int)
|
|
45
|
-
result << fraction_format.apply(frac, result, integer_format) # use formatted int for correct fraction formatting
|
|
46
|
-
result = result.join
|
|
47
|
-
result = signif_format.apply(result, integer_format, fraction_format)
|
|
48
|
-
result = result.tr(HEX_ALPHABETS, HEX_ALPHABETS.upcase) if upcase_hex?
|
|
49
|
-
result = pre_post_fixed(result) unless base_default?
|
|
50
|
-
"#{prefix_symbol}#{result}"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private
|
|
54
|
-
|
|
55
|
-
def upcase_hex?
|
|
56
|
-
@base == 16 && data_reader[:hex_capital]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def prefix_symbol
|
|
60
|
-
if number.negative?
|
|
61
|
-
"-"
|
|
62
|
-
elsif data_reader[:number_sign]&.to_sym == :plus
|
|
63
|
-
"+"
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def pre_post_fixed(result)
|
|
68
|
-
if data_reader.key?(:base_postfix)
|
|
69
|
-
"#{result}#{data_reader[:base_postfix]}"
|
|
70
|
-
else
|
|
71
|
-
"#{@base_prefix}#{result}"
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def partition_tokens(number)
|
|
76
|
-
int, fraction = parse_number(number)
|
|
77
|
-
[
|
|
78
|
-
int,
|
|
79
|
-
fraction,
|
|
80
|
-
Numbers::Integer.new(data_reader),
|
|
81
|
-
Numbers::Fraction.new(data_reader),
|
|
82
|
-
Numbers::Significant.new(data_reader),
|
|
83
|
-
]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def precision_from(number)
|
|
87
|
-
return 0 if number.fix == number
|
|
88
|
-
|
|
89
|
-
parts = number.to_s(STRING_SYMBOLS[:f]).split(STRING_SYMBOLS[:dot])
|
|
90
|
-
parts.size == 2 ? parts[1].size : 0
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def parse_number(number, options = data_reader)
|
|
94
|
-
precision = options[:precision] || precision_from(number)
|
|
95
|
-
|
|
96
|
-
abs = round_to(number, precision).abs
|
|
97
|
-
num = if precision.zero?
|
|
98
|
-
abs.fix.to_s(STRING_SYMBOLS[:f])
|
|
99
|
-
else
|
|
100
|
-
abs.round(precision).to_s(STRING_SYMBOLS[:f])
|
|
101
|
-
end
|
|
102
|
-
num.split(STRING_SYMBOLS[:dot])
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def round_to(number, precision)
|
|
106
|
-
factor = BigDecimal(10).power(precision)
|
|
107
|
-
(number * factor).fix / factor
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def base_default?
|
|
111
|
-
@base == DEFAULT_BASE
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|