measurement 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ v0.1 First version
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Jeremy Wells
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,15 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README.rdoc
5
+ Rakefile
6
+ lib/measurement.rb
7
+ lib/measurement/conversion.rb
8
+ lib/measurement/length.rb
9
+ lib/measurement/weight.rb
10
+ spec/lib/conversion_spec.rb
11
+ spec/lib/length_spec.rb
12
+ spec/lib/measurement_spec.rb
13
+ spec/lib/weight_spec.rb
14
+ spec/spec.opts
15
+ spec/spec_helper.rb
data/README.rdoc ADDED
@@ -0,0 +1,40 @@
1
+ = Library for holding, converting and formatting measurements
2
+
3
+ * http://github.com/jemmyw/measurement
4
+
5
+ == DESCRIPTION
6
+
7
+ == INSTALL:
8
+
9
+ * sudo gem install measurement
10
+
11
+ == EXAMPLE:
12
+
13
+ require 'measurement/length'
14
+ length = Length.parse('180.34cm')
15
+ puts length.in_feet_and_inches => 5' 11"
16
+
17
+ == LICENSE:
18
+
19
+ (The MIT License)
20
+
21
+ Copyright (c) 2009 Jeremy Wells
22
+
23
+ Permission is hereby granted, free of charge, to any person obtaining
24
+ a copy of this software and associated documentation files (the
25
+ 'Software'), to deal in the Software without restriction, including
26
+ without limitation the rights to use, copy, modify, merge, publish,
27
+ distribute, sublicense, and/or sell copies of the Software, and to
28
+ permit persons to whom the Software is furnished to do so, subject to
29
+ the following conditions:
30
+
31
+ The above copyright notice and this permission notice shall be
32
+ included in all copies or substantial portions of the Software.
33
+
34
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
35
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
38
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
39
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
40
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'spec/rake/spectask'
4
+ require 'echoe'
5
+ Echoe.new('measurement') do |gem|
6
+ gem.author = "Jeremy Wells"
7
+ gem.summary = "A library for holding, converting and formatting measurements"
8
+ gem.email = "jemmyw@gmail.com"
9
+ end
@@ -0,0 +1,129 @@
1
+ require File.join(File.dirname(__FILE__), 'measurement', 'conversion')
2
+
3
+ module Measurement
4
+ class NoScaleFoundException < Exception; end
5
+
6
+ class Base
7
+ def self.base(*args)
8
+ if args.any?
9
+ @base = Conversion.new(1.0, *args)
10
+ add_conversion(@base)
11
+ else
12
+ @base
13
+ end
14
+ end
15
+
16
+ def self.conversions
17
+ @conversions ||= []
18
+ end
19
+
20
+ def self.conversion(scale, *args)
21
+ add_conversion(Conversion.new(scale, *args))
22
+ end
23
+
24
+ def self.add_conversion(conversion)
25
+ conversions << conversion
26
+ end
27
+
28
+ def self.fetch_scale(scale = nil)
29
+ scale.nil? ? base : conversions.detect do |conversion|
30
+ conversion.has_name?(scale)
31
+ end
32
+ end
33
+
34
+ def self.find_scale(scale)
35
+ conversions.detect do |conversion|
36
+ conversion.has_name?(scale) ||
37
+ conversion.suffix == scale
38
+ end
39
+ end
40
+
41
+ def self.from(amount, scale)
42
+ fetch_scale(scale).from(amount)
43
+ end
44
+
45
+ def self.to(amount, scale = nil)
46
+ fetch_scale(scale).to(amount)
47
+ end
48
+
49
+ def self.format(amount, scale = nil, precision = 2)
50
+ fetch_scale(scale).format(amount, precision)
51
+ end
52
+
53
+ def self.parse(string)
54
+ string = string.dup
55
+ base_amount = 0.0
56
+
57
+ while string =~ /(\d+(\.\d+)?)([^\d]*)/
58
+ amount = $1.to_f
59
+ scale = $3 && $3.strip
60
+
61
+ if scale && scale.length > 0
62
+ scale = find_scale(scale)
63
+
64
+ if scale.nil?
65
+ raise NoScaleFoundException.new(scale)
66
+ else
67
+ base_amount += scale.from(amount)
68
+ end
69
+ else
70
+ base_amount += amount
71
+ end
72
+
73
+ string.sub!(/(\d+(\.\d+)?)([^\d]*)/, '')
74
+ end
75
+
76
+ self.new(base_amount)
77
+ end
78
+
79
+ def initialize(amount = 0, scale = nil)
80
+ @amount = self.class.from(amount, scale)
81
+ end
82
+
83
+ def to_i
84
+ @amount.to_i
85
+ end
86
+
87
+ def to_f
88
+ @amount.to_f
89
+ end
90
+
91
+ def as(scale)
92
+ self.class.to(@amount, scale)
93
+ end
94
+
95
+ def method_missing(method, *args)
96
+ if method.to_s =~ /^(as|in)_(.*)/
97
+ scale = $2
98
+ if scale =~ /and/
99
+ to_s(scale, *args)
100
+ else
101
+ as(scale.to_sym, *args)
102
+ end
103
+ else
104
+ super
105
+ end
106
+ end
107
+
108
+ def to_s(scale = nil, precision = 2)
109
+ if scale.to_s =~ /_and_/
110
+ scales = scale.to_s.split('_and_')
111
+ amount = @amount
112
+ strs = []
113
+
114
+ while scale = scales.shift
115
+ n_in = self.class.to(amount, scale.to_sym)
116
+ n_in = n_in.floor unless scales.empty?
117
+ n_out = self.class.from(n_in, scale.to_sym)
118
+ amount -= self.class.from(n_in, scale.to_sym)
119
+ strs << self.class.format(n_out, scale.to_sym, 0)
120
+ end
121
+
122
+ strs.join(' ')
123
+ else
124
+ self.class.format(@amount, scale, precision)
125
+ end
126
+ end
127
+ alias_method :format, :to_s
128
+ end
129
+ end
@@ -0,0 +1,35 @@
1
+ module Measurement
2
+ class Conversion
3
+ attr_reader :names
4
+
5
+ def initialize(scale, *args)
6
+ @options = args.last.is_a?(Hash) ? args.pop : {}
7
+ @names = args
8
+ @scale = scale
9
+ end
10
+
11
+ def has_name?(name)
12
+ names.include?(name)
13
+ end
14
+
15
+ def from(amount)
16
+ amount.to_f * @scale
17
+ end
18
+
19
+ def to(amount)
20
+ amount.to_f / @scale
21
+ end
22
+
23
+ def format(amount, precision = 2)
24
+ prefix + ("%.#{precision}f" % to(amount)) + suffix
25
+ end
26
+
27
+ def prefix
28
+ @options[:prefix] || ''
29
+ end
30
+
31
+ def suffix
32
+ @options[:suffix] || ''
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'measurement')
2
+
3
+ class Length < Measurement::Base
4
+ base :metre, :suffix => 'm'
5
+ conversion 1000, :kilometre, :kilometres, :km, :suffix => 'km'
6
+ conversion 0.01, :centimetre, :centimetres, :cm, :suffix => 'cm'
7
+ conversion 0.001, :millimetre, :mm, :suffix => 'mm'
8
+
9
+ conversion 0.0254, :inch, :inches, :suffix => '"'
10
+ conversion 0.3048, :feet, :foot, :suffix => "'"
11
+ conversion 1609.34, :mile, :miles, :suffix => ' miles'
12
+ conversion 0.1016, :hand, :hands, :suffix => ' hands'
13
+
14
+ conversion 299792458, :light_seconds, :suffix => ' light seconds'
15
+ conversion 1079252848800, :light_hours, :suffix => ' light hours'
16
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'measurement')
2
+
3
+ class Weight < Measurement::Base
4
+ base :grams, :suffix => 'g'
5
+ conversion 1000.0, :kilograms, :kg, :kgs, :suffix => 'kg'
6
+ conversion 453.59236, :pounds, :pound, :lbs, :suffix => 'lbs'
7
+ conversion 28.3495231, :ounces, :ounce, :oz, :suffix => 'oz'
8
+ conversion 6350.29318, :stone, :st, :suffix => 'st'
9
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{measurement}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jeremy Wells"]
9
+ s.date = %q{2010-02-27}
10
+ s.description = %q{A library for holding, converting and formatting measurements}
11
+ s.email = %q{jemmyw@gmail.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/measurement.rb", "lib/measurement/conversion.rb", "lib/measurement/length.rb", "lib/measurement/weight.rb"]
13
+ s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/measurement.rb", "lib/measurement/conversion.rb", "lib/measurement/length.rb", "lib/measurement/weight.rb", "spec/lib/conversion_spec.rb", "spec/lib/length_spec.rb", "spec/lib/measurement_spec.rb", "spec/lib/weight_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "measurement.gemspec"]
14
+ s.homepage = %q{}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Measurement", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{measurement}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{A library for holding, converting and formatting measurements}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Measurement::Conversion do
4
+ describe '#instance methods' do
5
+ before do
6
+ @conversion = Measurement::Conversion.new(150.0, :test, :other)
7
+ end
8
+
9
+ describe '#from' do
10
+ it 'should multiply the amount by the conversion scale' do
11
+ @conversion.from(1).should == 150.0
12
+ end
13
+ end
14
+
15
+ describe '#to' do
16
+ it 'should divide the amount by the conversion scale' do
17
+ @conversion.to(150).should == 1
18
+ end
19
+ end
20
+
21
+ describe '#format' do
22
+ it 'should return a string' do
23
+ @conversion.format(1).should be_a(String)
24
+ end
25
+
26
+ it 'should format using the given precision' do
27
+ @conversion.format(200,1).should == "1.3"
28
+ @conversion.format(200,2).should == "1.33"
29
+ end
30
+
31
+ it 'should apply the suffix' do
32
+ @conversion = Measurement::Conversion.new(150.0, :test, :suffix => 'test')
33
+ @conversion.format(150, 0).should == "1test"
34
+ end
35
+
36
+ it 'should apply the prefix' do
37
+ @conversion = Measurement::Conversion.new(150.0, :test, :prefix => 'test')
38
+ @conversion.format(150, 0).should == "test1"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Length do
4
+ it 'should have 10 conversions' do
5
+ Length.conversions.size.should == 10
6
+ end
7
+
8
+ it 'should use metres as a base' do
9
+ Length.new(1).to_s(nil, 0).should == '1m'
10
+ end
11
+
12
+ { :cm => 100,
13
+ :mm => 1000,
14
+ :inches => 39.370,
15
+ :feet => 3.281,
16
+ :hand => 9.842,
17
+ :km => 0.001
18
+ }.each do |key, value|
19
+ it "should have #{key} with 1 metre = #{value} #{key}" do
20
+ Length.new(1).as(key).should be_close(value, 0.001)
21
+ end
22
+ end
23
+
24
+ it 'should have miles' do
25
+ Length.new(1).in_miles.should be_close(0.0006213, 0.0000001)
26
+ end
27
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Measurement::Base do
4
+ describe '::parse' do
5
+ it 'should parse in the base unit if no unit is specified' do
6
+ Length.parse('113').to_f.should == 113.0
7
+ end
8
+
9
+ it 'should parse floating point numbers' do
10
+ Length.parse('113.43').to_f.should == 113.43
11
+ end
12
+
13
+ it 'should parse in the unit specified' do
14
+ Length.parse('32cm').to_f.should == 0.32
15
+ Length.parse('32cm').to_s(:cm, 0).should == '32cm'
16
+ end
17
+
18
+ it 'should parse multiple units' do
19
+ Length.parse('32cm 5mm').to_f.should == 0.325
20
+ Length.parse('32cm 5mm').to_s(:cm, 0).should == '32cm'
21
+ Length.parse('32cm 5mm').to_s(:cm_and_mm).should == '32cm 5mm'
22
+ end
23
+
24
+ it 'should be able to parse units based on their suffix' do
25
+ Length.parse('5"').in_inches.should == 5.0
26
+ Length.parse(%Q{5' 11"}).to_f.should == 1.8034
27
+ end
28
+
29
+ it 'should raise a NoScaleFoundException if there is no scale matching the one passed' do
30
+ lambda do
31
+ Length.parse('10giglygoops')
32
+ end.should raise_error(Measurement::NoScaleFoundException)
33
+ end
34
+ end
35
+
36
+ describe '#method_missing' do
37
+ it 'should call as if passed in_scale' do
38
+ Length.new(10).in_cm.should == Length.new(10).as(:cm)
39
+ end
40
+
41
+ it 'should call as if passed as_scale' do
42
+ Length.new(10).as_cm.should == Length.new(10).as(:cm)
43
+ end
44
+
45
+ it 'should call to_s if passed in_scale_and_another_scale' do
46
+ length = Length.new(123.52390842)
47
+ length.in_cm_and_mm.should == length.to_s(:cm_and_mm)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Weight do
4
+ it 'should use metres as a base' do
5
+ Weight.new(1).to_s(nil, 0).should == '1g'
6
+ end
7
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --reverse
3
+ --debugger
@@ -0,0 +1,3 @@
1
+ require 'lib/measurement'
2
+ require 'lib/measurement/length'
3
+ require 'lib/measurement/weight'
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: measurement
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Wells
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-27 00:00:00 +13:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A library for holding, converting and formatting measurements
17
+ email: jemmyw@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - CHANGELOG
24
+ - LICENSE
25
+ - README.rdoc
26
+ - lib/measurement.rb
27
+ - lib/measurement/conversion.rb
28
+ - lib/measurement/length.rb
29
+ - lib/measurement/weight.rb
30
+ files:
31
+ - CHANGELOG
32
+ - LICENSE
33
+ - Manifest
34
+ - README.rdoc
35
+ - Rakefile
36
+ - lib/measurement.rb
37
+ - lib/measurement/conversion.rb
38
+ - lib/measurement/length.rb
39
+ - lib/measurement/weight.rb
40
+ - spec/lib/conversion_spec.rb
41
+ - spec/lib/length_spec.rb
42
+ - spec/lib/measurement_spec.rb
43
+ - spec/lib/weight_spec.rb
44
+ - spec/spec.opts
45
+ - spec/spec_helper.rb
46
+ - measurement.gemspec
47
+ has_rdoc: true
48
+ homepage: ""
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --line-numbers
54
+ - --inline-source
55
+ - --title
56
+ - Measurement
57
+ - --main
58
+ - README.rdoc
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "1.2"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project: measurement
76
+ rubygems_version: 1.3.5
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A library for holding, converting and formatting measurements
80
+ test_files: []
81
+