height 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .DS_Store
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in height.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+ # Height
2
+
3
+ Convert height between metric and imperial systems. The main target of this gem are apps that have to deal with human's height.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'height'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install height
18
+
19
+ ## Usage
20
+ ```ruby
21
+ @height = Height.new(191)
22
+
23
+ @height.millimeters # 1910
24
+ @height.centimeters # 191
25
+ @height.meters # 1.91
26
+ @height.feet # 6.25
27
+ @height.inches # 75
28
+
29
+ @height.to_s(:default, :metric) # '1m 91cm'
30
+ @height.to_s(:default, :imperial) # '6 ft 3 in'
31
+
32
+ # or simply:
33
+ @height.to_s # '1m 91cm'
34
+ ```
35
+
36
+ ### I18n & Formats
37
+ The `to_s` method takes 2 optional arguments: `:format` and `:system_of_units`.
38
+
39
+ You can have as many formats as you like, add them into your locale file:
40
+ ```yaml
41
+ en:
42
+ height:
43
+ format:
44
+ metric:
45
+ default: '%{meters}m %{centimeters}cm'
46
+ only_meters: '%{only_meters}m'
47
+ only_centimeters: '%{only_centimeters}cm'
48
+ ```
49
+ You can now call:
50
+
51
+ ```ruby
52
+ @height = Height.new(191)
53
+
54
+ @height.to_s(:default) # '1m 91cm'
55
+ @height.to_s(:only_meters) # '1.91m'
56
+ @height.to_s(:only_centimeters) # '191cm'
57
+ ```
58
+ Same goes for the imperial system (`:only_feet`, `:only_inches`, etc).
59
+
60
+ ### System of units
61
+ You can specify which system of units(`metric` or `imperial`) you want when calling `to_s`:
62
+
63
+ ```ruby
64
+ Height.new(191).to_s(:default, :metric) # '1m 91cm'
65
+ Height.new(191).to_s(:default, :imperial) # '6 ft 3 in'
66
+ ```
67
+
68
+ If you don't want to specify it every time, you can set it globally:
69
+ ```ruby
70
+ Height.system_of_units = :imperial
71
+
72
+ Height.new(191).to_s # '6 ft 3 in'
73
+ ```
74
+ By default, `system_of_units` is `:metric`.
75
+
76
+ ## Contributing
77
+
78
+ 1. Fork it
79
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
80
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
81
+ 4. Push to the branch (`git push origin my-new-feature`)
82
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/height/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Alexander Zaytsev"]
6
+ gem.email = ["alexander@say26.com"]
7
+ gem.description = %q{Height support for metric and imperial systems}
8
+ gem.summary = %q{Convert height between metric and imperial systems}
9
+ gem.homepage = "http://github.com/AlexanderZaytsev/height"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "height"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Height::VERSION
17
+
18
+ gem.add_development_dependency 'rspec'
19
+ gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'pry'
21
+ gem.add_development_dependency 'i18n'
22
+ end
@@ -0,0 +1,95 @@
1
+ require "height/parser"
2
+ require "height/parsers/base"
3
+ require "height/parsers/metric"
4
+ require "height/parsers/imperial"
5
+ require "height/formatters/base"
6
+ require "height/formatters/imperial"
7
+ require "height/formatters/metric"
8
+ require "height/units/base"
9
+ require "height/units/millimeters"
10
+ require "height/units/centimeters"
11
+ require "height/units/meters"
12
+ require "height/units/inches"
13
+ require "height/units/feet"
14
+ require "height/version"
15
+ require "height/core_extensions"
16
+
17
+ class Height
18
+ include Comparable
19
+
20
+ MILLIMETERS_IN_CENTIMETER = 10
21
+ CENTIMETERS_IN_METER = 100
22
+ MILLIMETERS_IN_METER = MILLIMETERS_IN_CENTIMETER * CENTIMETERS_IN_METER
23
+ MILLIMETERS_IN_INCH = 25.4
24
+ INCHES_IN_FOOT = 12
25
+
26
+ class << self
27
+ attr_accessor :system_of_units, :units_precision
28
+ end
29
+
30
+ self.system_of_units = :metric
31
+ self.units_precision = {
32
+ millimeters: 0,
33
+ centimeters: 0,
34
+ meters: 2,
35
+ inches: 0,
36
+ feet: 2,
37
+ }
38
+
39
+ def initialize(input)
40
+ if input.respond_to? :to_millimeters
41
+ @millimeters = input.to_millimeters
42
+ else
43
+ @millimeters = Parser.new(input).millimeters
44
+ end
45
+ end
46
+
47
+ def millimeters
48
+ @millimeters
49
+ end
50
+
51
+ def centimeters
52
+ millimeters.to_centimeters
53
+ end
54
+
55
+ def meters
56
+ millimeters.to_meters
57
+ end
58
+
59
+ def inches
60
+ millimeters.to_inches
61
+ end
62
+
63
+ def feet
64
+ millimeters.to_feet
65
+ end
66
+
67
+ def +(other)
68
+ centimeters = (millimeters + other.millimeters).to_centimeters
69
+ self.class.new(centimeters)
70
+ end
71
+
72
+ def -(other)
73
+ centimeters = (millimeters - other.millimeters).to_centimeters
74
+ self.class.new(centimeters)
75
+ end
76
+
77
+ def <=>(other)
78
+ millimeters <=> other.millimeters
79
+ end
80
+
81
+ def to_s(format = :default, system_of_units = nil)
82
+ system_of_units ||= self.class.system_of_units
83
+
84
+ case system_of_units
85
+ when :metric
86
+ Formatters::Metric.new(millimeters).format(format)
87
+ when :imperial
88
+ Formatters::Imperial.new(millimeters).format(format)
89
+ else
90
+ raise ::ArgumentError.new('Invalid system of units provided, use either :metric or :imperial')
91
+ end
92
+ end
93
+
94
+ end
95
+
@@ -0,0 +1,11 @@
1
+ class Numeric
2
+ def to_height
3
+ Height.new(self)
4
+ end
5
+ end
6
+
7
+ class String
8
+ def to_height
9
+ Height.new(self)
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class Height
2
+ module Formatters
3
+ class Base
4
+ def initialize(value)
5
+ @value = value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ class Height
2
+ module Formatters
3
+ class Imperial < Base
4
+ def format(format = :default)
5
+ feet = @value.to_feet
6
+
7
+ result = "#{feet.feet} ft #{feet.inches} in"
8
+ if Object.const_defined?(:I18n)
9
+ ::I18n.t :"height.format.imperial.#{format}", {
10
+ feet: feet.feet,
11
+ inches: feet.inches,
12
+ only_feet: feet,
13
+ only_inches: feet.to_inches,
14
+ default: result
15
+ }
16
+ else
17
+ result
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ class Height
2
+ module Formatters
3
+ class Metric < Base
4
+ def format(format = :default)
5
+ meters = @value.to_meters
6
+
7
+ result = "#{meters.meters}m #{meters.centimeters}cm"
8
+
9
+ if Object.const_defined?(:I18n)
10
+ ::I18n.t :"height.format.metric.#{format}", {
11
+ meters: meters.meters,
12
+ centimeters: meters.centimeters,
13
+ only_meters: meters,
14
+ only_centimeters: meters.to_centimeters,
15
+ default: result
16
+ }
17
+ else
18
+ result
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ class Height
2
+ class Parser
3
+ def initialize(input)
4
+ @input = input
5
+
6
+ metric_parser = Parsers::Metric.new(@input)
7
+ imperial_parser = Parsers::Imperial.new(@input)
8
+
9
+ if metric_parser.parsed?
10
+ @millimeters = metric_parser.millimeters
11
+ elsif imperial_parser.parsed?
12
+ @millimeters = imperial_parser.inches.to_millimeters
13
+ else
14
+ raise ArgumentError.new("Could not parse `#{@input}` into valid height")
15
+ end
16
+ end
17
+
18
+ def millimeters
19
+ @millimeters
20
+ end
21
+
22
+ def centimeters
23
+ millimeters.to_centimeters
24
+ end
25
+
26
+ def meters
27
+ millimeters.to_meters
28
+ end
29
+
30
+ def inches
31
+ millimeters.to_inches
32
+ end
33
+
34
+ def feet
35
+ millimeters.to_feet
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ class Height
2
+ module Parsers
3
+ class Base
4
+ attr_reader :input, :value
5
+
6
+ def initialize(input)
7
+ @input = input
8
+ @value = self.class.parse(input)
9
+ end
10
+
11
+ def parsed?
12
+ @value
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,40 @@
1
+ class Height
2
+ module Parsers
3
+ class Imperial < Base
4
+
5
+ def inches
6
+ Height::Units::Inches.new(value)
7
+ end
8
+
9
+ def feet
10
+ inches.to_feet
11
+ end
12
+
13
+ def millimeters
14
+ inches.to_millimeters
15
+ end
16
+
17
+ def centimeters
18
+ inches.to_centimeters
19
+ end
20
+
21
+ def meters
22
+ inches.to_meters
23
+ end
24
+
25
+ def self.parse(input)
26
+ parse_string(input) if input.is_a? String
27
+ end
28
+
29
+ private
30
+
31
+ def self.parse_string(string)
32
+ match = string.match(/(\d+)\s*(?:'|ft|feet)(?:\s*(\d+)\s*(?:"|in|inches))?/)
33
+ if match
34
+ match[1].to_i * INCHES_IN_FOOT + match[2].to_i
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+ class Height
2
+ module Parsers
3
+ class Metric < Base
4
+
5
+ def millimeters
6
+ Height::Units::Millimeters.new(value)
7
+ end
8
+
9
+ def centimeters
10
+ millimeters.to_centimeters
11
+ end
12
+
13
+ def meters
14
+ millimeters.to_meters
15
+ end
16
+
17
+ def inches
18
+ millimeters.to_inches
19
+ end
20
+
21
+ def feet
22
+ inches.to_feet
23
+ end
24
+
25
+ def self.parse(input)
26
+ if input.is_a? Integer
27
+ parse_integer(input)
28
+ elsif input.is_a? Float
29
+ parse_float(input)
30
+ elsif input.is_a? String
31
+ parse_string(input)
32
+ end
33
+ end
34
+
35
+ private
36
+ # 191.5
37
+ def self.parse_float(float)
38
+ (float * MILLIMETERS_IN_CENTIMETER).to_i
39
+ end
40
+
41
+ # 191
42
+ def self.parse_integer(integer)
43
+ (integer * MILLIMETERS_IN_CENTIMETER).to_i
44
+ end
45
+
46
+ # 1.91, 1m 91cm, 191, 191 cm
47
+ def self.parse_string(string)
48
+ if string =~ /[0-9]+\.[0-9]+/
49
+ parse_float(string.to_f)
50
+ elsif (Float(string) != nil rescue false)
51
+ parse_integer(string.to_i)
52
+ else
53
+ match = string.match(/(?:([0-9]+)\s?m)?[^0-9]*(?:([0-9]+)\s?cm)?/)
54
+ if match[1] || match[2]
55
+ match[1].to_i * MILLIMETERS_IN_METER + match[2].to_i * MILLIMETERS_IN_CENTIMETER
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end