vector_number 0.5.0 → 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 +46 -21
- data/doc/vector_space.svg +94 -0
- data/lib/vector_number/comparing.rb +1 -8
- data/lib/vector_number/converting.rb +0 -15
- data/lib/vector_number/enumerating.rb +0 -13
- data/lib/vector_number/math_converting.rb +12 -12
- data/lib/vector_number/mathing.rb +26 -26
- data/lib/vector_number/querying.rb +12 -19
- data/lib/vector_number/special_unit.rb +36 -0
- data/lib/vector_number/stringifying.rb +50 -38
- data/lib/vector_number/version.rb +1 -1
- data/lib/vector_number.rb +47 -88
- data/sig/vector_number.rbs +23 -17
- metadata +13 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 686890049523273762a1dea1835f990e987d556bf9399356cf53572727df7ad9
|
|
4
|
+
data.tar.gz: 7c90c791c17eb9ffdcb1455174141ca857456642770acdff2e9d2ee3e19e4fab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d22a64381f58d7c8a1dd858510734e960326af64ca9f1d109c7fceee0f7e7fd2dfee2df7ba5b7a16fe5fc67dd1b192c60caa069215c20c03e231cee050a9acd0
|
|
7
|
+
data.tar.gz: 1c2de92ef2ae14f127c0fcd121ad361cb552875999a9c3eba31d90896fb104448c925793b34d47695785042a6a03420605d4ba017c91683348ac47f074cc7c86
|
data/README.md
CHANGED
|
@@ -18,12 +18,7 @@ Features:
|
|
|
18
18
|
- Enjoy a mix of vector-, complex- and polynomial-like behavior at appropriate times.
|
|
19
19
|
- No dependencies, no extensions. It just works!
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
- [vector_space](https://github.com/tomstuart/vector_space) aims to provide typed vector spaces with limited dimensions and nice formatting;
|
|
23
|
-
- [named_vector](https://rubygems.org/gems/named_vector) provides simple vectors with named dimensions;
|
|
24
|
-
- various quaternion libraries like [quaternion](https://github.com/tanahiro/quaternion) or [rmath3d](https://github.com/vaiorabbit/rmath3d).
|
|
25
|
-
|
|
26
|
-
However, none of them have been updated in *years*.
|
|
21
|
+
Other people have created some similar gems over the years, like [vector_space](https://github.com/tomstuart/vector_space) or [named_vector](https://rubygems.org/gems/named_vector) but they don't have the characterics that I wanted, and none of them have been updated in *years*.
|
|
27
22
|
|
|
28
23
|
## Table of contents
|
|
29
24
|
|
|
@@ -31,10 +26,12 @@ However, none of them have been updated in *years*.
|
|
|
31
26
|
- [Ruby engine support status](#ruby-engine-support-status)
|
|
32
27
|
- [Usage](#usage)
|
|
33
28
|
- [Basics](#basics)
|
|
29
|
+
- [Getting values back](#getting-values-back)
|
|
34
30
|
- [(Somewhat) advanced usage](#somewhat-advanced-usage)
|
|
35
31
|
- [Frozenness](#frozenness)
|
|
36
32
|
- [Numerical behavior](#numerical-behavior)
|
|
37
33
|
- [Enumeration and hash-like behavior](#enumeration-and-hash-like-behavior)
|
|
34
|
+
- [Conceptual basis](#conceptual-basis)
|
|
38
35
|
- [Development](#development)
|
|
39
36
|
- [Contributing](#contributing)
|
|
40
37
|
- [License](#license)
|
|
@@ -54,8 +51,8 @@ gem "vector_number"
|
|
|
54
51
|
### Ruby engine support status
|
|
55
52
|
|
|
56
53
|
VectorNumber is developed on MRI (CRuby) but should work on other engines too.
|
|
57
|
-
- TruffleRuby:
|
|
58
|
-
- JRuby:
|
|
54
|
+
- TruffleRuby: minor differences in behavior, but otherwise works as expected.
|
|
55
|
+
- JRuby: minor differences in behavior, but otherwise works as expected.
|
|
59
56
|
- Other engines: untested, but should work, depending on compatibility with MRI.
|
|
60
57
|
|
|
61
58
|
## Usage
|
|
@@ -66,12 +63,12 @@ VectorNumber is developed on MRI (CRuby) but should work on other engines too.
|
|
|
66
63
|
|
|
67
64
|
### Basics
|
|
68
65
|
|
|
69
|
-
VectorNumbers are mostly useful for
|
|
66
|
+
VectorNumbers are mostly useful for summing up heterogeneous objects:
|
|
70
67
|
```ruby
|
|
71
|
-
sum = [4
|
|
72
|
-
sum # => (17 + 2⋅
|
|
73
|
-
sum.to_h # => {1=>17, "death"=>2, nil=>1}
|
|
74
|
-
sum.to_a # => [[1, 17], ["death", 2], [nil, 1]]
|
|
68
|
+
sum = VectorNumber[4] + "death" + "death" + nil
|
|
69
|
+
sum # => (17 + 2⋅"death" + 1⋅)
|
|
70
|
+
sum.to_h # => {unit/1 => 17, "death" => 2, nil => 1}
|
|
71
|
+
sum.to_a # => [[unit/1, 17], ["death", 2], [nil, 1]]
|
|
75
72
|
|
|
76
73
|
# Alternatively, the same result can be equivalently (and more efficiently)
|
|
77
74
|
# achieved by passing all values to a constructor:
|
|
@@ -81,17 +78,36 @@ VectorNumber.new([4, "death", "death", 13, nil])
|
|
|
81
78
|
|
|
82
79
|
Doing arithmetic with vectors is simple and intuitive:
|
|
83
80
|
```ruby
|
|
84
|
-
VectorNumber["string"] + "string" # => (2⋅
|
|
85
|
-
VectorNumber["string"] - "str" # => (1⋅
|
|
86
|
-
VectorNumber[5] + VectorNumber["string"] - 0.5 # => (4.5 + 1⋅
|
|
87
|
-
VectorNumber["string", "string", "string", "str"] # => (3⋅
|
|
81
|
+
VectorNumber["string"] + "string" # => (2⋅"string")
|
|
82
|
+
VectorNumber["string"] - "str" # => (1⋅"string" - 1⋅"str")
|
|
83
|
+
VectorNumber[5] + VectorNumber["string"] - 0.5 # => (4.5 + 1⋅"string")
|
|
84
|
+
VectorNumber["string", "string", "string", "str"] # => (3⋅"string" + 1⋅"str")
|
|
88
85
|
# Multiply and divide by any real number:
|
|
89
|
-
VectorNumber[:s] * 2 + VectorNumber["string"] * 0.3 # => (2⋅s + 0.3⋅
|
|
86
|
+
VectorNumber[:s] * 2 + VectorNumber["string"] * 0.3 # => (2⋅s + 0.3⋅"string")
|
|
90
87
|
VectorNumber[:s] / VectorNumber[3] # => (1/3⋅s)
|
|
91
|
-
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Ruby numbers rely on `#coerce` to promote values to a common type. This allows using regular numbers as first operand in arithmetic operations:
|
|
91
|
+
```ruby
|
|
92
|
+
2 + VectorNumber["string"] # => (2 + 1⋅"string")
|
|
92
93
|
1/3r * VectorNumber[[]] # => (1/3⋅[])
|
|
94
|
+
13 / VectorNumber[2] # => (13/2)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> [!NOTE]
|
|
98
|
+
> VectorNumbers don't perform "integer division" to prevent unexpected loss of precision. `#div` and rounding methods can achieve this if required.
|
|
99
|
+
|
|
100
|
+
#### Getting values back
|
|
101
|
+
The simplest way to get a value for a specific unit is to use the `#[]` method:
|
|
102
|
+
```ruby
|
|
103
|
+
VectorNumber["string", "string", "string", "str"]["string"] # => 3
|
|
104
|
+
VectorNumber["string", "string", "string", "str"]["str"] # => 1
|
|
105
|
+
VectorNumber["string", "string", "string", "str"]["nonexistent"] # => 0
|
|
93
106
|
```
|
|
94
107
|
|
|
108
|
+
> [!NOTE]
|
|
109
|
+
> Accessing a unit that doesn't exist returns 0, not `nil` as you might expect.
|
|
110
|
+
|
|
95
111
|
### (Somewhat) advanced usage
|
|
96
112
|
|
|
97
113
|
> [!TIP]
|
|
@@ -118,8 +134,17 @@ VectorNumbers implement `each` (`each_pair`) in the same way as Hash does, allow
|
|
|
118
134
|
|
|
119
135
|
There are also the usual `[]`, `unit?` (`key?`), `units` (`keys`), `coefficients` (`values`) methods. `to_h` and `to_a` can be used if a regular Hash or Array is needed.
|
|
120
136
|
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
## Conceptual basis
|
|
138
|
+
|
|
139
|
+
VectorNumbers are based on the concept of a vector space over the field of real numbers (real vector space). In the case of VectorNumber, the dimensionality of the vector space is countably infinite, as most distinct objects in Ruby signify a separate dimension.
|
|
140
|
+
|
|
141
|
+
For most dimensions, an object is that distinct dimension's unit. There are two exceptions currently: real unit (1) and imaginary unit (i) which define the real and imaginary dimensions and subsume all real and complex numbers. A VectorNumber can not be a unit itself. Distinction of objects is determined by `eql?`, same as for Hash.
|
|
142
|
+
|
|
143
|
+
Length of a VectorNumber in any given dimension is given by a real number, called its coefficient. All dimensions are linearly independent — change in one coefficient does not affect any other coefficient. There is no distinction between a dimension explicitly specified as having a 0 coefficient (or arriving at 0 through calculation) and a dimension not specified at all.
|
|
144
|
+
|
|
145
|
+
This might be more easily imagined as a geometric vector. For example, this is a graphic representation of a vector `3 * VectorNumber[1] + 2 * VectorNumber[1i] + 3 * VectorNumber["string"] + 4.5 * VectorNumber[[1,2,3]]` in the vector space:
|
|
146
|
+
|
|
147
|
+

|
|
123
148
|
|
|
124
149
|
## Development
|
|
125
150
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<svg width="500" height="400" viewBox="-250 -200 500 400" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<style>
|
|
3
|
+
text {
|
|
4
|
+
font-family: 'Arial', sans-serif;
|
|
5
|
+
font-size: 14px;
|
|
6
|
+
}
|
|
7
|
+
.axis-label {
|
|
8
|
+
font-weight: bold;
|
|
9
|
+
font-size: 16px;
|
|
10
|
+
}
|
|
11
|
+
.dim-label {
|
|
12
|
+
font-size: 12px;
|
|
13
|
+
fill: #666;
|
|
14
|
+
}
|
|
15
|
+
</style>
|
|
16
|
+
|
|
17
|
+
<!-- Background -->
|
|
18
|
+
<rect x="-250" y="-200" width="500" height="400" fill="#fff0cc"/>
|
|
19
|
+
|
|
20
|
+
<!-- Coordinate system center -->
|
|
21
|
+
<circle cx="0" cy="0" r="5" fill="#000"/>
|
|
22
|
+
<text x="-50" y="-5" class="dim-label">(0,0,...)</text>
|
|
23
|
+
|
|
24
|
+
<!-- 1 (numeric) axis -->
|
|
25
|
+
<line x1="0" y1="0" x2="150" y2="0" stroke="#2196F3" stroke-width="2"/>
|
|
26
|
+
<polygon points="155,0 145,-4 145,4" fill="#2196F3"/>
|
|
27
|
+
<text x="160" y="5" class="axis-label">1</text>
|
|
28
|
+
|
|
29
|
+
<!-- i (imaginary) axis -->
|
|
30
|
+
<line x1="0" y1="0" x2="0" y2="-150" stroke="#4CAF50" stroke-width="2"/>
|
|
31
|
+
<polygon points="0,-155 -4,-145 4,-145" fill="#4CAF50"/>
|
|
32
|
+
<text x="10" y="-145" class="axis-label">i</text>
|
|
33
|
+
|
|
34
|
+
<!-- [1,2,3] axis -->
|
|
35
|
+
<line x1="0" y1="0" x2="-150" y2="150" stroke="#FF9800" stroke-width="2"/>
|
|
36
|
+
<polygon points="-154,154 -150,144 -144,150" fill="#FF9800"/>
|
|
37
|
+
<text x="-205" y="140" class="axis-label">[1,2,3]</text>
|
|
38
|
+
|
|
39
|
+
<!-- "string" axis -->
|
|
40
|
+
<line x1="0" y1="0" x2="100" y2="150" stroke="#9C27B0" stroke-width="2"/>
|
|
41
|
+
<polygon points="103,155 101,144 93,149" fill="#9C27B0"/>
|
|
42
|
+
<text x="110" y="160" class="axis-label">"string"</text>
|
|
43
|
+
|
|
44
|
+
<!-- VectorNumber -->
|
|
45
|
+
<line x1="0" y1="0" x2="118" y2="-78" stroke="#F44336" stroke-width="3"/>
|
|
46
|
+
<polygon points="120,-80 107,-78 113,-68" fill="#F44336"/>
|
|
47
|
+
<text x="120" y="-90" text-anchor="middle" font-weight="bold" fill="#F44336">
|
|
48
|
+
(3 + 2i + 3⋅"string" + 4.5⋅[1,2,3])
|
|
49
|
+
</text>
|
|
50
|
+
|
|
51
|
+
<!-- Projection lines to axes -->
|
|
52
|
+
<!-- To numeric axis -->
|
|
53
|
+
<line x1="120" y1="-80" x2="120" y2="0" stroke="#2196F3" stroke-width="1" stroke-dasharray="5,5"/>
|
|
54
|
+
<circle cx="120" cy="0" r="3" fill="#2196F3"/>
|
|
55
|
+
<text x="120" y="15" class="dim-label">3</text>
|
|
56
|
+
|
|
57
|
+
<!-- To imaginary axis -->
|
|
58
|
+
<line x1="120" y1="-80" x2="0" y2="-80" stroke="#4CAF50" stroke-width="1" stroke-dasharray="5,5"/>
|
|
59
|
+
<circle cx="0" cy="-80" r="3" fill="#4CAF50"/>
|
|
60
|
+
<text x="-15" y="-80" class="dim-label">2</text>
|
|
61
|
+
|
|
62
|
+
<!-- To [1,2,3] axis -->
|
|
63
|
+
<line x1="120" y1="-80" x2="-90" y2="90" stroke="#FF9800" stroke-width="1" stroke-dasharray="5,5"/>
|
|
64
|
+
<circle cx="-90" cy="90" r="3" fill="#FF9800"/>
|
|
65
|
+
<text x="-115" y="90" class="dim-label">4.5</text>
|
|
66
|
+
|
|
67
|
+
<!-- To "string" axis -->
|
|
68
|
+
<line x1="120" y1="-80" x2="55" y2="83" stroke="#9C27B0" stroke-width="1" stroke-dasharray="5,5"/>
|
|
69
|
+
<circle cx="55" cy="83" r="3" fill="#9C27B0"/>
|
|
70
|
+
<text x="45" y="95" class="dim-label">3</text>
|
|
71
|
+
|
|
72
|
+
<!-- Legend -->
|
|
73
|
+
<rect x="-220" y="-180" width="180" height="145" fill="white" stroke="#ccc" stroke-width="1"/>
|
|
74
|
+
|
|
75
|
+
<line x1="-210" y1="-160" x2="-202" y2="-168" stroke="#F44336" stroke-width="3"/>
|
|
76
|
+
<polygon points="-200,-170 -205,-169 -201,-165" fill="#F44336"/>
|
|
77
|
+
<text x="-190" y="-160">VectorNumber</text>
|
|
78
|
+
|
|
79
|
+
<line x1="-212" y1="-145" x2="-200" y2="-145" stroke="#2196F3" stroke-width="2"/>
|
|
80
|
+
<text x="-190" y="-140">Real dimension</text>
|
|
81
|
+
|
|
82
|
+
<line x1="-212" y1="-125" x2="-200" y2="-125" stroke="#4CAF50" stroke-width="2"/>
|
|
83
|
+
<text x="-190" y="-120">Imaginary dimension</text>
|
|
84
|
+
|
|
85
|
+
<line x1="-212" y1="-105" x2="-200" y2="-105" stroke="#9C27B0" stroke-width="2"/>
|
|
86
|
+
<text x="-190" y="-100">"string" dimension</text>
|
|
87
|
+
|
|
88
|
+
<line x1="-212" y1="-85" x2="-200" y2="-85" stroke="#FF9800" stroke-width="2"/>
|
|
89
|
+
<text x="-190" y="-80">[1,2,3] dimension</text>
|
|
90
|
+
|
|
91
|
+
<line x1="-212" y1="-65" x2="-200" y2="-65" stroke="gray" stroke-width="2"/>
|
|
92
|
+
<text x="-190" y="-60">Zero dimensions</text>
|
|
93
|
+
<text x="-190" y="-45">(not portrayed)</text>
|
|
94
|
+
</svg>
|
|
@@ -49,8 +49,6 @@ class VectorNumber
|
|
|
49
49
|
# and it has exactly the same units and coefficients, though possibly in a different order.
|
|
50
50
|
# Additionally, `a.eql?(b)` implies `a.hash == b.hash`.
|
|
51
51
|
#
|
|
52
|
-
# Note that {#options} are not considered for equality.
|
|
53
|
-
#
|
|
54
52
|
# @example
|
|
55
53
|
# VectorNumber["a", "b", "c"].eql? VectorNumber["c", "b", "a"] # => true
|
|
56
54
|
# VectorNumber[3.13].eql? 3.13 # => false
|
|
@@ -60,8 +58,6 @@ class VectorNumber
|
|
|
60
58
|
#
|
|
61
59
|
# @param other [Object]
|
|
62
60
|
# @return [Boolean]
|
|
63
|
-
#
|
|
64
|
-
# @since 0.1.0
|
|
65
61
|
def eql?(other)
|
|
66
62
|
return true if equal?(other)
|
|
67
63
|
return false unless other.is_a?(VectorNumber)
|
|
@@ -71,12 +67,9 @@ class VectorNumber
|
|
|
71
67
|
|
|
72
68
|
# Generate an Integer hash value for self.
|
|
73
69
|
#
|
|
74
|
-
# Hash values are stable during runtime, but not between processes.
|
|
75
|
-
# Options are disregarded for hash calculation.
|
|
76
|
-
#
|
|
77
70
|
# @example
|
|
78
71
|
# VectorNumber["b", "a"].hash # => 3081872088394655324
|
|
79
|
-
# VectorNumber["a", "b"
|
|
72
|
+
# VectorNumber["a", "b"].hash # => 3081872088394655324
|
|
80
73
|
# VectorNumber["b", "c"].hash # => -1002381358514682371
|
|
81
74
|
#
|
|
82
75
|
# @return [Integer]
|
|
@@ -10,8 +10,6 @@ class VectorNumber
|
|
|
10
10
|
# VectorNumber["a"].real # => 0
|
|
11
11
|
#
|
|
12
12
|
# @return [Integer, Float, Rational, BigDecimal]
|
|
13
|
-
#
|
|
14
|
-
# @since 0.1.0
|
|
15
13
|
def real = @data[R]
|
|
16
14
|
|
|
17
15
|
# Return imaginary part of the number.
|
|
@@ -21,8 +19,6 @@ class VectorNumber
|
|
|
21
19
|
# VectorNumber["a", Complex(1, 2r)].imag # => (2/1)
|
|
22
20
|
#
|
|
23
21
|
# @return [Integer, Float, Rational, BigDecimal]
|
|
24
|
-
#
|
|
25
|
-
# @since 0.1.0
|
|
26
22
|
def imaginary = @data[I]
|
|
27
23
|
|
|
28
24
|
# @since 0.2.1
|
|
@@ -42,15 +38,12 @@ class VectorNumber
|
|
|
42
38
|
#
|
|
43
39
|
# @return [Integer]
|
|
44
40
|
# @raise [RangeError] if any non-real part is non-zero
|
|
45
|
-
#
|
|
46
|
-
# @since 0.1.0
|
|
47
41
|
def to_i
|
|
48
42
|
raise_convert_error(Integer) unless numeric?(1)
|
|
49
43
|
|
|
50
44
|
real.to_i
|
|
51
45
|
end
|
|
52
46
|
|
|
53
|
-
# @since 0.1.0
|
|
54
47
|
alias to_int to_i
|
|
55
48
|
|
|
56
49
|
# Return value as a Float if only real part is non-zero.
|
|
@@ -66,8 +59,6 @@ class VectorNumber
|
|
|
66
59
|
#
|
|
67
60
|
# @return [Float]
|
|
68
61
|
# @raise [RangeError] if any non-real part is non-zero
|
|
69
|
-
#
|
|
70
|
-
# @since 0.1.0
|
|
71
62
|
def to_f
|
|
72
63
|
raise_convert_error(Float) unless numeric?(1)
|
|
73
64
|
|
|
@@ -87,8 +78,6 @@ class VectorNumber
|
|
|
87
78
|
#
|
|
88
79
|
# @return [Rational]
|
|
89
80
|
# @raise [RangeError] if any non-real part is non-zero
|
|
90
|
-
#
|
|
91
|
-
# @since 0.1.0
|
|
92
81
|
def to_r
|
|
93
82
|
raise_convert_error(Rational) unless numeric?(1)
|
|
94
83
|
|
|
@@ -117,8 +106,6 @@ class VectorNumber
|
|
|
117
106
|
#
|
|
118
107
|
# @see Kernel.BigDecimal
|
|
119
108
|
# @see NumericRefinements
|
|
120
|
-
#
|
|
121
|
-
# @since 0.1.0
|
|
122
109
|
def to_d(ndigits = nil)
|
|
123
110
|
raise_convert_error(BigDecimal) unless numeric?(1)
|
|
124
111
|
|
|
@@ -141,8 +128,6 @@ class VectorNumber
|
|
|
141
128
|
#
|
|
142
129
|
# @return [Complex]
|
|
143
130
|
# @raise [RangeError] if any non-real, non-imaginary part is non-zero
|
|
144
|
-
#
|
|
145
|
-
# @since 0.1.0
|
|
146
131
|
def to_c
|
|
147
132
|
raise_convert_error(Complex) unless numeric?(2)
|
|
148
133
|
|
|
@@ -7,8 +7,6 @@ class VectorNumber
|
|
|
7
7
|
# @example using Enumerable methods
|
|
8
8
|
# VectorNumber["a", "b", 6].include?(["a", 1]) # => true
|
|
9
9
|
# VectorNumber["a", "b", 6].select { |u, c| u.is_a?(String) } # => [["a", 1], ["b", 1]]
|
|
10
|
-
#
|
|
11
|
-
# @since 0.1.0
|
|
12
10
|
include ::Enumerable
|
|
13
11
|
|
|
14
12
|
# Iterate through every pair of unit and coefficient.
|
|
@@ -34,8 +32,6 @@ class VectorNumber
|
|
|
34
32
|
#
|
|
35
33
|
# @see Enumerable
|
|
36
34
|
# @see Enumerator
|
|
37
|
-
#
|
|
38
|
-
# @since 0.1.0
|
|
39
35
|
def each(&block)
|
|
40
36
|
return to_enum { size } unless block_given?
|
|
41
37
|
|
|
@@ -43,7 +39,6 @@ class VectorNumber
|
|
|
43
39
|
self
|
|
44
40
|
end
|
|
45
41
|
|
|
46
|
-
# @since 0.1.0
|
|
47
42
|
alias each_pair each
|
|
48
43
|
|
|
49
44
|
# Get a list of units with non-zero coefficients.
|
|
@@ -53,11 +48,8 @@ class VectorNumber
|
|
|
53
48
|
# VectorNumber.new.keys # => []
|
|
54
49
|
#
|
|
55
50
|
# @return [Array<Object>]
|
|
56
|
-
#
|
|
57
|
-
# @since 0.1.0
|
|
58
51
|
def units = @data.keys
|
|
59
52
|
|
|
60
|
-
# @since 0.1.0
|
|
61
53
|
alias keys units
|
|
62
54
|
|
|
63
55
|
# Get a list of non-zero coefficients.
|
|
@@ -67,11 +59,8 @@ class VectorNumber
|
|
|
67
59
|
# VectorNumber.new.values # => []
|
|
68
60
|
#
|
|
69
61
|
# @return [Array<Numeric>]
|
|
70
|
-
#
|
|
71
|
-
# @since 0.1.0
|
|
72
62
|
def coefficients = @data.values
|
|
73
63
|
|
|
74
|
-
# @since 0.1.0
|
|
75
64
|
alias values coefficients
|
|
76
65
|
|
|
77
66
|
# Get mutable hash with vector's data.
|
|
@@ -83,8 +72,6 @@ class VectorNumber
|
|
|
83
72
|
# VectorNumber["a", "b", 6].to_h["c"] # => 0
|
|
84
73
|
#
|
|
85
74
|
# @return [Hash{Object => Numeric}]
|
|
86
|
-
#
|
|
87
|
-
# @since 0.1.0
|
|
88
75
|
def to_h(&block)
|
|
89
76
|
# TODO: Remove block argument.
|
|
90
77
|
if block_given?
|
|
@@ -38,8 +38,8 @@ class VectorNumber
|
|
|
38
38
|
# @example
|
|
39
39
|
# VectorNumber[5.39].truncate # => (5)
|
|
40
40
|
# VectorNumber[-5.35i].truncate # => (-5i)
|
|
41
|
-
# VectorNumber[-5.35i, "i"].truncate # => (-5i + 1⋅
|
|
42
|
-
# VectorNumber[-5.35i, "i"].truncate(1) # => (-5.3i + 1⋅
|
|
41
|
+
# VectorNumber[-5.35i, "i"].truncate # => (-5i + 1⋅"i")
|
|
42
|
+
# VectorNumber[-5.35i, "i"].truncate(1) # => (-5.3i + 1⋅"i")
|
|
43
43
|
# VectorNumber[-5.35i, "i"].truncate(-1) # => (0)
|
|
44
44
|
#
|
|
45
45
|
# @param digits [Integer]
|
|
@@ -55,9 +55,9 @@ class VectorNumber
|
|
|
55
55
|
# @example
|
|
56
56
|
# VectorNumber[5.39].ceil # => (6)
|
|
57
57
|
# VectorNumber[-5.35i].ceil # => (-5i)
|
|
58
|
-
# VectorNumber[-5.35i, "i"].ceil # => (-5i + 1⋅
|
|
59
|
-
# VectorNumber[-5.35i, "i"].ceil(1) # => (-5.3i + 1⋅
|
|
60
|
-
# VectorNumber[-5.35i, "i"].ceil(-1) # => (10⋅
|
|
58
|
+
# VectorNumber[-5.35i, "i"].ceil # => (-5i + 1⋅"i")
|
|
59
|
+
# VectorNumber[-5.35i, "i"].ceil(1) # => (-5.3i + 1⋅"i")
|
|
60
|
+
# VectorNumber[-5.35i, "i"].ceil(-1) # => (10⋅"i")
|
|
61
61
|
#
|
|
62
62
|
# @param digits [Integer]
|
|
63
63
|
# @return [VectorNumber]
|
|
@@ -72,8 +72,8 @@ class VectorNumber
|
|
|
72
72
|
# @example
|
|
73
73
|
# VectorNumber[5.39].floor # => (5)
|
|
74
74
|
# VectorNumber[-5.35i].floor # => (-6i)
|
|
75
|
-
# VectorNumber[-5.35i, "i"].floor # => (-6i + 1⋅
|
|
76
|
-
# VectorNumber[-5.35i, "i"].floor(1) # => (-5.4i + 1⋅
|
|
75
|
+
# VectorNumber[-5.35i, "i"].floor # => (-6i + 1⋅"i")
|
|
76
|
+
# VectorNumber[-5.35i, "i"].floor(1) # => (-5.4i + 1⋅"i")
|
|
77
77
|
# VectorNumber[-5.35i, "i"].floor(-1) # => (-10i)
|
|
78
78
|
#
|
|
79
79
|
# @param digits [Integer]
|
|
@@ -92,11 +92,11 @@ class VectorNumber
|
|
|
92
92
|
# Other modes can not be specified.
|
|
93
93
|
#
|
|
94
94
|
# @example
|
|
95
|
-
# VectorNumber[-4.5i, "i"].round(half: :up) # => (-5i + 1⋅
|
|
96
|
-
# VectorNumber[-4.5i, "i"].round(half: :even) # => (-4i + 1⋅
|
|
97
|
-
# VectorNumber[-5.5i, "i"].round(half: :even) # => (-6i + 1⋅
|
|
98
|
-
# VectorNumber[-5.5i, "i"].round(half: :down) # => (-5i + 1⋅
|
|
99
|
-
# VectorNumber[-5.35i, "i"].round(1) # => (-5.4i + 1⋅
|
|
95
|
+
# VectorNumber[-4.5i, "i"].round(half: :up) # => (-5i + 1⋅"i")
|
|
96
|
+
# VectorNumber[-4.5i, "i"].round(half: :even) # => (-4i + 1⋅"i")
|
|
97
|
+
# VectorNumber[-5.5i, "i"].round(half: :even) # => (-6i + 1⋅"i")
|
|
98
|
+
# VectorNumber[-5.5i, "i"].round(half: :down) # => (-5i + 1⋅"i")
|
|
99
|
+
# VectorNumber[-5.35i, "i"].round(1) # => (-5.4i + 1⋅"i")
|
|
100
100
|
# VectorNumber[-5.35i, "i"].round(-1) # => (-10i)
|
|
101
101
|
#
|
|
102
102
|
# @param digits [Integer]
|
|
@@ -11,12 +11,12 @@ class VectorNumber
|
|
|
11
11
|
# Unlike other numeric types, VectorNumber can coerce *anything*.
|
|
12
12
|
#
|
|
13
13
|
# @example
|
|
14
|
-
# VectorNumber["a"].coerce(5) # => [(5), (1⋅
|
|
14
|
+
# VectorNumber["a"].coerce(5) # => [(5), (1⋅"a")]
|
|
15
15
|
# VectorNumber[7].coerce([]) # => [(1⋅[]), (7)]
|
|
16
|
-
# VectorNumber["a"] + 5 # => (1⋅
|
|
16
|
+
# VectorNumber["a"] + 5 # => (1⋅"a" + 5)
|
|
17
17
|
# # Direct reverse coercion doesn't work, but Numeric types know how to call #coerce:
|
|
18
18
|
# 5.coerce(VectorNumber["a"]) # RangeError
|
|
19
|
-
# 5 + VectorNumber["a"] # => (5 + 1⋅
|
|
19
|
+
# 5 + VectorNumber["a"] # => (5 + 1⋅"a")
|
|
20
20
|
#
|
|
21
21
|
# @param other [Object]
|
|
22
22
|
# @return [Array(VectorNumber, VectorNumber)]
|
|
@@ -34,8 +34,8 @@ class VectorNumber
|
|
|
34
34
|
# Return new vector with negated coefficients (additive inverse).
|
|
35
35
|
#
|
|
36
36
|
# @example
|
|
37
|
-
# -VectorNumber[12, "i"] # => (-12 - 1⋅
|
|
38
|
-
# VectorNumber["a", "b", "a"].neg # => (-2⋅
|
|
37
|
+
# -VectorNumber[12, "i"] # => (-12 - 1⋅"i")
|
|
38
|
+
# VectorNumber["a", "b", "a"].neg # => (-2⋅"a" - 1⋅"b")
|
|
39
39
|
# -VectorNumber["a"] + VectorNumber["a"] # => (0)
|
|
40
40
|
#
|
|
41
41
|
# @return [VectorNumber]
|
|
@@ -53,11 +53,11 @@ class VectorNumber
|
|
|
53
53
|
#
|
|
54
54
|
# @example
|
|
55
55
|
# VectorNumber[5] + 10 # => (15)
|
|
56
|
-
# VectorNumber["a"].add(VectorNumber["b"]) # => (1⋅
|
|
57
|
-
# VectorNumber["a"] + "b" # => (1⋅
|
|
56
|
+
# VectorNumber["a"].add(VectorNumber["b"]) # => (1⋅"a" + 1⋅"b")
|
|
57
|
+
# VectorNumber["a"] + "b" # => (1⋅"a" + 1⋅"b")
|
|
58
58
|
# @example numeric types can be added in reverse
|
|
59
59
|
# 10 + VectorNumber[5] # => (15)
|
|
60
|
-
# 10 + VectorNumber["a"] # => (10 + 1⋅
|
|
60
|
+
# 10 + VectorNumber["a"] # => (10 + 1⋅"a")
|
|
61
61
|
#
|
|
62
62
|
# @param other [Object]
|
|
63
63
|
# @return [VectorNumber]
|
|
@@ -76,11 +76,11 @@ class VectorNumber
|
|
|
76
76
|
#
|
|
77
77
|
# @example
|
|
78
78
|
# VectorNumber[5] - 3 # => (2)
|
|
79
|
-
# VectorNumber["a"].sub(VectorNumber["b"]) # => (1⋅
|
|
80
|
-
# VectorNumber["a"] - "b" # => (1⋅
|
|
79
|
+
# VectorNumber["a"].sub(VectorNumber["b"]) # => (1⋅"a" - 1⋅"b")
|
|
80
|
+
# VectorNumber["a"] - "b" # => (1⋅"a" - 1⋅"b")
|
|
81
81
|
# @example numeric types can be subtracted in reverse
|
|
82
82
|
# 3 - VectorNumber[5] # => (-2)
|
|
83
|
-
# 3 - VectorNumber["a"] # => (3 - 1⋅
|
|
83
|
+
# 3 - VectorNumber["a"] # => (3 - 1⋅"a")
|
|
84
84
|
#
|
|
85
85
|
# @param other [Object]
|
|
86
86
|
# @return [VectorNumber]
|
|
@@ -99,13 +99,13 @@ class VectorNumber
|
|
|
99
99
|
#
|
|
100
100
|
# @example
|
|
101
101
|
# VectorNumber[5] * 2 # => (10)
|
|
102
|
-
# VectorNumber["a", "b", 6].mult(2) # => (2⋅
|
|
103
|
-
# VectorNumber["a"] * VectorNumber[2] # => (2⋅
|
|
102
|
+
# VectorNumber["a", "b", 6].mult(2) # => (2⋅"a" + 2⋅"b" + 12)
|
|
103
|
+
# VectorNumber["a"] * VectorNumber[2] # => (2⋅"a")
|
|
104
104
|
# # Can't multiply by a non-real:
|
|
105
105
|
# VectorNumber["a"] * VectorNumber["b"] # RangeError
|
|
106
106
|
# @example numeric types can be multiplied in reverse
|
|
107
107
|
# 2 * VectorNumber[5] # => (10)
|
|
108
|
-
# 2 * VectorNumber["a"] # => (2⋅
|
|
108
|
+
# 2 * VectorNumber["a"] # => (2⋅"a")
|
|
109
109
|
#
|
|
110
110
|
# @param other [Integer, Float, Rational, BigDecimal, VectorNumber]
|
|
111
111
|
# @return [VectorNumber]
|
|
@@ -135,8 +135,8 @@ class VectorNumber
|
|
|
135
135
|
#
|
|
136
136
|
# @example
|
|
137
137
|
# VectorNumber[10] / 2 # => (5)
|
|
138
|
-
# VectorNumber["a", "b", 6].quo(2) # => (1/2⋅
|
|
139
|
-
# VectorNumber["a"] / VectorNumber[2] # => (1/2⋅
|
|
138
|
+
# VectorNumber["a", "b", 6].quo(2) # => (1/2⋅"a" + 1/2⋅"b" + 3/1)
|
|
139
|
+
# VectorNumber["a"] / VectorNumber[2] # => (1/2⋅"a")
|
|
140
140
|
# # Can't divide by a non-real:
|
|
141
141
|
# VectorNumber["a"] / VectorNumber["b"] # RangeError
|
|
142
142
|
# @example numeric types can be divided in reverse
|
|
@@ -172,8 +172,8 @@ class VectorNumber
|
|
|
172
172
|
#
|
|
173
173
|
# @example
|
|
174
174
|
# VectorNumber[10].fdiv(2) # => (5.0)
|
|
175
|
-
# VectorNumber["a", "b", 6].fdiv(2) # => (0.5⋅
|
|
176
|
-
# VectorNumber["a"].fdiv(VectorNumber[2]) # => (0.5⋅
|
|
175
|
+
# VectorNumber["a", "b", 6].fdiv(2) # => (0.5⋅"a" + 0.5⋅"b" + 3.0)
|
|
176
|
+
# VectorNumber["a"].fdiv(VectorNumber[2]) # => (0.5⋅"a")
|
|
177
177
|
# # Can't divide by a non-real:
|
|
178
178
|
# VectorNumber["a"].fdiv(VectorNumber["b"]) # RangeError
|
|
179
179
|
# @example reverse division may return non-vector results
|
|
@@ -200,8 +200,8 @@ class VectorNumber
|
|
|
200
200
|
#
|
|
201
201
|
# @example
|
|
202
202
|
# VectorNumber[10].div(3) # => (3)
|
|
203
|
-
# VectorNumber["a"].div(2) # => (0
|
|
204
|
-
# VectorNumber["a"].div(VectorNumber[2]) # => (0
|
|
203
|
+
# VectorNumber["a"].div(2) # => (0)
|
|
204
|
+
# VectorNumber["a"].div(VectorNumber[2]) # => (0)
|
|
205
205
|
# # Can't divide by a non-real:
|
|
206
206
|
# VectorNumber["a"].div(VectorNumber["b"]) # RangeError
|
|
207
207
|
# @example numeric types can be divided in reverse
|
|
@@ -233,8 +233,8 @@ class VectorNumber
|
|
|
233
233
|
#
|
|
234
234
|
# @example
|
|
235
235
|
# VectorNumber[10] % 3 # => (1)
|
|
236
|
-
# VectorNumber["a", "b", 6].modulo(2) # => (1⋅
|
|
237
|
-
# -VectorNumber["a"] % VectorNumber[2] # => (1⋅
|
|
236
|
+
# VectorNumber["a", "b", 6].modulo(2) # => (1⋅"a" + 1⋅"b")
|
|
237
|
+
# -VectorNumber["a"] % VectorNumber[2] # => (1⋅"a")
|
|
238
238
|
# # Can't divide by a non-real:
|
|
239
239
|
# VectorNumber["a"] % VectorNumber["b"] # RangeError
|
|
240
240
|
# @example numeric types can be divided in reverse
|
|
@@ -271,8 +271,8 @@ class VectorNumber
|
|
|
271
271
|
#
|
|
272
272
|
# @example
|
|
273
273
|
# VectorNumber[10].divmod(3) # => [(3), (1)]
|
|
274
|
-
# VectorNumber["a"].divmod(2) # => [(0
|
|
275
|
-
# VectorNumber["a"].divmod(VectorNumber[2]) # => [(0
|
|
274
|
+
# VectorNumber["a"].divmod(2) # => [(0), (1⋅"a")]
|
|
275
|
+
# VectorNumber["a"].divmod(VectorNumber[2]) # => [(0), (1⋅"a")]
|
|
276
276
|
# # Can't divide by a non-real:
|
|
277
277
|
# VectorNumber["a"].divmod(VectorNumber["b"]) # RangeError
|
|
278
278
|
# @example numeric types can be divided in reverse
|
|
@@ -299,8 +299,8 @@ class VectorNumber
|
|
|
299
299
|
#
|
|
300
300
|
# @example
|
|
301
301
|
# VectorNumber[10].remainder(3) # => (1)
|
|
302
|
-
# VectorNumber["a"].remainder(2) # => (1⋅
|
|
303
|
-
# -VectorNumber["a"].remainder(VectorNumber[2]) # => (-1⋅
|
|
302
|
+
# VectorNumber["a"].remainder(2) # => (1⋅"a")
|
|
303
|
+
# -VectorNumber["a"].remainder(VectorNumber[2]) # => (-1⋅"a")
|
|
304
304
|
# # Can't divide by a non-real:
|
|
305
305
|
# VectorNumber["a"].remainder(VectorNumber["b"]) # RangeError
|
|
306
306
|
# @example numeric types can be divided in reverse
|
|
@@ -5,7 +5,10 @@ class VectorNumber
|
|
|
5
5
|
#
|
|
6
6
|
# Mostly modelled after {::Complex}.
|
|
7
7
|
|
|
8
|
-
#
|
|
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?}.
|
|
9
12
|
#
|
|
10
13
|
# @example
|
|
11
14
|
# VectorNumber[2].numeric? # => true
|
|
@@ -16,7 +19,7 @@ class VectorNumber
|
|
|
16
19
|
# @param dimensions [Integer] number of dimensions to consider "numeric"
|
|
17
20
|
# - 0 — zero
|
|
18
21
|
# - 1 — real number
|
|
19
|
-
# - 2 — complex number
|
|
22
|
+
# - 2 — complex number
|
|
20
23
|
# @return [Boolean]
|
|
21
24
|
# @raise [ArgumentError] if +dimensions+ is negative
|
|
22
25
|
#
|
|
@@ -24,10 +27,14 @@ class VectorNumber
|
|
|
24
27
|
def numeric?(dimensions = 2)
|
|
25
28
|
raise ArgumentError, "`dimensions` must be non-negative" unless dimensions >= 0
|
|
26
29
|
|
|
27
|
-
size <= dimensions &&
|
|
30
|
+
size <= dimensions &&
|
|
31
|
+
(0...dimensions).count { (unit = NUMERIC_UNITS[_1]) && @data[unit].nonzero? } == size
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
#
|
|
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?}.
|
|
31
38
|
#
|
|
32
39
|
# @example
|
|
33
40
|
# VectorNumber[2].nonnumeric? # => false
|
|
@@ -50,8 +57,6 @@ class VectorNumber
|
|
|
50
57
|
# VectorNumber["a"].mult(Float::INFINITY).finite? # => false
|
|
51
58
|
#
|
|
52
59
|
# @return [Boolean]
|
|
53
|
-
#
|
|
54
|
-
# @since 0.1.0
|
|
55
60
|
def finite?
|
|
56
61
|
all? { |_u, v| v.finite? }
|
|
57
62
|
end
|
|
@@ -66,8 +71,6 @@ class VectorNumber
|
|
|
66
71
|
# VectorNumber["a"].mult(-Float::INFINITY).infinite? # => 1
|
|
67
72
|
#
|
|
68
73
|
# @return [1, nil]
|
|
69
|
-
#
|
|
70
|
-
# @since 0.1.0
|
|
71
74
|
def infinite?
|
|
72
75
|
finite? ? nil : 1 # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
|
73
76
|
end
|
|
@@ -83,8 +86,6 @@ class VectorNumber
|
|
|
83
86
|
# @see #size
|
|
84
87
|
#
|
|
85
88
|
# @return [Boolean]
|
|
86
|
-
#
|
|
87
|
-
# @since 0.1.0
|
|
88
89
|
def zero? = size.zero?
|
|
89
90
|
|
|
90
91
|
# Returns +self+ if there are any non-zero coefficients, +nil+ otherwise.
|
|
@@ -93,14 +94,12 @@ class VectorNumber
|
|
|
93
94
|
# Behavior of returning self or +nil+ is the same as +Numeric+'s.
|
|
94
95
|
#
|
|
95
96
|
# @example
|
|
96
|
-
# VectorNumber["ab", "cd"].nonzero? # => (1⋅
|
|
97
|
+
# VectorNumber["ab", "cd"].nonzero? # => (1⋅"ab" + 1⋅"cd")
|
|
97
98
|
# VectorNumber[].nonzero? # => nil
|
|
98
99
|
#
|
|
99
100
|
# @see #size
|
|
100
101
|
#
|
|
101
102
|
# @return [VectorNumber, nil]
|
|
102
|
-
#
|
|
103
|
-
# @since 0.1.0
|
|
104
103
|
def nonzero?
|
|
105
104
|
zero? ? nil : self # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
|
|
106
105
|
end
|
|
@@ -115,8 +114,6 @@ class VectorNumber
|
|
|
115
114
|
# VectorNumber[0].positive? # => false
|
|
116
115
|
#
|
|
117
116
|
# @return [Boolean]
|
|
118
|
-
#
|
|
119
|
-
# @since 0.1.0
|
|
120
117
|
def positive?
|
|
121
118
|
!zero? && all? { |_u, c| c.positive? }
|
|
122
119
|
end
|
|
@@ -131,8 +128,6 @@ class VectorNumber
|
|
|
131
128
|
# VectorNumber[0].negative? # => false
|
|
132
129
|
#
|
|
133
130
|
# @return [Boolean]
|
|
134
|
-
#
|
|
135
|
-
# @since 0.1.0
|
|
136
131
|
def negative?
|
|
137
132
|
!zero? && all? { |_u, c| c.negative? }
|
|
138
133
|
end
|
|
@@ -144,8 +139,6 @@ class VectorNumber
|
|
|
144
139
|
# @see #numeric?
|
|
145
140
|
#
|
|
146
141
|
# @return [false]
|
|
147
|
-
#
|
|
148
|
-
# @since 0.1.0
|
|
149
142
|
def real? = false
|
|
150
143
|
|
|
151
144
|
# Always returns +false+, as vectors are not +Integer+s.
|
|
@@ -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
|
|
@@ -4,8 +4,6 @@ class VectorNumber
|
|
|
4
4
|
# Predefined symbols for multiplication to display between unit and coefficient.
|
|
5
5
|
#
|
|
6
6
|
# @return [Hash{Symbol => String}]
|
|
7
|
-
#
|
|
8
|
-
# @since 0.1.0
|
|
9
7
|
MULT_STRINGS = {
|
|
10
8
|
asterisk: "*", # U+002A
|
|
11
9
|
cross: "×", # U+00D7
|
|
@@ -19,35 +17,42 @@ class VectorNumber
|
|
|
19
17
|
|
|
20
18
|
# Return string representation of the vector.
|
|
21
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
|
+
#
|
|
22
25
|
# @example
|
|
23
|
-
# VectorNumber[5, "s"].to_s # => "5 + 1
|
|
24
|
-
# VectorNumber["s", 5].to_s # => "1
|
|
26
|
+
# VectorNumber[5, "s"].to_s # => "5 + 1⋅\"s\""
|
|
27
|
+
# VectorNumber["s", 5].to_s # => "1⋅\"s\" + 5"
|
|
25
28
|
# @example with :mult argument
|
|
26
|
-
# VectorNumber[5,
|
|
27
|
-
#
|
|
28
|
-
#
|
|
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"
|
|
29
36
|
#
|
|
30
37
|
# @param mult [Symbol, String]
|
|
31
38
|
# text to use between coefficient and unit,
|
|
32
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
|
|
33
45
|
# @return [String]
|
|
34
46
|
# @raise [ArgumentError]
|
|
35
47
|
# if +mult+ is not a String and is not in {MULT_STRINGS}'s keys
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
39
52
|
return "0" if zero?
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if index.zero?
|
|
44
|
-
result << "-" if coefficient.negative?
|
|
45
|
-
else
|
|
46
|
-
result << (coefficient.positive? ? " + " : " - ")
|
|
47
|
-
end
|
|
48
|
-
result << value_to_s(unit, coefficient.abs, mult: mult)
|
|
49
|
-
end
|
|
50
|
-
result
|
|
54
|
+
operator = mult.is_a?(String) ? mult : MULT_STRINGS[mult]
|
|
55
|
+
build_string(operator, &block)
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
# Return string representation of the vector.
|
|
@@ -55,38 +60,45 @@ class VectorNumber
|
|
|
55
60
|
# This is similar to +Complex#inspect+: it returns result of {#to_s} in round brackets.
|
|
56
61
|
#
|
|
57
62
|
# @example
|
|
58
|
-
# VectorNumber[5,
|
|
63
|
+
# VectorNumber[5, :s].inspect # => "(5 + 1⋅s)"
|
|
59
64
|
#
|
|
60
65
|
# @return [String]
|
|
61
66
|
#
|
|
62
67
|
# @see to_s
|
|
63
|
-
#
|
|
64
|
-
# @since 0.1.0
|
|
65
68
|
def inspect
|
|
66
|
-
# TODO: Probably make this independent of options.
|
|
67
69
|
"(#{self})"
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
private
|
|
71
73
|
|
|
72
|
-
# @param
|
|
73
|
-
# @param coefficient [Numeric]
|
|
74
|
-
# @param mult [Symbol, String]
|
|
74
|
+
# @param operator [String]
|
|
75
75
|
# @return [String]
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
82
|
+
if index.zero?
|
|
83
|
+
result << "-" if coefficient.negative?
|
|
84
|
+
else
|
|
85
|
+
result << (coefficient.positive? ? " + " : " - ")
|
|
86
|
+
end
|
|
87
|
+
result << value_to_s(unit, coefficient.abs, operator)
|
|
88
|
+
end
|
|
80
89
|
end
|
|
90
|
+
result
|
|
91
|
+
end
|
|
81
92
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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}"
|
|
87
100
|
else
|
|
88
|
-
unit =
|
|
89
|
-
operator = mult.is_a?(String) ? mult : MULT_STRINGS[mult]
|
|
101
|
+
unit = unit.inspect if unit.is_a?(String)
|
|
90
102
|
"#{coefficient}#{operator}#{unit}"
|
|
91
103
|
end
|
|
92
104
|
end
|
data/lib/vector_number.rb
CHANGED
|
@@ -73,12 +73,14 @@
|
|
|
73
73
|
# - {#to_h}: convert to Hash
|
|
74
74
|
#
|
|
75
75
|
# **Miscellaneous** **methods**
|
|
76
|
-
# - {
|
|
77
|
-
# - {#
|
|
78
|
-
# - {#dup}/{#+}: return self
|
|
79
|
-
# - {#clone}: return self
|
|
76
|
+
# - {.numeric_unit?}: check if a unit represents a numeric dimension
|
|
77
|
+
# - {#size}: number of non-zero dimensions
|
|
80
78
|
# - {#to_s}: return string representation suitable for printing
|
|
81
79
|
# - {#inspect}: return string representation suitable for display
|
|
80
|
+
# - {#dup}/{#+}: return self
|
|
81
|
+
# - {#clone}: return self
|
|
82
|
+
#
|
|
83
|
+
# @since 0.1.0
|
|
82
84
|
class VectorNumber
|
|
83
85
|
require_relative "vector_number/comparing"
|
|
84
86
|
require_relative "vector_number/converting"
|
|
@@ -89,82 +91,73 @@ class VectorNumber
|
|
|
89
91
|
require_relative "vector_number/stringifying"
|
|
90
92
|
require_relative "vector_number/version"
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
# Unknown options will be rejected when creating a vector.
|
|
94
|
-
#
|
|
95
|
-
# @return [Array<Symbol>]
|
|
96
|
-
#
|
|
97
|
-
# @since 0.2.0
|
|
98
|
-
KNOWN_OPTIONS = %i[mult].freeze
|
|
94
|
+
require_relative "vector_number/special_unit"
|
|
99
95
|
|
|
100
|
-
#
|
|
96
|
+
# List of special numeric unit constants.
|
|
101
97
|
#
|
|
102
|
-
# @
|
|
98
|
+
# @since 0.6.0
|
|
99
|
+
NUMERIC_UNITS = [SpecialUnit.new("1", "").freeze, SpecialUnit.new("i", "i").freeze].freeze
|
|
100
|
+
# Constant for real unit (1).
|
|
103
101
|
#
|
|
104
|
-
#
|
|
105
|
-
DEFAULT_OPTIONS = { mult: :dot }.freeze
|
|
106
|
-
|
|
107
|
-
# Get a unit for +n+th numeric dimension, where 1 is real, 2 is imaginary.
|
|
102
|
+
# Its string representation is an empty string.
|
|
108
103
|
#
|
|
109
|
-
# @since 0.
|
|
110
|
-
|
|
111
|
-
# Constant for
|
|
104
|
+
# @since 0.6.0
|
|
105
|
+
R = NUMERIC_UNITS[0]
|
|
106
|
+
# Constant for imaginary unit (i).
|
|
112
107
|
#
|
|
113
|
-
#
|
|
114
|
-
R = UNIT[1]
|
|
115
|
-
# Constant for imaginary unit.
|
|
108
|
+
# Its string representation is "i".
|
|
116
109
|
#
|
|
117
|
-
# @since 0.
|
|
118
|
-
I =
|
|
110
|
+
# @since 0.6.0
|
|
111
|
+
I = NUMERIC_UNITS[1]
|
|
119
112
|
|
|
120
113
|
# @group Creation
|
|
121
|
-
# Create new VectorNumber from a list of values
|
|
114
|
+
# Create new VectorNumber from a list of values.
|
|
122
115
|
#
|
|
123
116
|
# @example
|
|
124
117
|
# VectorNumber[1, 2, 3] # => (6)
|
|
125
118
|
# VectorNumber[[1, 2, 3]] # => (1⋅[1, 2, 3])
|
|
126
|
-
# VectorNumber["b", VectorNumber::I, mult: :asterisk] # => (1*'b' + 1i)
|
|
127
119
|
# VectorNumber[] # => (0)
|
|
128
120
|
# VectorNumber["b", VectorNumber["b"]] # => (2⋅'b')
|
|
129
121
|
# VectorNumber["a", "b", "a"] # => (2⋅'a' + 1⋅'b')
|
|
130
122
|
#
|
|
131
123
|
# @param values [Array<Object>] values to put in the number
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# either a key from {MULT_STRINGS} or a literal string to use
|
|
135
|
-
# @return [VectorNumber]
|
|
136
|
-
#
|
|
137
|
-
# @since 0.1.0
|
|
138
|
-
def self.[](*values, **options)
|
|
139
|
-
new(values, options)
|
|
124
|
+
def self.[](*values, **nil)
|
|
125
|
+
new(values)
|
|
140
126
|
end
|
|
141
127
|
# @endgroup
|
|
142
128
|
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# @return [Integer]
|
|
129
|
+
# Check if an object is a unit representing a numeric dimension
|
|
130
|
+
# (real or imaginary unit).
|
|
146
131
|
#
|
|
147
|
-
# @
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
#
|
|
132
|
+
# @example
|
|
133
|
+
# VectorNumber.numeric_unit?(VectorNumber::R) # => true
|
|
134
|
+
# VectorNumber.numeric_unit?(VectorNumber::I) # => true
|
|
135
|
+
# VectorNumber.numeric_unit?(:i) # => false
|
|
151
136
|
#
|
|
152
|
-
# @
|
|
137
|
+
# @param unit [Object]
|
|
138
|
+
# @return [Boolean]
|
|
153
139
|
#
|
|
154
|
-
# @
|
|
140
|
+
# @since 0.6.0
|
|
141
|
+
def self.numeric_unit?(unit)
|
|
142
|
+
NUMERIC_UNITS.include?(unit)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Number of non-zero dimensions.
|
|
155
146
|
#
|
|
156
|
-
# @
|
|
157
|
-
attr_reader :
|
|
147
|
+
# @return [Integer]
|
|
148
|
+
attr_reader :size
|
|
158
149
|
|
|
159
150
|
# @group Creation
|
|
160
|
-
# Create new VectorNumber from
|
|
151
|
+
# Create new VectorNumber from an array of +values+,
|
|
161
152
|
# possibly modifying coefficients with a block.
|
|
162
153
|
#
|
|
154
|
+
# Using +VectorNumber.new([values...])+ directly is more efficient than +VectorNumber[values...]+.
|
|
155
|
+
#
|
|
163
156
|
# +values+ can be:
|
|
164
157
|
# - an array of values (see {.[]});
|
|
165
158
|
# - a VectorNumber to copy;
|
|
166
159
|
# - a hash in the format returned by {#to_h};
|
|
167
|
-
# - +nil+ to specify a 0-
|
|
160
|
+
# - +nil+ to specify a 0-sized vector (same as an empty array or hash).
|
|
168
161
|
#
|
|
169
162
|
# Using a hash as +values+ is an advanced technique which allows to quickly
|
|
170
163
|
# construct a VectorNumber with desired units and coefficients,
|
|
@@ -174,32 +167,24 @@ class VectorNumber
|
|
|
174
167
|
# @example
|
|
175
168
|
# VectorNumber.new(1, 2, 3) # ArgumentError
|
|
176
169
|
# VectorNumber.new([1, 2, 3]) # => (6)
|
|
177
|
-
# VectorNumber.new(["b", VectorNumber::I]
|
|
170
|
+
# VectorNumber.new(["b", VectorNumber::I]) # => (1⋅"b" + 1i)
|
|
178
171
|
# VectorNumber.new # => (0)
|
|
179
172
|
# @example with a block
|
|
180
|
-
# VectorNumber.new(["a", "b", "c", 3]) { _1 * 2 } # => (2⋅
|
|
181
|
-
# VectorNumber.new(["a", "b", "c", 3], &:-@) # => (-1⋅
|
|
173
|
+
# VectorNumber.new(["a", "b", "c", 3]) { _1 * 2 } # => (2⋅"a" + 2⋅"b" + 2⋅"c" + 6)
|
|
174
|
+
# VectorNumber.new(["a", "b", "c", 3], &:-@) # => (-1⋅"a" - 1⋅"b" - 1⋅"c" - 3)
|
|
182
175
|
# VectorNumber.new(["a", "b", "c", 3], &:digits) # RangeError
|
|
183
176
|
# @example using hash for values
|
|
184
|
-
# v = VectorNumber.new({1 => 15, "a" => 3.4, nil => -3}) # => (15 + 3.4⋅
|
|
177
|
+
# v = VectorNumber.new({1 => 15, "a" => 3.4, nil => -3}) # => (15 + 3.4⋅"a" - 3⋅)
|
|
185
178
|
# v.to_h # => {1 => 15, "a" => 3.4, nil => -3}
|
|
186
179
|
#
|
|
187
180
|
# @param values [Array, VectorNumber, Hash{Object => Numeric}, nil] values for this vector
|
|
188
|
-
# @param options [Hash{Symbol => Object}, nil]
|
|
189
|
-
# options for this vector, if +values+ is a VectorNumber or contains it,
|
|
190
|
-
# these will be merged with options from its +options+
|
|
191
|
-
# @option options [Symbol, String] :mult Multiplication symbol,
|
|
192
|
-
# either a key from {MULT_STRINGS} or a literal string to use
|
|
193
181
|
# @yieldparam coefficient [Numeric] a real number
|
|
194
182
|
# @yieldreturn [Numeric] new coefficient
|
|
195
183
|
# @raise [RangeError] if a block is used and it returns a non-number or non-real number
|
|
196
|
-
def initialize(values = nil,
|
|
197
|
-
# @type var options: Hash[Symbol, Object]
|
|
184
|
+
def initialize(values = nil, **nil, &transform)
|
|
198
185
|
initialize_from(values)
|
|
199
186
|
apply_transform(&transform)
|
|
200
187
|
finalize_contents
|
|
201
|
-
save_options(options, values)
|
|
202
|
-
@options.freeze
|
|
203
188
|
@data.freeze
|
|
204
189
|
freeze
|
|
205
190
|
end
|
|
@@ -241,7 +226,7 @@ class VectorNumber
|
|
|
241
226
|
# @yieldreturn [Numeric] new coefficient
|
|
242
227
|
# @return [VectorNumber]
|
|
243
228
|
def new(from = self, &transform)
|
|
244
|
-
self.class.new(from,
|
|
229
|
+
self.class.new(from, &transform)
|
|
245
230
|
end
|
|
246
231
|
|
|
247
232
|
# Check if +other+ is a real number.
|
|
@@ -319,32 +304,6 @@ class VectorNumber
|
|
|
319
304
|
end
|
|
320
305
|
end
|
|
321
306
|
|
|
322
|
-
# @param options [Hash{Symbol => Object}, nil]
|
|
323
|
-
# @param values [Object] initializing object
|
|
324
|
-
# @return [void]
|
|
325
|
-
def save_options(options, values)
|
|
326
|
-
@options =
|
|
327
|
-
case values
|
|
328
|
-
in VectorNumber
|
|
329
|
-
merge_options(values.options, options)
|
|
330
|
-
in Array[*, VectorNumber => vector, *]
|
|
331
|
-
merge_options(vector.options, options)
|
|
332
|
-
else
|
|
333
|
-
merge_options(DEFAULT_OPTIONS, options)
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
# @param base_options [Hash{Symbol => Object}]
|
|
338
|
-
# @param added_options [Hash{Symbol => Object}, nil]
|
|
339
|
-
# @return [Hash{Symbol => Object}]
|
|
340
|
-
def merge_options(base_options, added_options)
|
|
341
|
-
return base_options if !added_options || added_options.empty?
|
|
342
|
-
# Optimization for the common case of passing options through #new.
|
|
343
|
-
return base_options if added_options.equal?(base_options)
|
|
344
|
-
|
|
345
|
-
base_options.merge(added_options).slice(*KNOWN_OPTIONS)
|
|
346
|
-
end
|
|
347
|
-
|
|
348
307
|
# Compact coefficients, calculate size and freeze data.
|
|
349
308
|
# @return [void]
|
|
350
309
|
def finalize_contents
|
data/sig/vector_number.rbs
CHANGED
|
@@ -14,28 +14,24 @@ class VectorNumber
|
|
|
14
14
|
type coefficients_list_type = list[coefficient_type]
|
|
15
15
|
type each_value_type = [unit_type, coefficient_type]
|
|
16
16
|
|
|
17
|
-
type options_type = Hash[Symbol, untyped]
|
|
18
|
-
|
|
19
17
|
# ---- Constants ----
|
|
20
18
|
|
|
21
19
|
VERSION: String
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
UNIT: ^(Integer) -> Complex
|
|
27
|
-
R: Complex
|
|
28
|
-
I: Complex
|
|
21
|
+
NUMERIC_UNITS: list[SpecialUnit]
|
|
22
|
+
R: SpecialUnit
|
|
23
|
+
I: SpecialUnit
|
|
29
24
|
|
|
30
25
|
# ---- Public methods ----
|
|
31
26
|
|
|
32
|
-
def self.[]: (*unit_type values
|
|
27
|
+
def self.[]: (*unit_type values) -> instance
|
|
28
|
+
|
|
29
|
+
def self.numeric_unit?: (unit_type unit) -> bool
|
|
33
30
|
|
|
34
31
|
def size: -> Integer
|
|
35
|
-
def options: -> options_type
|
|
36
32
|
|
|
37
33
|
def initialize:
|
|
38
|
-
(?(units_list_type | plain_instance | instance)? values
|
|
34
|
+
(?(units_list_type | plain_instance | instance)? values)
|
|
39
35
|
?{ (coefficient_type coefficient) -> coefficient_type }
|
|
40
36
|
-> void
|
|
41
37
|
|
|
@@ -47,7 +43,6 @@ class VectorNumber
|
|
|
47
43
|
private
|
|
48
44
|
|
|
49
45
|
@size: Integer
|
|
50
|
-
@options: options_type
|
|
51
46
|
@data: plain_instance
|
|
52
47
|
|
|
53
48
|
def new: () { (coefficient_type value) -> coefficient_type } -> instance
|
|
@@ -69,9 +64,6 @@ class VectorNumber
|
|
|
69
64
|
|
|
70
65
|
def apply_transform: () ?{ (coefficient_type value) -> coefficient_type } -> void
|
|
71
66
|
|
|
72
|
-
def save_options: (options_type? options, in_value_type values) -> void
|
|
73
|
-
def merge_options: (options_type base_options, options_type added_options) -> options_type
|
|
74
|
-
|
|
75
67
|
def finalize_contents: () -> void
|
|
76
68
|
end
|
|
77
69
|
|
|
@@ -211,13 +203,16 @@ end
|
|
|
211
203
|
class VectorNumber
|
|
212
204
|
MULT_STRINGS: Hash[Symbol, String]
|
|
213
205
|
|
|
214
|
-
def to_s: (?mult: (Symbol | String)) -> String
|
|
206
|
+
def to_s: (?mult: (Symbol | String)) { (unit_type, coefficient_type, ?Integer index, ?String operator) -> String } -> String
|
|
215
207
|
|
|
216
208
|
def inspect: () -> String
|
|
217
209
|
|
|
218
210
|
private
|
|
219
211
|
|
|
220
|
-
def
|
|
212
|
+
def build_string: (String operator) -> String
|
|
213
|
+
| (String operator) { (unit_type, coefficient_type, ?Integer index, ?String operator) -> String } -> String
|
|
214
|
+
|
|
215
|
+
def value_to_s: (unit_type unit, coefficient_type coefficient, String operator) -> String
|
|
221
216
|
end
|
|
222
217
|
|
|
223
218
|
class VectorNumber
|
|
@@ -233,3 +228,14 @@ class VectorNumber
|
|
|
233
228
|
end
|
|
234
229
|
end
|
|
235
230
|
end
|
|
231
|
+
|
|
232
|
+
class VectorNumber
|
|
233
|
+
# Class for representing special numerical units.
|
|
234
|
+
class SpecialUnit
|
|
235
|
+
def initialize: (Object unit, String text) -> void
|
|
236
|
+
|
|
237
|
+
def to_s: () -> String
|
|
238
|
+
|
|
239
|
+
def inspect: () -> String
|
|
240
|
+
end
|
|
241
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vector_number
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Bulancov
|
|
@@ -13,18 +13,20 @@ description: |
|
|
|
13
13
|
VectorNumber provides a Numeric-like experience for doing arithmetics on heterogeneous objects, with more advanced operations based on real vector spaces available when needed.
|
|
14
14
|
|
|
15
15
|
Features:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
* Add and subtract (almost) any object, with no setup or declaration.
|
|
17
|
+
* Multiply and divide vectors by any real number to create 1.35 of an array and -2 of a string. What does that mean? Only you know!
|
|
18
|
+
* Use vectors instead of inbuilt numbers in most situtations with no difference in behavior. Or, use familiar methods from numerics with sane semantics!
|
|
19
|
+
* Enumerate vectors in a hash-like fashion, or transform to an array or hash as needed.
|
|
20
|
+
* Enjoy a mix of vector-, complex- and polynomial-like behavior at appropriate times.
|
|
21
|
+
* No dependencies, no extensions. It just works!
|
|
22
22
|
executables: []
|
|
23
23
|
extensions: []
|
|
24
24
|
extra_rdoc_files:
|
|
25
25
|
- README.md
|
|
26
|
+
- doc/vector_space.svg
|
|
26
27
|
files:
|
|
27
28
|
- README.md
|
|
29
|
+
- doc/vector_space.svg
|
|
28
30
|
- lib/vector_number.rb
|
|
29
31
|
- lib/vector_number/comparing.rb
|
|
30
32
|
- lib/vector_number/converting.rb
|
|
@@ -33,6 +35,7 @@ files:
|
|
|
33
35
|
- lib/vector_number/mathing.rb
|
|
34
36
|
- lib/vector_number/numeric_refinements.rb
|
|
35
37
|
- lib/vector_number/querying.rb
|
|
38
|
+
- lib/vector_number/special_unit.rb
|
|
36
39
|
- lib/vector_number/stringifying.rb
|
|
37
40
|
- lib/vector_number/version.rb
|
|
38
41
|
- sig/vector_number.rbs
|
|
@@ -42,9 +45,9 @@ licenses:
|
|
|
42
45
|
metadata:
|
|
43
46
|
homepage_uri: https://github.com/trinistr/vector_number
|
|
44
47
|
bug_tracker_uri: https://github.com/trinistr/vector_number/issues
|
|
45
|
-
documentation_uri: https://rubydoc.info/gems/vector_number/0.
|
|
46
|
-
source_code_uri: https://github.com/trinistr/vector_number/tree/v0.
|
|
47
|
-
changelog_uri: https://github.com/trinistr/vector_number/blob/v0.
|
|
48
|
+
documentation_uri: https://rubydoc.info/gems/vector_number/0.6.0
|
|
49
|
+
source_code_uri: https://github.com/trinistr/vector_number/tree/v0.6.0
|
|
50
|
+
changelog_uri: https://github.com/trinistr/vector_number/blob/v0.6.0/CHANGELOG.md
|
|
48
51
|
rubygems_mfa_required: 'true'
|
|
49
52
|
rdoc_options:
|
|
50
53
|
- "--main"
|