measurement 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Manifest +2 -2
- data/README.rdoc +4 -2
- data/lib/measurement/length.rb +30 -10
- data/lib/measurement/{conversion.rb → unit.rb} +1 -1
- data/lib/measurement/weight.rb +20 -5
- data/lib/measurement.rb +134 -35
- data/measurement.gemspec +3 -3
- data/spec/lib/length_spec.rb +2 -2
- data/spec/lib/measurement_spec.rb +1 -1
- data/spec/lib/unit_spec.rb +42 -0
- metadata +4 -4
- data/spec/lib/conversion_spec.rb +0 -42
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -4,12 +4,12 @@ Manifest
|
|
4
4
|
README.rdoc
|
5
5
|
Rakefile
|
6
6
|
lib/measurement.rb
|
7
|
-
lib/measurement/conversion.rb
|
8
7
|
lib/measurement/length.rb
|
8
|
+
lib/measurement/unit.rb
|
9
9
|
lib/measurement/weight.rb
|
10
|
-
spec/lib/conversion_spec.rb
|
11
10
|
spec/lib/length_spec.rb
|
12
11
|
spec/lib/measurement_spec.rb
|
12
|
+
spec/lib/unit_spec.rb
|
13
13
|
spec/lib/weight_spec.rb
|
14
14
|
spec/spec.opts
|
15
15
|
spec/spec_helper.rb
|
data/README.rdoc
CHANGED
data/lib/measurement/length.rb
CHANGED
@@ -1,16 +1,36 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'measurement')
|
2
2
|
|
3
|
+
# This class represents a Length measurement. The
|
4
|
+
# base units are metres. The available conversions
|
5
|
+
# are:
|
6
|
+
#
|
7
|
+
# * millimetres (mm)
|
8
|
+
# * centimetres (cm)
|
9
|
+
# * metres (m)
|
10
|
+
# * kilometres (km)
|
11
|
+
# * inches (")
|
12
|
+
# * feet (')
|
13
|
+
# * miles
|
14
|
+
# * hands
|
15
|
+
# * light_seconds
|
16
|
+
# * light_hours
|
17
|
+
#
|
18
|
+
# Example usage:
|
19
|
+
#
|
20
|
+
# require 'measurement/length'
|
21
|
+
# puts Length.parse('180.34cm').in_feet_and_inches => 5' 11"
|
22
|
+
#
|
3
23
|
class Length < Measurement::Base
|
4
|
-
base :metre, :suffix => 'm'
|
5
|
-
|
6
|
-
|
7
|
-
|
24
|
+
base :metre, :metres, :suffix => 'm'
|
25
|
+
unit 1000, :kilometre, :kilometres, :km, :suffix => 'km'
|
26
|
+
unit 0.01, :centimetre, :centimetres, :cm, :suffix => 'cm'
|
27
|
+
unit 0.001, :millimetre, :mm, :suffix => 'mm'
|
8
28
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
29
|
+
unit 0.0254, :inch, :inches, :suffix => '"'
|
30
|
+
unit 0.3048, :feet, :foot, :suffix => "'"
|
31
|
+
unit 1609.34, :mile, :miles, :suffix => ' miles'
|
32
|
+
unit 0.1016, :hand, :hands, :suffix => ' hands'
|
13
33
|
|
14
|
-
|
15
|
-
|
34
|
+
unit 299792458, :light_seconds, :suffix => ' light seconds'
|
35
|
+
unit 1079252848800, :light_hours, :suffix => ' light hours'
|
16
36
|
end
|
data/lib/measurement/weight.rb
CHANGED
@@ -1,9 +1,24 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'measurement')
|
2
2
|
|
3
|
+
# This class represents a Weight measurement. The
|
4
|
+
# base units are grams. The available conversions
|
5
|
+
# are:
|
6
|
+
#
|
7
|
+
# * grams (g)
|
8
|
+
# * kilograms (kg)
|
9
|
+
# * pounds (lbs)
|
10
|
+
# * ounces (oz)
|
11
|
+
# * stone (st)
|
12
|
+
#
|
13
|
+
# Example usage:
|
14
|
+
#
|
15
|
+
# require 'measurement/weight'
|
16
|
+
# puts Length.parse('100kg').in_lbs_and_oz => 220lbs 7oz
|
17
|
+
#
|
3
18
|
class Weight < Measurement::Base
|
4
|
-
base :grams, :suffix => 'g'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
19
|
+
base :gram, :grams, :suffix => 'g'
|
20
|
+
unit 1000.0, :kilograms, :kg, :kgs, :suffix => 'kg'
|
21
|
+
unit 453.59236, :pounds, :pound, :lbs, :suffix => 'lbs'
|
22
|
+
unit 28.3495231, :ounces, :ounce, :oz, :suffix => 'oz'
|
23
|
+
unit 6350.29318, :stone, :st, :suffix => 'st'
|
9
24
|
end
|
data/lib/measurement.rb
CHANGED
@@ -1,55 +1,121 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'measurement', '
|
1
|
+
require File.join(File.dirname(__FILE__), 'measurement', 'unit')
|
2
2
|
|
3
3
|
module Measurement
|
4
|
-
class
|
5
|
-
|
4
|
+
class NoUnitFoundException < Exception; end
|
5
|
+
|
6
|
+
# The Measurement::Base class provides a basis for types of
|
7
|
+
# measurement. For example, length or weight. It should
|
8
|
+
# be subclassed and not used directly.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# class Length < Measurement::Base
|
13
|
+
# base :metre, :metres, :suffix => 'm'
|
14
|
+
# unit 0.3048, :feet, :foot, :suffix => "'"
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Length.new(10).in_feet => 32.8083989501312
|
18
|
+
#
|
19
|
+
# Extending an existing measurement:
|
20
|
+
#
|
21
|
+
# Length.unit 2000, :quint, :qt, :suffix => 'qt'
|
22
|
+
# Length.new(10).to_s(:qt, 3) => 0.005qt
|
23
|
+
#
|
6
24
|
class Base
|
25
|
+
# Define the base measurement unit. This method accepts
|
26
|
+
# a list of names for the base measurement, followed
|
27
|
+
# by the standard unit options. See #unit
|
28
|
+
#
|
29
|
+
# Example, defining a base unit for weights:
|
30
|
+
#
|
31
|
+
# class Weight < Measurement::Base
|
32
|
+
# base :gram, :grams, :suffix => 'g'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Weight.new(1).to_s => "1g"
|
36
|
+
#
|
37
|
+
# The base unit should only be set once because all
|
38
|
+
# other units in this measurement are based off the
|
39
|
+
# base unit.
|
40
|
+
#
|
7
41
|
def self.base(*args)
|
8
42
|
if args.any?
|
9
|
-
@base =
|
10
|
-
|
43
|
+
@base = Unit.new(1.0, *args)
|
44
|
+
add_unit(@base)
|
11
45
|
else
|
12
46
|
@base
|
13
47
|
end
|
14
48
|
end
|
15
49
|
|
16
|
-
def self.
|
17
|
-
@
|
50
|
+
def self.units # :nodoc:
|
51
|
+
@units ||= []
|
18
52
|
end
|
19
53
|
|
20
|
-
|
21
|
-
|
54
|
+
# Define a unit of measurement. This must be a number based on
|
55
|
+
# the #base measurement unit.
|
56
|
+
# Takes a scaling number, a list of names and finally a
|
57
|
+
# hash of options.
|
58
|
+
#
|
59
|
+
# For example, if the base unit is metres, then defining the
|
60
|
+
# unit for centimetres would be as follows:
|
61
|
+
#
|
62
|
+
# unit 0.01, :centimetre, :centimetres, :cm, :suffix => 'cm'
|
63
|
+
#
|
64
|
+
# Here a centimetre is defined as one hundredth of a metre. The
|
65
|
+
# different name usages for centimetre are specified (for parsing, see #parse),
|
66
|
+
# and the suffix is set to 'cm'
|
67
|
+
#
|
68
|
+
# Available options:
|
69
|
+
#
|
70
|
+
# * <tt>prefix</tt> - A prefix to use when formatting the unit.
|
71
|
+
# * <tt>suffix</tt> - A suffix to use when formatting the unit.
|
72
|
+
#
|
73
|
+
def self.unit(scale, *args)
|
74
|
+
add_unit(Unit.new(scale, *args))
|
22
75
|
end
|
23
76
|
|
24
|
-
def self.
|
25
|
-
|
77
|
+
def self.add_unit(unit) # :nodoc:
|
78
|
+
units << unit
|
26
79
|
end
|
27
80
|
|
28
|
-
def self.fetch_scale(scale = nil)
|
29
|
-
scale.nil? ? base :
|
30
|
-
|
81
|
+
def self.fetch_scale(scale = nil) # :nodoc:
|
82
|
+
scale.nil? ? base : units.detect do |unit|
|
83
|
+
unit.has_name?(scale)
|
31
84
|
end
|
32
85
|
end
|
33
86
|
|
34
|
-
def self.find_scale(scale)
|
35
|
-
|
36
|
-
|
37
|
-
|
87
|
+
def self.find_scale(scale) # :nodoc:
|
88
|
+
units.detect do |unit|
|
89
|
+
unit.has_name?(scale) ||
|
90
|
+
unit.suffix == scale
|
38
91
|
end
|
39
92
|
end
|
40
93
|
|
41
|
-
def self.from(amount, scale)
|
94
|
+
def self.from(amount, scale) # :nodoc:
|
42
95
|
fetch_scale(scale).from(amount)
|
43
96
|
end
|
44
97
|
|
45
|
-
def self.to(amount, scale = nil)
|
98
|
+
def self.to(amount, scale = nil) # :nodoc:
|
46
99
|
fetch_scale(scale).to(amount)
|
47
100
|
end
|
48
101
|
|
49
|
-
def self.format(amount, scale = nil, precision = 2)
|
102
|
+
def self.format(amount, scale = nil, precision = 2) #:nodoc:
|
50
103
|
fetch_scale(scale).format(amount, precision)
|
51
104
|
end
|
52
105
|
|
106
|
+
# Parse a string containing this measurement. The string
|
107
|
+
# can use any of the defined units. This function will look
|
108
|
+
# for numbers in the string, followed by text. The text
|
109
|
+
# can be any unit name or suffix.
|
110
|
+
#
|
111
|
+
# Examples:
|
112
|
+
# Length.parse("180cm").in_cm => 180
|
113
|
+
# Length.parse("10m 11cm 12mm").in_metres => 10.122
|
114
|
+
#
|
115
|
+
# If a valid unit cannot be found an error is raised:
|
116
|
+
#
|
117
|
+
# Weight.parse("180cm") => Measurement::NoScaleException
|
118
|
+
#
|
53
119
|
def self.parse(string)
|
54
120
|
string = string.dup
|
55
121
|
base_amount = 0.0
|
@@ -62,7 +128,7 @@ module Measurement
|
|
62
128
|
scale = find_scale(scale)
|
63
129
|
|
64
130
|
if scale.nil?
|
65
|
-
raise
|
131
|
+
raise NoUnitFoundException.new(scale)
|
66
132
|
else
|
67
133
|
base_amount += scale.from(amount)
|
68
134
|
end
|
@@ -80,19 +146,32 @@ module Measurement
|
|
80
146
|
@amount = self.class.from(amount, scale)
|
81
147
|
end
|
82
148
|
|
149
|
+
# The base unit as an integer
|
83
150
|
def to_i
|
84
151
|
@amount.to_i
|
85
152
|
end
|
86
153
|
|
154
|
+
# The base unit as a float
|
87
155
|
def to_f
|
88
156
|
@amount.to_f
|
89
157
|
end
|
90
158
|
|
91
|
-
|
92
|
-
|
159
|
+
# This measurement converted to the specified unit.
|
160
|
+
#
|
161
|
+
# Example:
|
162
|
+
#
|
163
|
+
# Length.new(10).as(:feet) => 32.8083989501312
|
164
|
+
#
|
165
|
+
# This method can also be called using helper methods:
|
166
|
+
#
|
167
|
+
# Length.new(10).in_feet
|
168
|
+
# Length.new(10).as_feet
|
169
|
+
#
|
170
|
+
def as(unit)
|
171
|
+
self.class.to(@amount, unit)
|
93
172
|
end
|
94
173
|
|
95
|
-
def method_missing(method, *args)
|
174
|
+
def method_missing(method, *args) # :nodoc:
|
96
175
|
if method.to_s =~ /^(as|in)_(.*)/
|
97
176
|
scale = $2
|
98
177
|
if scale =~ /and/
|
@@ -105,23 +184,43 @@ module Measurement
|
|
105
184
|
end
|
106
185
|
end
|
107
186
|
|
108
|
-
|
109
|
-
|
110
|
-
|
187
|
+
# Format the measurement and return as a string.
|
188
|
+
# This will format using the base unit if no unit
|
189
|
+
# is specified.
|
190
|
+
#
|
191
|
+
# Example:
|
192
|
+
#
|
193
|
+
# Length.new(1.8034).to_s(:feet) => 6'
|
194
|
+
#
|
195
|
+
# Multiple units can be specified allowing for a
|
196
|
+
# more naturally formatted measurement. For example:
|
197
|
+
#
|
198
|
+
# Length.new(1.8034).to_s(:feet_and_inches) => 5' 11"
|
199
|
+
#
|
200
|
+
# Naturally formatted measurements can be returned using
|
201
|
+
# shorthand functions:
|
202
|
+
#
|
203
|
+
# Length.new(1.8034).in_feet_and_inches => 5' 11"
|
204
|
+
#
|
205
|
+
# A precision can be specified, otherwise the measurement
|
206
|
+
# is rounded to the nearest integer.
|
207
|
+
def to_s(unit = nil, precision = 0)
|
208
|
+
if unit.to_s =~ /_and_/
|
209
|
+
units = unit.to_s.split('_and_')
|
111
210
|
amount = @amount
|
112
211
|
strs = []
|
113
212
|
|
114
|
-
while
|
115
|
-
n_in = self.class.to(amount,
|
116
|
-
n_in = n_in.floor unless
|
117
|
-
n_out = self.class.from(n_in,
|
118
|
-
amount -= self.class.from(n_in,
|
119
|
-
strs << self.class.format(n_out,
|
213
|
+
while unit = units.shift
|
214
|
+
n_in = self.class.to(amount, unit.to_sym)
|
215
|
+
n_in = n_in.floor unless units.empty?
|
216
|
+
n_out = self.class.from(n_in, unit.to_sym)
|
217
|
+
amount -= self.class.from(n_in, unit.to_sym)
|
218
|
+
strs << self.class.format(n_out, unit.to_sym, 0)
|
120
219
|
end
|
121
220
|
|
122
221
|
strs.join(' ')
|
123
222
|
else
|
124
|
-
self.class.format(@amount,
|
223
|
+
self.class.format(@amount, unit, precision)
|
125
224
|
end
|
126
225
|
end
|
127
226
|
alias_method :format, :to_s
|
data/measurement.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{measurement}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Jeremy Wells"]
|
9
9
|
s.date = %q{2010-02-27}
|
10
10
|
s.description = %q{A library for holding, converting and formatting measurements}
|
11
11
|
s.email = %q{jemmyw@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/measurement.rb", "lib/measurement/
|
13
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/measurement.rb", "lib/measurement/
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "lib/measurement.rb", "lib/measurement/length.rb", "lib/measurement/unit.rb", "lib/measurement/weight.rb"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "lib/measurement.rb", "lib/measurement/length.rb", "lib/measurement/unit.rb", "lib/measurement/weight.rb", "spec/lib/length_spec.rb", "spec/lib/measurement_spec.rb", "spec/lib/unit_spec.rb", "spec/lib/weight_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "measurement.gemspec"]
|
14
14
|
s.homepage = %q{}
|
15
15
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Measurement", "--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
data/spec/lib/length_spec.rb
CHANGED
@@ -29,7 +29,7 @@ describe Measurement::Base do
|
|
29
29
|
it 'should raise a NoScaleFoundException if there is no scale matching the one passed' do
|
30
30
|
lambda do
|
31
31
|
Length.parse('10giglygoops')
|
32
|
-
end.should raise_error(Measurement::
|
32
|
+
end.should raise_error(Measurement::NoUnitFoundException)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Measurement::Unit do
|
4
|
+
describe '#instance methods' do
|
5
|
+
before do
|
6
|
+
@unit = Measurement::Unit.new(150.0, :test, :other)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#from' do
|
10
|
+
it 'should multiply the amount by the unit scale' do
|
11
|
+
@unit.from(1).should == 150.0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#to' do
|
16
|
+
it 'should divide the amount by the unit scale' do
|
17
|
+
@unit.to(150).should == 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#format' do
|
22
|
+
it 'should return a string' do
|
23
|
+
@unit.format(1).should be_a(String)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should format using the given precision' do
|
27
|
+
@unit.format(200,1).should == "1.3"
|
28
|
+
@unit.format(200,2).should == "1.33"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should apply the suffix' do
|
32
|
+
@unit = Measurement::Unit.new(150.0, :test, :suffix => 'test')
|
33
|
+
@unit.format(150, 0).should == "1test"
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should apply the prefix' do
|
37
|
+
@unit = Measurement::Unit.new(150.0, :test, :prefix => 'test')
|
38
|
+
@unit.format(150, 0).should == "test1"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: measurement
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Wells
|
@@ -24,8 +24,8 @@ extra_rdoc_files:
|
|
24
24
|
- LICENSE
|
25
25
|
- README.rdoc
|
26
26
|
- lib/measurement.rb
|
27
|
-
- lib/measurement/conversion.rb
|
28
27
|
- lib/measurement/length.rb
|
28
|
+
- lib/measurement/unit.rb
|
29
29
|
- lib/measurement/weight.rb
|
30
30
|
files:
|
31
31
|
- CHANGELOG
|
@@ -34,12 +34,12 @@ files:
|
|
34
34
|
- README.rdoc
|
35
35
|
- Rakefile
|
36
36
|
- lib/measurement.rb
|
37
|
-
- lib/measurement/conversion.rb
|
38
37
|
- lib/measurement/length.rb
|
38
|
+
- lib/measurement/unit.rb
|
39
39
|
- lib/measurement/weight.rb
|
40
|
-
- spec/lib/conversion_spec.rb
|
41
40
|
- spec/lib/length_spec.rb
|
42
41
|
- spec/lib/measurement_spec.rb
|
42
|
+
- spec/lib/unit_spec.rb
|
43
43
|
- spec/lib/weight_spec.rb
|
44
44
|
- spec/spec.opts
|
45
45
|
- spec/spec_helper.rb
|
data/spec/lib/conversion_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
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
|