fractional 0.1.0 → 1.0.1
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/.rspec +3 -0
- data/README.rdoc +30 -6
- data/VERSION +1 -1
- data/fractional.gemspec +2 -1
- data/lib/deprecated.rb +33 -0
- data/lib/fractional.rb +168 -67
- data/spec/fractional_spec.rb +469 -37
- data/spec/spec_helper.rb +1 -0
- metadata +18 -4
- data/spec/fractional_class_methods_spec.rb +0 -219
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e102c37bdea15e535451f4ace3e8427b5cd80ba3
|
4
|
+
data.tar.gz: aca489da451ff4ded33297324f3691878696dd8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dae17fc2ee51bbe1ea07eb0596a759fa5ae34ebd6a9a2418ef9c600c8ff9432a8a5ff354b6f6669edb09f78286e9c8e2432101fbb4712722a66e37eaabf08e5
|
7
|
+
data.tar.gz: 8eb87fbff148bee9e9c6c39c860c598aa0fd9adc1741688597666c7c77d1b6550b39d87b650b756678131d112ff3e775590a302ef07999347627b74db7524e5c
|
data/.rspec
ADDED
data/README.rdoc
CHANGED
@@ -1,13 +1,36 @@
|
|
1
1
|
= Fractional
|
2
2
|
|
3
|
-
Fractional is a library for parsing fractions.
|
3
|
+
Fractional is a library for parsing, representing and operating on fractions.
|
4
4
|
|
5
|
-
|
6
|
-
Fractional.to_f("1100 7/8") #=> 1100.875
|
5
|
+
=== Conversions
|
7
6
|
|
8
|
-
Convert
|
9
|
-
Fractional.
|
10
|
-
|
7
|
+
Convert fractional strings to floats:
|
8
|
+
Fractional.new("1100 7/8").to_f #=> 1100.875
|
9
|
+
|
10
|
+
Convert floats to fractional strings:
|
11
|
+
Fractional.new(1100.875).to_s #=> "1100 7/8"
|
12
|
+
Fractional.new(1100.875, :to_nearest => "1/2").to_s #=> "1101"
|
13
|
+
|
14
|
+
Also does a great job of guessing repeating decimal values:
|
15
|
+
Fractional.new(0.33333).to_s #=> "1/3"
|
16
|
+
Fractional.new(3.142857142857).to_s #=> "22/7"
|
17
|
+
If you want to prevent this "guesswork" pass the :exact option
|
18
|
+
Fractional.new(0.33333, exact: true).to_s #=> "33333/100000"
|
19
|
+
|
20
|
+
It can render back out mixed numbers:
|
21
|
+
Fractional.new(1.45).to_s #=> "29/20"
|
22
|
+
Fractional.new(1.45).to_s( mixed_number: true ) #=> "1 9/20"
|
23
|
+
|
24
|
+
|
25
|
+
=== Math and Comparisons
|
26
|
+
It will integrate nicely with Numerics:
|
27
|
+
a = Fractional.new("3/4")
|
28
|
+
puts a + 1.5 #=> "9/4"
|
29
|
+
|
30
|
+
And you can compare it to other Numerics:
|
31
|
+
puts Fractional.new("3/4") > -2.3 #=> true
|
32
|
+
|
33
|
+
=== Rounding
|
11
34
|
|
12
35
|
Round a value to the nearest fraction:
|
13
36
|
Fractional.round_to_nearest_fraction("1100 1/7", "1/64") #=> "1100 9/64"
|
@@ -28,6 +51,7 @@ Thanks to Jannis Harder for his hardcore float to rational method I nicked from
|
|
28
51
|
|
29
52
|
= Contributors
|
30
53
|
Joey Aghion https://github.com/joeyAghion
|
54
|
+
|
31
55
|
muff1nman https://github.com/muff1nman
|
32
56
|
|
33
57
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.1
|
data/fractional.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "fractional"
|
3
|
-
spec.version = "0.1
|
3
|
+
spec.version = "1.0.1"
|
4
4
|
spec.authors = ["Chris O'Sullivan"]
|
5
5
|
spec.email = ["thechrisoshow@gmail.com"]
|
6
6
|
spec.description = %q{Fractional is a Ruby library for parsing fractions.}
|
@@ -16,4 +16,5 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.add_development_dependency "bundler", "~> 1.3"
|
17
17
|
spec.add_development_dependency "rake"
|
18
18
|
spec.add_development_dependency "rspec"
|
19
|
+
spec.add_development_dependency "debugger"
|
19
20
|
end
|
data/lib/deprecated.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module DeprecatedFractionalMethods
|
2
|
+
|
3
|
+
def to_f(value)
|
4
|
+
warn("Fractional.to_f will be removed in v1.1.")
|
5
|
+
string_to_fraction(value).to_f
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_s(value, options={})
|
9
|
+
warn("Fractional.to_s will be removed in v1.1\nUse Fractional.new(value).to_s instead.")
|
10
|
+
new(float_to_fraction(value)).to_s(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def fraction?(value)
|
14
|
+
warn("Fractional.fraction? will be removed in v1.1\nUse Fractional.string_is_fraction? instead.")
|
15
|
+
string_is_fraction?(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def mixed_fraction?(value)
|
19
|
+
warn("Fractional.mixed_fraction? will be removed in v1.1\nUse Fractional.string_is_mixed_fraction? instead.")
|
20
|
+
string_is_mixed_fraction?(value)
|
21
|
+
end
|
22
|
+
|
23
|
+
def single_fraction?(value)
|
24
|
+
warn("Fractional.single_fraction? will be removed in v1.1\nUse Fractional.string_is_single_fraction? instead.")
|
25
|
+
string_is_single_fraction?(value)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def warn(message)
|
30
|
+
$stderr.puts "\n*** Fractional deprecation warning: #{message}\n\n"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/fractional.rb
CHANGED
@@ -1,119 +1,220 @@
|
|
1
1
|
require 'rational'
|
2
|
+
require 'deprecated'
|
3
|
+
|
4
|
+
class Fractional < Numeric
|
5
|
+
extend DeprecatedFractionalMethods
|
2
6
|
|
3
|
-
class Fractional
|
4
7
|
SINGLE_FRACTION = /^\s*(\-?\d+)\/(\-?\d+)\s*$/
|
5
8
|
MIXED_FRACTION = /^\s*(\-?\d*)\s+(\d+)\/(\d+)\s*$/
|
6
9
|
|
7
|
-
def initialize(value)
|
8
|
-
|
10
|
+
def initialize( value, options={} )
|
11
|
+
case value
|
12
|
+
when Rational
|
13
|
+
@value = value
|
14
|
+
when String
|
15
|
+
@value = Fractional.string_to_fraction( value, options )
|
16
|
+
when Fixnum
|
17
|
+
@value = Rational(value)
|
18
|
+
when Numeric
|
19
|
+
@value = Fractional.float_to_fraction( value.to_f, options )
|
20
|
+
else
|
21
|
+
raise TypeError, "Cannot instantiate Fractional from #{value.class}"
|
22
|
+
end
|
23
|
+
|
9
24
|
end
|
10
25
|
|
11
|
-
def
|
12
|
-
@value
|
26
|
+
def method_missing(name, *args, &blk)
|
27
|
+
return_value = @value.send(name, *args, &blk)
|
28
|
+
return_value.is_a?(Rational) ? Fractional.new(return_value) : return_value
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s( options={} )
|
32
|
+
if options[:mixed_fraction] or options[:mixed_number]
|
33
|
+
to_join = []
|
34
|
+
if whole_part != 0
|
35
|
+
to_join << whole_part.to_s
|
36
|
+
end
|
37
|
+
if fractional_part != 0
|
38
|
+
to_join << fractional_part.abs.to_s
|
39
|
+
end
|
40
|
+
to_join.join(" ")
|
41
|
+
else
|
42
|
+
@value.to_s
|
43
|
+
end
|
13
44
|
end
|
14
45
|
|
15
46
|
def to_f
|
16
|
-
|
47
|
+
@value.to_f
|
17
48
|
end
|
18
49
|
|
19
|
-
|
20
|
-
|
21
|
-
Fractional.new(Fractional.to_s(self.to_f.send(math_operator, another_fractional.to_f)))
|
22
|
-
end
|
50
|
+
def to_r
|
51
|
+
@value
|
23
52
|
end
|
24
53
|
|
25
|
-
def
|
26
|
-
|
54
|
+
def to_i
|
55
|
+
whole_part
|
56
|
+
end
|
27
57
|
|
28
|
-
|
29
|
-
|
58
|
+
def whole_part
|
59
|
+
@value.truncate
|
60
|
+
end
|
30
61
|
|
31
|
-
|
62
|
+
def fractional_part
|
63
|
+
@value - whole_part
|
64
|
+
end
|
32
65
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
66
|
+
def ==( other_num )
|
67
|
+
@value == other_num
|
68
|
+
end
|
69
|
+
|
70
|
+
def <=>(other)
|
71
|
+
case other
|
72
|
+
when Fractional, Rational
|
73
|
+
self.to_r <=> other.to_r
|
74
|
+
when Numeric
|
75
|
+
@value <=> other
|
76
|
+
when String
|
77
|
+
@value <=> Fractional.new(other).to_r
|
37
78
|
else
|
38
|
-
|
79
|
+
nil
|
39
80
|
end
|
40
|
-
|
41
|
-
result
|
42
81
|
end
|
43
82
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
83
|
+
def coerce(other)
|
84
|
+
case other
|
85
|
+
when Numeric
|
86
|
+
return Fractional.new(other), self
|
87
|
+
when String
|
88
|
+
return Fractional.new(other), self
|
89
|
+
else
|
90
|
+
raise TypeError, "#{other.class} cannot be coerced into #{Numeric}"
|
91
|
+
end
|
92
|
+
end
|
52
93
|
|
53
|
-
fractional_part = fractional_part_to_string(decimal_point_value.abs, args[:to_nearest])
|
54
94
|
|
55
|
-
|
56
|
-
|
95
|
+
[:+, :-, :*, :/, :**].each do |math_operator|
|
96
|
+
define_method(math_operator) do |another_fractional|
|
97
|
+
if another_fractional.is_a? Fractional or another_fractional.is_a? Rational
|
98
|
+
Fractional.new(@value.send(math_operator, another_fractional.to_r))
|
99
|
+
elsif another_fractional.is_a? Numeric
|
100
|
+
self.send(math_operator, Fractional.new(another_fractional))
|
57
101
|
else
|
58
|
-
|
102
|
+
Fractional.new(self.to_r.send(math_operator, another_fractional))
|
59
103
|
end
|
60
104
|
end
|
61
105
|
end
|
62
106
|
|
63
|
-
def self.
|
64
|
-
if value.
|
65
|
-
|
107
|
+
def self.float_to_fraction( value, options={} )
|
108
|
+
if value.to_f.nan?
|
109
|
+
return Rational(0,0) # Div by zero error
|
110
|
+
elsif value.to_f.infinite?
|
111
|
+
return Rational(value<0 ? -1 : 1,0) # Div by zero error
|
112
|
+
end
|
66
113
|
|
67
|
-
|
68
|
-
|
69
|
-
|
114
|
+
if options[:to_nearest]
|
115
|
+
return self.round_to_nearest_fraction( value, options[:to_nearest] )
|
116
|
+
end
|
70
117
|
|
71
|
-
|
118
|
+
# first try to convert a repeating decimal unless guesstimate is forbidden
|
119
|
+
unless options[:exact]
|
120
|
+
repeat = float_to_rational_repeat(value)
|
121
|
+
return repeat unless repeat.nil?
|
72
122
|
end
|
73
123
|
|
124
|
+
# finally assume a simple decimal
|
125
|
+
# The to_s helps with float rounding issues
|
126
|
+
return Rational(value.to_s)
|
127
|
+
|
74
128
|
end
|
75
129
|
|
76
|
-
|
130
|
+
def self.string_to_fraction( value, options={} )
|
131
|
+
if string_is_mixed_fraction?(value)
|
132
|
+
whole, numerator, denominator = value.scan(MIXED_FRACTION).flatten
|
133
|
+
return Rational( (whole.to_i.abs * denominator.to_i + numerator.to_i) *
|
134
|
+
whole.to_i / whole.to_i.abs, denominator.to_i )
|
135
|
+
elsif string_is_single_fraction?(value)
|
136
|
+
numerator, denominator = value.split("/")
|
137
|
+
return Rational(numerator.to_i, denominator.to_i)
|
138
|
+
else
|
139
|
+
return float_to_fraction(value.to_f, options)
|
140
|
+
end
|
141
|
+
end
|
77
142
|
|
78
|
-
def self.
|
143
|
+
def self.string_is_fraction?( value )
|
79
144
|
value.is_a? String and (value.match(SINGLE_FRACTION) or value.match(MIXED_FRACTION))
|
80
145
|
end
|
81
146
|
|
82
|
-
def self.
|
83
|
-
|
147
|
+
def self.string_is_mixed_fraction?( value )
|
148
|
+
string_is_fraction?(value) and value.match(MIXED_FRACTION)
|
84
149
|
end
|
85
150
|
|
86
|
-
def self.
|
87
|
-
|
151
|
+
def self.string_is_single_fraction?( value )
|
152
|
+
string_is_fraction?(value) and value.match(SINGLE_FRACTION)
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.float_to_rational_repeat(base_value)
|
156
|
+
normalized_value = base_value.to_f
|
157
|
+
repeat = find_repeat( normalized_value )
|
158
|
+
|
159
|
+
if repeat.nil? or repeat.length < 1
|
160
|
+
# try again chomping off the last number (fixes float rounding issues)
|
161
|
+
normalized_value = normalized_value.to_s[0...-1].to_f
|
162
|
+
repeat = find_repeat(normalized_value.to_s)
|
163
|
+
end
|
164
|
+
|
165
|
+
if !repeat or repeat.length < 1
|
166
|
+
return nil
|
167
|
+
else
|
168
|
+
return fractional_from_parts(
|
169
|
+
find_before_decimal(normalized_value),
|
170
|
+
find_after_decimal(normalized_value),
|
171
|
+
repeat)
|
172
|
+
end
|
88
173
|
end
|
89
174
|
|
90
|
-
def self.
|
91
|
-
|
175
|
+
def self.find_after_decimal( decimal )
|
176
|
+
s_decimal = decimal.to_s
|
177
|
+
regex = /(#{find_repeat(s_decimal)})+/
|
178
|
+
last = s_decimal.index( regex )
|
179
|
+
first = s_decimal.index( '.' ) + 1
|
180
|
+
s_decimal[first...last]
|
92
181
|
end
|
93
182
|
|
94
|
-
def self.
|
95
|
-
|
96
|
-
|
183
|
+
def self.find_before_decimal( decimal )
|
184
|
+
numeric = decimal.to_f.truncate.to_i
|
185
|
+
if numeric == 0
|
186
|
+
decimal.to_f < 0 ? "-0" : "0"
|
97
187
|
else
|
98
|
-
|
188
|
+
numeric.to_s
|
99
189
|
end
|
100
190
|
end
|
101
191
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
return
|
192
|
+
def self.find_repeat( decimal )
|
193
|
+
return largest_repeat( decimal.to_s.reverse, 0 ).reverse
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.largest_repeat( string, i )
|
197
|
+
if i * 2 > string.length
|
198
|
+
return ""
|
109
199
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
Rational(s)* Rational(2)**(-1024)*Rational("0#{f}".to_i(2),0x10000000000000)
|
200
|
+
repeat_string = string[0..i]
|
201
|
+
next_best = largest_repeat( string, i + 1)
|
202
|
+
if repeat_string == string[i+1..2*i + 1]
|
203
|
+
repeat_string.length > next_best.length ? repeat_string : next_best
|
204
|
+
else
|
205
|
+
next_best
|
117
206
|
end
|
118
207
|
end
|
208
|
+
|
209
|
+
def self.fractional_from_parts(before_decimal, after_decimal, repeat)
|
210
|
+
numerator = "#{before_decimal}#{after_decimal}#{repeat}".to_i - "#{before_decimal}#{after_decimal}".to_i
|
211
|
+
denominator = 10 ** (after_decimal.length + repeat.length) - 10 ** after_decimal.length
|
212
|
+
return Rational( numerator, denominator )
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.round_to_nearest_fraction(value, to_nearest_fraction)
|
216
|
+
to_nearest_float = Fractional.new(to_nearest_fraction).to_f
|
217
|
+
Fractional.new((Fractional.new(value).to_f / to_nearest_float).round * to_nearest_float)
|
218
|
+
end
|
219
|
+
|
119
220
|
end
|
data/spec/fractional_spec.rb
CHANGED
@@ -1,54 +1,486 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
|
3
|
+
##################################
|
4
|
+
# CLASS METHODS #
|
5
|
+
##################################
|
6
|
+
describe "Fractional::new" do
|
7
|
+
it "should accept Rationals" do
|
8
|
+
Fractional.new(Rational(3,4)).should_not be_nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should accept strings" do
|
12
|
+
Fractional.new("3/4").should_not be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should accept floats" do
|
16
|
+
Fractional.new(0.75).should_not be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should pass options down (such as exact)" do
|
20
|
+
Fractional.new(0.333, exact: true).should_not == Rational(1,3)
|
21
|
+
Fractional.new("0.333", exact: true).should_not == Rational(1,3)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "Fractional::float_to_fractional" do
|
27
|
+
it "should parse simple decimals" do
|
28
|
+
Fractional.float_to_fraction(0.5).should == Fractional.new(Rational(1,2))
|
29
|
+
Fractional.float_to_fraction(1.5).should == Fractional.new(Rational(3,2))
|
30
|
+
Fractional.float_to_fraction(1100).should == Fractional.new(Rational(1100,1))
|
31
|
+
# This next example is especially important as Rational(1.2) is not a nice
|
32
|
+
# number.
|
33
|
+
Fractional.float_to_fraction(1.2).should == Fractional.new(Rational(6,5))
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should parse more complex decimals" do
|
37
|
+
Fractional.float_to_fraction(1100.875).should == Fractional.new(Rational(8807,8))
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should allow for negative values for mixed fractions" do
|
41
|
+
Fractional.float_to_fraction(-1100.875).should == Fractional.new(Rational(-8807,8))
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should allow for negative values for single fractions" do
|
45
|
+
Fractional.float_to_fraction(-0.875).should == Fractional.new(Rational(-7,8))
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should allow for negative mixed fractions that that are rounded" do
|
49
|
+
Fractional.float_to_fraction(-101.140625, :to_nearest => "1/64").should == Fractional.new("-101 9/64")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should allow for negative single fractions that that are rounded" do
|
53
|
+
Fractional.float_to_fraction(-0.140625, :to_nearest => "1/64").should == Fractional.new("-9/64")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should round if passed 'to nearest'" do
|
57
|
+
Fractional.float_to_fraction(1100.14285714286, :to_nearest => "1/64").should == Fractional.new("1100 9/64")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should round if passed 'to_nearest' that is a float" do
|
61
|
+
Fractional.float_to_fraction(1100.14285714286, :to_nearest => 0.015625).should == Fractional.new("1100 9/64")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should round if passed 'to_nearest' and is a simple fraction" do
|
65
|
+
Fractional.float_to_fraction(0.14285714286, :to_nearest => "1/64").should == Fractional.new("9/64")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
69
|
+
Fractional.float_to_fraction(1100.875, :to_nearest => "1/2").should == Fractional.new("1101")
|
70
|
+
Fractional.float_to_fraction(1100.2, :to_nearest => "1/2").should == Fractional.new("1100")
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "Fractional::string_to_fractional" do
|
76
|
+
it "should parse a single fraction" do
|
77
|
+
Fractional.string_to_fraction('1/2').should == Fractional.new(Rational(1,2))
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should parse a mixed fraction" do
|
81
|
+
Fractional.string_to_fraction('1 2/4').should == Fractional.new(Rational(3,2))
|
82
|
+
Fractional.string_to_fraction("1100 7/8").should == Fractional.new(Rational(8807,8))
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should parse a simple decimal" do
|
86
|
+
Fractional.string_to_fraction('1.5').should == Fractional.new(Rational(3,2))
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should allow for negative mixed fractions" do
|
90
|
+
Fractional.string_to_fraction('-10 1/2').should == Fractional.new(Rational(-21,2))
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should allow for negative single fractions" do
|
94
|
+
Fractional.string_to_fraction("-1/64").should == Fractional.new(Rational(-1,64))
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should allow for negative denominators in single fractions" do
|
98
|
+
Fractional.string_to_fraction("1/-64").should == Fractional.new(Rational(-1,64))
|
99
|
+
Fractional.string_to_fraction("-1/-64").should == Fractional.new(Rational(1,64))
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should ignore repeated whitespace" do
|
103
|
+
Fractional.string_to_fraction("6 5/8").should == Fractional.string_to_fraction("6 5/8")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should try to get an accurate estimation of floating point values by default" do
|
107
|
+
Fractional.string_to_fraction("0.3333").should == Fractional.float_to_fraction(0.33333)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should not estimate if exact is specified" do
|
111
|
+
Fractional.string_to_fraction("0.3333", exact: true).should_not == Rational(1,3)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "Fractional::string_is_fraction?" do
|
117
|
+
it "should recognize a simple fraction" do
|
118
|
+
Fractional.string_is_fraction?("3/4").should be_true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should recognize a mixed fraction" do
|
122
|
+
Fractional.string_is_fraction?("1 11/12").should be_true
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should recognize a negative fraction" do
|
126
|
+
Fractional.string_is_fraction?("-3/4").should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should recognize a negative mixed fraction" do
|
130
|
+
Fractional.string_is_fraction?("-6 2/9").should be_true
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should accept more than one space between the whole number and fractional part" do
|
134
|
+
Fractional.string_is_fraction?("1 2/3").should be_true
|
135
|
+
Fractional.string_is_fraction?("3 1/2").should be_true
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should accept fractions with front and rear padding" do
|
139
|
+
Fractional.string_is_fraction?(" 2/3").should be_true
|
140
|
+
Fractional.string_is_fraction?("2/3 ").should be_true
|
141
|
+
Fractional.string_is_fraction?(" 2/3 ").should be_true
|
142
|
+
Fractional.string_is_fraction?(" 1 2/3").should be_true
|
143
|
+
Fractional.string_is_fraction?("1 2/3 ").should be_true
|
144
|
+
Fractional.string_is_fraction?(" 1 2/3 ").should be_true
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should not recognize decimals" do
|
148
|
+
Fractional.string_is_fraction?("2.3").should be_false
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should not recognize two consecutive fractions" do
|
152
|
+
Fractional.string_is_fraction?("2/3 9/5").should be_false
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should not recognize a string with a slash" do
|
156
|
+
Fractional.string_is_fraction?("n/a").should be_false
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not recognize a fraction mixed with non-decimals" do
|
160
|
+
Fractional.string_is_fraction?("3a/4").should be_false
|
161
|
+
Fractional.string_is_fraction?("a2/3").should be_false
|
162
|
+
Fractional.string_is_fraction?("1 2/3a").should be_false
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not recognize fractions with improper spacing" do
|
166
|
+
Fractional.string_is_fraction?("2 /2").should be_false
|
167
|
+
Fractional.string_is_fraction?("1/ 3").should be_false
|
168
|
+
Fractional.string_is_fraction?("1 2/ 3").should be_false
|
169
|
+
Fractional.string_is_fraction?("1 2 /3").should be_false
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "Fractional::string_is_mixed_fraction?" do
|
175
|
+
it "should recognize a mixed fraction" do
|
176
|
+
Fractional.string_is_mixed_fraction?("1 11/12").should be_true
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should recognize a negative mixed fraciton" do
|
180
|
+
Fractional.string_is_mixed_fraction?("-1 11/12").should be_true
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should not recognize a single fraction" do
|
184
|
+
Fractional.string_is_mixed_fraction?("3/4").should be_false
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "Fractional::string_is_single_fraction?" do
|
190
|
+
it "should recognize a single fraction" do
|
191
|
+
Fractional.string_is_single_fraction?("3/4").should be_true
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should recognize a negative numerator with a single fraction" do
|
195
|
+
Fractional.string_is_single_fraction?("-3/4").should be_true
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should not recognize a mixed fraction" do
|
199
|
+
Fractional.string_is_single_fraction?("1 11/12").should be_false
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should allow for negative denominators in single fractions" do
|
203
|
+
Fractional.string_is_single_fraction?("1/-64").should be_true
|
204
|
+
Fractional.string_is_single_fraction?("-1/-64").should be_true
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "Frational", "fractional_from_parts" do
|
210
|
+
it "should return rational values for various decimals" do
|
211
|
+
Fractional.fractional_from_parts("","","3").should eq(Rational(1,3))
|
212
|
+
Fractional.fractional_from_parts("","","7").should eq(Rational(7,9))
|
213
|
+
Fractional.fractional_from_parts("","","9").should eq(Rational(1,1))
|
214
|
+
Fractional.fractional_from_parts("5","8","144").should eq(Rational(3227,555))
|
215
|
+
Fractional.fractional_from_parts("","58","3").should eq(Rational(7,12))
|
216
|
+
Fractional.fractional_from_parts("","","012345679").should eq(Rational(1,81))
|
217
|
+
Fractional.fractional_from_parts("-0","","3333").should eq(Rational(-1,3))
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "Fractional", "find_repeat" do
|
222
|
+
it "should return the repeating decimals in a string" do
|
223
|
+
Fractional.find_repeat("1.0333").should eq("3")
|
224
|
+
Fractional.find_repeat("0.333").should eq("3")
|
225
|
+
Fractional.find_repeat("3.142857142857").should eq("142857")
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should return nil when there are not enough repeating decimals" do
|
229
|
+
Fractional.find_repeat("1.03").should eq("")
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "Fractional", "find_after_decimal" do
|
234
|
+
it "should return the decimal characters after the decimal but before the repeating characters" do
|
235
|
+
Fractional.find_after_decimal("1.0333").should eq("0")
|
236
|
+
Fractional.find_after_decimal("0.3333").should eq("")
|
237
|
+
Fractional.find_after_decimal("0.58333").should eq("58")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
|
242
|
+
describe "Fractional", "find_before_decimal" do
|
243
|
+
it "should return the decimal characters before the decimal" do
|
244
|
+
Fractional.find_before_decimal("1.0333").should eq("1")
|
245
|
+
Fractional.find_before_decimal(".3333").should eq("0")
|
246
|
+
Fractional.find_before_decimal("-1.4444").should eq("-1")
|
247
|
+
Fractional.find_before_decimal("-0.4444").should eq("-0")
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe "Fractional", "float_to_rational_repeat" do
|
252
|
+
it "should parse a repeating decimal into a fractional value" do
|
253
|
+
Fractional.float_to_rational_repeat("0.33").should eq(Rational(1,3))
|
254
|
+
Fractional.float_to_rational_repeat(".33").should eq(Rational(1,3))
|
255
|
+
Fractional.float_to_rational_repeat("0.8181").should eq(Rational(9,11))
|
256
|
+
Fractional.float_to_rational_repeat("3.142857142857").should eq(Rational(22,7))
|
257
|
+
Fractional.float_to_rational_repeat("-0.33333").should eq(Rational(-1,3))
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should be able to deal with a rounding error at the end of a float value" do
|
261
|
+
Fractional.string_to_fraction("3.1666666666666665").should eq(Rational(19,6))
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should not be able to parse a non repeating decimal" do
|
265
|
+
Fractional.float_to_rational_repeat("1.234").should be_nil
|
266
|
+
Fractional.float_to_rational_repeat("1.333312").should be_nil
|
267
|
+
Fractional.float_to_rational_repeat("as2342").should be_nil
|
268
|
+
end
|
269
|
+
end
|
4
270
|
|
5
|
-
|
6
|
-
|
271
|
+
|
272
|
+
##################################
|
273
|
+
# Arithematic #
|
274
|
+
##################################
|
275
|
+
|
276
|
+
describe "Fractional#+" do
|
277
|
+
it "should add with another Fractional" do
|
278
|
+
(Fractional.new(Rational(3,4)) + Fractional.new(Rational(1,2))).should == Fractional.new(1.25)
|
7
279
|
end
|
8
280
|
|
9
|
-
it "should
|
10
|
-
|
281
|
+
it "should add with other numerics" do
|
282
|
+
(Fractional.new(Rational(-4,5)) + 1).should == Fractional.new(Rational(1,5))
|
283
|
+
(Fractional.new("2/3") + 1.2).should == Fractional.new(1.86666666)
|
284
|
+
(Fractional.new(1.3) + BigDecimal.new(2)).should == Fractional.new("3.3")
|
11
285
|
end
|
12
286
|
|
13
|
-
it "should
|
14
|
-
|
287
|
+
it "should add with other numerics when other numerics are specified first" do
|
288
|
+
(1 + Fractional.new(Rational(-4,5)) ).should == Fractional.new(Rational(1,5))
|
289
|
+
(1.2 + Fractional.new("2/3")).should == Fractional.new(1.86666666)
|
290
|
+
(BigDecimal.new(2) + Fractional.new(1.3)).should == Fractional.new("3.3")
|
15
291
|
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "Fractional#-" do
|
295
|
+
(1 - Fractional.new(Rational(1,2))).should == Fractional.new(Rational(1,2))
|
296
|
+
end
|
297
|
+
|
298
|
+
describe "Fractional#*" do
|
299
|
+
(Fractional.new(Rational(1,2)) * Fractional.new(0.75)).should == Fractional.new(0.375)
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "Fractional#/" do
|
303
|
+
(Fractional.new(Rational(4,3)) / Fractional.new(Rational(3,2))).should == Fractional.new(Rational(8,9))
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "Fractional#**" do
|
307
|
+
(Fractional.new(8) ** Fractional.new(Rational(1,3))).should == Fractional.new(2)
|
308
|
+
end
|
309
|
+
|
310
|
+
##################################
|
311
|
+
# comparison #
|
312
|
+
##################################
|
313
|
+
|
314
|
+
describe "Fractional#==" do
|
315
|
+
it "should be equal to same Fractions" do
|
316
|
+
(Fractional.new(Rational(3,1)) == Fractional.new(Rational(3,1))).should be_true
|
20
317
|
end
|
21
|
-
|
22
|
-
it "should
|
23
|
-
|
24
|
-
one_half.to_f.should == 0.5
|
318
|
+
|
319
|
+
it "should not be equal to other Fractions" do
|
320
|
+
(Fractional.new(Rational(3,2)) == Fractional.new(Rational(3,1))).should be_false
|
25
321
|
end
|
26
|
-
|
27
|
-
it "should
|
28
|
-
|
29
|
-
another_one_half = Fractional.new("1/2")
|
30
|
-
|
31
|
-
(one_half + another_one_half).to_f.should == 1.0
|
322
|
+
|
323
|
+
it "should be equal regardless of type" do
|
324
|
+
(Fractional.new(Rational(3,4)) == Fractional.new(0.75)).should be_true
|
32
325
|
end
|
326
|
+
end
|
33
327
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
(one_and_a_half - one_quarter).to_f.should == 1.25
|
328
|
+
describe "Frational#<=>" do
|
329
|
+
it "should return 0 if fractions are equal" do
|
330
|
+
(Fractional.new(Rational(5,4)) <=> Fractional.new(1.25)).should == 0
|
39
331
|
end
|
40
332
|
|
41
|
-
it "should
|
42
|
-
|
43
|
-
second_fraction = Fractional.new("11 15/64")
|
44
|
-
|
45
|
-
(first_fraction * second_fraction).to_f.should == 21.064453125
|
333
|
+
it "should return -1 if the lhs is less" do
|
334
|
+
(Fractional.new(Rational(3,4)) <=> Fractional.new(Rational(8,9))).should == -1
|
46
335
|
end
|
47
|
-
|
48
|
-
it "should
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
336
|
+
|
337
|
+
it "should compare to other numerics" do
|
338
|
+
(Fractional.new(Rational(-1,2)) <=> -0.5).should == 0
|
339
|
+
(Fractional.new(Rational(-1,2)) <=> 1).should == -1
|
340
|
+
(Fractional.new(Rational(-1,2)) <=> BigDecimal.new(-2)).should == 1
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should work the other way too" do
|
344
|
+
( -0.5 <=> Fractional.new(Rational(-1,2))).should == 0
|
345
|
+
(1 <=> Fractional.new(Rational(-1,2))).should == 1
|
346
|
+
(BigDecimal.new(-2) <=> Fractional.new(Rational(-1,2))).should == -1
|
347
|
+
end
|
348
|
+
|
349
|
+
it "would be nice to compare to strings" do
|
350
|
+
(Fractional.new(Rational(1,2)) <=> "3/4").should == -1
|
351
|
+
("3/4" <=> Fractional.new(Rational(1,2))).should == 1
|
352
|
+
("-3/4" <=> Fractional.new(Rational(-1,2))).should == -1
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe "Frational", "comparsion" do
|
357
|
+
it "should use the numerics included comparsion module" do
|
358
|
+
(Fractional.new(Rational(-3,4)) < Fractional.new(Rational(1,2))).should be_true
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
##################################
|
363
|
+
# conversion #
|
364
|
+
##################################
|
365
|
+
|
366
|
+
describe "Fractional#to_s" do
|
367
|
+
it "should return nice representations of single fractions" do
|
368
|
+
Fractional.new(0.75).to_s.should == "3/4"
|
369
|
+
Fractional.new(-0.3333).to_s.should == "-1/3"
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should return nice representations of mixed fractions" do
|
374
|
+
Fractional.new(1.5).to_s.should == "3/2"
|
375
|
+
Fractional.new(-1.3333).to_s.should == "-4/3"
|
376
|
+
Fractional.new(0.0).to_s.should == "0/1"
|
377
|
+
end
|
378
|
+
|
379
|
+
it "should return mixed number representations if told so" do
|
380
|
+
Fractional.new(1.5).to_s(mixed_number: true).should == "1 1/2"
|
381
|
+
Fractional.new(Rational(-3,2)).to_s(mixed_number: true).should == "-1 1/2"
|
382
|
+
Fractional.new(1.00).to_s(mixed_number: true).should == "1"
|
383
|
+
Fractional.new(0.75).to_s(mixed_number: true).should == "3/4"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
describe "Fractional#to_f" do
|
388
|
+
it "should return float representations of fractions" do
|
389
|
+
Fractional.new("3/4").to_f.should == 0.75
|
390
|
+
Fractional.new("-2/3").to_f.should be_within(0.0000001).of(-0.6666666)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe "Fractional#to_r" do
|
395
|
+
it "should return a rational representation" do
|
396
|
+
Fractional.new("3/4").to_r.should == Rational(3,4)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe "Fractional#to_i" do
|
401
|
+
it "should return a truncated value" do
|
402
|
+
Fractional.new("1 3/4").to_i.should == 1
|
403
|
+
Fractional.new("-2 1/3").to_i.should == -2
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
describe "Fractional", "round" do
|
408
|
+
|
409
|
+
it "should round 0.142857142857143 to nearest 1/64th as 0.140625" do
|
410
|
+
Fractional.round_to_nearest_fraction(0.142857142857143, "1/64").should == Fractional.new(0.140625)
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should round '1/7' to nearest 1/64th as '9/64'" do
|
414
|
+
Fractional.round_to_nearest_fraction('1/7', "1/64").should == Fractional.new('9/64')
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should round 0.125 to nearest 1/64th as 0.125" do
|
418
|
+
Fractional.round_to_nearest_fraction(0.125, "1/64").should == Fractional.new(0.125)
|
419
|
+
end
|
420
|
+
|
421
|
+
it "should round '1100 1/7' to nearest 1/64th as '1100 9/64'" do
|
422
|
+
Fractional.round_to_nearest_fraction('1100 1/7', "1/64").should == Fractional.new('70409/64')
|
423
|
+
end
|
424
|
+
|
425
|
+
it "should round 1100.142857142857143 to nearest 1/64th as 1100.140625" do
|
426
|
+
Fractional.round_to_nearest_fraction(1100.142857142857143, "1/64").should == Fractional.new(1100.140625)
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
430
|
+
Fractional.round_to_nearest_fraction(1100.875, "1/2").should == Fractional.new(1101)
|
431
|
+
Fractional.round_to_nearest_fraction(1100.1, "1/2").should == Fractional.new(1100)
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should round if passed a float" do
|
435
|
+
Fractional.round_to_nearest_fraction(1100.875, 0.5).should == Fractional.new(1101)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
##################################
|
440
|
+
# misc #
|
441
|
+
##################################
|
442
|
+
|
443
|
+
describe 'Fractional#whole_part' do
|
444
|
+
it "should return the whole part, if it exists, of a fraction" do
|
445
|
+
Fractional.new(Rational(3,2)).whole_part.should eq(1)
|
446
|
+
Fractional.new(Rational(-3,2)).whole_part.should eq(-1)
|
447
|
+
Fractional.new(Rational(1,2)).whole_part.should eq(0)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
describe 'Fractional#fractional_part' do
|
452
|
+
it "should return the fractional part, if it exists, of a fraction" do
|
453
|
+
Fractional.new(Rational(3,2)).fractional_part.should eq(Fractional.new(Rational(1,2)))
|
454
|
+
Fractional.new(Rational(-3,2)).fractional_part.should eq(Fractional.new(Rational(-1,2)))
|
455
|
+
Fractional.new(Rational(1,2)).fractional_part.should eq(Fractional.new(Rational(1,2)))
|
456
|
+
Fractional.new(Rational(2,2)).fractional_part.should eq(Fractional.new(0))
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
##################################
|
462
|
+
# deprecated methods #
|
463
|
+
##################################
|
464
|
+
# remove in v1.1
|
465
|
+
describe "deprecated methods" do
|
466
|
+
it "Fractional.to_f" do
|
467
|
+
Fractional.to_f(1.5).should == 1.5
|
468
|
+
end
|
469
|
+
|
470
|
+
it "Fractional.to_s" do
|
471
|
+
Fractional.to_s(0.5).should == '1/2'
|
472
|
+
Fractional.to_s(-0.140625, :to_nearest => "1/64").should == "-9/64"
|
473
|
+
end
|
474
|
+
|
475
|
+
it "Fraction.fraction?" do
|
476
|
+
Fractional.fraction?("3/4").should be_true
|
477
|
+
end
|
478
|
+
|
479
|
+
it "Fraction.mixed_fraction?" do
|
480
|
+
Fractional.mixed_fraction?("1 11/12").should be_true
|
481
|
+
end
|
482
|
+
|
483
|
+
it "Fraction.single_fraction?" do
|
484
|
+
Fractional.single_fraction?("-3/4").should be_true
|
53
485
|
end
|
54
486
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fractional
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris O'Sullivan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: debugger
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: Fractional is a Ruby library for parsing fractions.
|
56
70
|
email:
|
57
71
|
- thechrisoshow@gmail.com
|
@@ -60,14 +74,15 @@ extensions: []
|
|
60
74
|
extra_rdoc_files: []
|
61
75
|
files:
|
62
76
|
- .gitignore
|
77
|
+
- .rspec
|
63
78
|
- Gemfile
|
64
79
|
- LICENSE
|
65
80
|
- README.rdoc
|
66
81
|
- Rakefile
|
67
82
|
- VERSION
|
68
83
|
- fractional.gemspec
|
84
|
+
- lib/deprecated.rb
|
69
85
|
- lib/fractional.rb
|
70
|
-
- spec/fractional_class_methods_spec.rb
|
71
86
|
- spec/fractional_spec.rb
|
72
87
|
- spec/spec_helper.rb
|
73
88
|
homepage: http://github.com/thechrisoshow/fractional
|
@@ -96,6 +111,5 @@ specification_version: 4
|
|
96
111
|
summary: 'You can use fractional to convert decimal numbers to string representations
|
97
112
|
of fractions. e.g: Fractional.to_s(1.5) #=> "1 1/2"'
|
98
113
|
test_files:
|
99
|
-
- spec/fractional_class_methods_spec.rb
|
100
114
|
- spec/fractional_spec.rb
|
101
115
|
- spec/spec_helper.rb
|
@@ -1,219 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe "Fractional", "to_f" do
|
4
|
-
|
5
|
-
it "should parse '1/2' to 0.5" do
|
6
|
-
Fractional.to_f('1/2').should == 0.5
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should parse '1 2/4' to 1.5" do
|
10
|
-
Fractional.to_f('1 2/4').should == 1.5
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should parse '1.5' to 1.5" do
|
14
|
-
Fractional.to_f('1.5').should == 1.5
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should parse 1.5 to 1.5" do
|
18
|
-
Fractional.to_f(1.5).should == 1.5
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should parse '1100 7/8' to 1100.875" do
|
22
|
-
Fractional.to_f("1100 7/8").should == 1100.875
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should allow for negative mixed fractions" do
|
26
|
-
Fractional.to_f('-10 1/2').should == -10.5
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should allow for negative single fractions" do
|
30
|
-
Fractional.to_f("-1/64").should == -0.015625
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should allow for negative denominators in single fractions" do
|
34
|
-
Fractional.to_f("1/-64").should == -0.015625
|
35
|
-
Fractional.to_f("-1/-64").should == 0.015625
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should ignore repeated whitespace" do
|
39
|
-
Fractional.to_f("6 5/8").should == Fractional.to_f("6 5/8")
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe "Fractional", "to_s" do
|
44
|
-
|
45
|
-
it "should return 0.5 as '1/2'" do
|
46
|
-
Fractional.to_s(0.5).should == '1/2'
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should return 1.5 as '1 1/2'" do
|
50
|
-
Fractional.to_s(1.5).should == '1 1/2'
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should parse 1100.875 to '1100 7/8'" do
|
54
|
-
Fractional.to_s(1100.875).should == "1100 7/8"
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should not have a fraction if it's just a whole number" do
|
58
|
-
Fractional.to_s(1100).should == "1100"
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should round if passed 'to nearest'" do
|
62
|
-
Fractional.to_s(1100.14285714286, :to_nearest => "1/64").should == "1100 9/64"
|
63
|
-
end
|
64
|
-
|
65
|
-
it "should round if passed 'to_nearest' that is a float" do
|
66
|
-
Fractional.to_s(1100.14285714286, :to_nearest => 0.015625).should == "1100 9/64"
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should round if passed 'to_nearest' and is a simple fraction" do
|
70
|
-
Fractional.to_s(0.14285714286, :to_nearest => "1/64").should == "9/64"
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
74
|
-
Fractional.to_s(1100.875, :to_nearest => "1/2").should == "1101"
|
75
|
-
Fractional.to_s(1100.2, :to_nearest => "1/2").should == "1100"
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should allow for negative values for mixed fractions" do
|
79
|
-
Fractional.to_s(-1100.875).should == "-1100 7/8"
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should allow for negative values for single fractions" do
|
83
|
-
Fractional.to_s(-0.875).should == "-7/8"
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should allow for negative mixed fractions that that are rounded" do
|
87
|
-
Fractional.to_s(-101.140625, :to_nearest => "1/64").should == "-101 9/64"
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should allow for negative single fractions that that are rounded" do
|
91
|
-
Fractional.to_s(-0.140625, :to_nearest => "1/64").should == "-9/64"
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
|
-
describe "Fractional", "round" do
|
98
|
-
|
99
|
-
it "should round 0.142857142857143 to nearest 1/64th as 0.140625" do
|
100
|
-
Fractional.round_to_nearest_fraction(0.142857142857143, "1/64").should == 0.140625
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should round '1/7' to nearest 1/64th as '9/64'" do
|
104
|
-
Fractional.round_to_nearest_fraction('1/7', "1/64").should == '9/64'
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should round 0.125 to nearest 1/64th as 0.125" do
|
108
|
-
Fractional.round_to_nearest_fraction(0.125, "1/64").should == 0.125
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should round '1100 1/7' to nearest 1/64th as '1100 9/64'" do
|
112
|
-
Fractional.round_to_nearest_fraction('1100 1/7', "1/64").should == '1100 9/64'
|
113
|
-
end
|
114
|
-
|
115
|
-
it "should round 1100.142857142857143 to nearest 1/64th as 1100.140625" do
|
116
|
-
Fractional.round_to_nearest_fraction(1100.142857142857143, "1/64").should == 1100.140625
|
117
|
-
end
|
118
|
-
|
119
|
-
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
120
|
-
Fractional.round_to_nearest_fraction(1100.875, "1/2").should == 1101
|
121
|
-
Fractional.round_to_nearest_fraction(1100.1, "1/2").should == 1100
|
122
|
-
end
|
123
|
-
|
124
|
-
it "should round if passed a float" do
|
125
|
-
Fractional.round_to_nearest_fraction(1100.875, 0.5).should == 1101
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe "Fractional", "fraction?" do
|
130
|
-
it "should recognize a simple fraction" do
|
131
|
-
Fractional.fraction?("3/4").should be_true
|
132
|
-
end
|
133
|
-
|
134
|
-
it "should recognize a mixed fraction" do
|
135
|
-
Fractional.fraction?("1 11/12").should be_true
|
136
|
-
end
|
137
|
-
|
138
|
-
it "should recognize a negative fraction" do
|
139
|
-
Fractional.fraction?("-3/4").should be_true
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should recognize a negative mixed fraction" do
|
143
|
-
Fractional.fraction?("-6 2/9").should be_true
|
144
|
-
end
|
145
|
-
|
146
|
-
it "should accept more than one space between the whole number and fractional part" do
|
147
|
-
Fractional.fraction?("1 2/3").should be_true
|
148
|
-
Fractional.fraction?("3 1/2").should be_true
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should accept fractions with front and rear padding" do
|
152
|
-
Fractional.fraction?(" 2/3").should be_true
|
153
|
-
Fractional.fraction?("2/3 ").should be_true
|
154
|
-
Fractional.fraction?(" 2/3 ").should be_true
|
155
|
-
Fractional.fraction?(" 1 2/3").should be_true
|
156
|
-
Fractional.fraction?("1 2/3 ").should be_true
|
157
|
-
Fractional.fraction?(" 1 2/3 ").should be_true
|
158
|
-
end
|
159
|
-
|
160
|
-
it "should not recognize decimals" do
|
161
|
-
Fractional.fraction?("2.3").should be_false
|
162
|
-
end
|
163
|
-
|
164
|
-
it "should not recognize two consecutive fractions" do
|
165
|
-
Fractional.fraction?("2/3 9/5").should be_false
|
166
|
-
end
|
167
|
-
|
168
|
-
it "should not recognize a string with a slash" do
|
169
|
-
Fractional.fraction?("n/a").should be_false
|
170
|
-
end
|
171
|
-
|
172
|
-
it "should not recognize a fraction mixed with non-decimals" do
|
173
|
-
Fractional.fraction?("3a/4").should be_false
|
174
|
-
Fractional.fraction?("a2/3").should be_false
|
175
|
-
Fractional.fraction?("1 2/3a").should be_false
|
176
|
-
end
|
177
|
-
|
178
|
-
it "should not recognize fractions with improper spacing" do
|
179
|
-
Fractional.fraction?("2 /2").should be_false
|
180
|
-
Fractional.fraction?("1/ 3").should be_false
|
181
|
-
Fractional.fraction?("1 2/ 3").should be_false
|
182
|
-
Fractional.fraction?("1 2 /3").should be_false
|
183
|
-
end
|
184
|
-
|
185
|
-
end
|
186
|
-
|
187
|
-
describe "Fractional", "single_fraction?" do
|
188
|
-
it "should recognize a single fraction" do
|
189
|
-
Fractional.single_fraction?("3/4").should be_true
|
190
|
-
end
|
191
|
-
|
192
|
-
it "should recognize a negative numerator with a single fraction" do
|
193
|
-
Fractional.single_fraction?("-3/4").should be_true
|
194
|
-
end
|
195
|
-
|
196
|
-
it "should not recognize a mixed fraction" do
|
197
|
-
Fractional.single_fraction?("1 11/12").should be_false
|
198
|
-
end
|
199
|
-
|
200
|
-
it "should allow for negative denominators in single fractions" do
|
201
|
-
Fractional.single_fraction?("1/-64").should be_true
|
202
|
-
Fractional.single_fraction?("-1/-64").should be_true
|
203
|
-
end
|
204
|
-
|
205
|
-
end
|
206
|
-
|
207
|
-
describe "Fractional", "mixed_fraction?" do
|
208
|
-
it "should recognize a mixed fraction" do
|
209
|
-
Fractional.mixed_fraction?("1 11/12").should be_true
|
210
|
-
end
|
211
|
-
|
212
|
-
it "should recognize a negative mixed fraciton" do
|
213
|
-
Fractional.mixed_fraction?("-1 11/12").should be_true
|
214
|
-
end
|
215
|
-
|
216
|
-
it "should not recognize a single fraction" do
|
217
|
-
Fractional.mixed_fraction?("3/4").should be_false
|
218
|
-
end
|
219
|
-
end
|