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 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