measured 2.3.0 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2957338dafe1bf300930f97c9d23678175281ec0
4
- data.tar.gz: f52c802978510562bfaf3df79b122a79c230addf
3
+ metadata.gz: b181078ed94c22d305d95b445287def5a9ee7386
4
+ data.tar.gz: 2694f75fc2085f93c93075435ad1955b5f872e36
5
5
  SHA512:
6
- metadata.gz: ad9b8f66e912f434c51d9a344a18adaa419e19b483ff4aaf7ab8df26f82cd644ca2f49aa5d3a2f5359491a36e58d62e5b0ee3a916b8f38ff1085b450ce4f1f4d
7
- data.tar.gz: 7292c1dfe2357087eee0e15f043b2ce572fe655faa40c3ea1fc228b7d8a102d472f9b9c5bd2b81d0b82401ffeef2ddba6d961c1883d789d2937d831ae4d4b40d
6
+ metadata.gz: 961ab0ba4ac6cec71002b1c4a65a179880db5e8336a722aef32849ab6bf1a1f3bb2b137687ca3a8e4fd651d90b76ab1616d6306f03e3a12d82e64c248ae377c7
7
+ data.tar.gz: 757eba32db074dfba1712fd1c9c751630d5f5bae413dbb9fea0735bc0255f63fd28ca1a8b39aea9057b308acc14d3de7330305b1711ef45f87d4bdcf4b8f879f
@@ -6,9 +6,12 @@ rvm:
6
6
  - 2.2.4
7
7
  - 2.3.1
8
8
  - 2.4.0
9
+ - 2.5.0
9
10
  gemfile:
10
11
  - Gemfile
11
12
  - gemfiles/activesupport-4.2.gemfile
13
+ before_script:
14
+ - gem update --system
12
15
  matrix:
13
16
  exclude:
14
17
  - gemfile: Gemfile
data/Rakefile CHANGED
@@ -8,9 +8,12 @@ task default: :test
8
8
 
9
9
  desc 'Run the test stuite'
10
10
  Rake::TestTask.new do |t|
11
+ files = ARGV[1..-1]
12
+ files = "test/**/*_test.rb" if !files || files.length == 0
13
+
11
14
  t.libs << "test"
12
15
  t.libs << "lib/**/*"
13
- t.test_files = FileList['test/**/*_test.rb']
16
+ t.test_files = FileList[files]
14
17
  t.verbose = true
15
18
  end
16
19
 
data/dev.yml CHANGED
@@ -14,5 +14,5 @@ commands:
14
14
  if [[ $# -eq 0 ]]; then
15
15
  bundle exec rake test
16
16
  else
17
- bundle exec ruby -Itest "$@"
17
+ bundle exec rake test "$@"
18
18
  fi
@@ -1,3 +1,4 @@
1
+ require "forwardable"
1
2
  require "measured/version"
2
3
  require "active_support/all"
3
4
  require "bigdecimal"
@@ -42,5 +43,5 @@ require "measured/parser"
42
43
  require "measured/unit"
43
44
  require "measured/unit_system"
44
45
  require "measured/unit_system_builder"
45
- require "measured/conversion_table"
46
+ require "measured/conversion_table_builder"
46
47
  require "measured/measurable"
@@ -0,0 +1,80 @@
1
+ class Measured::ConversionTableBuilder
2
+ attr_reader :units
3
+
4
+ def initialize(units)
5
+ @units = units
6
+ end
7
+
8
+ def to_h
9
+ table = {}
10
+
11
+ units.map{|u| u.name}.each do |to_unit|
12
+ to_table = {to_unit => Rational(1, 1)}
13
+
14
+ table.each do |from_unit, from_table|
15
+ conversion = find_conversion(to: from_unit, from: to_unit)
16
+ to_table[from_unit] = conversion
17
+ from_table[to_unit] = 1 / conversion
18
+ end
19
+
20
+ table[to_unit] = to_table
21
+ end
22
+
23
+ table
24
+ end
25
+
26
+ private
27
+
28
+ def find_conversion(to:, from:)
29
+ conversion = find_direct_conversion_cached(to: to, from: from) || find_tree_traversal_conversion(to: to, from: from)
30
+
31
+ raise Measured::UnitError, "Cannot find conversion path from #{ from } to #{ to }." unless conversion
32
+
33
+ conversion
34
+ end
35
+
36
+ def find_direct_conversion_cached(to:, from:)
37
+ @cache ||= {}
38
+ @cache[to] ||= {}
39
+
40
+ if @cache[to].key?(from)
41
+ @cache[to][from]
42
+ else
43
+ @cache[to][from] = find_direct_conversion(to: to, from: from)
44
+ end
45
+ end
46
+
47
+ def find_direct_conversion(to:, from:)
48
+ units.each do |unit|
49
+ return unit.conversion_amount if unit.name == from && unit.conversion_unit == to
50
+ return unit.inverse_conversion_amount if unit.name == to && unit.conversion_unit == from
51
+ end
52
+
53
+ nil
54
+ end
55
+
56
+ def find_tree_traversal_conversion(to:, from:)
57
+ traverse(from: from, to: to, units_remaining: units.map(&:name), amount: 1)
58
+ end
59
+
60
+ def traverse(from:, to:, units_remaining:, amount:)
61
+ units_remaining = units_remaining - [from]
62
+
63
+ units_remaining.each do |name|
64
+ conversion = find_direct_conversion_cached(from: from, to: name)
65
+
66
+ if conversion
67
+ new_amount = amount * conversion
68
+ if name == to
69
+ return new_amount
70
+ else
71
+ result = traverse(from: name, to: to, units_remaining: units_remaining, amount: new_amount)
72
+ return result if result
73
+ end
74
+ end
75
+ end
76
+
77
+ nil
78
+ end
79
+
80
+ end
@@ -54,7 +54,7 @@ class Measured::Unit
54
54
  end
55
55
 
56
56
  def inverse_conversion_amount
57
- @inverse_conversion_amount ||= 1 / conversion_amount
57
+ @inverse_conversion_amount ||= 1 / conversion_amount if conversion_amount
58
58
  end
59
59
 
60
60
  private
@@ -3,6 +3,7 @@ class Measured::UnitSystem
3
3
 
4
4
  def initialize(units)
5
5
  @units = units.map { |unit| unit.with_unit_system(self) }
6
+ @conversion_table_builder = Measured::ConversionTableBuilder.new(@units)
6
7
  end
7
8
 
8
9
  def unit_names_with_aliases
@@ -43,7 +44,7 @@ class Measured::UnitSystem
43
44
  protected
44
45
 
45
46
  def conversion_table
46
- @conversion_table ||= Measured::ConversionTable.build(@units)
47
+ @conversion_table ||= @conversion_table_builder.to_h
47
48
  end
48
49
 
49
50
  def unit_name_to_unit
@@ -1,3 +1,3 @@
1
1
  module Measured
2
- VERSION = "2.3.0"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -6,10 +6,10 @@ require 'measured/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "measured"
8
8
  spec.version = Measured::VERSION
9
- spec.authors = ["Kevin McPhillips"]
10
- spec.email = ["github@kevinmcphillips.ca"]
9
+ spec.authors = ["Kevin McPhillips", "Jason Gedge", "Javier Honduvilla Coto"]
10
+ spec.email = ["gems@shopify.com"]
11
11
  spec.summary = %q{Encapsulate measurements with their units in Ruby}
12
- spec.description = %q{Wrapper objects which encapsulate measurments and their associated units in Ruby.}
12
+ spec.description = %q{Wrapper objects which encapsulate measurements and their associated units in Ruby.}
13
13
  spec.homepage = "https://github.com/Shopify/measured"
14
14
  spec.license = "MIT"
15
15
 
@@ -0,0 +1,118 @@
1
+ require "test_helper"
2
+
3
+ class Measured::ConversionTableBuilderTest < ActiveSupport::TestCase
4
+ test "#initialize creates a new object with the units" do
5
+ units = [Measured::Unit.new(:test)]
6
+
7
+ assert_equal units, Measured::ConversionTableBuilder.new(units).units
8
+ end
9
+
10
+ test "#to_h should return a hash for the simple case" do
11
+ conversion_table = Measured::ConversionTableBuilder.new([Measured::Unit.new(:test)]).to_h
12
+
13
+ expected = {
14
+ "test" => {"test" => Rational(1, 1)}
15
+ }
16
+
17
+ assert_equal expected, conversion_table
18
+ assert_instance_of Rational, conversion_table.values.first.values.first
19
+ end
20
+
21
+ test "#to_h returns expected nested hashes with BigDecimal conversion factors in a tiny data set" do
22
+ conversion_table = Measured::ConversionTableBuilder.new([
23
+ Measured::Unit.new(:m),
24
+ Measured::Unit.new(:cm, value: "0.01 m"),
25
+ ]).to_h
26
+
27
+ expected = {
28
+ "m" => {
29
+ "m" => Rational(1, 1),
30
+ "cm" => Rational(100, 1),
31
+ },
32
+ "cm" => {
33
+ "m" => Rational(1, 100),
34
+ "cm" => Rational(1, 1),
35
+ }
36
+ }
37
+
38
+ assert_equal expected, conversion_table
39
+
40
+ conversion_table.values.map(&:values).flatten.each do |value|
41
+ assert_instance_of Rational, value
42
+ end
43
+ end
44
+
45
+ test "#to_h returns expected nested hashes factors" do
46
+ conversion_table = Measured::ConversionTableBuilder.new([
47
+ Measured::Unit.new(:m),
48
+ Measured::Unit.new(:cm, value: "0.01 m"),
49
+ Measured::Unit.new(:mm, value: "0.001 m"),
50
+ ]).to_h
51
+
52
+ expected = {
53
+ "m" => {
54
+ "m" => Rational(1, 1),
55
+ "cm" => Rational(100, 1),
56
+ "mm" => Rational(1000, 1),
57
+ },
58
+ "cm" => {
59
+ "m" => Rational(1, 100),
60
+ "cm" => Rational(1, 1),
61
+ "mm" => Rational(10, 1),
62
+ },
63
+ "mm" => {
64
+ "m" => Rational(1, 1000),
65
+ "cm" => Rational(1, 10),
66
+ "mm" => Rational(1, 1),
67
+ }
68
+ }
69
+
70
+ assert_equal expected, conversion_table
71
+
72
+ conversion_table.values.map(&:values).flatten.each do |value|
73
+ assert_instance_of Rational, value
74
+ end
75
+ end
76
+
77
+ test "#to_h returns expected nested hashes in an indrect path" do
78
+ conversion_table = Measured::ConversionTableBuilder.new([
79
+ Measured::Unit.new(:mm),
80
+ Measured::Unit.new(:cm, value: "10 mm"),
81
+ Measured::Unit.new(:dm, value: "10 cm"),
82
+ Measured::Unit.new(:m, value: "10 dm"),
83
+ ]).to_h
84
+
85
+ expected = {
86
+ "m" => {
87
+ "m" => Rational(1, 1),
88
+ "dm" => Rational(10, 1),
89
+ "cm" => Rational(100, 1),
90
+ "mm" => Rational(1000, 1),
91
+ },
92
+ "cm" => {
93
+ "m" => Rational(1, 100),
94
+ "dm" => Rational(1, 10),
95
+ "cm" => Rational(1, 1),
96
+ "mm" => Rational(10, 1),
97
+ },
98
+ "dm" => {
99
+ "m" => Rational(1, 10),
100
+ "cm" => Rational(10, 1),
101
+ "dm" => Rational(1, 1),
102
+ "mm" => Rational(100, 1),
103
+ },
104
+ "mm" => {
105
+ "m" => Rational(1, 1000),
106
+ "dm" => Rational(1, 100),
107
+ "cm" => Rational(1, 10),
108
+ "mm" => Rational(1, 1),
109
+ }
110
+ }
111
+
112
+ assert_equal expected, conversion_table
113
+
114
+ conversion_table.values.map(&:values).flatten.each do |value|
115
+ assert_instance_of Rational, value
116
+ end
117
+ end
118
+ end
@@ -2,7 +2,7 @@ require "measured"
2
2
  require "minitest/reporters"
3
3
  require "minitest/autorun"
4
4
  require "mocha/setup"
5
- require "pry"
5
+ require "pry" unless ENV["CI"]
6
6
 
7
7
  ActiveSupport.test_order = :random
8
8
 
@@ -78,4 +78,8 @@ class Measured::UnitTest < ActiveSupport::TestCase
78
78
  test "#inverse_conversion_amount returns 1/amount" do
79
79
  assert_equal Rational(1, 10), @unit.inverse_conversion_amount
80
80
  end
81
+
82
+ test "#inverse_conversion_amount handles nil for base unit" do
83
+ assert_nil Measured::Unit.new(:pie).inverse_conversion_amount
84
+ end
81
85
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: measured
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McPhillips
8
+ - Jason Gedge
9
+ - Javier Honduvilla Coto
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2018-01-17 00:00:00.000000000 Z
13
+ date: 2018-01-24 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: activesupport
@@ -94,10 +96,10 @@ dependencies:
94
96
  - - ">="
95
97
  - !ruby/object:Gem::Version
96
98
  version: '0'
97
- description: Wrapper objects which encapsulate measurments and their associated units
99
+ description: Wrapper objects which encapsulate measurements and their associated units
98
100
  in Ruby.
99
101
  email:
100
- - github@kevinmcphillips.ca
102
+ - gems@shopify.com
101
103
  executables: []
102
104
  extensions: []
103
105
  extra_rdoc_files: []
@@ -113,7 +115,7 @@ files:
113
115
  - lib/measured.rb
114
116
  - lib/measured/arithmetic.rb
115
117
  - lib/measured/base.rb
116
- - lib/measured/conversion_table.rb
118
+ - lib/measured/conversion_table_builder.rb
117
119
  - lib/measured/measurable.rb
118
120
  - lib/measured/parser.rb
119
121
  - lib/measured/unit.rb
@@ -126,7 +128,7 @@ files:
126
128
  - measured.gemspec
127
129
  - shipit.rubygems.yml
128
130
  - test/arithmetic_test.rb
129
- - test/conversion_table_test.rb
131
+ - test/conversion_table_builder_test.rb
130
132
  - test/measurable_test.rb
131
133
  - test/parser_test.rb
132
134
  - test/support/fake_system.rb
@@ -164,7 +166,7 @@ specification_version: 4
164
166
  summary: Encapsulate measurements with their units in Ruby
165
167
  test_files:
166
168
  - test/arithmetic_test.rb
167
- - test/conversion_table_test.rb
169
+ - test/conversion_table_builder_test.rb
168
170
  - test/measurable_test.rb
169
171
  - test/parser_test.rb
170
172
  - test/support/fake_system.rb
@@ -1,65 +0,0 @@
1
- module Measured::ConversionTable
2
- extend self
3
-
4
- def build(units)
5
- table = {}
6
-
7
- units.map{|u| u.name}.each do |to_unit|
8
- to_table = {to_unit => BigDecimal("1")}
9
-
10
- table.each do |from_unit, from_table|
11
- to_table[from_unit] = find_conversion(units, to: from_unit, from: to_unit)
12
- from_table[to_unit] = find_conversion(units, to: to_unit, from: from_unit)
13
- end
14
-
15
- table[to_unit] = to_table
16
- end
17
-
18
- table
19
- end
20
-
21
- private
22
-
23
- def find_conversion(units, to:, from:)
24
- conversion = find_direct_conversion(units, to: to, from: from) || find_tree_traversal_conversion(units, to: to, from: from)
25
-
26
- raise Measured::UnitError, "Cannot find conversion path from #{ from } to #{ to }." unless conversion
27
-
28
- conversion
29
- end
30
-
31
- def find_direct_conversion(units, to:, from:)
32
- units.each do |unit|
33
- return unit.conversion_amount if unit.name == from && unit.conversion_unit == to
34
- end
35
-
36
- units.each do |unit|
37
- return unit.inverse_conversion_amount if unit.name == to && unit.conversion_unit == from
38
- end
39
-
40
- nil
41
- end
42
-
43
- def find_tree_traversal_conversion(units, to:, from:)
44
- traverse(units, from: from, to: to, unit_names: units.map(&:name), amount: 1)
45
- end
46
-
47
- def traverse(units, from:, to:, unit_names:, amount:)
48
- unit_names = unit_names - [from]
49
-
50
- unit_names.each do |name|
51
- if conversion = find_direct_conversion(units, from: from, to: name)
52
- new_amount = amount * conversion
53
- if name == to
54
- return new_amount
55
- else
56
- result = traverse(units, from: name, to: to, unit_names: unit_names, amount: new_amount)
57
- return result if result
58
- end
59
- end
60
- end
61
-
62
- nil
63
- end
64
-
65
- end
@@ -1,98 +0,0 @@
1
- require "test_helper"
2
-
3
- class Measured::ConversionTableTest < ActiveSupport::TestCase
4
- test ".build should return a hash for the simple case" do
5
- expected = {
6
- "test" => {"test" => BigDecimal("1")}
7
- }
8
-
9
- assert_equal expected, Measured::ConversionTable.build([Measured::Unit.new(:test)])
10
- end
11
-
12
- test ".build returns expected nested hashes with BigDecimal conversion factors in a tiny data set" do
13
- conversion_table = Measured::ConversionTable.build([
14
- Measured::Unit.new(:m),
15
- Measured::Unit.new(:cm, value: "0.01 m"),
16
- ])
17
-
18
- expected = {
19
- "m" => {
20
- "m" => BigDecimal("1"),
21
- "cm" => BigDecimal("100"),
22
- },
23
- "cm" => {
24
- "m" => BigDecimal("0.01"),
25
- "cm" => BigDecimal("1"),
26
- }
27
- }
28
-
29
- assert_equal expected, conversion_table
30
- end
31
-
32
- test ".build returns expected nested hashes with BigDecimal conversion factors" do
33
- conversion_table = Measured::ConversionTable.build([
34
- Measured::Unit.new(:m),
35
- Measured::Unit.new(:cm, value: "0.01 m"),
36
- Measured::Unit.new(:mm, value: "0.001 m"),
37
- ])
38
-
39
- expected = {
40
- "m" => {
41
- "m" => BigDecimal("1"),
42
- "cm" => BigDecimal("100"),
43
- "mm" => BigDecimal("1000"),
44
- },
45
- "cm" => {
46
- "m" => BigDecimal("0.01"),
47
- "cm" => BigDecimal("1"),
48
- "mm" => BigDecimal("10"),
49
- },
50
- "mm" => {
51
- "m" => BigDecimal("0.001"),
52
- "cm" => BigDecimal("0.1"),
53
- "mm" => BigDecimal("1"),
54
- }
55
- }
56
-
57
- assert_equal expected, conversion_table
58
- end
59
-
60
- test ".build returns expected nested hashes with BigDecimal conversion factors in an indrect path" do
61
- conversion_table = Measured::ConversionTable.build([
62
- Measured::Unit.new(:mm),
63
- Measured::Unit.new(:cm, value: "10 mm"),
64
- Measured::Unit.new(:dm, value: "10 cm"),
65
- Measured::Unit.new(:m, value: "10 dm"),
66
- ])
67
-
68
- expected = {
69
- "m" => {
70
- "m" => BigDecimal("1"),
71
- "dm" => BigDecimal("10"),
72
- "cm" => BigDecimal("100"),
73
- "mm" => BigDecimal("1000"),
74
- },
75
- "cm" => {
76
- "m" => BigDecimal("0.01"),
77
- "dm" => BigDecimal("0.1"),
78
- "cm" => BigDecimal("1"),
79
- "mm" => BigDecimal("10"),
80
- },
81
- "dm" => {
82
- "m" => BigDecimal("0.1"),
83
- "cm" => BigDecimal("10"),
84
- "dm" => BigDecimal("1"),
85
- "mm" => BigDecimal("100"),
86
- },
87
- "mm" => {
88
- "m" => BigDecimal("0.001"),
89
- "dm" => BigDecimal("0.01"),
90
- "cm" => BigDecimal("0.1"),
91
- "mm" => BigDecimal("1"),
92
- }
93
- }
94
-
95
- assert_equal expected, conversion_table
96
- end
97
-
98
- end