fractional 0.0.3
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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +31 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/fractional.gemspec +53 -0
- data/lib/fractional.rb +99 -0
- data/spec/fractional_spec.rb +119 -0
- data/spec/spec_helper.rb +9 -0
- metadata +75 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Chris O'Sullivan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= Fractional
|
2
|
+
|
3
|
+
Fractional is a library for parsing fractions.
|
4
|
+
|
5
|
+
Convert fractional string to float:
|
6
|
+
Fractional.to_f("1100 7/8") #=> 1100.875
|
7
|
+
|
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"
|
11
|
+
|
12
|
+
Round a value to the nearest fraction:
|
13
|
+
Fractional.round_to_nearest_fraction("1100 1/7", "1/64") #=> "1100 9/64"
|
14
|
+
Fractional.round_to_nearest_fraction(1100.142857142857143, "1/64") #=> 1100.140625
|
15
|
+
|
16
|
+
== Note on Patches/Pull Requests
|
17
|
+
|
18
|
+
* Fork the project.
|
19
|
+
* Make your feature addition or bug fix.
|
20
|
+
* Add tests for it. This is important so I don't break it in a
|
21
|
+
future version unintentionally.
|
22
|
+
* Commit, do not mess with rakefile, version, or history.
|
23
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
24
|
+
* Send me a pull request. Bonus points for topic branches.
|
25
|
+
|
26
|
+
== Special thanks
|
27
|
+
Thanks to Jannis Harder for his hardcore float to rational method I nicked from http://markmail.org/message/nqgrsmaixwbrvsno
|
28
|
+
|
29
|
+
== Copyright
|
30
|
+
|
31
|
+
Copyright (c) 2009 Chris O'Sullivan. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "fractional"
|
8
|
+
gem.summary = %Q{Fractional is a Ruby library for parsing fractions}
|
9
|
+
gem.description = %Q{Fractional is a Ruby library for parsing fractions.}
|
10
|
+
gem.email = "thechrisoshow@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/thechrisoshow/fractional"
|
12
|
+
gem.authors = ["Chris O'Sullivan"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
if File.exist?('VERSION')
|
40
|
+
version = File.read('VERSION')
|
41
|
+
else
|
42
|
+
version = ""
|
43
|
+
end
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "fractional #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.3
|
data/fractional.gemspec
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{fractional}
|
8
|
+
s.version = "0.0.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Chris O'Sullivan"]
|
12
|
+
s.date = %q{2009-10-14}
|
13
|
+
s.description = %q{Fractional is a Ruby library for parsing fractions.}
|
14
|
+
s.email = %q{thechrisoshow@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"fractional.gemspec",
|
27
|
+
"lib/fractional.rb",
|
28
|
+
"spec/fractional_spec.rb",
|
29
|
+
"spec/spec_helper.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/thechrisoshow/fractional}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.3.5}
|
35
|
+
s.summary = %q{Fractional is a Ruby library for parsing fractions}
|
36
|
+
s.test_files = [
|
37
|
+
"spec/fractional_spec.rb",
|
38
|
+
"spec/spec_helper.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
43
|
+
s.specification_version = 3
|
44
|
+
|
45
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
46
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
52
|
+
end
|
53
|
+
end
|
data/lib/fractional.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rational'
|
2
|
+
|
3
|
+
module Fractional
|
4
|
+
|
5
|
+
def self.to_f(value)
|
6
|
+
result = 0
|
7
|
+
|
8
|
+
if mixed_fraction?(value)
|
9
|
+
whole, numerator, denominator = value.scan(/(\-?\d*)\s(\d+)\/(\d+)/).flatten
|
10
|
+
|
11
|
+
result = (numerator.to_f / denominator.to_f) + whole.to_f.abs
|
12
|
+
|
13
|
+
result = whole.to_f > 0 ? result : -result
|
14
|
+
elsif single_fraction?(value)
|
15
|
+
numerator, denominator = value.split("/")
|
16
|
+
result = numerator.to_f / denominator.to_f
|
17
|
+
else
|
18
|
+
result = value.to_f
|
19
|
+
end
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.to_s(value, args={})
|
25
|
+
whole_number = value.to_f.truncate.to_i
|
26
|
+
|
27
|
+
if whole_number == 0 # Single fraction
|
28
|
+
fractional_part_to_string(value, args[:to_nearest])
|
29
|
+
else # Mixed fraction
|
30
|
+
decimal_point_value = get_decimal_point_value(value.to_f)
|
31
|
+
return whole_number.to_s if decimal_point_value == 0
|
32
|
+
|
33
|
+
fractional_part = fractional_part_to_string(decimal_point_value.abs, args[:to_nearest])
|
34
|
+
|
35
|
+
if (fractional_part == "1") || (fractional_part == "0")
|
36
|
+
(whole_number + fractional_part.to_i).to_s
|
37
|
+
else
|
38
|
+
whole_number.to_s + " " + fractional_part
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.round_to_nearest_fraction(value, to_nearest_fraction)
|
44
|
+
if value.is_a? String
|
45
|
+
to_nearest_float = to_f(to_nearest_fraction)
|
46
|
+
|
47
|
+
to_s((self.to_f(value) / to_nearest_float).round * to_nearest_float)
|
48
|
+
else
|
49
|
+
to_nearest_float = to_f(to_nearest_fraction)
|
50
|
+
|
51
|
+
(value / to_nearest_float).round * to_nearest_float
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def self.fraction?(value)
|
59
|
+
value.to_s.count('/') == 1
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.single_fraction?(value)
|
63
|
+
fraction?(value) and !mixed_fraction?(value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.mixed_fraction?(value)
|
67
|
+
fraction?(value) and value.match(/\-?\d*\s+\d+\/\d+/)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.get_decimal_point_value(value)
|
71
|
+
value - value.truncate
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.fractional_part_to_string(value, round)
|
75
|
+
if round
|
76
|
+
round_to_nearest_fraction(float_to_rational(value.to_f).to_s, round)
|
77
|
+
else
|
78
|
+
float_to_rational(value.to_f).to_s
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Whoa this method is crazy
|
83
|
+
# I nicked it from Jannis Harder at http://markmail.org/message/nqgrsmaixwbrvsno
|
84
|
+
def self.float_to_rational(value)
|
85
|
+
if value.nan?
|
86
|
+
return Rational(0,0) # Div by zero error
|
87
|
+
elsif value.infinite?
|
88
|
+
return Rational(value<0 ? -1 : 1,0) # Div by zero error
|
89
|
+
end
|
90
|
+
s,e,f = [value].pack("G").unpack("B*").first.unpack("AA11A52")
|
91
|
+
s = (-1)**s.to_i
|
92
|
+
e = e.to_i(2)
|
93
|
+
if e.nonzero? and e<2047
|
94
|
+
Rational(s)* Rational(2)**(e-1023)*Rational("1#{f}".to_i(2),0x10000000000000)
|
95
|
+
elsif e.zero?
|
96
|
+
Rational(s)* Rational(2)**(-1024)*Rational("0#{f}".to_i(2),0x10000000000000)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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
|
+
end
|
34
|
+
|
35
|
+
describe "Fractional", "to_s" do
|
36
|
+
|
37
|
+
it "should return 0.5 as '1/2'" do
|
38
|
+
Fractional.to_s(0.5).should == '1/2'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return 1.5 as '1 1/2'" do
|
42
|
+
Fractional.to_s(1.5).should == '1 1/2'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should parse 1100.875 to '1100 7/8'" do
|
46
|
+
Fractional.to_s(1100.875).should == "1100 7/8"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not have a fraction if it's just a whole number" do
|
50
|
+
Fractional.to_s(1100).should == "1100"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should round if passed 'to nearest'" do
|
54
|
+
Fractional.to_s(1100.14285714286, :to_nearest => "1/64").should == "1100 9/64"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should round if passed 'to_nearest' that is a float" do
|
58
|
+
Fractional.to_s(1100.14285714286, :to_nearest => 0.015625).should == "1100 9/64"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should round if passed 'to_nearest' and is a simple fraction" do
|
62
|
+
Fractional.to_s(0.14285714286, :to_nearest => "1/64").should == "9/64"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
66
|
+
Fractional.to_s(1100.875, :to_nearest => "1/2").should == "1101"
|
67
|
+
Fractional.to_s(1100.2, :to_nearest => "1/2").should == "1100"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should allow for negative values for mixed fractions" do
|
71
|
+
Fractional.to_s(-1100.875).should == "-1100 7/8"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should allow for negative values for single fractions" do
|
75
|
+
Fractional.to_s(-0.875).should == "-7/8"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should allow for negative mixed fractions that that are rounded" do
|
79
|
+
Fractional.to_s(-101.140625, :to_nearest => "1/64").should == "-101 9/64"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should allow for negative single fractions that that are rounded" do
|
83
|
+
Fractional.to_s(-0.140625, :to_nearest => "1/64").should == "-9/64"
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "Fractional", "round" do
|
90
|
+
|
91
|
+
it "should round 0.142857142857143 to nearest 1/64th as 0.140625" do
|
92
|
+
Fractional.round_to_nearest_fraction(0.142857142857143, "1/64").should == 0.140625
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should round '1/7' to nearest 1/64th as '9/64'" do
|
96
|
+
Fractional.round_to_nearest_fraction('1/7', "1/64").should == '9/64'
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should round 0.125 to nearest 1/64th as 0.125" do
|
100
|
+
Fractional.round_to_nearest_fraction(0.125, "1/64").should == 0.125
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should round '1100 1/7' to nearest 1/64th as '1100 9/64'" do
|
104
|
+
Fractional.round_to_nearest_fraction('1100 1/7', "1/64").should == '1100 9/64'
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should round 1100.142857142857143 to nearest 1/64th as 1100.140625" do
|
108
|
+
Fractional.round_to_nearest_fraction(1100.142857142857143, "1/64").should == 1100.140625
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should round if passed 'to_nearest' that rounds to nearest whole number" do
|
112
|
+
Fractional.round_to_nearest_fraction(1100.875, "1/2").should == 1101
|
113
|
+
Fractional.round_to_nearest_fraction(1100.1, "1/2").should == 1100
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should round if passed a float" do
|
117
|
+
Fractional.round_to_nearest_fraction(1100.875, 0.5).should == 1101
|
118
|
+
end
|
119
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fractional
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris O'Sullivan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-14 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Fractional is a Ruby library for parsing fractions.
|
26
|
+
email: thechrisoshow@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- .document
|
36
|
+
- .gitignore
|
37
|
+
- LICENSE
|
38
|
+
- README.rdoc
|
39
|
+
- Rakefile
|
40
|
+
- VERSION
|
41
|
+
- fractional.gemspec
|
42
|
+
- lib/fractional.rb
|
43
|
+
- spec/fractional_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/thechrisoshow/fractional
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Fractional is a Ruby library for parsing fractions
|
73
|
+
test_files:
|
74
|
+
- spec/fractional_spec.rb
|
75
|
+
- spec/spec_helper.rb
|