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.
- checksums.yaml +4 -4
- data/.gitignore +14 -1
- data/.rubocop.yml +4 -0
- data/README.md +57 -58
- data/Rakefile +1 -1
- data/box_packer.gemspec +9 -12
- data/lib/box_packer.rb +13 -3
- data/lib/box_packer/box.rb +29 -39
- data/lib/box_packer/builder.rb +14 -21
- data/lib/box_packer/container.rb +94 -107
- data/lib/box_packer/dimensions.rb +40 -42
- data/lib/box_packer/item.rb +27 -31
- data/lib/box_packer/packer.rb +52 -57
- data/lib/box_packer/packing.rb +30 -31
- data/lib/box_packer/position.rb +6 -8
- data/lib/box_packer/svg_exporter.rb +115 -119
- data/lib/box_packer/version.rb +1 -1
- data/spec/lib/box_spec.rb +51 -52
- data/spec/lib/container_spec.rb +88 -87
- data/spec/lib/dimensions_spec.rb +53 -51
- data/spec/lib/item_spec.rb +23 -26
- data/spec/lib/packer_spec.rb +69 -70
- data/spec/lib/packing_spec.rb +63 -60
- data/spec/spec_helper.rb +1 -14
- data/spec/support/matchers/yield_each_once.rb +38 -0
- metadata +27 -53
- data/spec/support/matchers/box_packer.rb +0 -40
data/spec/lib/packing_spec.rb
CHANGED
@@ -1,73 +1,76 @@
|
|
1
1
|
module BoxPacker
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
2
|
+
describe Packing do
|
3
|
+
subject(:packing) { Packing.new(total_volume, total_weight) }
|
4
|
+
let(:total_volume) { 200 }
|
5
|
+
let(:total_weight) { 50 }
|
6
|
+
let(:items) do
|
7
|
+
[
|
8
|
+
Item.new([2, 4, 1], weight: 5),
|
9
|
+
Item.new([5, 2, 7], weight: 6),
|
10
|
+
Item.new([8, 4, 2], weight: 3)
|
11
|
+
]
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
it 'defaults to empty' do
|
15
|
+
expect(packing).to eql([])
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
describe '#<<' do
|
19
|
+
before { items.each { |i| packing << i } }
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
context 'with items that do not have weight' do
|
23
|
-
let(:items) {[
|
24
|
-
Item.new([2, 4, 1]),
|
25
|
-
Item.new([5, 2, 7]),
|
26
|
-
Item.new([8, 4, 2])
|
27
|
-
]}
|
21
|
+
it { expect(packing.remaining_volume).to eql(58) }
|
22
|
+
it { expect(packing.remaining_weight).to eql(36) }
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
24
|
+
context 'with items that do not have weight' do
|
25
|
+
let(:items) do
|
26
|
+
[
|
27
|
+
Item.new([2, 4, 1]),
|
28
|
+
Item.new([5, 2, 7]),
|
29
|
+
Item.new([8, 4, 2])
|
30
|
+
]
|
31
|
+
end
|
37
32
|
|
38
|
-
|
39
|
-
|
33
|
+
it { expect(packing.remaining_weight).to be(50) }
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
context 'with total_weight nil' do
|
37
|
+
let(:total_weight) { nil }
|
38
|
+
it { expect(packing.remaining_weight).to be(nil) }
|
39
|
+
end
|
40
|
+
end
|
45
41
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
42
|
+
describe '#fit?' do
|
43
|
+
before { items.each { |i| packing << i } }
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
45
|
+
context 'with item that fits' do
|
46
|
+
let(:item) { Item.new([1, 5, 5], weight: 5) }
|
47
|
+
it { expect(packing.fit?(item)).to be(true) }
|
48
|
+
end
|
54
49
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
50
|
+
context 'with item thats already packed' do
|
51
|
+
it { expect(packing.fit?(items[0])).to be(false) }
|
52
|
+
end
|
59
53
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
54
|
+
context 'with item thats too large' do
|
55
|
+
let(:item) { Item.new([3, 5, 5], weight: 25) }
|
56
|
+
it { expect(packing.fit?(item)).to be(false) }
|
57
|
+
end
|
65
58
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
59
|
+
context 'with item thats too heavy' do
|
60
|
+
let(:item) { Item.new([1, 5, 5], weight: 45) }
|
61
|
+
it { expect(packing.fit?(item)).to be(false) }
|
62
|
+
end
|
71
63
|
|
72
|
-
|
73
|
-
|
64
|
+
context 'with total_weight nil and item that fits' do
|
65
|
+
let(:total_weight) { nil }
|
66
|
+
let(:item) { Item.new([1, 5, 5], weight: 5) }
|
67
|
+
it { expect(packing.fit?(item)).to be(true) }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with item that has no weight but fits' do
|
71
|
+
let(:item) { Item.new([1, 5, 5]) }
|
72
|
+
it { expect(packing.fit?(item)).to be(true) }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,14 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
config.expect_with :rspec do |expectations|
|
4
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
5
|
-
end
|
6
|
-
|
7
|
-
config.mock_with :rspec do |mocks|
|
8
|
-
mocks.verify_partial_doubles = true
|
9
|
-
end
|
10
|
-
|
11
|
-
require_relative '../lib/box_packer'
|
12
|
-
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
13
|
-
config.include BoxPacker::Matchers
|
14
|
-
end
|
1
|
+
require 'box_packer'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rspec/matchers/built_in/yield'
|
2
|
+
|
3
|
+
module BoxPacker
|
4
|
+
module Matchers
|
5
|
+
class YieldEachOnce
|
6
|
+
attr_init :expected
|
7
|
+
|
8
|
+
def matches?(block)
|
9
|
+
@probe = RSpec::Matchers::BuiltIn::YieldProbe.probe(block)
|
10
|
+
@actual = @probe.successive_yield_args
|
11
|
+
|
12
|
+
@actual.each do |value|
|
13
|
+
unless expected.delete(value)
|
14
|
+
@failure_value = value
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def supports_block_expectations?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def description
|
26
|
+
'be in expected array'
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message
|
30
|
+
"value #{@failure_value.to_a} was not in expected array"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def yield_each_once(expected)
|
35
|
+
YieldEachOnce.new(expected)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,94 +1,67 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: box_packer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max White
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ~>
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.3'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ~>
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.3'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
13
|
- !ruby/object:Gem::Dependency
|
42
14
|
name: rspec
|
43
15
|
requirement: !ruby/object:Gem::Requirement
|
44
16
|
requirements:
|
45
|
-
- -
|
17
|
+
- - "~>"
|
46
18
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
19
|
+
version: '3.1'
|
48
20
|
type: :development
|
49
21
|
prerelease: false
|
50
22
|
version_requirements: !ruby/object:Gem::Requirement
|
51
23
|
requirements:
|
52
|
-
- -
|
24
|
+
- - "~>"
|
53
25
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
26
|
+
version: '3.1'
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
28
|
+
name: attire
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
58
30
|
requirements:
|
59
|
-
- - ~>
|
31
|
+
- - "~>"
|
60
32
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
33
|
+
version: '0'
|
62
34
|
type: :runtime
|
63
35
|
prerelease: false
|
64
36
|
version_requirements: !ruby/object:Gem::Requirement
|
65
37
|
requirements:
|
66
|
-
- - ~>
|
38
|
+
- - "~>"
|
67
39
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
40
|
+
version: '0'
|
69
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: rasem
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|
72
44
|
requirements:
|
73
|
-
- - ~>
|
45
|
+
- - "~>"
|
74
46
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.6
|
47
|
+
version: '0.6'
|
76
48
|
type: :runtime
|
77
49
|
prerelease: false
|
78
50
|
version_requirements: !ruby/object:Gem::Requirement
|
79
51
|
requirements:
|
80
|
-
- - ~>
|
52
|
+
- - "~>"
|
81
53
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.6
|
83
|
-
description:
|
54
|
+
version: '0.6'
|
55
|
+
description:
|
84
56
|
email:
|
85
57
|
- mushishi78@gmail.com
|
86
58
|
executables: []
|
87
59
|
extensions: []
|
88
60
|
extra_rdoc_files: []
|
89
61
|
files:
|
90
|
-
- .gitignore
|
91
|
-
- .rspec
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
92
65
|
- Gemfile
|
93
66
|
- LICENSE.txt
|
94
67
|
- README.md
|
@@ -113,8 +86,8 @@ files:
|
|
113
86
|
- spec/lib/packer_spec.rb
|
114
87
|
- spec/lib/packing_spec.rb
|
115
88
|
- spec/spec_helper.rb
|
116
|
-
- spec/support/matchers/
|
117
|
-
homepage:
|
89
|
+
- spec/support/matchers/yield_each_once.rb
|
90
|
+
homepage: https://github.com/mushishi78/box_packer
|
118
91
|
licenses:
|
119
92
|
- MIT
|
120
93
|
metadata: {}
|
@@ -124,20 +97,21 @@ require_paths:
|
|
124
97
|
- lib
|
125
98
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
99
|
requirements:
|
127
|
-
- -
|
100
|
+
- - ">="
|
128
101
|
- !ruby/object:Gem::Version
|
129
102
|
version: '0'
|
130
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
104
|
requirements:
|
132
|
-
- -
|
105
|
+
- - ">="
|
133
106
|
- !ruby/object:Gem::Version
|
134
107
|
version: '0'
|
135
108
|
requirements: []
|
136
109
|
rubyforge_project:
|
137
|
-
rubygems_version: 2.
|
110
|
+
rubygems_version: 2.2.2
|
138
111
|
signing_key:
|
139
112
|
specification_version: 4
|
140
|
-
summary:
|
113
|
+
summary: Heuristic first-fit 3D bin-packing algorithmwith optional weight and bin
|
114
|
+
limits.
|
141
115
|
test_files:
|
142
116
|
- spec/lib/box_spec.rb
|
143
117
|
- spec/lib/container_spec.rb
|
@@ -146,4 +120,4 @@ test_files:
|
|
146
120
|
- spec/lib/packer_spec.rb
|
147
121
|
- spec/lib/packing_spec.rb
|
148
122
|
- spec/spec_helper.rb
|
149
|
-
- spec/support/matchers/
|
123
|
+
- spec/support/matchers/yield_each_once.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'attr_extras'
|
2
|
-
require 'rspec/matchers/built_in/yield'
|
3
|
-
|
4
|
-
module BoxPacker
|
5
|
-
module Matchers
|
6
|
-
class YieldEachOnce
|
7
|
-
pattr_initialize :expected
|
8
|
-
|
9
|
-
def matches?(block)
|
10
|
-
@probe = RSpec::Matchers::BuiltIn::YieldProbe.probe(block)
|
11
|
-
@actual = @probe.successive_yield_args
|
12
|
-
|
13
|
-
@actual.each do |value|
|
14
|
-
unless expected.delete(value)
|
15
|
-
@failure_value = value
|
16
|
-
return false
|
17
|
-
end
|
18
|
-
end
|
19
|
-
true
|
20
|
-
end
|
21
|
-
|
22
|
-
def supports_block_expectations?
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
def description
|
27
|
-
'be in expected array'
|
28
|
-
end
|
29
|
-
|
30
|
-
def failure_message
|
31
|
-
"value #{@failure_value.to_a} was not in expected array"
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
def yield_each_once(expected)
|
37
|
-
YieldEachOnce.new(expected)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|