physical 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +84 -18
- data/lib/physical/box.rb +22 -0
- data/lib/physical/cuboid.rb +12 -4
- data/lib/physical/package.rb +5 -14
- data/lib/physical/spec_support/factories/box_factory.rb +3 -4
- data/lib/physical/spec_support/factories/item_factory.rb +2 -4
- data/lib/physical/spec_support/factories/package_factory.rb +1 -1
- data/lib/physical/spec_support/shared_examples.rb +9 -1
- data/lib/physical/types.rb +14 -0
- data/lib/physical/version.rb +1 -1
- data/lib/physical.rb +1 -0
- data/physical.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdda01f27d8c75a1b222e13ca9f84e54e1f2a4c0
|
4
|
+
data.tar.gz: ee3cdd019c063a04141e29a6a1e83f2d25d3b483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48f2da61f204e7ebb71339f5be3c0379928121ce1a94af7e2cc84179e49331789d8316a85fe66c3d1f45557a1089595df1a4ee990634abd4dc30e7f27303edc4
|
7
|
+
data.tar.gz: a3170e37c25c1d677bb2028d31bdc8905c4418b3fdb9ff49cf81c9deb7a73faa4e87463ce4b4cdc3a3fb45a42fe98a4dcd6a27bdc1e3245fe74e1f5ed820bbfd
|
data/README.md
CHANGED
@@ -34,42 +34,108 @@ Or install it yourself as:
|
|
34
34
|
|
35
35
|
## Usage
|
36
36
|
|
37
|
+
### Basic Package
|
38
|
+
|
39
|
+
A basic Package has no items and is simply assigned a weight and dimensions. Weights and Dimensions have to be given as `Measured::Weight` or as an Array of `Measured::Length` objects:
|
40
|
+
|
37
41
|
```ruby
|
38
|
-
|
42
|
+
Physical::Package.new(
|
43
|
+
weight: Measured::Weight(1, :pound),
|
44
|
+
dimensions: [
|
45
|
+
Measured::Length(3, :inch),
|
46
|
+
Measured::Length(4, :inch),
|
47
|
+
Measured::Length(5, :inch)
|
48
|
+
]
|
49
|
+
)
|
50
|
+
```
|
51
|
+
You will be able to retrieve the package's weight and dimensions using the `#weight` and `#dimensions` attribute reader methods.
|
52
|
+
|
53
|
+
### Convenience methods
|
54
|
+
|
55
|
+
The length, width and height of a package are defined as the package's longest, middle, and shortest side, respectively. For the package from the previous example, `package.length` will be 5 inches, `package.width` will be 4 inches, and `package.height` will be 3 inches. Packages do not have a notion of "right side up" yet.
|
56
|
+
|
57
|
+
The package's `length` is also accessible as `package.x`. The package's `width` is also accessible as `package.y`. The package's `height` is also accessible as `package.z` as well as `package.depth`.
|
58
|
+
|
59
|
+
### Packages with Items
|
60
|
+
|
61
|
+
The following example is a somewhat more elaborate package: We know the items inside! `Physical::Item` objects are Cuboids, so they have three dimensions and a weight. They also have a `properties` hash that can hold things like any hazardous properties that might impede shipping.
|
62
|
+
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
sku_one = Physical::Item.new(
|
39
66
|
id: '12345',
|
40
|
-
dimensions: [
|
41
|
-
|
42
|
-
|
43
|
-
|
67
|
+
dimensions: [
|
68
|
+
Measured::Length(2, :inch),
|
69
|
+
Measured::Length(4, :inch),
|
70
|
+
Measured::Length(5, :inch)
|
71
|
+
],
|
72
|
+
weight: Measured::Weight(1, :kg),
|
44
73
|
)
|
45
74
|
|
46
|
-
|
75
|
+
sku_two = Physical::Item.new(
|
47
76
|
id: "54321",
|
48
|
-
dimensions: [
|
49
|
-
|
50
|
-
|
51
|
-
|
77
|
+
dimensions: [
|
78
|
+
Measured::Length(1, :cm),
|
79
|
+
Measured::Length(1, :cm),
|
80
|
+
Measured::Length(1, :cm)
|
81
|
+
],
|
82
|
+
weight: Measured::Weight(23, :g)
|
83
|
+
)
|
84
|
+
```
|
85
|
+
|
86
|
+
You can initialize a package with items as follows:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
package_with_items = Physical::Package.new(
|
90
|
+
items: [sku_one, sku_two]
|
52
91
|
)
|
92
|
+
```
|
93
|
+
|
94
|
+
This package has no defined container. This means we assume a box that is infinitely large, and that has zero weight. Thus the weight of this `package_with_items` will be 1023 gram (1 kg + 23 g = 1000 g + 23 g).
|
53
95
|
|
96
|
+
### Packages with Boxes
|
97
|
+
|
98
|
+
A package also has a box that wraps it. This box is assumed to be a Cuboid, too - but one that has inner dimensions, and a weight that is it's own weight which must be added to any item's weight in order to find out the total weight of a package.
|
99
|
+
|
100
|
+
```ruby
|
54
101
|
my_carton = Physical::Box.new(
|
55
|
-
dimensions: [
|
56
|
-
|
57
|
-
|
58
|
-
|
102
|
+
dimensions: [
|
103
|
+
Measured::Length(10, :cm),
|
104
|
+
Measured::Length(15, :cm),
|
105
|
+
Measured::Length(15, :cm)
|
106
|
+
],
|
107
|
+
inner_dimensions: [
|
108
|
+
Measured::Length(9, :cm),
|
109
|
+
Measured::Length(14, :cm),
|
110
|
+
Measured::Length(14, :cm)
|
111
|
+
],
|
112
|
+
weight: Measured::Weight(350, :g),
|
59
113
|
)
|
114
|
+
```
|
60
115
|
|
116
|
+
If you create a carton and omit the inner dimensions, we will assume that the carton's inner dimensions are equal to its outer dimensions. This will, in many cases, be good enough (but in some you'll need the extra precision).
|
117
|
+
|
118
|
+
### Calculating Void Fill
|
119
|
+
|
120
|
+
For an elaborate package with a container box and items, we still cannot find out the full weight of the package without taking into account void fill (styrofoam, bubble wrap or crumpled newspaper maybe). We can instruct the package to fill up all the volume not used up by items with void fill. You can pass the density as a `Measured::Weight` object that refers to the weight of 1 cubic centimeter of void fill:
|
121
|
+
|
122
|
+
```ruby
|
61
123
|
package = Physical::Package.new(
|
62
124
|
id: "my_package",
|
63
125
|
container: my_carton,
|
64
|
-
items: [
|
65
|
-
void_fill_density: 0.007
|
126
|
+
items: [sku_one, sku_two],
|
127
|
+
void_fill_density: Measured::Weight(0.007, :g)
|
66
128
|
)
|
129
|
+
```
|
130
|
+
|
131
|
+
In this case, the package's weight will be slightly above the sum of carton weight and the sum of item weights, as we incorporate the approximate weight of the void fill material:
|
67
132
|
|
133
|
+
```ruby
|
68
134
|
package.weight
|
69
|
-
=> #<Measured::Weight:
|
135
|
+
=> #<Measured::Weight: 1380.75262208 #<Measured::Unit: g (gram, grams)>>
|
70
136
|
|
71
137
|
package.remaining_volume
|
72
|
-
=> #<Measured::Volume:
|
138
|
+
=> #<Measured::Volume: 1107.51744 #<Measured::Unit: ml (milliliter, millilitre, milliliters, millilitres) 1/1000 l>>
|
73
139
|
```
|
74
140
|
## Development
|
75
141
|
|
data/lib/physical/box.rb
CHANGED
@@ -5,5 +5,27 @@ require 'measured'
|
|
5
5
|
module Physical
|
6
6
|
class Box < Cuboid
|
7
7
|
DEFAULT_LENGTH = BigDecimal::INFINITY
|
8
|
+
attr_reader :inner_dimensions,
|
9
|
+
:inner_length,
|
10
|
+
:inner_width,
|
11
|
+
:inner_height
|
12
|
+
|
13
|
+
def initialize(inner_dimensions: [], **args)
|
14
|
+
super args
|
15
|
+
@inner_dimensions = fill_dimensions(Types::Dimensions[inner_dimensions])
|
16
|
+
@inner_length, @inner_width, @inner_height = *@inner_dimensions.reverse
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :inner_x :inner_length
|
20
|
+
alias :inner_y :inner_width
|
21
|
+
alias :inner_z :inner_height
|
22
|
+
alias :inner_depth :inner_height
|
23
|
+
|
24
|
+
def inner_volume
|
25
|
+
Measured::Volume(
|
26
|
+
inner_dimensions.map { |d| d.convert_to(:cm).value }.reduce(1, &:*),
|
27
|
+
:ml
|
28
|
+
)
|
29
|
+
end
|
8
30
|
end
|
9
31
|
end
|
data/lib/physical/cuboid.rb
CHANGED
@@ -6,11 +6,11 @@ module Physical
|
|
6
6
|
class Cuboid
|
7
7
|
attr_reader :dimensions, :length, :width, :height, :weight, :id, :properties
|
8
8
|
|
9
|
-
def initialize(id: nil, dimensions: [],
|
9
|
+
def initialize(id: nil, dimensions: [], weight: Measured::Weight(0, :g), properties: {})
|
10
10
|
@id = id || SecureRandom.uuid
|
11
|
-
@weight =
|
12
|
-
@dimensions =
|
13
|
-
@dimensions
|
11
|
+
@weight = Types::Weight[weight]
|
12
|
+
@dimensions = []
|
13
|
+
@dimensions = fill_dimensions(Types::Dimensions[dimensions])
|
14
14
|
@length, @width, @height = *@dimensions.reverse
|
15
15
|
@properties = properties
|
16
16
|
end
|
@@ -27,5 +27,13 @@ module Physical
|
|
27
27
|
def ==(other)
|
28
28
|
id == other.id
|
29
29
|
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def fill_dimensions(dimensions)
|
34
|
+
dimensions.fill(dimensions.length..2) do |index|
|
35
|
+
@dimensions[index] || Measured::Length(self.class::DEFAULT_LENGTH, :cm)
|
36
|
+
end.sort
|
37
|
+
end
|
30
38
|
end
|
31
39
|
end
|
data/lib/physical/package.rb
CHANGED
@@ -5,14 +5,14 @@ module Physical
|
|
5
5
|
extend Forwardable
|
6
6
|
attr_reader :container, :items, :void_fill_density, :id
|
7
7
|
|
8
|
-
def initialize(id: nil, container:
|
8
|
+
def initialize(id: nil, container: nil, items: [], void_fill_density: Measured::Weight(0, :g), dimensions: nil, weight: nil, properties: {})
|
9
9
|
@id = id || SecureRandom.uuid
|
10
|
-
@void_fill_density =
|
11
|
-
@container = container
|
10
|
+
@void_fill_density = Types::Weight[void_fill_density]
|
11
|
+
@container = container || Physical::Box.new(dimensions: dimensions || [], weight: weight || Measured::Weight(0, :g), properties: properties)
|
12
12
|
@items = Set[*items]
|
13
13
|
end
|
14
14
|
|
15
|
-
delegate [:dimensions, :width, :length, :height, :depth, :x, :y, :z] => :container
|
15
|
+
delegate [:dimensions, :width, :length, :height, :depth, :x, :y, :z, :properties] => :container
|
16
16
|
|
17
17
|
def <<(item)
|
18
18
|
@items.add(item)
|
@@ -27,7 +27,7 @@ module Physical
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def remaining_volume
|
30
|
-
container.
|
30
|
+
container.inner_volume - items.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
|
31
31
|
end
|
32
32
|
|
33
33
|
def void_fill_weight
|
@@ -35,14 +35,5 @@ module Physical
|
|
35
35
|
|
36
36
|
Measured::Weight(void_fill_density.value * remaining_volume.value, void_fill_density.unit)
|
37
37
|
end
|
38
|
-
|
39
|
-
def measured_void_fill_density(void_fill_density, void_fill_density_unit)
|
40
|
-
case void_fill_density
|
41
|
-
when Measured::Weight
|
42
|
-
void_fill_density
|
43
|
-
else
|
44
|
-
Measured::Weight(void_fill_density, void_fill_density_unit)
|
45
|
-
end
|
46
|
-
end
|
47
38
|
end
|
48
39
|
end
|
@@ -4,10 +4,9 @@ require 'factory_bot'
|
|
4
4
|
|
5
5
|
FactoryBot.define do
|
6
6
|
factory :physical_box, class: "Physical::Box" do
|
7
|
-
dimensions { [4, 5, 6] }
|
8
|
-
|
9
|
-
weight { 0.1 }
|
10
|
-
weight_unit { :kg }
|
7
|
+
dimensions { [4, 5, 6].map { |d| Measured::Length(d, :dm) } }
|
8
|
+
inner_dimensions { dimensions.map { |d| d - Measured::Length(1, :cm) } }
|
9
|
+
weight { Measured::Weight(0.1, :kg) }
|
11
10
|
initialize_with { new(attributes) }
|
12
11
|
end
|
13
12
|
end
|
@@ -4,10 +4,8 @@ require 'factory_bot'
|
|
4
4
|
|
5
5
|
FactoryBot.define do
|
6
6
|
factory :physical_item, class: "Physical::Item" do
|
7
|
-
dimensions { [1, 2, 3] }
|
8
|
-
|
9
|
-
weight { 50 }
|
10
|
-
weight_unit { :g }
|
7
|
+
dimensions { [1, 2, 3].map { |d| Measured::Length(d, :cm)} }
|
8
|
+
weight { Measured::Weight(50, :g) }
|
11
9
|
initialize_with { new(attributes) }
|
12
10
|
end
|
13
11
|
end
|
@@ -6,7 +6,7 @@ FactoryBot.define do
|
|
6
6
|
factory :physical_package, class: "Physical::Package" do
|
7
7
|
container { FactoryBot.build(:physical_box) }
|
8
8
|
items { build_list(:physical_item, 2) }
|
9
|
-
void_fill_density { 0.01 }
|
9
|
+
void_fill_density { Measured::Weight(0.01, :g) }
|
10
10
|
initialize_with { new(attributes) }
|
11
11
|
end
|
12
12
|
end
|
@@ -1,7 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.shared_examples 'a cuboid' do
|
4
|
-
let(:args)
|
4
|
+
let(:args) do
|
5
|
+
{
|
6
|
+
dimensions: [
|
7
|
+
Measured::Length.new(1.1, :cm),
|
8
|
+
Measured::Length.new(2.2, :cm),
|
9
|
+
Measured::Length.new(3.3, :cm)
|
10
|
+
].shuffle
|
11
|
+
}
|
12
|
+
end
|
5
13
|
|
6
14
|
it { is_expected.to be_a(Physical::Cuboid) }
|
7
15
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'measured'
|
2
|
+
require 'dry-types'
|
3
|
+
|
4
|
+
module Physical
|
5
|
+
module Types
|
6
|
+
include Dry::Types.module
|
7
|
+
|
8
|
+
Weight = Types.Instance(::Measured::Weight)
|
9
|
+
Length = Types.Instance(::Measured::Length)
|
10
|
+
Volume = Types.Instance(::Measured::Volume)
|
11
|
+
|
12
|
+
Dimensions = Types::Strict::Array.of(Length)
|
13
|
+
end
|
14
|
+
end
|
data/lib/physical/version.rb
CHANGED
data/lib/physical.rb
CHANGED
data/physical.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.required_ruby_version = '>= 2.4'
|
23
23
|
spec.add_runtime_dependency "carmen", "~> 1.0"
|
24
24
|
spec.add_runtime_dependency "measured", "~> 2.4.0"
|
25
|
+
spec.add_runtime_dependency "dry-types", "~> 1.0.0"
|
25
26
|
|
26
27
|
spec.add_development_dependency "bundler", [">= 1.16", "< 3"]
|
27
28
|
spec.add_development_dependency "factory_bot", "~> 4.8"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: physical
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Meyerhoff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: carmen
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.4.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-types
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +148,7 @@ files:
|
|
134
148
|
- lib/physical/spec_support/factories/package_factory.rb
|
135
149
|
- lib/physical/spec_support/factories/shipment_factory.rb
|
136
150
|
- lib/physical/spec_support/shared_examples.rb
|
151
|
+
- lib/physical/types.rb
|
137
152
|
- lib/physical/version.rb
|
138
153
|
- physical.gemspec
|
139
154
|
homepage: https://github.com/mamhoff/physical
|