physical 0.4.8 → 0.5.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
  SHA256:
3
- metadata.gz: 45adbe9fa036b31165e380d114a9742467b551368e2a2dfc720452f2fba97e4c
4
- data.tar.gz: 351f94658f866fe313b7499bcacef7de4a00c8370587dbbde9d81b093f6dd04d
3
+ metadata.gz: 03d9eb10ac73675e3aa2bac745e7a6d8a30f4b9c0c6cb810d4dac0235d0cc55f
4
+ data.tar.gz: ed902ddd5a9349009a43d0a883a5526f7097d759e742c6ff43b8baf904765f63
5
5
  SHA512:
6
- metadata.gz: 7fd937c2f74862b1d28a0f819622e8d7a29b141bca24b175707adea171ef1a7e95f86494757fe32d9d24088356ebc31967688a0b1c6b895171f0e5a746fd4e35
7
- data.tar.gz: df819d350b08f636b8afd2d56294982564f2662205b091b429fd58cc1d1c7db507a385a04966b2c153c336ae5eb46887ae1f9f226267ae227db21a69ef2ecb36
6
+ metadata.gz: 52d08252ebda560e9abf682eb011c5e2281afbf0c3eead4acc650b9af8714555f465ffc9c613318eb2bed9e86caf72edddde1ad8edb5f26aea2233b7ebc38b96
7
+ data.tar.gz: cfdb971e4bdf9d1ce7c830b8f6da93614e630251ca7307f91baddf05353f43e1c1ef51aa84dc3db505ffb8221bf7fde68ee1e6348462e4fd9cacc9c820c2efb8
data/CHANGELOG.md CHANGED
@@ -6,6 +6,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## [0.5.0] - 2023-12-19
10
+
11
+ ### Added
12
+ - Introduce `Physical::Structure` class [#31]
13
+
14
+ ### Changed
15
+ - Use legitimate state/zip in location factory [#30]
16
+
17
+ ## [0.4.9] - 2023-08-02
18
+
19
+ ### Added
20
+ - Extract cuboid property handling into mixin [#25]
21
+ - Add properties to `Physical::Location` [#26]
22
+ - Add pallets to `Physical::Shipment` [#29]
23
+
24
+ ### Changed
25
+ - Faster package weight and volume calculations [#23]
26
+
9
27
  ## [0.4.8] - 2023-03-21
10
28
 
11
29
  ### Added
@@ -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)
@@ -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?
@@ -3,24 +3,32 @@
3
3
  module Physical
4
4
  class Package
5
5
  extend Forwardable
6
- attr_reader :container, :items, :void_fill_density, :id
6
+ attr_reader :id, :container, :items, :void_fill_density, :items_weight, :used_volume, :description
7
7
 
8
- def initialize(id: nil, container: nil, items: [], void_fill_density: Measured::Density(0, :g_ml), dimensions: nil, weight: nil, properties: {})
8
+ def initialize(id: nil, container: nil, items: [], void_fill_density: Measured::Density(0, :g_ml), dimensions: nil, weight: nil, description: 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
+ @description = description
13
+
12
14
  @items = Set[*items]
15
+ @items_weight = @items.map(&:weight).reduce(Measured::Weight(0, :g), &:+)
16
+ @used_volume = @items.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
13
17
  end
14
18
 
15
19
  delegate [:dimensions, :width, :length, :height, :properties, :volume] => :container
16
20
 
17
21
  def <<(other)
18
22
  @items.add(other)
23
+ @items_weight += other.weight
24
+ @used_volume += other.volume
19
25
  end
20
26
  alias_method :add, :<<
21
27
 
22
28
  def >>(other)
23
29
  @items.delete(other)
30
+ @items_weight -= other.weight
31
+ @used_volume -= other.volume
24
32
  end
25
33
  alias_method :delete, :>>
26
34
 
@@ -29,29 +37,19 @@ module Physical
29
37
  end
30
38
 
31
39
  # Cost is optional. We will only return an aggregate if all items
32
- # have cost defined. Otherwise we will retun nil.
40
+ # have cost defined. Otherwise we will return nil.
33
41
  # @return Money
34
42
  def items_value
35
43
  items_cost = items.map(&:cost)
36
44
  items_cost.reduce(&:+) if items_cost.compact.size == items_cost.size
37
45
  end
38
46
 
39
- # @return [Measured::Weight]
40
- def items_weight
41
- items.map(&:weight).reduce(Measured::Weight(0, :g), &:+)
42
- end
43
-
44
47
  def void_fill_weight
45
48
  return Measured::Weight(0, :g) if container.volume.value.infinite?
46
49
 
47
50
  Measured::Weight(void_fill_density.convert_to(:g_ml).value * remaining_volume.convert_to(:ml).value, :g)
48
51
  end
49
52
 
50
- # @return [Measured::Volume]
51
- def used_volume
52
- items.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
53
- end
54
-
55
53
  def remaining_volume
56
54
  container.inner_volume - used_volume
57
55
  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
@@ -6,16 +6,24 @@ module Physical
6
6
  :origin,
7
7
  :destination,
8
8
  :service_code,
9
+ :pallets,
10
+ :structures,
9
11
  :packages,
10
12
  :options
11
13
 
12
- def initialize(id: nil, origin: nil, destination: nil, service_code: nil, packages: [], options: {})
14
+ def initialize(id: nil, origin: nil, destination: nil, service_code: nil, pallets: [], structures: [], packages: [], options: {})
13
15
  @id = id || SecureRandom.uuid
14
16
  @origin = origin
15
17
  @destination = destination
16
18
  @service_code = service_code
19
+ @structures = structures
17
20
  @packages = packages
18
21
  @options = options
22
+
23
+ return unless pallets.any?
24
+
25
+ warn "[DEPRECATION] `pallets` is deprecated. Please use `structures` instead."
26
+ @pallets = pallets
19
27
  end
20
28
  end
21
29
  end
@@ -4,16 +4,17 @@ FactoryBot.define do
4
4
  factory :physical_location, class: 'Physical::Location' do
5
5
  transient do
6
6
  country_code { 'US' }
7
- region_code { 'IL' }
7
+ region_code { 'VA' }
8
8
  end
9
9
 
10
10
  name { 'Jane Doe' }
11
11
  company_name { 'Company' }
12
12
  address1 { '11 Lovely Street' }
13
- address2 { 'South' }
13
+ address2 { 'Suite 100' }
14
14
  city { 'Herndon' }
15
- sequence(:zip, 10_001, &:to_s)
15
+ zip { '20170' }
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,8 +4,14 @@ 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) } # deprecated, will be removed
7
8
  packages { build_list(:physical_package, 2) }
8
9
  service_code { "usps_priority_mail" }
9
10
  initialize_with { new(**attributes) }
11
+
12
+ trait :freight do
13
+ structures { build_list(:physical_structure, 1) }
14
+ service_code { "tforce_freight" }
15
+ end
10
16
  end
11
17
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :physical_structure, class: "Physical::Structure" do
5
+ container { FactoryBot.build(:physical_pallet) }
6
+ packages { build_list(:physical_package, 2) }
7
+ initialize_with { new(**attributes) }
8
+ end
9
+ end
@@ -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
- RSpec.shared_examples 'a cuboid' do
4
- let(:args) do
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"
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Physical
4
+ class Structure
5
+ extend Forwardable
6
+ attr_reader :id, :container, :packages, :packages_weight, :used_volume
7
+
8
+ def initialize(id: nil, container: nil, packages: [], dimensions: nil, weight: nil, properties: {})
9
+ @id = id || SecureRandom.uuid
10
+ @container = container || Physical::Pallet.new(dimensions: dimensions || [], weight: weight || Measured::Weight(0, :g), properties: properties)
11
+
12
+ @packages = Set[*packages]
13
+ @packages_weight = @packages.map(&:weight).reduce(Measured::Weight(0, :g), &:+)
14
+ @used_volume = @packages.map(&:volume).reduce(Measured::Volume(0, :ml), &:+)
15
+ end
16
+
17
+ delegate [:dimensions, :width, :length, :height, :properties, :volume] => :container
18
+
19
+ def <<(other)
20
+ @packages.add(other)
21
+ @packages_weight += other.weight
22
+ @used_volume += other.volume
23
+ end
24
+ alias_method :add, :<<
25
+
26
+ def >>(other)
27
+ @packages.delete(other)
28
+ @packages_weight -= other.weight
29
+ @used_volume -= other.volume
30
+ end
31
+ alias_method :delete, :>>
32
+
33
+ def weight
34
+ container.weight + packages_weight
35
+ end
36
+
37
+ # Cost is optional. We will only return an aggregate if all packages
38
+ # have items value defined. Otherwise we will return nil.
39
+ # @return Money
40
+ def packages_value
41
+ packages_cost = packages.map(&:items_value)
42
+ packages_cost.reduce(&:+) if packages_cost.compact.size == packages_cost.size
43
+ end
44
+
45
+ def remaining_volume
46
+ container.inner_volume - used_volume
47
+ end
48
+
49
+ def density
50
+ return Measured::Density(Float::INFINITY, :g_ml) if container.volume.value.zero?
51
+ return Measured::Density(0.0, :g_ml) if container.volume.value.infinite?
52
+
53
+ Measured::Density(weight.convert_to(:g).value / container.volume.convert_to(:ml).value, :g_ml)
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Physical
4
- VERSION = "0.4.8"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/physical.rb CHANGED
@@ -4,6 +4,7 @@ require "money"
4
4
  require "measured/density"
5
5
  require "physical/types"
6
6
  require "physical/version"
7
+ require "physical/property_readers"
7
8
  require "physical/cuboid"
8
9
  require "physical/box"
9
10
  require "physical/package"
@@ -11,6 +12,7 @@ require "physical/pallet"
11
12
  require "physical/item"
12
13
  require "physical/location"
13
14
  require "physical/shipment"
15
+ require "physical/structure"
14
16
 
15
17
  module Physical
16
18
  # Your code goes here...
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.8
4
+ version: 0.5.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: 2023-03-21 00:00:00.000000000 Z
11
+ date: 2023-12-19 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
@@ -206,7 +207,11 @@ files:
206
207
  - lib/physical/spec_support/factories/package_factory.rb
207
208
  - lib/physical/spec_support/factories/pallet_factory.rb
208
209
  - lib/physical/spec_support/factories/shipment_factory.rb
210
+ - lib/physical/spec_support/factories/structure_factory.rb
209
211
  - lib/physical/spec_support/shared_examples.rb
212
+ - lib/physical/spec_support/shared_examples/a_cuboid.rb
213
+ - lib/physical/spec_support/shared_examples/has_property_readers.rb
214
+ - lib/physical/structure.rb
210
215
  - lib/physical/test_support.rb
211
216
  - lib/physical/types.rb
212
217
  - lib/physical/version.rb
@@ -230,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
235
  - !ruby/object:Gem::Version
231
236
  version: '0'
232
237
  requirements: []
233
- rubygems_version: 3.3.26
238
+ rubygems_version: 3.4.22
234
239
  signing_key:
235
240
  specification_version: 4
236
241
  summary: A facade to deal with physical packages