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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fef2bf465e3f0fb5a870268e07e3f5587d772bf
4
- data.tar.gz: b1a895f28cc4138b09f7ef67570a18689a1771b3
3
+ metadata.gz: e102c37bdea15e535451f4ace3e8427b5cd80ba3
4
+ data.tar.gz: aca489da451ff4ded33297324f3691878696dd8a
5
5
  SHA512:
6
- metadata.gz: 078854ddb0cb3b5aa76b2407fef374bef578e456ff9978da0a1794e37422fe12703a90ffa40a364040551f86354492273fc20aafa246672e999ef10cd9c32992
7
- data.tar.gz: 34812c79b93d3f3b7ab1153e6cee209a17978906363d7ee3527f7e335fcee86c0c23eb3b7d3416f72e9eb14b5ef76833c27a144f64495444d72fc1cded18a135
6
+ metadata.gz: 4dae17fc2ee51bbe1ea07eb0596a759fa5ae34ebd6a9a2418ef9c600c8ff9432a8a5ff354b6f6669edb09f78286e9c8e2432101fbb4712722a66e37eaabf08e5
7
+ data.tar.gz: 8eb87fbff148bee9e9c6c39c860c598aa0fd9adc1741688597666c7c77d1b6550b39d87b650b756678131d112ff3e775590a302ef07999347627b74db7524e5c
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --debug
3
+ --order rand
@@ -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
- Convert fractional string to float:
6
- Fractional.to_f("1100 7/8") #=> 1100.875
5
+ === Conversions
7
6
 
8
- Convert float to fractional string:
9
- Fractional.to_s(1100.875) #=> "1100 7/8"
10
- Fractional.to_s(1100.875, :to_nearest => "1/2") #=> "1101"
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.3.0
1
+ 1.0.1
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "fractional"
3
- spec.version = "0.1.0"
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
@@ -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
@@ -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
- @value = value
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 to_s
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
- Fractional.to_f(@value)
47
+ @value.to_f
17
48
  end
18
49
 
19
- [:+, :-, :*, :/].each do |math_operator|
20
- define_method(math_operator) do |another_fractional|
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 self.to_f(value)
26
- result = 0
54
+ def to_i
55
+ whole_part
56
+ end
27
57
 
28
- if mixed_fraction?(value)
29
- whole, numerator, denominator = value.scan(MIXED_FRACTION).flatten
58
+ def whole_part
59
+ @value.truncate
60
+ end
30
61
 
31
- result = (numerator.to_f / denominator.to_f) + whole.to_f.abs
62
+ def fractional_part
63
+ @value - whole_part
64
+ end
32
65
 
33
- result = whole.to_f > 0 ? result : -result
34
- elsif single_fraction?(value)
35
- numerator, denominator = value.split("/")
36
- result = numerator.to_f / denominator.to_f
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
- result = value.to_f
79
+ nil
39
80
  end
40
-
41
- result
42
81
  end
43
82
 
44
- def self.to_s(value, args={})
45
- whole_number = value.to_f.truncate.to_i
46
-
47
- if whole_number == 0 # Single fraction
48
- fractional_part_to_string(value, args[:to_nearest])
49
- else # Mixed fraction
50
- decimal_point_value = get_decimal_point_value(value.to_f)
51
- return whole_number.to_s if decimal_point_value == 0
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
- if (fractional_part == "1") || (fractional_part == "0")
56
- (whole_number + fractional_part.to_i).to_s
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
- whole_number.to_s + " " + fractional_part
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.round_to_nearest_fraction(value, to_nearest_fraction)
64
- if value.is_a? String
65
- to_nearest_float = to_f(to_nearest_fraction)
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
- to_s((self.to_f(value) / to_nearest_float).round * to_nearest_float)
68
- else
69
- to_nearest_float = to_f(to_nearest_fraction)
114
+ if options[:to_nearest]
115
+ return self.round_to_nearest_fraction( value, options[:to_nearest] )
116
+ end
70
117
 
71
- (value / to_nearest_float).round * to_nearest_float
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
- private
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.fraction?(value)
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.single_fraction?(value)
83
- fraction?(value) and value.match(SINGLE_FRACTION)
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.mixed_fraction?(value)
87
- fraction?(value) and value.match(MIXED_FRACTION)
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.get_decimal_point_value(value)
91
- value - value.truncate
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.fractional_part_to_string(value, round)
95
- if round
96
- round_to_nearest_fraction(float_to_rational(value.to_f).to_s, round)
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
- float_to_rational(value.to_f).to_s
188
+ numeric.to_s
99
189
  end
100
190
  end
101
191
 
102
- # Whoa this method is crazy
103
- # I nicked it from Jannis Harder at http://markmail.org/message/nqgrsmaixwbrvsno
104
- def self.float_to_rational(value)
105
- if value.nan?
106
- return Rational(0,0) # Div by zero error
107
- elsif value.infinite?
108
- return Rational(value<0 ? -1 : 1,0) # Div by zero error
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
- s,e,f = [value].pack("G").unpack("B*").first.unpack("AA11A52")
111
- s = (-1)**s.to_i
112
- e = e.to_i(2)
113
- if e.nonzero? and e<2047
114
- Rational(s)* Rational(2)**(e-1023)*Rational("1#{f}".to_i(2),0x10000000000000)
115
- elsif e.zero?
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
@@ -1,54 +1,486 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "Fractional" do
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
- it "should create a fractional object from a string" do
6
- one_half = Fractional.new("1/2")
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 create a fractional object from a string" do
10
- one_half = Fractional.new("1/2")
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 create a fractional object from a string" do
14
- one_half = Fractional.new("1/2")
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
- it "should convert fractional to string" do
18
- one_half = Fractional.new("1/2")
19
- one_half.to_s.should == "1/2"
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 convert fractional to float" do
23
- one_half = Fractional.new("1/2")
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 add two fractionals together" do
28
- one_half = Fractional.new("1/2")
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
- it "should minus a fractional from another fractional" do
35
- one_and_a_half = Fractional.new("1 1/2")
36
- one_quarter = Fractional.new("1/4")
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 multiply 2 fractionals together" do
42
- first_fraction = Fractional.new("1 7/8")
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 divide 2 fractionals together" do
49
- first_fraction = Fractional.new("1 7/8")
50
- second_fraction = Fractional.new("21 33/512")
51
-
52
- (second_fraction / first_fraction).to_s.should == "11 15/64"
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
@@ -1,5 +1,6 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
  require 'fractional'
3
+ require 'bigdecimal'
3
4
 
4
5
  RSpec.configure do |config|
5
6
  config.treat_symbols_as_metadata_keys_with_true_values = true
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.0
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 00:00:00.000000000 Z
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