vector_number 0.4.3 → 0.6.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/README.md +47 -22
- data/doc/vector_space.svg +94 -0
- data/lib/vector_number/comparing.rb +103 -107
- data/lib/vector_number/converting.rb +137 -147
- data/lib/vector_number/enumerating.rb +94 -108
- data/lib/vector_number/math_converting.rb +113 -109
- data/lib/vector_number/mathing.rb +305 -312
- data/lib/vector_number/numeric_refinements.rb +7 -0
- data/lib/vector_number/querying.rb +136 -136
- data/lib/vector_number/special_unit.rb +36 -0
- data/lib/vector_number/stringifying.rb +89 -80
- data/lib/vector_number/version.rb +1 -1
- data/lib/vector_number.rb +155 -126
- data/sig/vector_number.rbs +141 -168
- metadata +14 -11
|
@@ -16,6 +16,10 @@ class VectorNumber
|
|
|
16
16
|
#
|
|
17
17
|
# @since 0.2.0
|
|
18
18
|
module NumericRefinements
|
|
19
|
+
# CommutativeShuttle refinement works only on 3.1, so it almost never actually runs.
|
|
20
|
+
# There are tests for the correct behavior, however, so it's fine.
|
|
21
|
+
# :nocov:
|
|
22
|
+
|
|
19
23
|
# Refinement module to provide a +#<=>+ method that can work backwards.
|
|
20
24
|
#
|
|
21
25
|
# @note Currently only applies to Complex on *3.1*,
|
|
@@ -49,6 +53,7 @@ class VectorNumber
|
|
|
49
53
|
warn "Numeric refinements are not available on Ruby < 3.1"
|
|
50
54
|
end
|
|
51
55
|
end
|
|
56
|
+
# :nocov:
|
|
52
57
|
|
|
53
58
|
# Refinement module to change Kernel#BigDecimal so it works with +#to_d+.
|
|
54
59
|
#
|
|
@@ -79,6 +84,7 @@ class VectorNumber
|
|
|
79
84
|
end
|
|
80
85
|
end
|
|
81
86
|
|
|
87
|
+
# :nocov:
|
|
82
88
|
if defined?(BigDecimal)
|
|
83
89
|
refine(Kernel) do
|
|
84
90
|
import_methods BigDecimalToD
|
|
@@ -86,5 +92,6 @@ class VectorNumber
|
|
|
86
92
|
warn "Numeric refinements are not available on Ruby < 3.1"
|
|
87
93
|
end
|
|
88
94
|
end
|
|
95
|
+
# :nocov:
|
|
89
96
|
end
|
|
90
97
|
end
|
|
@@ -1,150 +1,150 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class VectorNumber
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
# Whether this VectorNumber can be considered strictly numeric, e.g. real or complex.
|
|
8
|
-
#
|
|
9
|
-
# @example
|
|
10
|
-
# VectorNumber[2].numeric? # => true
|
|
11
|
-
# VectorNumber[2, 3i].numeric? # => true
|
|
12
|
-
# VectorNumber[2, "a"].numeric? # => false
|
|
13
|
-
# VectorNumber[2, 3i].numeric?(1) # => false
|
|
14
|
-
#
|
|
15
|
-
# @param dimensions [Integer] number of dimensions to consider "numeric"
|
|
16
|
-
# - 0 — zero
|
|
17
|
-
# - 1 — real number
|
|
18
|
-
# - 2 — complex number, etc.
|
|
19
|
-
# @return [Boolean]
|
|
20
|
-
# @raise [ArgumentError] if +dimensions+ is negative
|
|
21
|
-
#
|
|
22
|
-
# @since 0.2.0
|
|
23
|
-
def numeric?(dimensions = 2)
|
|
24
|
-
raise ArgumentError, "`dimensions` must be non-negative" unless dimensions >= 0
|
|
4
|
+
# @group Querying
|
|
5
|
+
#
|
|
6
|
+
# Mostly modelled after {::Complex}.
|
|
25
7
|
|
|
26
|
-
|
|
27
|
-
|
|
8
|
+
# Returns +true+ if all non-zero dimensions in this VectorNumber are numeric (real or complex),
|
|
9
|
+
# and +false+ otherwise.
|
|
10
|
+
#
|
|
11
|
+
# This is exactly the opposite of {#nonnumeric?}.
|
|
12
|
+
#
|
|
13
|
+
# @example
|
|
14
|
+
# VectorNumber[2].numeric? # => true
|
|
15
|
+
# VectorNumber[2, 3i].numeric? # => true
|
|
16
|
+
# VectorNumber[2, "a"].numeric? # => false
|
|
17
|
+
# VectorNumber[2, 3i].numeric?(1) # => false
|
|
18
|
+
#
|
|
19
|
+
# @param dimensions [Integer] number of dimensions to consider "numeric"
|
|
20
|
+
# - 0 — zero
|
|
21
|
+
# - 1 — real number
|
|
22
|
+
# - 2 — complex number
|
|
23
|
+
# @return [Boolean]
|
|
24
|
+
# @raise [ArgumentError] if +dimensions+ is negative
|
|
25
|
+
#
|
|
26
|
+
# @since 0.2.0
|
|
27
|
+
def numeric?(dimensions = 2)
|
|
28
|
+
raise ArgumentError, "`dimensions` must be non-negative" unless dimensions >= 0
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# VectorNumber[2].nonnumeric? # => false
|
|
33
|
-
# VectorNumber[2, 3i].nonnumeric? # => false
|
|
34
|
-
# VectorNumber[2, "a"].nonnumeric? # => true
|
|
35
|
-
# VectorNumber[2, 3i].nonnumeric?(1) # => true
|
|
36
|
-
#
|
|
37
|
-
# @param (see #numeric?)
|
|
38
|
-
# @return (see #numeric?)
|
|
39
|
-
# @raise (see #numeric?)
|
|
40
|
-
#
|
|
41
|
-
# @since 0.2.1
|
|
42
|
-
def nonnumeric?(dimensions = 2) = !numeric?(dimensions)
|
|
43
|
-
|
|
44
|
-
# Returns +true+ if all coefficients are finite, +false+ otherwise.
|
|
45
|
-
#
|
|
46
|
-
# @example
|
|
47
|
-
# VectorNumber[2].finite? # => true
|
|
48
|
-
# VectorNumber[Float::NAN].finite? # => false
|
|
49
|
-
# VectorNumber["a"].mult(Float::INFINITY).finite? # => false
|
|
50
|
-
#
|
|
51
|
-
# @return [Boolean]
|
|
52
|
-
#
|
|
53
|
-
# @since 0.1.0
|
|
54
|
-
def finite?
|
|
55
|
-
all? { |_u, v| v.finite? }
|
|
56
|
-
end
|
|
30
|
+
size <= dimensions &&
|
|
31
|
+
(0...dimensions).count { (unit = NUMERIC_UNITS[_1]) && @data[unit].nonzero? } == size
|
|
32
|
+
end
|
|
57
33
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
34
|
+
# Returns +true+ if this VectorNumber contains any non-zero dimensions with non-numeric units,
|
|
35
|
+
# and +false+ otherwise.
|
|
36
|
+
#
|
|
37
|
+
# This is exactly the opposite of {#numeric?}.
|
|
38
|
+
#
|
|
39
|
+
# @example
|
|
40
|
+
# VectorNumber[2].nonnumeric? # => false
|
|
41
|
+
# VectorNumber[2, 3i].nonnumeric? # => false
|
|
42
|
+
# VectorNumber[2, "a"].nonnumeric? # => true
|
|
43
|
+
# VectorNumber[2, 3i].nonnumeric?(1) # => true
|
|
44
|
+
#
|
|
45
|
+
# @param (see #numeric?)
|
|
46
|
+
# @return (see #numeric?)
|
|
47
|
+
# @raise (see #numeric?)
|
|
48
|
+
#
|
|
49
|
+
# @since 0.2.1
|
|
50
|
+
def nonnumeric?(dimensions = 2) = !numeric?(dimensions)
|
|
73
51
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
52
|
+
# Returns +true+ if all coefficients are finite, +false+ otherwise.
|
|
53
|
+
#
|
|
54
|
+
# @example
|
|
55
|
+
# VectorNumber[2].finite? # => true
|
|
56
|
+
# VectorNumber[Float::NAN].finite? # => false
|
|
57
|
+
# VectorNumber["a"].mult(Float::INFINITY).finite? # => false
|
|
58
|
+
#
|
|
59
|
+
# @return [Boolean]
|
|
60
|
+
def finite?
|
|
61
|
+
all? { |_u, v| v.finite? }
|
|
62
|
+
end
|
|
84
63
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
end
|
|
64
|
+
# Returns +1+ if any coefficients are non-finite, +nil+ otherwise.
|
|
65
|
+
#
|
|
66
|
+
# This behavior is the same as +Complex+'s.
|
|
67
|
+
#
|
|
68
|
+
# @example
|
|
69
|
+
# VectorNumber[2].infinite? # => nil
|
|
70
|
+
# VectorNumber[Float::NAN].infinite? # => 1
|
|
71
|
+
# VectorNumber["a"].mult(-Float::INFINITY).infinite? # => 1
|
|
72
|
+
#
|
|
73
|
+
# @return [1, nil]
|
|
74
|
+
def infinite?
|
|
75
|
+
finite? ? nil : 1 # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
|
76
|
+
end
|
|
99
77
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def positive?
|
|
113
|
-
!zero? && all? { |_u, c| c.positive? }
|
|
114
|
-
end
|
|
78
|
+
# Returns +true+ if there are no non-zero coefficients, and +false+ otherwise.
|
|
79
|
+
#
|
|
80
|
+
# This is synonymous with +size+ being 0.
|
|
81
|
+
#
|
|
82
|
+
# @example
|
|
83
|
+
# VectorNumber["c"].zero? # => false
|
|
84
|
+
# VectorNumber[].zero? # => true
|
|
85
|
+
#
|
|
86
|
+
# @see #size
|
|
87
|
+
#
|
|
88
|
+
# @return [Boolean]
|
|
89
|
+
def zero? = size.zero?
|
|
115
90
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
91
|
+
# Returns +self+ if there are any non-zero coefficients, +nil+ otherwise.
|
|
92
|
+
#
|
|
93
|
+
# This is synonymous with +size+ not being equal to 0.
|
|
94
|
+
# Behavior of returning self or +nil+ is the same as +Numeric+'s.
|
|
95
|
+
#
|
|
96
|
+
# @example
|
|
97
|
+
# VectorNumber["ab", "cd"].nonzero? # => (1⋅"ab" + 1⋅"cd")
|
|
98
|
+
# VectorNumber[].nonzero? # => nil
|
|
99
|
+
#
|
|
100
|
+
# @see #size
|
|
101
|
+
#
|
|
102
|
+
# @return [VectorNumber, nil]
|
|
103
|
+
def nonzero?
|
|
104
|
+
zero? ? nil : self # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
|
105
|
+
end
|
|
131
106
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
107
|
+
# Returns +true+ if number is non-zero and all non-zero coefficients are positive,
|
|
108
|
+
# and +false+ otherwise.
|
|
109
|
+
#
|
|
110
|
+
# @example
|
|
111
|
+
# VectorNumber["a"].positive? # => true
|
|
112
|
+
# VectorNumber[2].neg.positive? # => false
|
|
113
|
+
# (VectorNumber["1"] - VectorNumber[1]).positive? # => false
|
|
114
|
+
# VectorNumber[0].positive? # => false
|
|
115
|
+
#
|
|
116
|
+
# @return [Boolean]
|
|
117
|
+
def positive?
|
|
118
|
+
!zero? && all? { |_u, c| c.positive? }
|
|
119
|
+
end
|
|
142
120
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
121
|
+
# Returns +true+ if number is non-zero and all non-zero coefficients are negative,
|
|
122
|
+
# and +false+ otherwise.
|
|
123
|
+
#
|
|
124
|
+
# @example
|
|
125
|
+
# VectorNumber["a"].neg.negative? # => true
|
|
126
|
+
# VectorNumber[-2].neg.negative? # => false
|
|
127
|
+
# (VectorNumber["1"] - VectorNumber[1]).negative? # => false
|
|
128
|
+
# VectorNumber[0].negative? # => false
|
|
129
|
+
#
|
|
130
|
+
# @return [Boolean]
|
|
131
|
+
def negative?
|
|
132
|
+
!zero? && all? { |_u, c| c.negative? }
|
|
149
133
|
end
|
|
134
|
+
|
|
135
|
+
# Always returns +false+, as vectors are not real numbers.
|
|
136
|
+
#
|
|
137
|
+
# This behavior is the same as +Complex+'s.
|
|
138
|
+
#
|
|
139
|
+
# @see #numeric?
|
|
140
|
+
#
|
|
141
|
+
# @return [false]
|
|
142
|
+
def real? = false
|
|
143
|
+
|
|
144
|
+
# Always returns +false+, as vectors are not +Integer+s.
|
|
145
|
+
#
|
|
146
|
+
# @return [false]
|
|
147
|
+
#
|
|
148
|
+
# @since 0.2.1
|
|
149
|
+
def integer? = false
|
|
150
150
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class VectorNumber
|
|
4
|
+
# Class for representing special units.
|
|
5
|
+
#
|
|
6
|
+
# The public API consists of:
|
|
7
|
+
# - +#==+/+#eql?+/+#equal?+ (from +Object+)
|
|
8
|
+
# - +#hash+ (from +Object+)
|
|
9
|
+
# - {#to_s}
|
|
10
|
+
# - {#inspect}
|
|
11
|
+
#
|
|
12
|
+
# @since 0.6.0
|
|
13
|
+
class SpecialUnit
|
|
14
|
+
# @api private
|
|
15
|
+
# @param unit [#to_s] name for {#inspect}
|
|
16
|
+
# @param text [String] text for {#to_s}
|
|
17
|
+
def initialize(unit, text)
|
|
18
|
+
@unit = unit
|
|
19
|
+
@text = text
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Get predefined string representation of the unit.
|
|
23
|
+
#
|
|
24
|
+
# @return [String]
|
|
25
|
+
def to_s
|
|
26
|
+
@text
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get string representation of the unit for debugging.
|
|
30
|
+
#
|
|
31
|
+
# @return [String]
|
|
32
|
+
def inspect
|
|
33
|
+
"unit/#{@unit}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,96 +1,105 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class VectorNumber
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
invisible: "", # U+2062, zero-width multiplication operator
|
|
16
|
-
space: " ",
|
|
17
|
-
none: "",
|
|
18
|
-
}.freeze
|
|
4
|
+
# Predefined symbols for multiplication to display between unit and coefficient.
|
|
5
|
+
#
|
|
6
|
+
# @return [Hash{Symbol => String}]
|
|
7
|
+
MULT_STRINGS = {
|
|
8
|
+
asterisk: "*", # U+002A
|
|
9
|
+
cross: "×", # U+00D7
|
|
10
|
+
dot: "⋅", # U+22C5
|
|
11
|
+
invisible: "", # U+2062, zero-width multiplication operator
|
|
12
|
+
space: " ",
|
|
13
|
+
none: "",
|
|
14
|
+
}.freeze
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
# @example
|
|
23
|
-
# VectorNumber[5, "s"].to_s # => "5 + 1⋅'s'"
|
|
24
|
-
# VectorNumber["s", 5].to_s # => "1⋅'s' + 5"
|
|
25
|
-
# @example with :mult argument
|
|
26
|
-
# VectorNumber[5, "s"].to_s(mult: :asterisk) # => "5 + 1*'s'"
|
|
27
|
-
# @example :mult option specified for the vector
|
|
28
|
-
# VectorNumber[5, "s", mult: :none].to_s # => "5 + 1's'"
|
|
29
|
-
#
|
|
30
|
-
# @param mult [Symbol, String]
|
|
31
|
-
# text to use between coefficient and unit,
|
|
32
|
-
# can be one of the keys in {MULT_STRINGS} or an arbitrary string
|
|
33
|
-
# @return [String]
|
|
34
|
-
# @raise [ArgumentError]
|
|
35
|
-
# if +mult+ is not a String and is not in {MULT_STRINGS}'s keys
|
|
36
|
-
#
|
|
37
|
-
# @since 0.1.0
|
|
38
|
-
def to_s(mult: options[:mult])
|
|
39
|
-
return "0" if zero?
|
|
16
|
+
# @group Miscellaneous methods
|
|
40
17
|
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
# Return string representation of the vector.
|
|
19
|
+
#
|
|
20
|
+
# An optional block can be supplied to provide customized substrings
|
|
21
|
+
# for each unit and coefficient pair.
|
|
22
|
+
# Care needs to be taken in handling +VectorNumber::R+ and +VectorNumber::I+ units.
|
|
23
|
+
# {.numeric_unit?} can be used to check if a particular unit needs special handling.
|
|
24
|
+
#
|
|
25
|
+
# @example
|
|
26
|
+
# VectorNumber[5, "s"].to_s # => "5 + 1⋅\"s\""
|
|
27
|
+
# VectorNumber["s", 5].to_s # => "1⋅\"s\" + 5"
|
|
28
|
+
# @example with :mult argument
|
|
29
|
+
# VectorNumber[5, :s].to_s(mult: :asterisk) # => "5 + 1*s"
|
|
30
|
+
# (-VectorNumber[5, :s]).to_s(mult: "~~~") # => "-5 - 1~~~s"
|
|
31
|
+
# @example with a block
|
|
32
|
+
# VectorNumber[5, :s].to_s { |k, v| "#{format("%+.0f", v)}%#{k}" } # => "+5%1+1%s"
|
|
33
|
+
# VectorNumber[5, :s].to_s(mult: :cross) { |k, v, i, op|
|
|
34
|
+
# "#{',' unless i.zero?}#{v}#{op+k.to_s unless k == VectorNumber::R}"
|
|
35
|
+
# } # => "5,1×s"
|
|
36
|
+
#
|
|
37
|
+
# @param mult [Symbol, String]
|
|
38
|
+
# text to use between coefficient and unit,
|
|
39
|
+
# can be one of the keys in {MULT_STRINGS} or an arbitrary string
|
|
40
|
+
# @yieldparam unit [Object]
|
|
41
|
+
# @yieldparam coefficient [Numeric]
|
|
42
|
+
# @yieldparam index [Integer]
|
|
43
|
+
# @yieldparam operator [String]
|
|
44
|
+
# @yieldreturn [String] a string for this unit and coefficient
|
|
45
|
+
# @return [String]
|
|
46
|
+
# @raise [ArgumentError]
|
|
47
|
+
# if +mult+ is not a String and is not in {MULT_STRINGS}'s keys
|
|
48
|
+
def to_s(mult: :dot, &block)
|
|
49
|
+
if !mult.is_a?(String) && !MULT_STRINGS.key?(mult)
|
|
50
|
+
raise ArgumentError, "unknown key #{mult.inspect}", caller
|
|
51
|
+
end
|
|
52
|
+
return "0" if zero?
|
|
53
|
+
|
|
54
|
+
operator = mult.is_a?(String) ? mult : MULT_STRINGS[mult]
|
|
55
|
+
build_string(operator, &block)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Return string representation of the vector.
|
|
59
|
+
#
|
|
60
|
+
# This is similar to +Complex#inspect+: it returns result of {#to_s} in round brackets.
|
|
61
|
+
#
|
|
62
|
+
# @example
|
|
63
|
+
# VectorNumber[5, :s].inspect # => "(5 + 1⋅s)"
|
|
64
|
+
#
|
|
65
|
+
# @return [String]
|
|
66
|
+
#
|
|
67
|
+
# @see to_s
|
|
68
|
+
def inspect
|
|
69
|
+
"(#{self})"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# @param operator [String]
|
|
75
|
+
# @return [String]
|
|
76
|
+
def build_string(operator)
|
|
77
|
+
result = +""
|
|
78
|
+
each_with_index do |(unit, coefficient), index|
|
|
79
|
+
if block_given?
|
|
80
|
+
result << (yield unit, coefficient, index, operator).to_s
|
|
81
|
+
else
|
|
43
82
|
if index.zero?
|
|
44
83
|
result << "-" if coefficient.negative?
|
|
45
84
|
else
|
|
46
85
|
result << (coefficient.positive? ? " + " : " - ")
|
|
47
86
|
end
|
|
48
|
-
result << value_to_s(unit, coefficient.abs,
|
|
87
|
+
result << value_to_s(unit, coefficient.abs, operator)
|
|
49
88
|
end
|
|
50
|
-
result
|
|
51
89
|
end
|
|
90
|
+
result
|
|
91
|
+
end
|
|
52
92
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
64
|
-
# @since 0.1.0
|
|
65
|
-
def inspect
|
|
66
|
-
# TODO: Probably make this independent of options.
|
|
67
|
-
"(#{self})"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
private
|
|
71
|
-
|
|
72
|
-
# @param unit [Object]
|
|
73
|
-
# @param coefficient [Numeric]
|
|
74
|
-
# @param mult [Symbol, String]
|
|
75
|
-
# @return [String]
|
|
76
|
-
# @raise [ArgumentError] if +mult+ is not in {MULT_STRINGS}'s keys
|
|
77
|
-
#
|
|
78
|
-
# @since 0.1.0
|
|
79
|
-
def value_to_s(unit, coefficient, mult:)
|
|
80
|
-
if !mult.is_a?(String) && !MULT_STRINGS.key?(mult)
|
|
81
|
-
raise ArgumentError, "unknown key #{mult.inspect}", caller
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
case unit
|
|
85
|
-
when R
|
|
86
|
-
coefficient.to_s
|
|
87
|
-
when I
|
|
88
|
-
"#{coefficient}i"
|
|
89
|
-
else
|
|
90
|
-
unit = "'#{unit}'" if unit.is_a?(String)
|
|
91
|
-
operator = mult.is_a?(String) ? mult : MULT_STRINGS[mult]
|
|
92
|
-
"#{coefficient}#{operator}#{unit}"
|
|
93
|
-
end
|
|
93
|
+
# @param unit [Object]
|
|
94
|
+
# @param coefficient [Numeric]
|
|
95
|
+
# @param operator [String]
|
|
96
|
+
# @return [String]
|
|
97
|
+
def value_to_s(unit, coefficient, operator)
|
|
98
|
+
if NUMERIC_UNITS.include?(unit)
|
|
99
|
+
"#{coefficient}#{unit}"
|
|
100
|
+
else
|
|
101
|
+
unit = unit.inspect if unit.is_a?(String)
|
|
102
|
+
"#{coefficient}#{operator}#{unit}"
|
|
94
103
|
end
|
|
95
104
|
end
|
|
96
105
|
end
|