measurements 0.3.0

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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ Gemfile.lock
2
+ .yardoc
3
+ doc/*
4
+ .DS_Store*
5
+ gems/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --no-private
2
+ --protected
3
+ --markup markdown
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+ # Capybara request specs
17
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
18
+ end
19
+
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Measurements Ruby Gem
2
+ This gem was created to assist in converting cooking measurements when scaling up a recipe.
3
+ I was having fun with it so I decided to go a little above and beyond.
4
+
5
+ **Note:** This project ended up getting bigger than I had expected and now there are quite a few things that need fixing.
6
+ I should have had a plan from the beginning...
7
+
8
+ ## Using the Gem
9
+
10
+ Install it with
11
+
12
+ ```shell
13
+ gem install measurements
14
+ ```
15
+
16
+ and enjoy.
17
+
18
+ ## Documentation
19
+ ```shell
20
+ yardoc
21
+ ```
22
+
23
+ ## Usage Examples
24
+ Create an Ounce object with a quantity of 3oz
25
+
26
+ ```ruby
27
+ ounce = Measurements.new_unit :ounce, 3
28
+ ```
29
+
30
+ Convert that 3oz object to a Pound object
31
+
32
+ ```ruby
33
+ pound = ounce.convert_to :pound
34
+ ```
35
+
36
+ Convert the current unit by altering the unit itself
37
+
38
+ ```ruby
39
+ ounce.convert_to! :pound
40
+ ```
41
+
42
+ Create an Ounce object with a type of solid. This would be used to make sure when you convert
43
+ using the smart convert (not yet implemented) the unit doesn't get converted to a fluid measurement
44
+
45
+ ```ruby
46
+ ounce = Measurements.new_unit :ounce, 3.5, :solid
47
+ ```
48
+
49
+ Get the list of available units
50
+
51
+ ```ruby
52
+ Measurements.available_units
53
+ => [:ounce, :pound, :teaspoon, :tablespoon, :cup, :pint, :quart, :gallon, :inch, :foot, :yard, :furlong, :chain, :mile, :thou, :league]
54
+ ```
55
+
56
+ Get the list of available types of units. ex: Solid, Fluid or Neutral
57
+
58
+ ```ruby
59
+ Measurements.available_types
60
+ => [:solid, :fluid, :neutral, :base]
61
+ ```
62
+
63
+ ## Getting Started with Development
64
+ Make sure you have rubygems installed. You can find instructions at [rubygems.org](http://docs.rubygems.org/read/chapter/3)
65
+
66
+ Have bundler installed on your system
67
+
68
+ gem install bundler
69
+
70
+ Run bundler to make sure you have all the right gems
71
+
72
+ bundle install
73
+
74
+ Generate some docs to browse while I work on getting some tests ready. After running the following command
75
+ browse to the doc directory and open the index.html file in your favorite browser.
76
+
77
+ yardoc
78
+
79
+ Right now when I've been testing the gem inside irb I've been running the ruby line.
80
+
81
+ ```ruby
82
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+"/lib"); require 'measurements'
83
+ ```
84
+
85
+ You should also note that this only works if you launch irb from within the measurements directory.
86
+
87
+ If you want to be snazy and grab this line to load without using a text editor you can run one of these commands
88
+
89
+ ##### Unix
90
+
91
+ ```shell
92
+ cat README.md | grep "LOAD_PATH"
93
+ ```
94
+
95
+ ##### Windows
96
+
97
+ ```shell
98
+ type README.md | find "LOAD_PATH"
99
+ ```
100
+
101
+ ## Copyright
102
+ Copyright (c) 2012 Casey Stehlik.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ desc "Run tests"
7
+ task :test => :spec
8
+
9
+ task :default => :spec
@@ -0,0 +1,19 @@
1
+ # Always make the version available
2
+ require 'measurements/version'
3
+
4
+ # @author Casey Stehlik
5
+ module Measurements
6
+
7
+ # This is the local to use when looking up abbreviations. Later on you will be able
8
+ # to select other locales, but for now you get only english
9
+ LOCALE = "en"
10
+
11
+ autoload :Type, 'measurements/type'
12
+ autoload :System, 'measurements/system'
13
+ autoload :Unit, 'measurements/unit'
14
+ autoload :Exception, 'measurements/exception'
15
+
16
+ # Load in the helper methods to be able to access them
17
+ require 'measurements/helpers'
18
+
19
+ end
@@ -0,0 +1,34 @@
1
+ abbreviations:
2
+ en:
3
+ singular:
4
+ pound: lb
5
+ cup: c
6
+ ounce: oz
7
+ tablespoon: tbsp
8
+ teaspoon: tsp
9
+ quart: qt
10
+ pint: pt
11
+ gallon: gal
12
+ inch: in
13
+ foot: ft
14
+ mile: mi
15
+ furlong: fur
16
+ thou: th
17
+ chain: ch
18
+ league: lea
19
+ plural:
20
+ pound: lbs
21
+ cup: c
22
+ ounce: oz
23
+ tablespoon: tbsp
24
+ teaspoon: tsp
25
+ quart: qt
26
+ pint: pt
27
+ gallon: gal
28
+ inch: in
29
+ foot: ft
30
+ mile: mi
31
+ furlong: fur
32
+ thou: th
33
+ chain: ch
34
+ league: lea
@@ -0,0 +1,31 @@
1
+ conversions:
2
+ cooking:
3
+ solid:
4
+ base: pound
5
+ cup: 2
6
+ ounce: 16
7
+ tablespoon: 32
8
+ teaspoon: 96
9
+ fluid:
10
+ base: gallon
11
+ quart: 4
12
+ pint: 8
13
+ cup: 16
14
+ ounce: 128
15
+ tablespoon: 256
16
+ teaspoon: 768
17
+ neutral:
18
+ base: cup
19
+ ounce: 8
20
+ tablespoon: 16
21
+ teaspoon: 48
22
+ imperial:
23
+ base:
24
+ base: league
25
+ mile: 3
26
+ furlong: 24
27
+ chain: 240
28
+ yard: 5280
29
+ foot: 15840
30
+ inch: 190080
31
+ thou: 190080000
@@ -0,0 +1,22 @@
1
+ module Measurements
2
+ module Exception
3
+
4
+ # This is an extention of the StandardError and it will be raised when
5
+ # you try to convert to a unit that doesn't exist. An example would
6
+ # be Ounce.new(3).convert_to :fake_unit
7
+ class NoUnitError < StandardError
8
+ end
9
+
10
+ # This is an extention of the StandardError and it will be raised when
11
+ # you try to convert a unit to a new unit that isn't in the same
12
+ # system type. Such as converting an ounce to a foot.
13
+ class InvalidConversionError < StandardError
14
+ end
15
+
16
+ # This is an extention of the StandardError and it will be raised when
17
+ # you try to set the type of a unit that doesn't allow it.
18
+ class InvalidTypeSettingError < StandardError
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ module Measurements
2
+
3
+ # Helper method to get what units are currently implemented
4
+ # @return [Array] an Array of currently implemented units
5
+ def available_units
6
+ Measurements::Unit.available_units
7
+ end
8
+
9
+ # Helper method to get what types are available
10
+ # @return [Array] an Array of types that are available
11
+ def available_types
12
+ Measurements::Type.available_types
13
+ end
14
+
15
+ # Helper method to create a unit class without having to explicitly
16
+ # call {Measurements::Unit::BaseUnit#initialize}
17
+ # @param [Symbol] klass the class of the unit you wish to initialize
18
+ # @param [Float] quantity the amount of the unit
19
+ # @param [Symbol] type optional unit type such as :solid or :fluid
20
+ # @return [BaseUnit] a new unit instance of class = klass
21
+ def new_unit(klass, quantity, type = nil)
22
+ if available_units.include? klass
23
+ unit = eval('Measurements::Unit::' + klass.to_s.capitalize).new quantity, type
24
+ Measurements::Unit::Unit.new(unit)
25
+ else
26
+ raise Measurements::Exception::NoUnitError, "The unit requested does not exist."
27
+ end
28
+ end
29
+
30
+ module_function :new_unit
31
+ module_function :available_units
32
+ module_function :available_types
33
+
34
+ class << self
35
+ alias_method :create_unit, :new_unit
36
+ end
37
+
38
+ end
@@ -0,0 +1,14 @@
1
+ module Measurements
2
+ module System
3
+
4
+ # System type for metric units
5
+ SI = "metric"
6
+
7
+ # System type for United States units
8
+ IMPERIAL = "imperial"
9
+
10
+ # System type for cooking units
11
+ COOK = "cooking"
12
+
13
+ end
14
+ end
@@ -0,0 +1,27 @@
1
+ module Measurements
2
+ module Type
3
+
4
+ # Measurement state for unit of type solid
5
+ SOLID = "solid"
6
+
7
+ # Measurement state for unit of type fluid
8
+ FLUID = "fluid"
9
+
10
+ # Measurement state for unit that can be either a fluid or solid measure
11
+ NEUTRAL = "neutral"
12
+
13
+ # Measurement state for the unit that is not a cooking unit
14
+ BASE = "base"
15
+
16
+ # Helper method to get what types are available
17
+ # @deprecated Use {Measurements#available_types} instead of this method because
18
+ # it's a more obvious method to use instead of diving down to the Type module.
19
+ # @return [Array] an Array of types that are available
20
+ def available_types
21
+ self.constants.map{|types| types.downcase.to_sym}
22
+ end
23
+
24
+ module_function :available_types
25
+
26
+ end
27
+ end
@@ -0,0 +1,51 @@
1
+ require 'yaml'
2
+
3
+ module Measurements
4
+ module Unit
5
+
6
+ # All conversions are loaded from the conversions.yml.
7
+ # The conversions.yml file lives in the /measurements directory of the project
8
+ CONVERSIONS = YAML::load(File.open(File.join(File.dirname(__FILE__), 'config', 'conversions.yml')))
9
+
10
+ # All abbreviations are loaded from the abbreviations.yml.
11
+ # The abbreviations.yml file lives in the /measurements/config directory of the project
12
+ ABBREVIATIONS = YAML::load(File.open(File.join(File.dirname(__FILE__), 'config', 'abbreviations.yml')))
13
+
14
+ autoload :BaseUnit, 'measurements/unit/baseunit'
15
+ autoload :Unit, 'measurements/unit/unit'
16
+
17
+ # Cooking Units
18
+ autoload :Ounce, 'measurements/unit/ounce'
19
+ autoload :Pound, 'measurements/unit/pound'
20
+ autoload :Teaspoon, 'measurements/unit/teaspoon'
21
+ autoload :Tablespoon, 'measurements/unit/tablespoon'
22
+ autoload :Cup, 'measurements/unit/cup'
23
+ autoload :Pint, 'measurements/unit/pint'
24
+ autoload :Quart, 'measurements/unit/quart'
25
+ autoload :Gallon, 'measurements/unit/gallon'
26
+
27
+ # Imperial Units
28
+ autoload :Inch, 'measurements/unit/inch'
29
+ autoload :Foot, 'measurements/unit/foot'
30
+ autoload :Yard, 'measurements/unit/yard'
31
+ autoload :Furlong, 'measurements/unit/furlong'
32
+ autoload :Chain, 'measurements/unit/chain'
33
+ autoload :Mile, 'measurements/unit/mile'
34
+ autoload :Thou, 'measurements/unit/thou'
35
+ autoload :League, 'measurements/unit/league'
36
+
37
+ # Helper method to get what units are currently implemented
38
+ # @deprecated Use {Measurements#available_units} instead of this method because
39
+ # it's a more obvious method to use instead of diving down to the Unit module.
40
+ # @return [Array] an Array of currently implemented units
41
+ def available_units
42
+ self.constants.reject{|unit| unit.eql?(:BaseUnit) ||
43
+ unit.eql?(:Unit) ||
44
+ unit.eql?(:CONVERSIONS) ||
45
+ unit.eql?(:ABBREVIATIONS)}.map{|unit| unit.to_s.downcase.to_sym}
46
+ end
47
+
48
+ module_function :available_units
49
+
50
+ end
51
+ end
@@ -0,0 +1,186 @@
1
+ module Measurements
2
+ module Unit
3
+ module BaseUnit
4
+
5
+ # @attribute [rw]
6
+ # The quantity of a unit
7
+ attr_accessor :quantity
8
+
9
+ def initialize(quantity, type = nil)
10
+ @quantity = quantity.to_f
11
+
12
+ if !type.nil?
13
+ self.type = type
14
+ else
15
+ @type = type
16
+ end
17
+ end
18
+
19
+ # Set the unit type of a unit manually. A type can only be set for units with the
20
+ # unit type of "neutral", any other unit type will raise and error.
21
+ # @attribute [w]
22
+ # @param [String] type the type of unit the unit should be.
23
+ def type=(type)
24
+ if self.unit_type.eql? "neutral"
25
+ @type = type
26
+ else
27
+ raise Measurements::Exception::InvalidTypeSettingError, "Types can only be set on neutral units."
28
+ end
29
+ end
30
+
31
+ # @attribute [r]
32
+ # The manual set unit_type
33
+ def type
34
+ @type
35
+ end
36
+
37
+ # @attribute [r]
38
+ # The type of the editable type of the unit. This is
39
+ # used to limit the conversions from fluid to solid
40
+ def unit
41
+ self.class.name.split('::').last.downcase.to_s
42
+ end
43
+
44
+ # @attribute [r]
45
+ # The system of measurement of the unit
46
+ def unit_system
47
+ eval(self.class.to_s + "::UNIT_SYSTEM")
48
+ end
49
+
50
+ # @attribute [r]
51
+ # The class type of the unit, such as Liquid or Neutral
52
+ def unit_type
53
+ eval(self.class.to_s + "::UNIT_TYPE")
54
+ end
55
+
56
+ # @attribute [r]
57
+ # The abbreviation of the unit depending on the locale
58
+ def unit_abbr
59
+ if @quantity <= 1
60
+ Measurements::Unit::ABBREVIATIONS["abbreviations"][Measurements::LOCALE]["singular"][self.unit]
61
+ else
62
+ Measurements::Unit::ABBREVIATIONS["abbreviations"][Measurements::LOCALE]["plural"][self.unit]
63
+ end
64
+ end
65
+
66
+ # When you look at a unit object the quantity will be displayed.
67
+ # It seemed like a nicer way to display the unit, kind of like a [Float]
68
+ def inspect
69
+ @quantity
70
+ end
71
+
72
+ # Convert the current unit into a new unit of the type given
73
+ # @param [Symbol] type the type of unit to convert to
74
+ # @return [BaseUnit] the new unit, it will be a subclass of [BaseUnit].
75
+ # @raise [InvalidConversionError] gets raised if the type of conversion is not valid.
76
+ def convert_to(type)
77
+ type = type.to_s
78
+
79
+ if !validate_system(type)
80
+ raise Measurements::Exception::InvalidConversionError, "A conversion must be from the same system type."
81
+ end
82
+
83
+ if validate_conversion(type)
84
+ base = convert_to_base(self, type)
85
+ return convert_to_type(base, type)
86
+ else
87
+ raise Measurements::Exception::InvalidConversionError, "A conversion must be from the same type or neutral."
88
+ end
89
+ end
90
+
91
+ # Convert the current unit into a new unit of highest bestfit unit that
92
+ # would make sense while measuring something. An example would be that a better way
93
+ # to display 6 tsps would be 2 tbsps.
94
+ # @return [BaseUnit] the new unit, it will be the unit that is the bestfit conversion.
95
+ def smart_convert
96
+ #TODO
97
+ end
98
+
99
+ private
100
+
101
+ # Get the unit type of the class passed in as a string
102
+ # @param [String] type the class name as a string
103
+ # @return [String] the unit type of the class that was passed in.
104
+ def unit_type_from_type(type)
105
+ eval("Measurements::Unit::" + type.capitalize + "::UNIT_TYPE")
106
+ end
107
+
108
+ # Get the unit system of the class passed in as a string
109
+ # @param [String] type the class name as a string
110
+ # @return [String] the unit system of the class that was passed in.
111
+ def unit_system_from_type(type)
112
+ eval("Measurements::Unit::" + type.capitalize + "::UNIT_SYSTEM")
113
+ end
114
+
115
+ # Validate if the systems of the converting units match. A conversion will only
116
+ # be allowed if the two units are from the same unit system.
117
+ # @param [String] to the unit type to convert to
118
+ # @return [Boolean] true if the conversion is valid.
119
+ # @raise [NoUnitError] gets raised if the from or to units could not be found
120
+ def validate_system(to)
121
+ from = self.unit
122
+
123
+ begin
124
+ from = unit_system_from_type from
125
+ to = unit_system_from_type to
126
+ rescue
127
+ raise Measurements::Exception::NoUnitError, "The unit you're trying to convert to does not exist."
128
+ end
129
+
130
+ from.eql? to
131
+ end
132
+
133
+ # Validate if a conversion will be valid. A conversion will be valid if one
134
+ # of the units types are neutral or if the unit types are the same.
135
+ # @param [String] to the unit type to convert to
136
+ # @return [Boolean] True if the conversion is valid.
137
+ # @raise [NoUnitError] gets raised if the from or to units could not be found
138
+ def validate_conversion(to)
139
+ from = self.unit
140
+
141
+ begin
142
+ from = unit_type_from_type from
143
+ to = unit_type_from_type to
144
+ rescue
145
+ raise Measurements::Exception::NoUnitError, "The unit you're trying to convert to does not exist."
146
+ end
147
+
148
+ (from.eql?("neutral") || to.eql?("neutral") || from.eql?(to)) && (self.type.nil? || self.type.eql?("neutral") || self.type.eql?(to))
149
+ end
150
+
151
+ # Convert the current unit into the base unit for its type.
152
+ # @param [BaseUnit] current the unit to be converted, it should be a subclass of [BaseUnit]
153
+ # @return [BaseUnit] the base unit.
154
+ def convert_to_base(current, type)
155
+ unit_type = unit_type_from_type type
156
+
157
+ if !unit_type.eql? "neutral"
158
+ measurement_list = Measurements::Unit::CONVERSIONS["conversions"][current.unit_system][unit_type]
159
+ else
160
+ measurement_list = Measurements::Unit::CONVERSIONS["conversions"][current.unit_system][current.unit_type]
161
+ end
162
+
163
+ quantity_to_mst = measurement_list[current.unit].to_f != 0.0 ? measurement_list[current.unit] : 1.0
164
+ base_type = measurement_list["base"]
165
+
166
+ eval("Measurements::Unit::" + base_type.capitalize).new(current.quantity / quantity_to_mst, current.type)
167
+ end
168
+
169
+ # Take the base unit and convert it to the requested type. If the type requested
170
+ # is the same type as the base, just return the base unit back.
171
+ # @param [BaseUnit] base the base unit to be converted
172
+ # @param [String] type the type of unit the base should be converted to
173
+ # @return [BaseUnit] the new unit, it will be a subclass of [BaseUnit]
174
+ def convert_to_type(base, type)
175
+ if base.unit.eql? type
176
+ return base
177
+ else
178
+ measurement_list = Measurements::Unit::CONVERSIONS["conversions"][base.unit_system][base.unit_type]
179
+ quantity_to_type = measurement_list[type]
180
+
181
+ eval("Measurements::Unit::" + type.capitalize).new(base.quantity * quantity_to_type, base.type)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a chain. A chain is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Chain
7
+ include BaseUnit
8
+
9
+ # Type for the Chain unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Chain unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a cup. A cup is a neutral unit that belongs to the cooking unit
5
+ # system.
6
+ class Cup
7
+ include BaseUnit
8
+
9
+ # Type for the Cup unit
10
+ UNIT_TYPE = Measurements::Type::NEUTRAL
11
+
12
+ # System type for the Cup unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a foot. A foot is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Foot
7
+ include BaseUnit
8
+
9
+ # Type for the Foot unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Foot unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a furlong. A furlong is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Furlong
7
+ include BaseUnit
8
+
9
+ # Type for the Furlong unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Furlong unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a gallon. A gallon is a fluid unit that belongs to the cooking unit
5
+ # system.
6
+ class Gallon
7
+ include BaseUnit
8
+
9
+ # Type for the Gallon unit
10
+ UNIT_TYPE = Measurements::Type::FLUID
11
+
12
+ # System type for the Gallon unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a inch. A inch is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Inch
7
+ include BaseUnit
8
+
9
+ # Type for the Inch unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Inch unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a league. A league is a unit that belongs to the imperial unit
5
+ # system.
6
+ class League
7
+ include BaseUnit
8
+
9
+ # Type for the League unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the League unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a mile. A mile is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Mile
7
+ include BaseUnit
8
+
9
+ # Type for the Mile unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Mile unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a ounce. A ounce is a neutral unit that belongs to the cooking unit
5
+ # system.
6
+ class Ounce
7
+ include BaseUnit
8
+
9
+ # Type for the Ounce unit
10
+ UNIT_TYPE = Measurements::Type::NEUTRAL
11
+
12
+ # System type for the Ounce unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a pint. A pint is a fluid unit that belongs to the cooking unit
5
+ # system.
6
+ class Pint
7
+ include BaseUnit
8
+
9
+ # Type for the Pint unit
10
+ UNIT_TYPE = Measurements::Type::FLUID
11
+
12
+ # System type for the Pint unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a pound. A pound is a solid unit that belongs to the cooking unit
5
+ # system.
6
+ class Pound
7
+ include BaseUnit
8
+
9
+ # Type for the Pound unit
10
+ UNIT_TYPE = Measurements::Type::SOLID
11
+
12
+ # System type for the Pound unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a quart. A quart is a fluid unit that belongs to the cooking unit
5
+ # system.
6
+ class Quart
7
+ include BaseUnit
8
+
9
+ # Type for the Quart unit
10
+ UNIT_TYPE = Measurements::Type::FLUID
11
+
12
+ # System type for the Quart unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a teaspoon. A teaspoon is a neutral unit that belongs to the cooking unit
5
+ # system.
6
+ class Tablespoon
7
+ include BaseUnit
8
+
9
+ # Type for the Tablespoon unit
10
+ UNIT_TYPE = Measurements::Type::NEUTRAL
11
+
12
+ # System type for the Tablespoon unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a teaspoon. A teaspoon is a neutral unit that belongs to the cooking unit
5
+ # system.
6
+ class Teaspoon
7
+ include BaseUnit
8
+
9
+ # Type for the Teaspoon unit
10
+ UNIT_TYPE = Measurements::Type::NEUTRAL
11
+
12
+ # System type for the Teaspoon unit
13
+ UNIT_SYSTEM = Measurements::System::COOK
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a thou. A thou is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Thou
7
+ include BaseUnit
8
+
9
+ # Type for the Thou unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Thou unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,85 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # A wrapper for all of the units, this class was added to make the conversion of classes
5
+ # keep the same object class instead of changing everytime you convert a unit.
6
+ class Unit
7
+
8
+ def initialize(klass)
9
+ @klass = klass
10
+ end
11
+
12
+ # @see Measurements::Unit::BaseUnit#inspect
13
+ def inspect
14
+ self.quantity
15
+ end
16
+
17
+ # A pretty print method that will return a human readable version
18
+ # of a unit
19
+ # @return [String] a human readable unit description
20
+ def humanize
21
+ return "#{self.quantity.to_s} #{self.unit_abbr}"
22
+ end
23
+
24
+ # @see Measurements::Unit::BaseUnit#type=
25
+ def type=(type)
26
+ @klass.type = type
27
+ end
28
+
29
+ # @see Measurements::Unit::BaseUnit#type
30
+ def type
31
+ @klass.type
32
+ end
33
+
34
+ # Get the quantity of the unit
35
+ # @return [Float] the quantitiy of the unit
36
+ def quantity
37
+ @klass.quantity
38
+ end
39
+
40
+ # Set the quantity of a unit
41
+ # @param [Float] quanity the quantity of the unit
42
+ def quantity=(quantity)
43
+ @klass.quantity = quantity
44
+ end
45
+
46
+ # @see Measurements::Unit::BaseUnit#unit
47
+ def unit
48
+ @klass.unit
49
+ end
50
+
51
+ # @see Measurements::Unit::BaseUnit#unit_type
52
+ def unit_type
53
+ @klass.unit_type
54
+ end
55
+
56
+ # @see Measurements::Unit::BaseUnit#unit_system
57
+ def unit_system
58
+ @klass.unit_system
59
+ end
60
+
61
+ # @see Measurements::Unit::BaseUnit#unit_abbr
62
+ def unit_abbr
63
+ @klass.unit_abbr
64
+ end
65
+
66
+ # This method will call the current units convert_to method. This is the dangerous version and it will
67
+ # change the callers unit.
68
+ # @see Measurements::Unit::BaseUnit#convert_to
69
+ def convert_to!(type)
70
+ @klass = @klass.convert_to(type)
71
+ end
72
+
73
+ # The safe version of converting a unit. This method will duplicate the caller object and return the new
74
+ # version of the object instead of the original caller
75
+ # @param [Symbol] type the unit to be converted to
76
+ # @return [Unit] the new Unit object
77
+ def convert_to(type)
78
+ new_unit = self.dup
79
+ new_unit.convert_to!(type)
80
+ new_unit
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,17 @@
1
+ module Measurements
2
+ module Unit
3
+
4
+ # The implementation of a yard. A yard is a unit that belongs to the imperial unit
5
+ # system.
6
+ class Yard
7
+ include BaseUnit
8
+
9
+ # Type for the Yard unit
10
+ UNIT_TYPE = Measurements::Type::BASE
11
+
12
+ # System type for the Yard unit
13
+ UNIT_SYSTEM = Measurements::System::IMPERIAL
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Measurements
2
+
3
+ # The current version of the gem, the numbers stand for
4
+ # major.minor.patch
5
+ Version = "0.3.0"
6
+
7
+ end
@@ -0,0 +1,18 @@
1
+ $:.unshift File.expand_path('../lib/', __FILE__)
2
+ require 'measurements/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'measurements'
6
+ spec.author = 'Casey Stehlik'
7
+ spec.email = 'casey.stehlik@stehlikc.net'
8
+ spec.homepage = 'http://www.stehlikc.net/'
9
+ spec.add_development_dependency 'yard'
10
+ spec.add_development_dependency 'redcarpet'
11
+ spec.add_development_dependency 'rspec'
12
+ spec.add_development_dependency 'guard-rspec'
13
+ spec.version = Measurements::Version
14
+ spec.require_paths = ['lib']
15
+ spec.files = `git ls-files`.split("\n")
16
+ spec.description = "A measurement conversion gem"
17
+ spec.summary = "A measurement conversion"
18
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+ '/lib')
2
+
3
+ require 'measurements'
4
+
@@ -0,0 +1,101 @@
1
+ require 'helper'
2
+
3
+ describe Measurements do
4
+ it "should return the available system types" do
5
+ Measurements.available_types.should == Measurements::Type.available_types
6
+ end
7
+
8
+ it "should return the available units that are implemented" do
9
+ Measurements.available_units.should == Measurements::Unit.available_units
10
+ end
11
+
12
+ it "should create a 3 ounces object" do
13
+ ounce = Measurements.create_unit :ounce, 3
14
+ ounce.unit.should == "ounce" && ounce.quantity.should == 3
15
+ end
16
+
17
+ it "should create a 4 pound object" do
18
+ pound = Measurements.new_unit :pound, 4
19
+ pound.unit.should == "pound" && pound.quantity.should == 4
20
+ end
21
+
22
+ it "should raise an error if the unit requested has not been implemented" do
23
+ expect{ Measurements.new_unit(:unimplemented_unit, 2) }.should raise_error()
24
+ end
25
+
26
+ it "should convert 1 quart to 4 cups" do
27
+ quart = Measurements.new_unit :quart, 1
28
+ cup = quart.convert_to :cup
29
+ cup.quantity.should == 4
30
+ end
31
+
32
+ it "should convert 8 cups to 0.5 gallons" do
33
+ cup = Measurements.new_unit :cup, 8
34
+ gallon = cup.convert_to :gallon
35
+ gallon.quantity.should == 0.5
36
+ end
37
+
38
+ it "should convert 6 teaspoons to 2 tablespoons" do
39
+ teaspoon = Measurements.new_unit :teaspoon, 6
40
+ tablespoon = teaspoon.convert_to :tablespoon
41
+ tablespoon.quantity.should == 2
42
+ end
43
+
44
+ it "should raise an error if the unit type is set to solid and you try to convert to a fluid" do
45
+ cup = Measurements.new_unit :cup, 2, :solid
46
+ expect{ ounce = cup.convert_to(:gallon) }.should raise_error()
47
+ end
48
+
49
+ it "should raise an error if the unit type is set to fluid and you try to convert to a solid" do
50
+ cup = Measurements.new_unit :gallon, 1
51
+ expect{ ounce = cup.convert_to(:pound) }.should raise_error()
52
+ end
53
+
54
+ it "should raise an error if you try to set the unit type of a fluid only unit" do
55
+ expect{ gallon = Measurements.new_unit :gallon, 1, :fluid }.should raise_error()
56
+ end
57
+
58
+ it "should raise an error if you try to set the unit type of a solid only unit" do
59
+ expect{ pound = Measurements.new_unit :pound, 2, :solid }.should raise_error()
60
+ end
61
+
62
+ it "should raise an error when trying to set the unit type of a unit on the fly" do
63
+ cup = Measurements.new_unit :gallon, 2
64
+ expect { cup.type = :solid }.should raise_error()
65
+ end
66
+
67
+ it "should convert 2 feet to 24 inches" do
68
+ feet = Measurements.new_unit :foot, 2
69
+ inches = feet.convert_to :inch
70
+ inches.quantity.should == 24
71
+ end
72
+
73
+ it "should convert 30 inches to 1.5 feet" do
74
+ inches = Measurements.new_unit :inch, 30
75
+ feet = inches.convert_to :foot
76
+ feet.quantity.should == 2.5
77
+ end
78
+
79
+ it "should raise an error if you try to convert a unit across system types" do
80
+ inches = Measurements.new_unit :inch, 55
81
+ expect { cup = inches.convert_to :cup }.should raise_error()
82
+ end
83
+
84
+ it "should raise an error if you try to set a type manually for imperial units" do
85
+ expect { inch = Measurements.new_unit :inch, 51, :solid }.should raise_error()
86
+ end
87
+
88
+ it "should convert 2.5 leagues to 475200 inches" do
89
+ leagues = Measurements.new_unit :league, 2.5
90
+ inches = leagues.convert_to :inch
91
+ inches.quantity.should == 475200
92
+ end
93
+
94
+ it "should humanize 3.5 ounces to 3.5 oz" do
95
+ Measurements.new_unit(:ounce, 3.5).humanize.should == "3.5 oz"
96
+ end
97
+
98
+ it "should humanize 4 pounds to 4 lbs" do
99
+ Measurements.new_unit(:pound, 4).humanize.should == "4.0 lbs"
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: measurements
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Casey Stehlik
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: yard
16
+ requirement: &70325023315160 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70325023315160
25
+ - !ruby/object:Gem::Dependency
26
+ name: redcarpet
27
+ requirement: &70325023314240 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70325023314240
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70325023313740 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70325023313740
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: &70325023312860 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70325023312860
58
+ description: A measurement conversion gem
59
+ email: casey.stehlik@stehlikc.net
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - .rspec
66
+ - .yardopts
67
+ - Gemfile
68
+ - Guardfile
69
+ - README.md
70
+ - Rakefile
71
+ - lib/measurements.rb
72
+ - lib/measurements/config/abbreviations.yml
73
+ - lib/measurements/config/conversions.yml
74
+ - lib/measurements/exception.rb
75
+ - lib/measurements/helpers.rb
76
+ - lib/measurements/system.rb
77
+ - lib/measurements/type.rb
78
+ - lib/measurements/unit.rb
79
+ - lib/measurements/unit/baseunit.rb
80
+ - lib/measurements/unit/chain.rb
81
+ - lib/measurements/unit/cup.rb
82
+ - lib/measurements/unit/foot.rb
83
+ - lib/measurements/unit/furlong.rb
84
+ - lib/measurements/unit/gallon.rb
85
+ - lib/measurements/unit/inch.rb
86
+ - lib/measurements/unit/league.rb
87
+ - lib/measurements/unit/mile.rb
88
+ - lib/measurements/unit/ounce.rb
89
+ - lib/measurements/unit/pint.rb
90
+ - lib/measurements/unit/pound.rb
91
+ - lib/measurements/unit/quart.rb
92
+ - lib/measurements/unit/tablespoon.rb
93
+ - lib/measurements/unit/teaspoon.rb
94
+ - lib/measurements/unit/thou.rb
95
+ - lib/measurements/unit/unit.rb
96
+ - lib/measurements/unit/yard.rb
97
+ - lib/measurements/version.rb
98
+ - measurements.gemspec
99
+ - spec/helper.rb
100
+ - spec/measurements_spec.rb
101
+ homepage: http://www.stehlikc.net/
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 1.8.15
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: A measurement conversion
125
+ test_files: []
126
+ has_rdoc: