height 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +82 -0
- data/Rakefile +2 -0
- data/height.gemspec +22 -0
- data/lib/height.rb +95 -0
- data/lib/height/core_extensions.rb +11 -0
- data/lib/height/formatters/base.rb +9 -0
- data/lib/height/formatters/imperial.rb +23 -0
- data/lib/height/formatters/metric.rb +24 -0
- data/lib/height/parser.rb +38 -0
- data/lib/height/parsers/base.rb +16 -0
- data/lib/height/parsers/imperial.rb +40 -0
- data/lib/height/parsers/metric.rb +62 -0
- data/lib/height/units/base.rb +66 -0
- data/lib/height/units/centimeters.rb +31 -0
- data/lib/height/units/feet.rb +37 -0
- data/lib/height/units/inches.rb +29 -0
- data/lib/height/units/meters.rb +38 -0
- data/lib/height/units/millimeters.rb +30 -0
- data/lib/height/version.rb +3 -0
- data/spec/core_extensions_spec.rb +15 -0
- data/spec/formatters/imperial_spec.rb +37 -0
- data/spec/formatters/metric_spec.rb +40 -0
- data/spec/height_spec.rb +66 -0
- data/spec/parser_spec.rb +10 -0
- data/spec/parsers/imperial_spec.rb +9 -0
- data/spec/parsers/metric_spec.rb +9 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/units/base_spec.rb +94 -0
- data/spec/units/centimeters_spec.rb +36 -0
- data/spec/units/feet_spec.rb +45 -0
- data/spec/units/inches_spec.rb +37 -0
- data/spec/units/meters_spec.rb +45 -0
- data/spec/units/millimeters_spec.rb +41 -0
- metadata +166 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Base
|
4
|
+
include Comparable
|
5
|
+
include Math
|
6
|
+
attr_reader :value
|
7
|
+
|
8
|
+
def self.round_value(value)
|
9
|
+
key = self.name.split('::').last.downcase.to_sym
|
10
|
+
|
11
|
+
precision = ::Height.units_precision[key]
|
12
|
+
|
13
|
+
value.round(precision)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(value)
|
17
|
+
@value = self.class.round_value(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def <=>(other)
|
21
|
+
value <=> other_value(other)
|
22
|
+
end
|
23
|
+
|
24
|
+
def +(other)
|
25
|
+
result = value + other_value(other)
|
26
|
+
self.class.new(result)
|
27
|
+
end
|
28
|
+
|
29
|
+
def -(other)
|
30
|
+
result = value - other_value(other)
|
31
|
+
|
32
|
+
self.class.new(result)
|
33
|
+
end
|
34
|
+
|
35
|
+
def *(other)
|
36
|
+
result = value * other_value(other)
|
37
|
+
self.class.new(result)
|
38
|
+
end
|
39
|
+
|
40
|
+
def /(other)
|
41
|
+
result = value / other_value(other)
|
42
|
+
self.class.new(result)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_unit(klass)
|
46
|
+
class_name = klass.name.split('::').last.downcase
|
47
|
+
method = "to_#{class_name}"
|
48
|
+
send(method)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"%g" % ("%0.2f" % value)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def other_value(other)
|
57
|
+
if other.respond_to? :to_unit
|
58
|
+
other.to_unit(self.class).value
|
59
|
+
else
|
60
|
+
other
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Centimeters < Base
|
4
|
+
|
5
|
+
def to_millimeters
|
6
|
+
millimeters = value * MILLIMETERS_IN_CENTIMETER
|
7
|
+
Millimeters.new(millimeters)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_centimeters
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_meters
|
15
|
+
to_millimeters.to_meters
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_inches
|
19
|
+
to_millimeters.to_inches
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_feet
|
23
|
+
to_inches.to_feet
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
value.round.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Feet < Base
|
4
|
+
|
5
|
+
def to_feet
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_inches
|
10
|
+
inches = value * Height::INCHES_IN_FOOT
|
11
|
+
Inches.new(inches)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_millimeters
|
15
|
+
to_inches.to_millimeters
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_centimeters
|
19
|
+
to_millimeters.to_centimeters
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_meters
|
23
|
+
to_millimeters.to_meters
|
24
|
+
end
|
25
|
+
|
26
|
+
def feet
|
27
|
+
self.class.new(value.floor)
|
28
|
+
end
|
29
|
+
|
30
|
+
def inches
|
31
|
+
inches = value.modulo(1) * Height::INCHES_IN_FOOT
|
32
|
+
Inches.new(inches)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Inches < Base
|
4
|
+
|
5
|
+
def to_inches
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_millimeters
|
10
|
+
millimeters = value * Height::MILLIMETERS_IN_INCH
|
11
|
+
Millimeters.new(millimeters)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_centimeters
|
15
|
+
to_millimeters.to_centimeters
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_meters
|
19
|
+
to_centimeters.to_meters
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_feet
|
23
|
+
feet = value / Height::INCHES_IN_FOOT.to_f
|
24
|
+
Feet.new(feet)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Meters < Base
|
4
|
+
|
5
|
+
def to_millimeters
|
6
|
+
millimeters = value * MILLIMETERS_IN_METER
|
7
|
+
Millimeters.new(millimeters)
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_centimeters
|
11
|
+
to_millimeters.to_centimeters
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_meters
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_inches
|
19
|
+
to_centimeters.to_inches
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_feet
|
23
|
+
to_inches.to_feet
|
24
|
+
end
|
25
|
+
|
26
|
+
def meters
|
27
|
+
Meters.new(value.floor)
|
28
|
+
end
|
29
|
+
|
30
|
+
def centimeters
|
31
|
+
millimeters = (to_millimeters.value - meters.to_millimeters.value)
|
32
|
+
|
33
|
+
Millimeters.new(millimeters).to_centimeters
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Height
|
2
|
+
module Units
|
3
|
+
class Millimeters < Base
|
4
|
+
|
5
|
+
def to_millimeters
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_centimeters
|
10
|
+
centimeters = value / Height::MILLIMETERS_IN_CENTIMETER.to_f
|
11
|
+
Centimeters.new(centimeters)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_meters
|
15
|
+
meters = value / Height::MILLIMETERS_IN_METER.to_f
|
16
|
+
Meters.new(meters)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_inches
|
20
|
+
inches = value / Height::MILLIMETERS_IN_INCH.to_f
|
21
|
+
Inches.new(inches)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_feet
|
25
|
+
to_inches.to_feet
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Numeric do
|
5
|
+
describe '#to_height' do
|
6
|
+
it { 191.to_height.should == Height.new(191) }
|
7
|
+
it { 191.5.to_height.should == Height.new(191.5) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe String do
|
12
|
+
describe '#to_height' do
|
13
|
+
it { '191 cm'.to_height.should == Height.new(191) }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Height::Formatters::Imperial do
|
3
|
+
describe '#format' do
|
4
|
+
|
5
|
+
context 'without I18n' do
|
6
|
+
it 'formats' do
|
7
|
+
units.each do |unit|
|
8
|
+
Height::Formatters::Imperial.new(unit).format.should == "6 ft 3 in"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with I18n' do
|
14
|
+
before do
|
15
|
+
::I18n.backend.store_translations :en,
|
16
|
+
height: {
|
17
|
+
format: {
|
18
|
+
imperial: {
|
19
|
+
default: '%{feet}\' %{inches}"'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
reset_i18n
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'uses i18n formats' do
|
30
|
+
units.each do |unit|
|
31
|
+
Height::Formatters::Imperial.new(unit).format.should == '6\' 3"'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Height::Formatters::Metric do
|
3
|
+
describe '#format' do
|
4
|
+
context 'without I18n' do
|
5
|
+
it 'formats' do
|
6
|
+
units.each do |unit|
|
7
|
+
Height::Formatters::Metric.new(unit).format.should == '1m 91cm'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'with I18n' do
|
13
|
+
before do
|
14
|
+
I18n.backend.store_translations :en,
|
15
|
+
height: {
|
16
|
+
format: {
|
17
|
+
metric: {
|
18
|
+
default: '%{meters}meters %{centimeters}centimeters',
|
19
|
+
only_meters: '%{only_meters} meters',
|
20
|
+
only_centimeters: '%{only_centimeters} centimeters'
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
after do
|
27
|
+
reset_i18n
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'formats' do
|
31
|
+
units.each do |unit|
|
32
|
+
formatter = Height::Formatters::Metric.new(unit)
|
33
|
+
formatter.format.should == '1meters 91centimeters'
|
34
|
+
formatter.format(:only_meters).should == '1.91 meters'
|
35
|
+
formatter.format(:only_centimeters).should == '191 centimeters'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/height_spec.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Height do
|
4
|
+
it 'is comparable' do
|
5
|
+
Height.new(191).should > Height.new(190)
|
6
|
+
Height.new(191).should == Height.new(191)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.system_of_units' do
|
10
|
+
it 'can be changed in Height class' do
|
11
|
+
Height.system_of_units = :imperial
|
12
|
+
Height.new(191).to_s.should == '6 ft 3 in'
|
13
|
+
Height.system_of_units = :metric
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.units_precision' do
|
18
|
+
before do
|
19
|
+
@previous_unit_precision = Height.units_precision.dup
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'can be changed in Height class' do
|
23
|
+
Height.units_precision[:centimeters] = 2
|
24
|
+
Height.new(190.5).centimeters.should == 190.50
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
Height.units_precision = @previous_unit_precision
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it '+' do
|
33
|
+
(Height.new(200) + Height.new(10)).should == Height.new(210)
|
34
|
+
end
|
35
|
+
|
36
|
+
it '-' do
|
37
|
+
(Height.new(200) - Height.new(10)).should == Height.new(190)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#initialize' do
|
41
|
+
it 'accepts Height::Units' do
|
42
|
+
centimeters = Height::Units::Centimeters.new(191)
|
43
|
+
|
44
|
+
Height.new(centimeters).centimeters.should == centimeters
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#to_s' do
|
49
|
+
it 'works without arguments' do
|
50
|
+
Height.new(191).to_s.should == '1m 91cm'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'formats with metric system' do
|
54
|
+
Height.new(191).to_s(:default, :metric).should == '1m 91cm'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'formats with imperial system' do
|
58
|
+
Height.new('6ft 3in').to_s(:default, :imperial).should == '6 ft 3 in'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises when invalid system provided' do
|
62
|
+
expect { Height.new(191).to_s(:default, :alien) }.to raise_error(ArgumentError)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Height::Parser do
|
4
|
+
describe '#centimeters' do
|
5
|
+
it { Height::Parser.new(191).centimeters.should == Height::Units::Centimeters.new(191) }
|
6
|
+
it { Height::Parser.new('191').centimeters.should == Height::Units::Centimeters.new(191) }
|
7
|
+
it { Height::Parser.new('1m 91cm').centimeters.should == Height::Units::Centimeters.new(191) }
|
8
|
+
it { Height::Parser.new('6 feet 3 inches').centimeters.should == Height::Units::Centimeters.new(191) }
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Height::Parsers::Imperial do
|
4
|
+
it { Height::Parsers::Imperial.new('6 feet 3 inches').inches.should == Height::Units::Inches.new(75) }
|
5
|
+
it { Height::Parsers::Imperial.new('6 feet').centimeters.should == Height::Units::Centimeters.new(183) }
|
6
|
+
it { Height::Parsers::Imperial.new('6 \'').meters.should == Height::Units::Meters.new(1.83) }
|
7
|
+
it { Height::Parsers::Imperial.new('6\' 3"').feet.should == Height::Units::Feet.new(6.25) }
|
8
|
+
it { Height::Parsers::Imperial.new('6ft 3in').feet.should == Height::Units::Feet.new(6.25) }
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Height::Parsers::Metric do
|
4
|
+
it { Height::Parsers::Metric.new(191).centimeters.should == Height::Units::Centimeters.new(191) }
|
5
|
+
it { Height::Parsers::Metric.new('191').centimeters.should == Height::Units::Centimeters.new(191) }
|
6
|
+
it { Height::Parsers::Metric.new('191 cm').centimeters.should == Height::Units::Centimeters.new(191) }
|
7
|
+
it { Height::Parsers::Metric.new('1m 91cm').inches.should == Height::Units::Inches.new(75) }
|
8
|
+
it { Height::Parsers::Metric.new('1m').meters.should == Height::Units::Meters.new(1) }
|
9
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'height'
|
2
|
+
require 'pry'
|
3
|
+
require 'i18n'
|
4
|
+
|
5
|
+
def reset_i18n
|
6
|
+
I18n.backend = I18n::Backend::Simple.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def units
|
10
|
+
[
|
11
|
+
Height::Units::Feet.new(6.25),
|
12
|
+
Height::Units::Inches.new(75),
|
13
|
+
Height::Units::Meters.new(1.91),
|
14
|
+
Height::Units::Centimeters.new(191)
|
15
|
+
]
|
16
|
+
end
|