image_optim 0.13.3 → 0.14.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 +8 -8
- data/.rubocop.yml +56 -0
- data/.travis.yml +3 -1
- data/README.markdown +23 -10
- data/bin/image_optim +25 -15
- data/image_optim.gemspec +5 -2
- data/lib/image_optim.rb +47 -37
- data/lib/image_optim/bin_resolver.rb +17 -12
- data/lib/image_optim/bin_resolver/comparable_condition.rb +23 -7
- data/lib/image_optim/bin_resolver/simple_version.rb +2 -0
- data/lib/image_optim/config.rb +21 -13
- data/lib/image_optim/handler.rb +18 -12
- data/lib/image_optim/hash_helpers.rb +23 -13
- data/lib/image_optim/image_meta.rb +1 -0
- data/lib/image_optim/image_path.rb +14 -13
- data/lib/image_optim/option_definition.rb +11 -9
- data/lib/image_optim/option_helpers.rb +1 -2
- data/lib/image_optim/railtie.rb +18 -15
- data/lib/image_optim/runner.rb +67 -61
- data/lib/image_optim/space.rb +29 -0
- data/lib/image_optim/true_false_nil.rb +9 -1
- data/lib/image_optim/worker.rb +40 -16
- data/lib/image_optim/worker/advpng.rb +8 -1
- data/lib/image_optim/worker/gifsicle.rb +13 -1
- data/lib/image_optim/worker/jhead.rb +5 -0
- data/lib/image_optim/worker/jpegoptim.rb +17 -4
- data/lib/image_optim/worker/jpegtran.rb +9 -1
- data/lib/image_optim/worker/optipng.rb +13 -2
- data/lib/image_optim/worker/pngcrush.rb +14 -5
- data/lib/image_optim/worker/pngout.rb +10 -2
- data/lib/image_optim/worker/svgo.rb +1 -0
- data/script/update_worker_options_in_readme +42 -27
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +13 -13
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +4 -4
- data/spec/image_optim/bin_resolver_spec.rb +65 -37
- data/spec/image_optim/config_spec.rb +121 -110
- data/spec/image_optim/handler_spec.rb +29 -18
- data/spec/image_optim/hash_helpers_spec.rb +29 -27
- data/spec/image_optim/image_path_spec.rb +17 -17
- data/spec/image_optim/space_spec.rb +24 -0
- data/spec/image_optim/worker_spec.rb +18 -0
- data/spec/image_optim_spec.rb +134 -74
- metadata +27 -7
- data/script/update_instructions_in_readme +0 -44
@@ -1,47 +1,58 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
2
2
|
require 'rspec'
|
3
3
|
require 'image_optim/handler'
|
4
4
|
|
5
5
|
describe ImageOptim::Handler do
|
6
|
-
it
|
6
|
+
it 'should use original as source for first conversion '\
|
7
|
+
'and two temp files for further conversions' do
|
7
8
|
original = double(:original)
|
8
|
-
original.
|
9
|
+
allow(original).to receive(:temp_path) do
|
10
|
+
fail 'temp_path called unexpectedly'
|
11
|
+
end
|
9
12
|
|
10
13
|
handler = ImageOptim::Handler.new(original)
|
14
|
+
temp_a = double(:temp_a)
|
15
|
+
temp_b = double(:temp_b)
|
16
|
+
expect(original).to receive(:temp_path).once.and_return(temp_a)
|
17
|
+
expect(original).to receive(:temp_path).once.and_return(temp_b)
|
11
18
|
|
12
|
-
|
19
|
+
# first unsuccessful run
|
13
20
|
handler.process do |src, dst|
|
14
|
-
[src, dst].
|
21
|
+
expect([src, dst]).to eq([original, temp_a]); false
|
15
22
|
end
|
16
|
-
handler.result.
|
23
|
+
expect(handler.result).to be_nil
|
17
24
|
|
25
|
+
# first successful run
|
18
26
|
handler.process do |src, dst|
|
19
|
-
[src, dst].
|
27
|
+
expect([src, dst]).to eq([original, temp_a]); true
|
20
28
|
end
|
21
|
-
handler.result.
|
29
|
+
expect(handler.result).to eq(temp_a)
|
22
30
|
|
23
|
-
|
31
|
+
# second unsuccessful run
|
24
32
|
handler.process do |src, dst|
|
25
|
-
[src, dst].
|
33
|
+
expect([src, dst]).to eq([temp_a, temp_b]); false
|
26
34
|
end
|
27
|
-
handler.result.
|
35
|
+
expect(handler.result).to eq(temp_a)
|
28
36
|
|
37
|
+
# second successful run
|
29
38
|
handler.process do |src, dst|
|
30
|
-
[src, dst].
|
39
|
+
expect([src, dst]).to eq([temp_a, temp_b]); true
|
31
40
|
end
|
32
|
-
handler.result.
|
41
|
+
expect(handler.result).to eq(temp_b)
|
33
42
|
|
43
|
+
# third successful run
|
34
44
|
handler.process do |src, dst|
|
35
|
-
[src, dst].
|
45
|
+
expect([src, dst]).to eq([temp_b, temp_a]); true
|
36
46
|
end
|
37
|
-
handler.result.
|
47
|
+
expect(handler.result).to eq(temp_a)
|
38
48
|
|
49
|
+
# forth successful run
|
39
50
|
handler.process do |src, dst|
|
40
|
-
[src, dst].
|
51
|
+
expect([src, dst]).to eq([temp_a, temp_b]); true
|
41
52
|
end
|
42
|
-
handler.result.
|
53
|
+
expect(handler.result).to eq(temp_b)
|
43
54
|
|
44
|
-
temp_a.
|
55
|
+
expect(temp_a).to receive(:unlink).once
|
45
56
|
handler.cleanup
|
46
57
|
handler.cleanup
|
47
58
|
end
|
@@ -1,55 +1,53 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
2
2
|
require 'rspec'
|
3
3
|
require 'image_optim/hash_helpers'
|
4
4
|
|
5
5
|
describe ImageOptim::HashHelpers do
|
6
6
|
HH = ImageOptim::HashHelpers
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
context 'stringify/simbolyze' do
|
9
|
+
WITH_SYMBOL_KEYS = {
|
10
10
|
:a => 1,
|
11
11
|
:b => {
|
12
|
-
:c => :a,
|
12
|
+
:c => [:a, 'a'],
|
13
13
|
:d => {},
|
14
14
|
},
|
15
|
-
}).should == {
|
16
|
-
'a' => 1,
|
17
|
-
'b' => {
|
18
|
-
'c' => :a,
|
19
|
-
'd' => {},
|
20
|
-
},
|
21
15
|
}
|
22
|
-
end
|
23
16
|
|
24
|
-
|
25
|
-
HH.deep_symbolise_keys({
|
17
|
+
WITH_STRING_KEYS = {
|
26
18
|
'a' => 1,
|
27
19
|
'b' => {
|
28
|
-
'c' => 'a',
|
20
|
+
'c' => [:a, 'a'],
|
29
21
|
'd' => {},
|
30
22
|
},
|
31
|
-
}).should == {
|
32
|
-
:a => 1,
|
33
|
-
:b => {
|
34
|
-
:c => 'a',
|
35
|
-
:d => {},
|
36
|
-
},
|
37
23
|
}
|
24
|
+
|
25
|
+
it 'should deep stringify hash keys' do
|
26
|
+
expect(HH.deep_stringify_keys(WITH_SYMBOL_KEYS)).to eq(WITH_STRING_KEYS)
|
27
|
+
expect(HH.deep_stringify_keys(WITH_STRING_KEYS)).to eq(WITH_STRING_KEYS)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should deep symbolise hash keys' do
|
31
|
+
expect(HH.deep_symbolise_keys(WITH_STRING_KEYS)).to eq(WITH_SYMBOL_KEYS)
|
32
|
+
expect(HH.deep_symbolise_keys(WITH_SYMBOL_KEYS)).to eq(WITH_SYMBOL_KEYS)
|
33
|
+
end
|
38
34
|
end
|
39
35
|
|
40
|
-
it
|
41
|
-
|
36
|
+
it 'should deep merge hashes' do
|
37
|
+
merge_a = {
|
42
38
|
:a => {
|
43
39
|
:b => 1,
|
44
40
|
:c => {
|
45
41
|
:d => 2,
|
46
42
|
:e => {
|
47
|
-
:f => true
|
43
|
+
:f => true,
|
48
44
|
},
|
49
45
|
},
|
50
46
|
},
|
51
47
|
:y => 10,
|
52
|
-
}
|
48
|
+
}
|
49
|
+
|
50
|
+
merge_b = {
|
53
51
|
:a => {
|
54
52
|
:b => 2,
|
55
53
|
:c => {
|
@@ -57,8 +55,10 @@ describe ImageOptim::HashHelpers do
|
|
57
55
|
:e => false,
|
58
56
|
},
|
59
57
|
},
|
60
|
-
|
61
|
-
}
|
58
|
+
'z' => 20,
|
59
|
+
}
|
60
|
+
|
61
|
+
merge_result = {
|
62
62
|
:a => {
|
63
63
|
:b => 2,
|
64
64
|
:c => {
|
@@ -67,8 +67,10 @@ describe ImageOptim::HashHelpers do
|
|
67
67
|
},
|
68
68
|
},
|
69
69
|
:y => 10,
|
70
|
-
|
70
|
+
'z' => 20,
|
71
71
|
}
|
72
|
+
|
73
|
+
expect(HH.deep_merge(merge_a, merge_b)).to eq(merge_result)
|
72
74
|
end
|
73
75
|
|
74
76
|
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
2
2
|
require 'rspec'
|
3
3
|
require 'image_optim/image_path'
|
4
4
|
|
5
5
|
describe ImageOptim::ImagePath do
|
6
6
|
ImagePath = ImageOptim::ImagePath
|
7
7
|
|
8
|
-
describe
|
9
|
-
it
|
8
|
+
describe 'convert' do
|
9
|
+
it 'should return ImagePath for string' do
|
10
10
|
path = 'a'
|
11
11
|
|
12
|
-
ImagePath.convert(path).
|
13
|
-
ImagePath.convert(path).
|
12
|
+
expect(ImagePath.convert(path)).to be_a(ImageOptim::ImagePath)
|
13
|
+
expect(ImagePath.convert(path)).to eq(ImageOptim::ImagePath.new(path))
|
14
14
|
|
15
|
-
ImagePath.convert(path).
|
16
|
-
ImagePath.convert(path).
|
15
|
+
expect(ImagePath.convert(path)).not_to eq(path)
|
16
|
+
expect(ImagePath.convert(path)).not_to be(path)
|
17
17
|
end
|
18
18
|
|
19
|
-
it
|
19
|
+
it 'should return ImagePath for Pathname' do
|
20
20
|
pathname = Pathname.new('a')
|
21
21
|
|
22
|
-
ImagePath.convert(pathname).
|
23
|
-
ImagePath.convert(pathname).
|
22
|
+
expect(ImagePath.convert(pathname)).to be_a(ImageOptim::ImagePath)
|
23
|
+
expect(ImagePath.convert(pathname)).to eq(ImageOptim::ImagePath.new(pathname))
|
24
24
|
|
25
|
-
ImagePath.convert(pathname).
|
26
|
-
ImagePath.convert(pathname).
|
25
|
+
expect(ImagePath.convert(pathname)).to eq(pathname)
|
26
|
+
expect(ImagePath.convert(pathname)).not_to be(pathname)
|
27
27
|
end
|
28
28
|
|
29
|
-
it
|
29
|
+
it 'should return same instance for ImagePath' do
|
30
30
|
image_path = ImageOptim::ImagePath.new('a')
|
31
31
|
|
32
|
-
ImagePath.convert(image_path).
|
33
|
-
ImagePath.convert(image_path).
|
32
|
+
expect(ImagePath.convert(image_path)).to be_a(ImageOptim::ImagePath)
|
33
|
+
expect(ImagePath.convert(image_path)).to eq(ImageOptim::ImagePath.new(image_path))
|
34
34
|
|
35
|
-
ImagePath.convert(image_path).
|
36
|
-
ImagePath.convert(image_path).
|
35
|
+
expect(ImagePath.convert(image_path)).to eq(image_path)
|
36
|
+
expect(ImagePath.convert(image_path)).to be(image_path)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
2
|
+
require 'rspec'
|
3
|
+
require 'image_optim/space'
|
4
|
+
|
5
|
+
describe ImageOptim::Space do
|
6
|
+
Space = ImageOptim::Space
|
7
|
+
|
8
|
+
{
|
9
|
+
0 => ' ',
|
10
|
+
1 => ' 1B',
|
11
|
+
10 => ' 10B',
|
12
|
+
100 => ' 100B',
|
13
|
+
1_000 => ' 1000B',
|
14
|
+
10_000 => ' 9.8K',
|
15
|
+
100_000 => ' 97.7K',
|
16
|
+
1_000_000 => '976.6K',
|
17
|
+
10_000_000 => ' 9.5M',
|
18
|
+
100_000_000 => ' 95.4M',
|
19
|
+
}.each do |size, space|
|
20
|
+
it "should convert #{size} to #{space}" do
|
21
|
+
expect(Space.space(size)).to eq(space)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
|
2
|
+
require 'rspec'
|
3
|
+
require 'image_optim/worker'
|
4
|
+
|
5
|
+
describe ImageOptim::Worker do
|
6
|
+
Worker = ImageOptim::Worker
|
7
|
+
|
8
|
+
describe 'optimize' do
|
9
|
+
it 'should raise NotImplementedError unless overriden' do
|
10
|
+
class Abc < ImageOptim::Worker; end
|
11
|
+
|
12
|
+
expect do
|
13
|
+
Abc.new({}).optimize(double, double)
|
14
|
+
end.to raise_error NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/spec/image_optim_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
2
|
require 'rspec'
|
3
3
|
require 'image_optim'
|
4
4
|
require 'tempfile'
|
@@ -41,23 +41,61 @@ end
|
|
41
41
|
|
42
42
|
describe ImageOptim do
|
43
43
|
before do
|
44
|
-
ImageOptim::Config.
|
44
|
+
allow(ImageOptim::Config).to receive(:global).and_return({})
|
45
|
+
allow(ImageOptim::Config).to receive(:local).and_return({})
|
45
46
|
end
|
46
47
|
|
47
|
-
describe
|
48
|
-
|
49
|
-
|
48
|
+
describe 'workers' do
|
49
|
+
it 'should be ordered by run_order' do
|
50
|
+
original_klasses = ImageOptim::Worker.klasses
|
51
|
+
formats = original_klasses.map do |klass|
|
52
|
+
klass.new({}).image_formats
|
53
|
+
end.flatten.uniq
|
54
|
+
|
55
|
+
[
|
56
|
+
original_klasses,
|
57
|
+
original_klasses.reverse,
|
58
|
+
original_klasses.shuffle,
|
59
|
+
].each do |klasses|
|
60
|
+
expect(ImageOptim::Worker).to receive(:klasses).and_return(klasses)
|
61
|
+
|
62
|
+
image_optim = ImageOptim.new
|
63
|
+
|
64
|
+
formats.each do |format|
|
65
|
+
path = ImagePath.new("test.#{format}")
|
66
|
+
expect(path).to receive(:format).and_return(format)
|
67
|
+
|
68
|
+
workers = image_optim.workers_for_image(path)
|
69
|
+
expect(workers).to eq(workers.sort)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'worker' do
|
76
|
+
base_options = Hash[ImageOptim::Worker.klasses.map do |klass|
|
77
|
+
[klass.bin_sym, false]
|
78
|
+
end]
|
79
|
+
|
80
|
+
real_workers = ImageOptim::Worker.klasses.reject do |klass|
|
81
|
+
klass.new({}).image_formats.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
real_workers.each do |worker_klass|
|
50
85
|
describe worker_klass.bin_sym do
|
51
|
-
it
|
52
|
-
|
53
|
-
|
86
|
+
it 'should optimize at least one test image' do
|
87
|
+
options = base_options.merge(worker_klass.bin_sym => true)
|
88
|
+
image_optim = ImageOptim.new(options)
|
89
|
+
expect(TEST_IMAGES.any? do |original|
|
90
|
+
image_optim.optimize_image(original.temp_copy)
|
91
|
+
end).to be true
|
54
92
|
end
|
55
93
|
end
|
56
94
|
end
|
57
95
|
end
|
58
96
|
|
59
|
-
describe
|
60
|
-
describe
|
97
|
+
describe 'isolated' do
|
98
|
+
describe 'optimize' do
|
61
99
|
TEST_IMAGES.each do |original|
|
62
100
|
it "should optimize #{original}" do
|
63
101
|
copy = original.temp_copy
|
@@ -66,53 +104,55 @@ describe ImageOptim do
|
|
66
104
|
image_optim = ImageOptim.new
|
67
105
|
optimized_image = image_optim.optimize_image(copy)
|
68
106
|
expect(optimized_image).to be_a(ImageOptim::ImagePath::Optimized)
|
69
|
-
optimized_image.size.
|
70
|
-
optimized_image.read.
|
71
|
-
copy.read.
|
107
|
+
expect(optimized_image.size).to be_in_range(1...original.size)
|
108
|
+
expect(optimized_image.read).not_to eq(original.read)
|
109
|
+
expect(copy.read).to eq(original.read)
|
72
110
|
|
73
111
|
if image_optim.workers_for_image(original).length > 1
|
74
|
-
Tempfile.init_count.
|
112
|
+
expect(Tempfile.init_count).to be_in_range(1..2)
|
75
113
|
else
|
76
|
-
Tempfile.init_count.
|
114
|
+
expect(Tempfile.init_count).to eq(1)
|
77
115
|
end
|
78
116
|
end
|
79
117
|
end
|
80
118
|
end
|
81
119
|
|
82
|
-
describe
|
120
|
+
describe 'optimize in place' do
|
83
121
|
TEST_IMAGES.each do |original|
|
84
122
|
it "should optimize #{original}" do
|
85
123
|
copy = original.temp_copy
|
86
124
|
|
87
125
|
Tempfile.reset_init_count
|
88
126
|
image_optim = ImageOptim.new
|
89
|
-
image_optim.optimize_image!(copy).
|
90
|
-
copy.size.
|
91
|
-
copy.read.
|
127
|
+
expect(image_optim.optimize_image!(copy)).to be_truthy
|
128
|
+
expect(copy.size).to be_in_range(1...original.size)
|
129
|
+
expect(copy.read).not_to eq(original.read)
|
92
130
|
|
93
131
|
if image_optim.workers_for_image(original).length > 1
|
94
|
-
Tempfile.init_count.
|
132
|
+
expect(Tempfile.init_count).to be_in_range(2..3)
|
95
133
|
else
|
96
|
-
Tempfile.init_count.
|
134
|
+
expect(Tempfile.init_count).to eq(2)
|
97
135
|
end
|
98
136
|
end
|
99
137
|
end
|
100
138
|
end
|
101
139
|
|
102
|
-
describe
|
140
|
+
describe 'optimize image data' do
|
103
141
|
TEST_IMAGES.each do |original|
|
104
142
|
it "should optimize #{original}" do
|
105
143
|
image_optim = ImageOptim.new
|
106
144
|
optimized_data = image_optim.optimize_image_data(original.read)
|
107
|
-
optimized_data.
|
108
|
-
|
145
|
+
expect(optimized_data).not_to be_nil
|
146
|
+
|
147
|
+
expected_path = image_optim.optimize_image(original.temp_copy)
|
148
|
+
expect(optimized_data).to eq(expected_path.open('rb', &:read))
|
109
149
|
|
110
|
-
image_optim.optimize_image_data(optimized_data).
|
150
|
+
expect(image_optim.optimize_image_data(optimized_data)).to be_nil
|
111
151
|
end
|
112
152
|
end
|
113
153
|
end
|
114
154
|
|
115
|
-
describe
|
155
|
+
describe 'stop optimizing' do
|
116
156
|
TEST_IMAGES.each do |original|
|
117
157
|
it "should stop optimizing #{original}" do
|
118
158
|
copy = original.temp_copy
|
@@ -122,62 +162,65 @@ describe ImageOptim do
|
|
122
162
|
tries += 1
|
123
163
|
break unless ImageOptim.optimize_image!(copy)
|
124
164
|
end
|
125
|
-
tries.
|
165
|
+
expect(tries).to be_in_range(2...3)
|
126
166
|
end
|
127
167
|
end
|
128
168
|
end
|
129
169
|
end
|
130
170
|
|
131
|
-
describe
|
132
|
-
it
|
171
|
+
describe 'bunch' do
|
172
|
+
it 'should optimize' do
|
133
173
|
copies = TEST_IMAGES.map(&:temp_copy)
|
134
174
|
optimized_images = ImageOptim.optimize_images(copies)
|
135
|
-
TEST_IMAGES.zip(copies, optimized_images)
|
175
|
+
zipped = TEST_IMAGES.zip(copies, optimized_images)
|
176
|
+
zipped.each do |original, copy, optimized_image|
|
136
177
|
expect(optimized_image).to be_a(ImageOptim::ImagePath::Optimized)
|
137
|
-
optimized_image.size.
|
138
|
-
optimized_image.read.
|
139
|
-
copy.read.
|
178
|
+
expect(optimized_image.size).to be_in_range(1...original.size)
|
179
|
+
expect(optimized_image.read).not_to eq(original.read)
|
180
|
+
expect(copy.read).to eq(original.read)
|
140
181
|
end
|
141
182
|
end
|
142
183
|
|
143
|
-
it
|
184
|
+
it 'should optimize in place' do
|
144
185
|
copies = TEST_IMAGES.map(&:temp_copy)
|
145
186
|
ImageOptim.optimize_images!(copies)
|
146
187
|
TEST_IMAGES.zip(copies).each do |original, copy|
|
147
|
-
copy.size.
|
148
|
-
copy.read.
|
188
|
+
expect(copy.size).to be_in_range(1...original.size)
|
189
|
+
expect(copy.read).not_to eq(original.read)
|
149
190
|
end
|
150
191
|
end
|
151
192
|
|
152
|
-
it
|
153
|
-
|
154
|
-
TEST_IMAGES.zip(
|
155
|
-
|
156
|
-
|
193
|
+
it 'should optimize datas' do
|
194
|
+
optimized_datas = ImageOptim.optimize_images_data(TEST_IMAGES.map(&:read))
|
195
|
+
TEST_IMAGES.zip(optimized_datas).each do |original, optimized_data|
|
196
|
+
expect(optimized_data).not_to be_nil
|
197
|
+
|
198
|
+
expected_path = ImageOptim.optimize_image(original.temp_copy)
|
199
|
+
expect(optimized_data).to eq(expected_path.open('rb', &:read))
|
157
200
|
end
|
158
201
|
end
|
159
202
|
end
|
160
203
|
|
161
|
-
describe
|
204
|
+
describe 'unsupported' do
|
162
205
|
let(:original){ ImageOptim::ImagePath.new(__FILE__) }
|
163
206
|
|
164
|
-
it
|
207
|
+
it 'should ignore' do
|
165
208
|
copy = original.temp_copy
|
166
209
|
|
167
210
|
Tempfile.reset_init_count
|
168
211
|
optimized_image = ImageOptim.optimize_image(copy)
|
169
|
-
Tempfile.init_count.
|
170
|
-
optimized_image.
|
171
|
-
copy.read.
|
212
|
+
expect(Tempfile.init_count).to eq(0)
|
213
|
+
expect(optimized_image).to be_nil
|
214
|
+
expect(copy.read).to eq(original.read)
|
172
215
|
end
|
173
216
|
|
174
|
-
it
|
217
|
+
it 'should ignore in place' do
|
175
218
|
copy = original.temp_copy
|
176
219
|
|
177
220
|
Tempfile.reset_init_count
|
178
|
-
ImageOptim.optimize_image!(copy).
|
179
|
-
Tempfile.init_count.
|
180
|
-
copy.read.
|
221
|
+
expect(ImageOptim.optimize_image!(copy)).not_to be_truthy
|
222
|
+
expect(Tempfile.init_count).to eq(0)
|
223
|
+
expect(copy.read).to eq(original.read)
|
181
224
|
end
|
182
225
|
|
183
226
|
{
|
@@ -186,65 +229,74 @@ describe ImageOptim do
|
|
186
229
|
}.each do |type, data|
|
187
230
|
describe "broken #{type}" do
|
188
231
|
before do
|
189
|
-
ImageOptim::ImageMeta.
|
232
|
+
expect(ImageOptim::ImageMeta).to receive(:warn)
|
190
233
|
end
|
191
234
|
|
192
|
-
it
|
235
|
+
it 'should ignore path' do
|
193
236
|
path = FSPath.temp_file_path
|
194
237
|
path.write(data)
|
195
|
-
ImageOptim.optimize_image(path).
|
238
|
+
expect(ImageOptim.optimize_image(path)).to be_nil
|
196
239
|
end
|
197
240
|
|
198
|
-
it
|
199
|
-
ImageOptim.optimize_image_data(data).
|
241
|
+
it 'should ignore data' do
|
242
|
+
expect(ImageOptim.optimize_image_data(data)).to be_nil
|
200
243
|
end
|
201
244
|
end
|
202
245
|
end
|
203
246
|
end
|
204
247
|
|
205
|
-
describe
|
248
|
+
describe 'optimize multiple' do
|
206
249
|
let(:srcs){ ('a'..'z').to_a }
|
207
250
|
|
208
251
|
%w[optimize_images optimize_images!].each do |list_method|
|
209
252
|
describe list_method do
|
210
|
-
|
211
|
-
describe
|
212
|
-
it
|
253
|
+
method = list_method.sub('images', 'image')
|
254
|
+
describe 'without block' do
|
255
|
+
it 'should optimize images and return array of results' do
|
213
256
|
image_optim = ImageOptim.new
|
214
257
|
dsts = srcs.map do |src|
|
215
258
|
dst = "#{src}_"
|
216
|
-
image_optim.
|
259
|
+
expect(image_optim).to receive(method).with(src).and_return(dst)
|
217
260
|
dst
|
218
261
|
end
|
219
|
-
image_optim.send(list_method, srcs).
|
262
|
+
expect(image_optim.send(list_method, srcs)).to eq(dsts)
|
220
263
|
end
|
221
264
|
end
|
222
265
|
|
223
|
-
describe
|
224
|
-
it
|
266
|
+
describe 'given block' do
|
267
|
+
it 'should optimize images, yield path and result for each and '\
|
268
|
+
'return array of yield results' do
|
225
269
|
image_optim = ImageOptim.new
|
226
270
|
results = srcs.map do |src|
|
227
271
|
dst = "#{src}_"
|
228
|
-
image_optim.
|
272
|
+
expect(image_optim).to receive(method).with(src).and_return(dst)
|
229
273
|
"#{src} #{dst}"
|
230
274
|
end
|
231
|
-
image_optim.send(list_method, srcs) do |src, dst|
|
275
|
+
expect(image_optim.send(list_method, srcs) do |src, dst|
|
232
276
|
"#{src} #{dst}"
|
233
|
-
end.
|
277
|
+
end).to eq(results)
|
234
278
|
end
|
235
279
|
end
|
236
280
|
end
|
237
281
|
end
|
238
282
|
end
|
239
283
|
|
240
|
-
describe
|
241
|
-
|
242
|
-
|
284
|
+
describe 'losslessness' do
|
285
|
+
images_dir = ImageOptim::ImagePath.new(__FILE__).dirname / 'images'
|
286
|
+
rotated = images_dir / 'orient/original.jpg'
|
287
|
+
rotate_images = images_dir.glob('orient/?.jpg')
|
243
288
|
|
244
289
|
def flatten_animation(image)
|
245
290
|
if image.format == :gif
|
246
291
|
flattened = image.temp_path
|
247
|
-
|
292
|
+
flatten_command = %W[
|
293
|
+
convert
|
294
|
+
#{image.to_s.shellescape}
|
295
|
+
-coalesce
|
296
|
+
-append
|
297
|
+
#{flattened.to_s.shellescape}
|
298
|
+
].join(' ')
|
299
|
+
expect(system(flatten_command)).to be_truthy
|
248
300
|
flattened
|
249
301
|
else
|
250
302
|
image
|
@@ -252,12 +304,20 @@ describe ImageOptim do
|
|
252
304
|
end
|
253
305
|
|
254
306
|
def check_lossless_optimization(original, optimized)
|
255
|
-
optimized.
|
307
|
+
expect(optimized).not_to be_nil
|
256
308
|
original = flatten_animation(original)
|
257
309
|
optimized = flatten_animation(optimized)
|
258
|
-
|
259
|
-
|
260
|
-
|
310
|
+
nrmse_command = %W[
|
311
|
+
compare
|
312
|
+
-metric RMSE
|
313
|
+
#{original.to_s.shellescape}
|
314
|
+
#{optimized.to_s.shellescape}
|
315
|
+
/dev/null
|
316
|
+
2>&1
|
317
|
+
].join(' ')
|
318
|
+
nrmse = `#{nrmse_command}`[/\((\d+(\.\d+)?)\)/, 1]
|
319
|
+
expect(nrmse).not_to be_nil
|
320
|
+
expect(nrmse.to_f).to eq(0)
|
261
321
|
end
|
262
322
|
|
263
323
|
rotate_images.each do |image|
|