box_packer 1.1.2 → 1.2.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.
@@ -1,3 +1,3 @@
1
1
  module BoxPacker
2
- VERSION = '1.1.2'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -1,53 +1,52 @@
1
1
  module BoxPacker
2
- describe Box do
3
- subject(:box) { Box.new(dimensions, position: position) }
4
- let(:dimensions) { Dimensions[25, 30, 10] }
5
- let(:position) { Position[10, 25, 5] }
6
- let(:item) { Item.new(Dimensions[5, 2, 1]) }
7
-
8
- context 'if no position is given' do
9
- let(:position) { nil }
10
-
11
- it "defaults to origin position" do
12
- expect(box.position).to eql(Position[0, 0, 0])
13
- end
14
- end
15
-
16
- describe '#orient!' do
17
- before { box.orient! }
18
- it { expect(box.dimensions).to eql(Dimensions[30, 25, 10]) }
19
- end
20
-
21
- describe '#sub_boxes_args' do
22
- let(:expected_args) {[
23
- [ Dimensions[20, 30, 10], position: Position[15, 25, 5] ],
24
- [ Dimensions[5, 28, 10], position: Position[10, 27, 5] ],
25
- [ Dimensions[5, 2, 9], position: Position[10, 25, 6] ]
26
- ]}
27
-
28
- it 'calculates the correct dimensions and positions' do
29
- expect(box.send(:sub_boxes_args, item)).to eql(expected_args)
30
- end
31
- end
32
-
33
- describe '#sub_boxes' do
34
-
35
- it 'orders sub-boxes by volumes' do
36
- sub_boxes = box.sub_boxes(item)
37
- expect(sub_boxes[0].volume).to be >=(sub_boxes[1].volume)
38
- expect(sub_boxes[1].volume).to be >=(sub_boxes[2].volume)
39
- end
40
-
41
- context 'with an item that reaches a side' do
42
- let(:item) { Box.new(Dimensions[15, 2, 10]) }
43
-
44
- it 'only returns 2 sub-boxes' do
45
- sub_boxes = box.sub_boxes(item)
46
- expect(sub_boxes.length).to eql(2)
47
- end
48
- end
49
-
50
- end
51
-
52
- end
53
- end
2
+ describe Box do
3
+ subject(:box) { Box.new(dimensions, position: position) }
4
+ let(:dimensions) { Dimensions[25, 30, 10] }
5
+ let(:position) { Position[10, 25, 5] }
6
+ let(:item) { Item.new(Dimensions[5, 2, 1]) }
7
+
8
+ context 'if no position is given' do
9
+ let(:position) { nil }
10
+
11
+ it 'defaults to origin position' do
12
+ expect(box.position).to eql(Position[0, 0, 0])
13
+ end
14
+ end
15
+
16
+ describe '#orient!' do
17
+ before { box.orient! }
18
+ it { expect(box.dimensions).to eql(Dimensions[30, 25, 10]) }
19
+ end
20
+
21
+ describe '#sub_boxes_args' do
22
+ let(:expected_args) do
23
+ [
24
+ [Dimensions[20, 30, 10], position: Position[15, 25, 5]],
25
+ [Dimensions[5, 28, 10], position: Position[10, 27, 5]],
26
+ [Dimensions[5, 2, 9], position: Position[10, 25, 6]]
27
+ ]
28
+ end
29
+
30
+ it 'calculates the correct dimensions and positions' do
31
+ expect(box.send(:sub_boxes_args, item)).to eql(expected_args)
32
+ end
33
+ end
34
+
35
+ describe '#sub_boxes' do
36
+ it 'orders sub-boxes by volumes' do
37
+ sub_boxes = box.sub_boxes(item)
38
+ expect(sub_boxes[0].volume).to be >= (sub_boxes[1].volume)
39
+ expect(sub_boxes[1].volume).to be >= (sub_boxes[2].volume)
40
+ end
41
+
42
+ context 'with an item that reaches a side' do
43
+ let(:item) { Box.new(Dimensions[15, 2, 10]) }
44
+
45
+ it 'only returns 2 sub-boxes' do
46
+ sub_boxes = box.sub_boxes(item)
47
+ expect(sub_boxes.length).to eql(2)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,88 +1,89 @@
1
1
  module BoxPacker
2
- describe Container do
3
- subject(:container) { Container.new([25, 30, 15]) }
4
-
5
- it { expect(container.packings).to eql(nil) }
6
-
7
- context 'with items' do
8
- let(:items) { [
9
- Item.new([15, 24, 8], weight: 25),
10
- Item.new([ 2, 1, 2], weight: 6),
11
- Item.new([ 9, 9, 10], weight: 30)
12
- ] }
13
- before { container.items = items }
14
-
15
- context 'with container prepared' do
16
- before do
17
- container.send(:prepare_to_pack!)
18
- end
19
-
20
- describe '#prepare_to_pack!' do
21
- let(:expected_dimensions){[
22
- Dimensions[24, 15, 8],
23
- Dimensions[2, 2, 1],
24
- Dimensions[10, 9, 9]
25
- ]}
26
-
27
- it { expect(container.items.map(&:dimensions)).to eql(expected_dimensions) }
28
- it { expect(container.packings).to eql([]) }
29
- end
30
-
31
- context 'with some items packed' do
32
- before do
33
- container.new_packing!
34
- container.packing << items[1]
35
- container.packing << items[2]
36
- end
37
-
38
- it { expect(container.packings.length).to eql(1) }
39
- it { expect(container.packing).to match_array([items[1], items[2]]) }
40
-
41
- describe '#new_packing!!' do
42
- before { container.new_packing! }
43
- it { expect(container.packings.length).to eql(2) }
44
- it { expect(container.packing).to eql([]) }
45
- end
46
- end
47
- end
48
-
49
- describe '#packable?' do
50
-
51
- context 'with no items' do
52
- before { container.items = [] }
53
- it { expect(container.send(:packable?)).to be(false) }
54
- end
55
-
56
- context 'with items that fit' do
57
- it { expect(container.send(:packable?)).to be(true) }
58
- end
59
-
60
- context 'with an item to large' do
61
- before { container.items[0].dimensions = Dimensions[26, 34, 8] }
62
- it { expect(container.send(:packable?)).to be(false) }
63
- end
64
-
65
- context 'with a weight limit thats lighter than one of the items' do
66
- before { container.weight_limit = 24 }
67
- it { expect(container.send(:packable?)).to be(false) }
68
- end
69
-
70
- context 'with a packings limit of one packing' do
71
- before { container.packings_limit = 1 }
72
-
73
- context 'with a weight limit thats lighter than items' do
74
- before { container.weight_limit = 50 }
75
- it { expect(container.send(:packable?)).to be(false) }
76
- end
77
-
78
- context 'with a weight limit thats heavier than items' do
79
- before { container.weight_limit = 70 }
80
- it { expect(container.send(:packable?)).to be(true) }
81
- end
82
-
83
- end
84
-
85
- end
86
- end
87
- end
88
- end
2
+ describe Container do
3
+ subject(:container) { Container.new([25, 30, 15]) }
4
+
5
+ it { expect(container.packings).to eql(nil) }
6
+
7
+ context 'with items' do
8
+ let(:items) do
9
+ [
10
+ Item.new([15, 24, 8], weight: 25),
11
+ Item.new([2, 1, 2], weight: 6),
12
+ Item.new([9, 9, 10], weight: 30)
13
+ ]
14
+ end
15
+ before { container.items = items }
16
+
17
+ context 'with container prepared' do
18
+ before do
19
+ container.send(:prepare_to_pack!)
20
+ end
21
+
22
+ describe '#prepare_to_pack!' do
23
+ let(:expected_dimensions)do
24
+ [
25
+ Dimensions[24, 15, 8],
26
+ Dimensions[2, 2, 1],
27
+ Dimensions[10, 9, 9]
28
+ ]
29
+ end
30
+
31
+ it { expect(container.items.map(&:dimensions)).to eql(expected_dimensions) }
32
+ it { expect(container.packings).to eql([]) }
33
+ end
34
+
35
+ context 'with some items packed' do
36
+ before do
37
+ container.new_packing!
38
+ container.packing << items[1]
39
+ container.packing << items[2]
40
+ end
41
+
42
+ it { expect(container.packings.length).to eql(1) }
43
+ it { expect(container.packing).to match_array([items[1], items[2]]) }
44
+
45
+ describe '#new_packing!!' do
46
+ before { container.new_packing! }
47
+ it { expect(container.packings.length).to eql(2) }
48
+ it { expect(container.packing).to eql([]) }
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#packable?' do
54
+ context 'with no items' do
55
+ before { container.items = [] }
56
+ it { expect(container.send(:packable?)).to be(false) }
57
+ end
58
+
59
+ context 'with items that fit' do
60
+ it { expect(container.send(:packable?)).to be(true) }
61
+ end
62
+
63
+ context 'with an item to large' do
64
+ before { container.items[0].dimensions = Dimensions[26, 34, 8] }
65
+ it { expect(container.send(:packable?)).to be(false) }
66
+ end
67
+
68
+ context 'with a weight limit thats lighter than one of the items' do
69
+ before { container.weight_limit = 24 }
70
+ it { expect(container.send(:packable?)).to be(false) }
71
+ end
72
+
73
+ context 'with a packings limit of one packing' do
74
+ before { container.packings_limit = 1 }
75
+
76
+ context 'with a weight limit thats lighter than items' do
77
+ before { container.weight_limit = 50 }
78
+ it { expect(container.send(:packable?)).to be(false) }
79
+ end
80
+
81
+ context 'with a weight limit thats heavier than items' do
82
+ before { container.weight_limit = 70 }
83
+ it { expect(container.send(:packable?)).to be(true) }
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -1,52 +1,54 @@
1
+ require_relative '../support/matchers/yield_each_once'
2
+
1
3
  module BoxPacker
2
- describe Dimensions do
3
- subject(:dimensions){ Dimensions[2, 10, 3] }
4
-
5
- describe '#volume' do
6
- it { expect(dimensions.volume).to eql(60) }
7
- end
8
-
9
- describe '#>=' do
10
-
11
- context 'when compared with Dimensions that are all bigger' do
12
- let(:other_dimensions) { Dimensions[1, 5, 2] }
13
- it { expect(dimensions >= other_dimensions).to be(true) }
14
- end
15
-
16
- context 'when compared with Dimensions where some are bigger and some are equal' do
17
- let(:other_dimensions) { Dimensions[2, 5, 3] }
18
- it { expect(dimensions >= other_dimensions).to be(true) }
19
- end
20
-
21
- context 'when compared with Dimensions that are all equal' do
22
- let(:other_dimensions) { Dimensions[2, 10, 3] }
23
- it { expect(dimensions >= other_dimensions).to be(true) }
24
- end
25
-
26
- context 'when compared with Dimensions where some are bigger and some are smaller' do
27
- let(:other_dimensions) { Dimensions[5, 5, 1] }
28
- it { expect(dimensions >= other_dimensions).to be(false) }
29
- end
30
-
31
- context 'when compared with Dimensions where none are bigger' do
32
- let(:other_dimensions) { Dimensions[5, 15, 11] }
33
- it { expect(dimensions >= other_dimensions).to be(false) }
34
- end
35
-
36
- end
37
-
38
- describe '#each_rotation' do
39
- let(:rotations){[
40
- Dimensions[2, 10, 3],
41
- Dimensions[2, 3, 10],
42
- Dimensions[10, 2, 3],
43
- Dimensions[10, 3, 2],
44
- Dimensions[3, 10, 2],
45
- Dimensions[3, 2, 10]
46
- ]}
47
-
48
- it { expect{|b| dimensions.each_rotation(&b)}.to yield_each_once(rotations) }
49
- end
50
-
51
- end
52
- end
4
+ describe Dimensions do
5
+ include BoxPacker::Matchers
6
+ subject(:dimensions) { Dimensions[2, 10, 3] }
7
+
8
+ describe '#volume' do
9
+ it { expect(dimensions.volume).to eql(60) }
10
+ end
11
+
12
+ describe '#>=' do
13
+ context 'when compared with Dimensions that are all bigger' do
14
+ let(:other_dimensions) { Dimensions[1, 5, 2] }
15
+ it { expect(dimensions >= other_dimensions).to be(true) }
16
+ end
17
+
18
+ context 'when compared with Dimensions where some are bigger and some are equal' do
19
+ let(:other_dimensions) { Dimensions[2, 5, 3] }
20
+ it { expect(dimensions >= other_dimensions).to be(true) }
21
+ end
22
+
23
+ context 'when compared with Dimensions that are all equal' do
24
+ let(:other_dimensions) { Dimensions[2, 10, 3] }
25
+ it { expect(dimensions >= other_dimensions).to be(true) }
26
+ end
27
+
28
+ context 'when compared with Dimensions where some are bigger and some are smaller' do
29
+ let(:other_dimensions) { Dimensions[5, 5, 1] }
30
+ it { expect(dimensions >= other_dimensions).to be(false) }
31
+ end
32
+
33
+ context 'when compared with Dimensions where none are bigger' do
34
+ let(:other_dimensions) { Dimensions[5, 15, 11] }
35
+ it { expect(dimensions >= other_dimensions).to be(false) }
36
+ end
37
+ end
38
+
39
+ describe '#each_rotation' do
40
+ let(:rotations)do
41
+ [
42
+ Dimensions[2, 10, 3],
43
+ Dimensions[2, 3, 10],
44
+ Dimensions[10, 2, 3],
45
+ Dimensions[10, 3, 2],
46
+ Dimensions[3, 10, 2],
47
+ Dimensions[3, 2, 10]
48
+ ]
49
+ end
50
+
51
+ it { expect { |b| dimensions.each_rotation(&b) }.to yield_each_once(rotations) }
52
+ end
53
+ end
54
+ end
@@ -1,30 +1,27 @@
1
1
  module BoxPacker
2
- describe Item do
3
- subject(:item){ Item.new(dimensions) }
4
- let(:dimensions){ [12, 5, 7] }
2
+ describe Item do
3
+ subject(:item) { Item.new(dimensions) }
4
+ let(:dimensions) { [12, 5, 7] }
5
5
 
6
- describe '#fit_into' do
7
-
8
- context 'when box is larger than box' do
9
- let(:box) { Box.new(Dimensions[6, 15, 9]) }
10
- let(:rotated_dimensions) { Dimensions[5, 12, 7] }
11
-
12
- it 'fits and orientation is rotated to fit' do
13
- expect(item.fit_into?(box)).to be(true)
14
- expect(item.dimensions).to eql(rotated_dimensions)
15
- end
16
- end
6
+ describe '#fit_into' do
7
+ context 'when box is larger than box' do
8
+ let(:box) { Box.new(Dimensions[6, 15, 9]) }
9
+ let(:rotated_dimensions) { Dimensions[5, 12, 7] }
17
10
 
18
- context 'when other box has a smaller side than box' do
19
- let(:box) { Box.new(Dimensions[11, 6, 7]) }
20
-
21
- it 'does not fit and orientation is unchanged' do
22
- expect(item.fit_into?(box)).to be(false)
23
- expect(item.dimensions).to eql(Dimensions[*dimensions])
24
- end
25
- end
11
+ it 'fits and orientation is rotated to fit' do
12
+ expect(item.fit_into?(box)).to be(true)
13
+ expect(item.dimensions).to eql(rotated_dimensions)
14
+ end
15
+ end
26
16
 
27
- end
28
-
29
- end
30
- end
17
+ context 'when other box has a smaller side than box' do
18
+ let(:box) { Box.new(Dimensions[11, 6, 7]) }
19
+
20
+ it 'does not fit and orientation is unchanged' do
21
+ expect(item.fit_into?(box)).to be(false)
22
+ expect(item.dimensions).to eql(Dimensions[*dimensions])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,81 +1,80 @@
1
1
  module BoxPacker
2
- describe Packer do
3
- subject(:container) { Container.new(dimensions) }
4
- let(:dimensions) { [10, 15, 5] }
5
- let(:opts) { nil }
6
- let(:items){[
7
- Item.new([1,1,1], weight: 1),
8
- Item.new([3,1,1], weight: 6),
9
- Item.new([5,5,1], weight: 15),
10
- Item.new([5,5,5], weight: 20)
11
- ]}
2
+ describe Packer do
3
+ subject(:container) { Container.new(dimensions) }
4
+ let(:dimensions) { [10, 15, 5] }
5
+ let(:opts) { nil }
6
+ let(:items)do
7
+ [
8
+ Item.new([1, 1, 1], weight: 1),
9
+ Item.new([3, 1, 1], weight: 6),
10
+ Item.new([5, 5, 1], weight: 15),
11
+ Item.new([5, 5, 5], weight: 20)
12
+ ]
13
+ end
12
14
 
13
- describe '#pack' do
15
+ describe '#pack' do
16
+ context 'with items that fit exactly in one packing' do
17
+ before do
18
+ 20.times { container.items << items[0].dup }
19
+ 10.times { container.items << items[1].dup }
20
+ 8.times { container.items << items[2].dup }
21
+ 4.times { container.items << items[3].dup }
22
+ end
14
23
 
15
- context 'with items that fit exactly in one packing' do
16
- before do
17
- 20.times { container.items << items[0].dup }
18
- 10.times { container.items << items[1].dup }
19
- 8.times { container.items << items[2].dup }
20
- 4.times { container.items << items[3].dup }
21
- end
22
-
23
- it do
24
- expect(container.pack!).to eql(1)
25
- expect(container.packed_successfully).to be(true)
26
- end
27
- end
24
+ it do
25
+ expect(container.pack!).to eql(1)
26
+ expect(container.packed_successfully).to be(true)
27
+ end
28
+ end
28
29
 
29
- context 'with items that fit exactly in three packings' do
30
- before do
31
- 35.times { container.items << items[0].dup }
32
- 30.times { container.items << items[1].dup }
33
- 10.times { container.items << items[2].dup }
34
- 15.times { container.items << items[3].dup }
35
- end
30
+ context 'with items that fit exactly in three packings' do
31
+ before do
32
+ 35.times { container.items << items[0].dup }
33
+ 30.times { container.items << items[1].dup }
34
+ 10.times { container.items << items[2].dup }
35
+ 15.times { container.items << items[3].dup }
36
+ end
36
37
 
37
- it do
38
- expect(container.pack!).to eql(3)
39
- expect(container.packed_successfully).to be(true)
40
- end
41
- end
38
+ it do
39
+ expect(container.pack!).to eql(3)
40
+ expect(container.packed_successfully).to be(true)
41
+ end
42
+ end
42
43
 
43
- context 'with a packing limit of one and too many items' do
44
- before do
45
- container.packings_limit = 1
46
- 35.times { container.items << items[0].dup }
47
- 30.times { container.items << items[1].dup }
48
- 10.times { container.items << items[2].dup }
49
- 15.times { container.items << items[3].dup }
50
- end
44
+ context 'with a packing limit of one and too many items' do
45
+ before do
46
+ container.packings_limit = 1
47
+ 35.times { container.items << items[0].dup }
48
+ 30.times { container.items << items[1].dup }
49
+ 10.times { container.items << items[2].dup }
50
+ 15.times { container.items << items[3].dup }
51
+ end
51
52
 
52
- it do
53
- expect(container.pack!).to be(false)
54
- expect(container.packed_successfully).to be(false)
55
- end
56
- end
53
+ it do
54
+ expect(container.pack!).to be(false)
55
+ expect(container.packed_successfully).to be(false)
56
+ end
57
+ end
57
58
 
58
- context 'with random container and random items' do
59
- let(:dimensions) { [x, y, z] }
60
- let(:x) { rand(1..75) }
61
- let(:y) { rand(1..75) }
62
- let(:z) { rand(1..75) }
59
+ context 'with random container and random items' do
60
+ let(:dimensions) { [x, y, z] }
61
+ let(:x) { rand(1..75) }
62
+ let(:y) { rand(1..75) }
63
+ let(:z) { rand(1..75) }
63
64
 
64
- let(:items) do
65
- (1..rand(1..100)).map do
66
- Item.new([x / rand(1..5), y / rand(1..5), z / rand(1..5)])
67
- end
68
- end
65
+ let(:items) do
66
+ (1..rand(1..100)).map do
67
+ Item.new([x / rand(1..5), y / rand(1..5), z / rand(1..5)])
68
+ end
69
+ end
69
70
 
70
- before do
71
- container.items = items
72
- container.pack!
73
- end
71
+ before do
72
+ container.items = items
73
+ container.pack!
74
+ end
74
75
 
75
- it { expect(container.packed_successfully).to be(true) }
76
- end
77
-
78
- end
79
-
80
- end
81
- end
76
+ it { expect(container.packed_successfully).to be(true) }
77
+ end
78
+ end
79
+ end
80
+ end