measurement 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1 +1,3 @@
1
+ v0.2 Documentation
2
+
1
3
  v0.1 First version
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
@@ -2,12 +2,14 @@
2
2
 
3
3
  * http://github.com/jemmyw/measurement
4
4
 
5
- == DESCRIPTION
6
-
7
5
  == INSTALL:
8
6
 
9
7
  * sudo gem install measurement
10
8
 
9
+ == DOCUMENTATION:
10
+
11
+ * http://rdoc.info/projects/jemmyw/measurement
12
+
11
13
  == EXAMPLE:
12
14
 
13
15
  require 'measurement/length'
@@ -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
- conversion 1000, :kilometre, :kilometres, :km, :suffix => 'km'
6
- conversion 0.01, :centimetre, :centimetres, :cm, :suffix => 'cm'
7
- conversion 0.001, :millimetre, :mm, :suffix => 'mm'
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
- 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'
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
- conversion 299792458, :light_seconds, :suffix => ' light seconds'
15
- conversion 1079252848800, :light_hours, :suffix => ' light hours'
34
+ unit 299792458, :light_seconds, :suffix => ' light seconds'
35
+ unit 1079252848800, :light_hours, :suffix => ' light hours'
16
36
  end
@@ -1,5 +1,5 @@
1
1
  module Measurement
2
- class Conversion
2
+ class Unit
3
3
  attr_reader :names
4
4
 
5
5
  def initialize(scale, *args)
@@ -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
- 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'
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', 'conversion')
1
+ require File.join(File.dirname(__FILE__), 'measurement', 'unit')
2
2
 
3
3
  module Measurement
4
- class NoScaleFoundException < Exception; end
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 = Conversion.new(1.0, *args)
10
- add_conversion(@base)
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.conversions
17
- @conversions ||= []
50
+ def self.units # :nodoc:
51
+ @units ||= []
18
52
  end
19
53
 
20
- def self.conversion(scale, *args)
21
- add_conversion(Conversion.new(scale, *args))
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.add_conversion(conversion)
25
- conversions << conversion
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 : conversions.detect do |conversion|
30
- conversion.has_name?(scale)
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
- conversions.detect do |conversion|
36
- conversion.has_name?(scale) ||
37
- conversion.suffix == scale
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 NoScaleFoundException.new(scale)
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
- def as(scale)
92
- self.class.to(@amount, scale)
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
- def to_s(scale = nil, precision = 2)
109
- if scale.to_s =~ /_and_/
110
- scales = scale.to_s.split('_and_')
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 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)
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, scale, precision)
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.1"
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/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"]
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"]
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Length do
4
- it 'should have 10 conversions' do
5
- Length.conversions.size.should == 10
4
+ it 'should have 10 units' do
5
+ Length.units.size.should == 10
6
6
  end
7
7
 
8
8
  it 'should use metres as a base' do
@@ -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::NoScaleFoundException)
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.1"
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
@@ -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