box_packer 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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