measurement 0.1 → 0.2
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/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
|