physical 0.4.7 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/lib/physical/cuboid.rb +2 -21
- data/lib/physical/location.rb +7 -2
- data/lib/physical/package.rb +14 -9
- data/lib/physical/property_readers.rb +28 -0
- data/lib/physical/shipment.rb +3 -1
- data/lib/physical/spec_support/factories/location_factory.rb +1 -0
- data/lib/physical/spec_support/factories/shipment_factory.rb +1 -0
- data/lib/physical/spec_support/shared_examples/a_cuboid.rb +197 -0
- data/lib/physical/spec_support/shared_examples/has_property_readers.rb +87 -0
- data/lib/physical/spec_support/shared_examples.rb +2 -43
- data/lib/physical/version.rb +1 -1
- data/lib/physical.rb +1 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8198a4417d9f1dd923a4bfee9bf8695ecb1c270853182a92835e64c1b9f4e10c
|
4
|
+
data.tar.gz: 8a007792624c95421bce9a09abb978de1142b8a2bfbfe6cef049c860ca101416
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b39b9310b28cd5bd9cfe3ea0511f6c615f3c130060693296e6aa01b18d3c893c9cd1704954133e9655c6a47fbe66f636eabc95c4a012f1e34ae4a0e634f6c0b3
|
7
|
+
data.tar.gz: 4881137e7cd922d5a9e56bcaec2fd5701b1e21f3e4ed53528585c14a2c24e0f2b90d93b2b36c7327160dae03cdc9c3e0f3a6171abb898d17843de862bf1f02a1
|
data/CHANGELOG.md
CHANGED
@@ -6,12 +6,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
6
6
|
|
7
7
|
## Unreleased
|
8
8
|
|
9
|
+
## [0.4.9] - 2023-08-02
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- Extract cuboid property handling into mixin [#25]
|
13
|
+
- Add properties to `Physical::Location` [#26]
|
14
|
+
- Add pallets to `Physical::Shipment` [#29]
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
- Faster package weight and volume calculations [#23]
|
18
|
+
|
19
|
+
## [0.4.8] - 2023-03-21
|
20
|
+
|
21
|
+
### Added
|
22
|
+
- Add `#items_value` to `Physical::Package` [#21]
|
23
|
+
|
9
24
|
## [0.4.7] - 2022-12-14
|
10
25
|
|
11
26
|
### Changed
|
12
|
-
- Relax Dry::Types dependency to "~> 1.0"
|
27
|
+
- Relax Dry::Types dependency to "~> 1.0" [#20]
|
13
28
|
|
14
29
|
## [0.4.5] - 2022-09-28
|
30
|
+
|
15
31
|
### Added
|
16
32
|
- Add `Physical::Pallet` class [#12]
|
17
33
|
- Convenience methods for weight, volume, and fill [#15]
|
@@ -24,22 +40,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
24
40
|
- Ruby 3 support [#18]
|
25
41
|
|
26
42
|
## [0.4.4] - 2019-10-29
|
43
|
+
|
27
44
|
### Added
|
28
45
|
- Add `#sku`, `#cost` and `#description` to `Physical::Item`
|
29
46
|
|
30
47
|
## [0.4.3] - 2019-10-14
|
48
|
+
|
31
49
|
### Added
|
32
50
|
- Add `#latitude` and `#longitude` to `Physical::Location`
|
33
51
|
|
34
52
|
## [0.4.2] - 2019-09-04
|
53
|
+
|
35
54
|
### Changed
|
36
55
|
- Relax `Measured` Gem dependency
|
37
56
|
|
38
57
|
## [0.4.1] - 2019-07-15
|
58
|
+
|
39
59
|
### Added
|
40
60
|
- Add `max_weight` to `Physical::Package`
|
41
61
|
|
42
62
|
## [0.4.0] - 2019-07-10
|
63
|
+
|
43
64
|
### Added
|
44
65
|
- `Measured::Density` Type and density calculations [@tvdeyen](https://github.com/mamhoff/physical/pull/19)
|
45
66
|
- Use `Measured::Density` Type when initializing `Physical::Package#void_fill_density` [@mamhoff](https://github.com/mamhoff/physical/pull/22)
|
data/lib/physical/cuboid.rb
CHANGED
@@ -4,6 +4,8 @@ require 'measured'
|
|
4
4
|
|
5
5
|
module Physical
|
6
6
|
class Cuboid
|
7
|
+
include PropertyReaders
|
8
|
+
|
7
9
|
attr_reader :dimensions, :length, :width, :height, :weight, :id, :properties
|
8
10
|
|
9
11
|
def initialize(id: nil, dimensions: [], weight: Measured::Weight(0, :g), properties: {})
|
@@ -33,27 +35,6 @@ module Physical
|
|
33
35
|
|
34
36
|
private
|
35
37
|
|
36
|
-
NORMALIZED_METHOD_REGEX = /(\w+)\??$/.freeze
|
37
|
-
|
38
|
-
def method_missing(method)
|
39
|
-
symbolized_properties = properties.symbolize_keys
|
40
|
-
method_name = normalize_method_name(method)
|
41
|
-
if symbolized_properties.key?(method_name)
|
42
|
-
symbolized_properties[method_name]
|
43
|
-
else
|
44
|
-
super
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def respond_to_missing?(method, *args)
|
49
|
-
method_name = normalize_method_name(method)
|
50
|
-
properties.symbolize_keys.key?(method_name) || super
|
51
|
-
end
|
52
|
-
|
53
|
-
def normalize_method_name(method)
|
54
|
-
method.to_s.sub(NORMALIZED_METHOD_REGEX, '\1').to_sym
|
55
|
-
end
|
56
|
-
|
57
38
|
def fill_dimensions(dimensions)
|
58
39
|
dimensions.fill(dimensions.length..2) do |index|
|
59
40
|
@dimensions[index] || Measured::Length(self.class::DEFAULT_LENGTH, :cm)
|
data/lib/physical/location.rb
CHANGED
@@ -4,6 +4,8 @@ require 'carmen'
|
|
4
4
|
|
5
5
|
module Physical
|
6
6
|
class Location
|
7
|
+
include PropertyReaders
|
8
|
+
|
7
9
|
ADDRESS_TYPES = %w(residential commercial po_box).freeze
|
8
10
|
|
9
11
|
attr_reader :country,
|
@@ -20,7 +22,8 @@ module Physical
|
|
20
22
|
:address_type,
|
21
23
|
:company_name,
|
22
24
|
:latitude,
|
23
|
-
:longitude
|
25
|
+
:longitude,
|
26
|
+
:properties
|
24
27
|
|
25
28
|
def initialize(
|
26
29
|
name: nil,
|
@@ -37,7 +40,8 @@ module Physical
|
|
37
40
|
email: nil,
|
38
41
|
address_type: nil,
|
39
42
|
latitude: nil,
|
40
|
-
longitude: nil
|
43
|
+
longitude: nil,
|
44
|
+
properties: {}
|
41
45
|
)
|
42
46
|
|
43
47
|
@country = if country.is_a?(Carmen::Country)
|
@@ -65,6 +69,7 @@ module Physical
|
|
65
69
|
@address_type = address_type
|
66
70
|
@latitude = latitude
|
67
71
|
@longitude = longitude
|
72
|
+
@properties = properties
|
68
73
|
end
|
69
74
|
|
70
75
|
def residential?
|
data/lib/physical/package.rb
CHANGED
@@ -3,24 +3,31 @@
|
|
3
3
|
module Physical
|
4
4
|
class Package
|
5
5
|
extend Forwardable
|
6
|
-
attr_reader :container, :items, :void_fill_density, :
|
6
|
+
attr_reader :id, :container, :items, :void_fill_density, :items_weight, :used_volume
|
7
7
|
|
8
8
|
def initialize(id: nil, container: nil, items: [], void_fill_density: Measured::Density(0, :g_ml), dimensions: nil, weight: nil, properties: {})
|
9
9
|
@id = id || SecureRandom.uuid
|
10
10
|
@void_fill_density = Types::Density[void_fill_density]
|
11
11
|
@container = container || Physical::Box.new(dimensions: dimensions || [], weight: weight || Measured::Weight(0, :g), properties: properties)
|
12
|
+
|
12
13
|
@items = Set[*items]
|
14
|
+
@items_weight = @items.map(&:weight).reduce(Measured::Weight(0, :g), &:+)
|
15
|
+
@used_volume = @items.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
|
13
16
|
end
|
14
17
|
|
15
18
|
delegate [:dimensions, :width, :length, :height, :properties, :volume] => :container
|
16
19
|
|
17
20
|
def <<(other)
|
18
21
|
@items.add(other)
|
22
|
+
@items_weight += other.weight
|
23
|
+
@used_volume += other.volume
|
19
24
|
end
|
20
25
|
alias_method :add, :<<
|
21
26
|
|
22
27
|
def >>(other)
|
23
28
|
@items.delete(other)
|
29
|
+
@items_weight -= other.weight
|
30
|
+
@used_volume -= other.volume
|
24
31
|
end
|
25
32
|
alias_method :delete, :>>
|
26
33
|
|
@@ -28,9 +35,12 @@ module Physical
|
|
28
35
|
container.weight + items_weight + void_fill_weight
|
29
36
|
end
|
30
37
|
|
31
|
-
#
|
32
|
-
|
33
|
-
|
38
|
+
# Cost is optional. We will only return an aggregate if all items
|
39
|
+
# have cost defined. Otherwise we will return nil.
|
40
|
+
# @return Money
|
41
|
+
def items_value
|
42
|
+
items_cost = items.map(&:cost)
|
43
|
+
items_cost.reduce(&:+) if items_cost.compact.size == items_cost.size
|
34
44
|
end
|
35
45
|
|
36
46
|
def void_fill_weight
|
@@ -39,11 +49,6 @@ module Physical
|
|
39
49
|
Measured::Weight(void_fill_density.convert_to(:g_ml).value * remaining_volume.convert_to(:ml).value, :g)
|
40
50
|
end
|
41
51
|
|
42
|
-
# @return [Measured::Volume]
|
43
|
-
def used_volume
|
44
|
-
items.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
|
45
|
-
end
|
46
|
-
|
47
52
|
def remaining_volume
|
48
53
|
container.inner_volume - used_volume
|
49
54
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Physical
|
4
|
+
module PropertyReaders
|
5
|
+
private
|
6
|
+
|
7
|
+
NORMALIZED_METHOD_REGEX = /(\w+)\??$/.freeze
|
8
|
+
|
9
|
+
def method_missing(method)
|
10
|
+
symbolized_properties = properties.symbolize_keys
|
11
|
+
method_name = normalize_method_name(method)
|
12
|
+
if symbolized_properties.key?(method_name)
|
13
|
+
symbolized_properties[method_name]
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(method, *args)
|
20
|
+
method_name = normalize_method_name(method)
|
21
|
+
properties.symbolize_keys.key?(method_name) || super
|
22
|
+
end
|
23
|
+
|
24
|
+
def normalize_method_name(method)
|
25
|
+
method.to_s.sub(NORMALIZED_METHOD_REGEX, '\1').to_sym
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/physical/shipment.rb
CHANGED
@@ -6,14 +6,16 @@ module Physical
|
|
6
6
|
:origin,
|
7
7
|
:destination,
|
8
8
|
:service_code,
|
9
|
+
:pallets,
|
9
10
|
:packages,
|
10
11
|
:options
|
11
12
|
|
12
|
-
def initialize(id: nil, origin: nil, destination: nil, service_code: nil, packages: [], options: {})
|
13
|
+
def initialize(id: nil, origin: nil, destination: nil, service_code: nil, pallets: [], packages: [], options: {})
|
13
14
|
@id = id || SecureRandom.uuid
|
14
15
|
@origin = origin
|
15
16
|
@destination = destination
|
16
17
|
@service_code = service_code
|
18
|
+
@pallets = pallets
|
17
19
|
@packages = packages
|
18
20
|
@options = options
|
19
21
|
end
|
@@ -14,6 +14,7 @@ FactoryBot.define do
|
|
14
14
|
city { 'Herndon' }
|
15
15
|
sequence(:zip, 10_001, &:to_s)
|
16
16
|
phone { '555-555-0199' }
|
17
|
+
email { 'jane@company.com' }
|
17
18
|
region { country.subregions.coded(region_code) }
|
18
19
|
country { Carmen::Country.coded(country_code) }
|
19
20
|
initialize_with { new(**attributes) }
|
@@ -4,6 +4,7 @@ FactoryBot.define do
|
|
4
4
|
factory :physical_shipment, class: "Physical::Shipment" do
|
5
5
|
origin { FactoryBot.build(:physical_location) }
|
6
6
|
destination { FactoryBot.build(:physical_location) }
|
7
|
+
pallets { build_list(:physical_pallet, 1) }
|
7
8
|
packages { build_list(:physical_package, 2) }
|
8
9
|
service_code { "usps_priority_mail" }
|
9
10
|
initialize_with { new(**attributes) }
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples "a cuboid" do
|
4
|
+
subject(:cuboid) { described_class.new(**args) }
|
5
|
+
|
6
|
+
it_behaves_like "has property readers"
|
7
|
+
|
8
|
+
let(:args) do
|
9
|
+
{
|
10
|
+
dimensions: [
|
11
|
+
Measured::Length.new(1.1, :cm),
|
12
|
+
Measured::Length.new(3.3, :cm),
|
13
|
+
Measured::Length.new(2.2, :cm)
|
14
|
+
]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
it { is_expected.to be_a(Physical::Cuboid) }
|
19
|
+
it { is_expected.to respond_to(:id) }
|
20
|
+
|
21
|
+
describe "#dimensions" do
|
22
|
+
subject(:dimensions) { cuboid.dimensions }
|
23
|
+
|
24
|
+
it "has dimensions as Measured::Length objects with rational values" do
|
25
|
+
expect(dimensions).to eq(
|
26
|
+
[
|
27
|
+
Measured::Length.new(1.1, :cm),
|
28
|
+
Measured::Length.new(3.3, :cm),
|
29
|
+
Measured::Length.new(2.2, :cm)
|
30
|
+
]
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when given a one-element dimensions array" do
|
35
|
+
let(:args) do
|
36
|
+
{
|
37
|
+
dimensions: [Measured::Length(2, :cm)]
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "the other dimensions are filled up with default length" do
|
42
|
+
expect(dimensions).to eq(
|
43
|
+
[
|
44
|
+
Measured::Length.new(2, :cm),
|
45
|
+
Measured::Length.new(default_length, :cm),
|
46
|
+
Measured::Length.new(default_length, :cm)
|
47
|
+
]
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when given a two-element dimensions array" do
|
53
|
+
let(:args) do
|
54
|
+
{
|
55
|
+
dimensions: [1, 2].map { |d| Measured::Length(d, :cm) }
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it "the last dimension is filled up with default length" do
|
60
|
+
expect(dimensions).to eq(
|
61
|
+
[
|
62
|
+
Measured::Length.new(1, :cm),
|
63
|
+
Measured::Length.new(2, :cm),
|
64
|
+
Measured::Length.new(default_length, :cm)
|
65
|
+
]
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when given no arguments" do
|
71
|
+
let(:args) { {} }
|
72
|
+
|
73
|
+
it "assumes cm as the dimension_unit and the default length as value" do
|
74
|
+
expect(dimensions).to eq(
|
75
|
+
[
|
76
|
+
Measured::Length.new(default_length, :cm),
|
77
|
+
Measured::Length.new(default_length, :cm),
|
78
|
+
Measured::Length.new(default_length, :cm)
|
79
|
+
]
|
80
|
+
)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "dimension methods" do
|
86
|
+
it "has getter methods for each dimension as Measured::Length object" do
|
87
|
+
expect(cuboid.length).to eq(Measured::Length.new(1.1, :cm))
|
88
|
+
expect(cuboid.width).to eq(Measured::Length.new(3.3, :cm))
|
89
|
+
expect(cuboid.height).to eq(Measured::Length.new(2.2, :cm))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#weight" do
|
94
|
+
subject(:weight) { cuboid.weight }
|
95
|
+
|
96
|
+
context "with no weight given" do
|
97
|
+
let(:args) { {} }
|
98
|
+
it { is_expected.to eq(Measured::Weight(0, :g)) }
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with a weight" do
|
102
|
+
let(:args) { { weight: Measured::Weight(1, :lb) } }
|
103
|
+
it { is_expected.to eq(Measured::Weight(453.59237, :g)) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#volume" do
|
108
|
+
subject(:volume) { cuboid.volume }
|
109
|
+
|
110
|
+
context "if all three dimensions are given" do
|
111
|
+
let(:args) do
|
112
|
+
{
|
113
|
+
dimensions: [1.1, 2.1, 3.2].map { |d| Measured::Length(d, :cm) }
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
it { is_expected.to eq(Measured::Volume(7.392, :ml)) }
|
118
|
+
end
|
119
|
+
|
120
|
+
context "if a dimension is missing" do
|
121
|
+
let(:args) do
|
122
|
+
{
|
123
|
+
dimensions: [1.1, 2.1].map { |d| Measured::Length(d, :cm) }
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
it { is_expected.to eq(Measured::Volume(default_length, :ml)) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#density" do
|
132
|
+
subject(:density) { cuboid.density.value.to_f }
|
133
|
+
|
134
|
+
let(:args) do
|
135
|
+
{
|
136
|
+
dimensions: dimensions,
|
137
|
+
weight: weight
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
context "if volume is larger than 0" do
|
142
|
+
let(:dimensions) do
|
143
|
+
[1.1, 2.1, 3.2].map { |d| Measured::Length(d, :in) }
|
144
|
+
end
|
145
|
+
|
146
|
+
context "if weight is 1" do
|
147
|
+
let(:weight) { Measured::Weight(1, :pound) }
|
148
|
+
|
149
|
+
it "returns the density in gramms per cubiq centimeter (ml)" do
|
150
|
+
is_expected.to eq(3.7445758536530196)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "if weight is 0" do
|
155
|
+
let(:weight) { Measured::Weight(0, :pound) }
|
156
|
+
|
157
|
+
it { is_expected.to eq(0.0) }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "if volume is 0" do
|
162
|
+
let(:dimensions) do
|
163
|
+
[1.1, 2.1].map { |d| Measured::Length(d, :in) }
|
164
|
+
end
|
165
|
+
|
166
|
+
let(:weight) { Measured::Weight(1, :pound) }
|
167
|
+
let(:expected_volume) { default_length.zero? ? BigDecimal::INFINITY : 0 }
|
168
|
+
|
169
|
+
it { is_expected.to eq(expected_volume) }
|
170
|
+
end
|
171
|
+
|
172
|
+
context "if volume is infinite" do
|
173
|
+
let(:dimensions) do
|
174
|
+
[1.1, 2.1].map { |d| Measured::Length(d, :in) }
|
175
|
+
end
|
176
|
+
|
177
|
+
let(:weight) { Measured::Weight(1, :pound) }
|
178
|
+
let(:expected_volume) { default_length.zero? ? BigDecimal::INFINITY : 0 }
|
179
|
+
|
180
|
+
it { is_expected.to eq(expected_volume) }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#==" do
|
185
|
+
let(:args) { Hash[id: 123] }
|
186
|
+
let(:other_cuboid) { described_class.new(**args) }
|
187
|
+
let(:non_cuboid) { double(id: 123) }
|
188
|
+
|
189
|
+
it "compares cuboids" do
|
190
|
+
aggregate_failures do
|
191
|
+
expect(cuboid == other_cuboid).to be(true)
|
192
|
+
expect(cuboid == non_cuboid).to be(false)
|
193
|
+
expect(cuboid.nil?).to be(false)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples 'has property readers' do
|
4
|
+
subject(:instance) { described_class.new(**args) }
|
5
|
+
|
6
|
+
describe "#properties" do
|
7
|
+
subject(:properties) { instance.properties }
|
8
|
+
|
9
|
+
let(:args) do
|
10
|
+
{
|
11
|
+
properties: { flammable: true }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
it { is_expected.to eq({ flammable: true }) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "properties methods" do
|
19
|
+
context "if method is a property" do
|
20
|
+
let(:args) do
|
21
|
+
{
|
22
|
+
properties: { already_packaged: true }
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns its value" do
|
27
|
+
expect(instance.already_packaged).to be(true)
|
28
|
+
end
|
29
|
+
|
30
|
+
it { is_expected.to respond_to(:already_packaged?) }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "if method is a string property" do
|
34
|
+
let(:args) do
|
35
|
+
{
|
36
|
+
properties: { "already_packaged" => true }
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns its value" do
|
41
|
+
expect(instance.already_packaged).to be(true)
|
42
|
+
end
|
43
|
+
|
44
|
+
it { is_expected.to respond_to(:already_packaged?) }
|
45
|
+
end
|
46
|
+
|
47
|
+
context "if method is a boolean property" do
|
48
|
+
let(:args) do
|
49
|
+
{
|
50
|
+
properties: { already_packaged: true }
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "it is also accessible by its predicate method" do
|
55
|
+
expect(instance.already_packaged?).to be(true)
|
56
|
+
end
|
57
|
+
|
58
|
+
it { is_expected.to respond_to(:already_packaged?) }
|
59
|
+
|
60
|
+
context "with a falsey value" do
|
61
|
+
let(:args) do
|
62
|
+
{
|
63
|
+
properties: { already_packaged: false }
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns its value" do
|
68
|
+
expect(instance.already_packaged).to be(false)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "if method is not a property" do
|
74
|
+
let(:args) do
|
75
|
+
{
|
76
|
+
properties: {}
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
it "raises method missing" do
|
81
|
+
expect { instance.already_packaged? }.to raise_error(NoMethodError)
|
82
|
+
end
|
83
|
+
|
84
|
+
it { is_expected.not_to respond_to(:already_packaged?) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,45 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
{
|
6
|
-
dimensions: [
|
7
|
-
Measured::Length.new(1.1, :cm),
|
8
|
-
Measured::Length.new(3.3, :cm),
|
9
|
-
Measured::Length.new(2.2, :cm)
|
10
|
-
]
|
11
|
-
}
|
12
|
-
end
|
13
|
-
|
14
|
-
it { is_expected.to be_a(Physical::Cuboid) }
|
15
|
-
|
16
|
-
it "has dimensions as Measured::Length objects with rational values" do
|
17
|
-
expect(subject.dimensions).to eq(
|
18
|
-
[
|
19
|
-
Measured::Length.new(1.1, :cm),
|
20
|
-
Measured::Length.new(3.3, :cm),
|
21
|
-
Measured::Length.new(2.2, :cm)
|
22
|
-
]
|
23
|
-
)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "has getter methods for each dimension as Measured::Length object" do
|
27
|
-
expect(subject.length).to eq(Measured::Length.new(1.1, :cm))
|
28
|
-
expect(subject.width).to eq(Measured::Length.new(3.3, :cm))
|
29
|
-
expect(subject.height).to eq(Measured::Length.new(2.2, :cm))
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "#==" do
|
33
|
-
let(:args) { Hash[id: 123] }
|
34
|
-
let(:other_cuboid) { described_class.new(**args) }
|
35
|
-
let(:non_cuboid) { double(id: 123) }
|
36
|
-
|
37
|
-
it "compares cuboids" do
|
38
|
-
aggregate_failures do
|
39
|
-
expect(subject == other_cuboid).to be(true)
|
40
|
-
expect(subject == non_cuboid).to be(false)
|
41
|
-
expect(subject.nil?).to be(false)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
3
|
+
require "physical/spec_support/shared_examples/a_cuboid"
|
4
|
+
require "physical/spec_support/shared_examples/has_property_readers"
|
data/lib/physical/version.rb
CHANGED
data/lib/physical.rb
CHANGED
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.
|
4
|
+
version: 0.4.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Meyerhoff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: carmen
|
@@ -199,6 +199,7 @@ files:
|
|
199
199
|
- lib/physical/location.rb
|
200
200
|
- lib/physical/package.rb
|
201
201
|
- lib/physical/pallet.rb
|
202
|
+
- lib/physical/property_readers.rb
|
202
203
|
- lib/physical/shipment.rb
|
203
204
|
- lib/physical/spec_support/factories/box_factory.rb
|
204
205
|
- lib/physical/spec_support/factories/item_factory.rb
|
@@ -207,6 +208,8 @@ files:
|
|
207
208
|
- lib/physical/spec_support/factories/pallet_factory.rb
|
208
209
|
- lib/physical/spec_support/factories/shipment_factory.rb
|
209
210
|
- lib/physical/spec_support/shared_examples.rb
|
211
|
+
- lib/physical/spec_support/shared_examples/a_cuboid.rb
|
212
|
+
- lib/physical/spec_support/shared_examples/has_property_readers.rb
|
210
213
|
- lib/physical/test_support.rb
|
211
214
|
- lib/physical/types.rb
|
212
215
|
- lib/physical/version.rb
|
@@ -230,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
233
|
- !ruby/object:Gem::Version
|
231
234
|
version: '0'
|
232
235
|
requirements: []
|
233
|
-
rubygems_version: 3.
|
236
|
+
rubygems_version: 3.4.10
|
234
237
|
signing_key:
|
235
238
|
specification_version: 4
|
236
239
|
summary: A facade to deal with physical packages
|