fractional 0.1.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|