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