image_optim 0.29.0 → 0.30.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/CHANGELOG.markdown +4 -0
- data/README.markdown +2 -1
- data/Vagrantfile +1 -1
- data/image_optim.gemspec +1 -1
- data/lib/image_optim.rb +15 -3
- data/lib/image_optim/bin_resolver/bin.rb +7 -7
- data/lib/image_optim/cache.rb +6 -0
- data/lib/image_optim/cmd.rb +45 -6
- data/lib/image_optim/config.rb +9 -1
- data/lib/image_optim/elapsed_time.rb +26 -0
- data/lib/image_optim/errors.rb +9 -0
- data/lib/image_optim/runner/option_parser.rb +4 -0
- data/lib/image_optim/timer.rb +25 -0
- data/lib/image_optim/worker.rb +24 -12
- data/lib/image_optim/worker/advpng.rb +2 -2
- data/lib/image_optim/worker/gifsicle.rb +3 -3
- data/lib/image_optim/worker/jhead.rb +2 -2
- data/lib/image_optim/worker/jpegoptim.rb +2 -2
- data/lib/image_optim/worker/jpegrecompress.rb +2 -2
- data/lib/image_optim/worker/jpegtran.rb +3 -3
- data/lib/image_optim/worker/optipng.rb +2 -2
- data/lib/image_optim/worker/pngcrush.rb +2 -2
- data/lib/image_optim/worker/pngout.rb +2 -2
- data/lib/image_optim/worker/pngquant.rb +2 -2
- data/lib/image_optim/worker/svgo.rb +2 -2
- data/script/worker_analysis +4 -4
- data/spec/image_optim/bin_resolver_spec.rb +5 -5
- data/spec/image_optim/cache_path_spec.rb +3 -7
- data/spec/image_optim/cache_spec.rb +7 -7
- data/spec/image_optim/cmd_spec.rb +58 -6
- data/spec/image_optim/config_spec.rb +36 -20
- data/spec/image_optim/elapsed_time_spec.rb +14 -0
- data/spec/image_optim/hash_helpers_spec.rb +18 -18
- data/spec/image_optim/option_definition_spec.rb +6 -6
- data/spec/image_optim/path_spec.rb +4 -8
- data/spec/image_optim/runner/option_parser_spec.rb +4 -4
- data/spec/image_optim/timer_spec.rb +32 -0
- data/spec/image_optim/worker/jpegrecompress_spec.rb +2 -2
- data/spec/image_optim/worker/optipng_spec.rb +11 -11
- data/spec/image_optim/worker/pngquant_spec.rb +5 -5
- data/spec/image_optim/worker_spec.rb +17 -17
- data/spec/image_optim_spec.rb +46 -9
- data/spec/spec_helper.rb +16 -15
- metadata +11 -4
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'image_optim/elapsed_time'
|
5
|
+
|
6
|
+
describe ImageOptim::ElapsedTime do
|
7
|
+
let(:timeout){ 0.01 }
|
8
|
+
|
9
|
+
describe '.now' do
|
10
|
+
it 'returns incrementing value' do
|
11
|
+
expect{ sleep timeout }.to change{ described_class.now }.by_at_least(timeout)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -10,10 +10,10 @@ describe ImageOptim::HashHelpers do
|
|
10
10
|
|
11
11
|
context 'stringify/simbolyze' do
|
12
12
|
symbol_keys = {
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
13
|
+
a: 1,
|
14
|
+
b: {
|
15
|
+
c: [:a, 'a'],
|
16
|
+
d: {},
|
17
17
|
},
|
18
18
|
}
|
19
19
|
|
@@ -38,22 +38,22 @@ describe ImageOptim::HashHelpers do
|
|
38
38
|
|
39
39
|
it 'deep merges hashes' do
|
40
40
|
merge_a = {
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
41
|
+
a: {
|
42
|
+
b: 1,
|
43
|
+
c: {
|
44
|
+
d: 2,
|
45
|
+
e: {f: true},
|
46
46
|
},
|
47
47
|
},
|
48
|
-
:
|
48
|
+
y: 10,
|
49
49
|
}
|
50
50
|
|
51
51
|
merge_b = {
|
52
52
|
:a => {
|
53
|
-
:
|
54
|
-
:
|
55
|
-
:
|
56
|
-
:
|
53
|
+
b: 2,
|
54
|
+
c: {
|
55
|
+
d: 3,
|
56
|
+
e: false,
|
57
57
|
},
|
58
58
|
},
|
59
59
|
'z' => 20,
|
@@ -61,10 +61,10 @@ describe ImageOptim::HashHelpers do
|
|
61
61
|
|
62
62
|
merge_result = {
|
63
63
|
:a => {
|
64
|
-
:
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:
|
64
|
+
b: 2,
|
65
|
+
c: {
|
66
|
+
d: 3,
|
67
|
+
e: false,
|
68
68
|
},
|
69
69
|
},
|
70
70
|
:y => 10,
|
@@ -58,13 +58,13 @@ describe ImageOptim::OptionDefinition do
|
|
58
58
|
|
59
59
|
context 'when option is nil' do
|
60
60
|
it 'returns nil' do
|
61
|
-
expect(subject.value(nil, :
|
61
|
+
expect(subject.value(nil, abc: nil)).to eq(nil)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
65
|
context 'when option is set' do
|
66
66
|
it 'returns value' do
|
67
|
-
expect(subject.value(nil, :
|
67
|
+
expect(subject.value(nil, abc: 123)).to eq(123)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
end
|
@@ -84,13 +84,13 @@ describe ImageOptim::OptionDefinition do
|
|
84
84
|
|
85
85
|
context 'when option is nil' do
|
86
86
|
it 'returns nil passed through proc' do
|
87
|
-
expect(subject.value(nil, :
|
87
|
+
expect(subject.value(nil, abc: nil)).to eq('nil')
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
91
|
context 'when option is set' do
|
92
92
|
it 'returns value passed through proc' do
|
93
|
-
expect(subject.value(nil, :
|
93
|
+
expect(subject.value(nil, abc: 123)).to eq('123')
|
94
94
|
end
|
95
95
|
end
|
96
96
|
end
|
@@ -108,13 +108,13 @@ describe ImageOptim::OptionDefinition do
|
|
108
108
|
|
109
109
|
context 'when option is nil' do
|
110
110
|
it 'returns nil passed through proc' do
|
111
|
-
expect(subject.value(nil, :
|
111
|
+
expect(subject.value(nil, abc: nil)).to eq(['nil', subject])
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
115
|
context 'when option is set' do
|
116
116
|
it 'returns value passed through proc' do
|
117
|
-
expect(subject.value(nil, :
|
117
|
+
expect(subject.value(nil, abc: 123)).to eq(['123', subject])
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
@@ -5,8 +5,6 @@ require 'image_optim/path'
|
|
5
5
|
require 'tempfile'
|
6
6
|
|
7
7
|
describe ImageOptim::Path do
|
8
|
-
include CapabilityCheckHelpers
|
9
|
-
|
10
8
|
before do
|
11
9
|
stub_const('Path', ImageOptim::Path)
|
12
10
|
end
|
@@ -76,8 +74,7 @@ describe ImageOptim::Path do
|
|
76
74
|
expect(src).to_not exist
|
77
75
|
end
|
78
76
|
|
79
|
-
it 'preserves attributes of destination file' do
|
80
|
-
skip 'full file modes are not support' unless any_file_modes_allowed?
|
77
|
+
it 'preserves attributes of destination file', skip: SkipConditions[:any_file_mode_allowed] do
|
81
78
|
mode = 0o666
|
82
79
|
|
83
80
|
dst.chmod(mode)
|
@@ -98,8 +95,7 @@ describe ImageOptim::Path do
|
|
98
95
|
expect(dst.mtime).to be >= time
|
99
96
|
end
|
100
97
|
|
101
|
-
it 'changes inode of destination' do
|
102
|
-
skip 'inodes are not supported' unless inodes_supported?
|
98
|
+
it 'changes inode of destination', skip: SkipConditions[:inodes_support] do
|
103
99
|
expect{ src.replace(dst) }.to change{ dst.stat.ino }
|
104
100
|
end
|
105
101
|
end
|
@@ -120,7 +116,7 @@ describe ImageOptim::Path do
|
|
120
116
|
include_examples 'replaces file'
|
121
117
|
|
122
118
|
it 'is using temporary file with .tmp extension' do
|
123
|
-
expect(src).to receive(:move).with(having_attributes(:
|
119
|
+
expect(src).to receive(:move).with(having_attributes(extname: '.tmp'))
|
124
120
|
|
125
121
|
src.replace(dst)
|
126
122
|
end
|
@@ -135,7 +131,7 @@ describe ImageOptim::Path do
|
|
135
131
|
include_examples 'replaces file'
|
136
132
|
|
137
133
|
it 'is using temporary file with .tmp extension' do
|
138
|
-
expect(src).to receive(:move).with(having_attributes(:
|
134
|
+
expect(src).to receive(:move).with(having_attributes(extname: '.tmp'))
|
139
135
|
|
140
136
|
src.replace(dst)
|
141
137
|
end
|
@@ -37,7 +37,7 @@ describe ImageOptim::Runner::OptionParser do
|
|
37
37
|
%w[-r -R --recursive].each do |flag|
|
38
38
|
it "is parsed from #{flag}" do
|
39
39
|
args = %W[#{flag} foo bar]
|
40
|
-
expect(OptionParser.parse!(args)).to eq(:
|
40
|
+
expect(OptionParser.parse!(args)).to eq(recursive: true)
|
41
41
|
expect(args).to eq(%w[foo bar])
|
42
42
|
end
|
43
43
|
end
|
@@ -46,19 +46,19 @@ describe ImageOptim::Runner::OptionParser do
|
|
46
46
|
describe 'numeric option threads' do
|
47
47
|
it 'is parsed with space separator' do
|
48
48
|
args = %w[--threads 616 foo bar]
|
49
|
-
expect(OptionParser.parse!(args)).to eq(:
|
49
|
+
expect(OptionParser.parse!(args)).to eq(threads: 616)
|
50
50
|
expect(args).to eq(%w[foo bar])
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'is parsed with equal separator' do
|
54
54
|
args = %w[--threads=616 foo bar]
|
55
|
-
expect(OptionParser.parse!(args)).to eq(:
|
55
|
+
expect(OptionParser.parse!(args)).to eq(threads: 616)
|
56
56
|
expect(args).to eq(%w[foo bar])
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'is parsed with no- prefix' do
|
60
60
|
args = %w[--no-threads 616 foo bar]
|
61
|
-
expect(OptionParser.parse!(args)).to eq(:
|
61
|
+
expect(OptionParser.parse!(args)).to eq(threads: false)
|
62
62
|
expect(args).to eq(%w[616 foo bar])
|
63
63
|
end
|
64
64
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'image_optim/timer'
|
5
|
+
|
6
|
+
describe ImageOptim::Timer do
|
7
|
+
let!(:timer){ described_class.new(1) }
|
8
|
+
|
9
|
+
describe '#elapsed' do
|
10
|
+
it 'returns elapsed time' do
|
11
|
+
sleep 0.01
|
12
|
+
|
13
|
+
expect(timer.elapsed).to be >= 0.01
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#left' do
|
18
|
+
it 'returns time left' do
|
19
|
+
sleep 0.01
|
20
|
+
|
21
|
+
expect(timer.left).to be <= 0.99
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#to_f' do
|
26
|
+
it 'returns time left' do
|
27
|
+
sleep 0.01
|
28
|
+
|
29
|
+
expect(timer.to_f).to be <= 0.99
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -14,7 +14,7 @@ describe ImageOptim::Worker::Jpegrecompress do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'uses default when invalid' do
|
17
|
-
let(:method){ {:
|
17
|
+
let(:method){ {method: 'invalid'} }
|
18
18
|
|
19
19
|
it 'warns and keeps default' do
|
20
20
|
expect_any_instance_of(described_class).
|
@@ -24,7 +24,7 @@ describe ImageOptim::Worker::Jpegrecompress do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'can use a valid option' do
|
27
|
-
let(:method){ {:
|
27
|
+
let(:method){ {method: 'smallfry'} }
|
28
28
|
|
29
29
|
it{ is_expected.to eq('smallfry') }
|
30
30
|
end
|
@@ -10,7 +10,7 @@ describe ImageOptim::Worker::Optipng do
|
|
10
10
|
|
11
11
|
let(:options){ {} }
|
12
12
|
let(:optipng_version){ '0.7' }
|
13
|
-
let(:src){ instance_double(ImageOptim::Path, :
|
13
|
+
let(:src){ instance_double(ImageOptim::Path, copy: nil) }
|
14
14
|
let(:dst){ instance_double(ImageOptim::Path) }
|
15
15
|
|
16
16
|
before do
|
@@ -34,7 +34,7 @@ describe ImageOptim::Worker::Optipng do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
context 'when strip is disabled' do
|
37
|
-
let(:options){ {:
|
37
|
+
let(:options){ {strip: false} }
|
38
38
|
|
39
39
|
it 'should not add -strip all to arguments' do
|
40
40
|
expect(subject).to receive(:execute) do |_bin, *args|
|
@@ -61,42 +61,42 @@ describe ImageOptim::Worker::Optipng do
|
|
61
61
|
describe '#optimized?' do
|
62
62
|
let(:src){ instance_double(ImageOptim::Path, src_options) }
|
63
63
|
let(:dst){ instance_double(ImageOptim::Path, dst_options) }
|
64
|
-
let(:src_options){ {:
|
65
|
-
let(:dst_options){ {
|
64
|
+
let(:src_options){ {size: 10} }
|
65
|
+
let(:dst_options){ {size?: 9} }
|
66
66
|
let(:instance){ described_class.new(ImageOptim.new, instance_options) }
|
67
67
|
let(:instance_options){ {} }
|
68
68
|
|
69
69
|
subject{ instance.optimized?(src, dst) }
|
70
70
|
|
71
71
|
context 'when interlace option is enabled' do
|
72
|
-
let(:instance_options){ {:
|
72
|
+
let(:instance_options){ {interlace: true} }
|
73
73
|
|
74
74
|
context 'when dst is empty' do
|
75
|
-
let(:dst_options){ {
|
75
|
+
let(:dst_options){ {size?: nil} }
|
76
76
|
it{ is_expected.to be_falsy }
|
77
77
|
end
|
78
78
|
|
79
79
|
context 'when dst is not empty' do
|
80
|
-
let(:dst_options){ {
|
80
|
+
let(:dst_options){ {size?: 20} }
|
81
81
|
it{ is_expected.to be_truthy }
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
85
|
context 'when interlace option is disabled' do
|
86
|
-
let(:instance_options){ {:
|
86
|
+
let(:instance_options){ {interlace: false} }
|
87
87
|
|
88
88
|
context 'when dst is empty' do
|
89
|
-
let(:dst_options){ {
|
89
|
+
let(:dst_options){ {size?: nil} }
|
90
90
|
it{ is_expected.to be_falsy }
|
91
91
|
end
|
92
92
|
|
93
93
|
context 'when dst is greater than or equal to src' do
|
94
|
-
let(:dst_options){ {
|
94
|
+
let(:dst_options){ {size?: 10} }
|
95
95
|
it{ is_expected.to be_falsy }
|
96
96
|
end
|
97
97
|
|
98
98
|
context 'when dst is less than src' do
|
99
|
-
let(:dst_options){ {
|
99
|
+
let(:dst_options){ {size?: 9} }
|
100
100
|
it{ is_expected.to be_truthy }
|
101
101
|
end
|
102
102
|
end
|
@@ -22,7 +22,7 @@ describe ImageOptim::Worker::Pngquant do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'when value is passed through options' do
|
25
|
-
let(:options){ {:
|
25
|
+
let(:options){ {quality: 10..90} }
|
26
26
|
|
27
27
|
it 'warns and keeps default' do
|
28
28
|
expect_any_instance_of(described_class).
|
@@ -34,13 +34,13 @@ describe ImageOptim::Worker::Pngquant do
|
|
34
34
|
|
35
35
|
context 'when lossy allowed' do
|
36
36
|
context 'by default' do
|
37
|
-
let(:options){ {:
|
37
|
+
let(:options){ {allow_lossy: true} }
|
38
38
|
|
39
39
|
it{ is_expected.to eq(0..100) }
|
40
40
|
end
|
41
41
|
|
42
42
|
context 'when value is passed through options' do
|
43
|
-
let(:options){ {:
|
43
|
+
let(:options){ {allow_lossy: true, quality: 10..90} }
|
44
44
|
|
45
45
|
it 'sets the value without warning' do
|
46
46
|
expect_any_instance_of(described_class).not_to receive(:warn)
|
@@ -49,7 +49,7 @@ describe ImageOptim::Worker::Pngquant do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
context 'when passed range begin is less than 0' do
|
52
|
-
let(:options){ {:
|
52
|
+
let(:options){ {allow_lossy: true, quality: -50..50} }
|
53
53
|
|
54
54
|
it 'sets begin to 0' do
|
55
55
|
is_expected.to eq(0..50)
|
@@ -57,7 +57,7 @@ describe ImageOptim::Worker::Pngquant do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
context 'when passed range end is more than 100' do
|
60
|
-
let(:options){ {:
|
60
|
+
let(:options){ {allow_lossy: true, quality: 50..150} }
|
61
61
|
|
62
62
|
it 'sets end to 100' do
|
63
63
|
is_expected.to eq(50..100)
|
@@ -29,9 +29,9 @@ describe ImageOptim::Worker do
|
|
29
29
|
option(:three, 3, 'Three')
|
30
30
|
end
|
31
31
|
|
32
|
-
worker = worker_class.new(ImageOptim.new, :
|
32
|
+
worker = worker_class.new(ImageOptim.new, three: '...')
|
33
33
|
|
34
|
-
expect(worker.options).to eq(:
|
34
|
+
expect(worker.options).to eq(one: 1, two: 2, three: '...')
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -72,7 +72,7 @@ describe ImageOptim::Worker do
|
|
72
72
|
option(:three, 3, 'Three')
|
73
73
|
end)
|
74
74
|
|
75
|
-
worker = DefOptim.new(ImageOptim.new, :
|
75
|
+
worker = DefOptim.new(ImageOptim.new, three: '...')
|
76
76
|
|
77
77
|
expect(worker.inspect).to eq('#<DefOptim @one=1, @two=2, @three="...">')
|
78
78
|
end
|
@@ -104,17 +104,17 @@ describe ImageOptim::Worker do
|
|
104
104
|
|
105
105
|
it 'create hash by format' do
|
106
106
|
workers = [
|
107
|
-
double(:
|
108
|
-
double(:
|
109
|
-
double(:
|
107
|
+
double(image_formats: [:a]),
|
108
|
+
double(image_formats: [:a, :b]),
|
109
|
+
double(image_formats: [:b, :c]),
|
110
110
|
]
|
111
111
|
|
112
112
|
expect(Worker).to receive(:create_all).and_return(workers)
|
113
113
|
|
114
114
|
worker_by_format = {
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
115
|
+
a: [workers[0], workers[1]],
|
116
|
+
b: [workers[1], workers[2]],
|
117
|
+
c: [workers[2]],
|
118
118
|
}
|
119
119
|
|
120
120
|
expect(Worker.create_all_by_format(double)).to eq(worker_by_format)
|
@@ -123,21 +123,21 @@ describe ImageOptim::Worker do
|
|
123
123
|
|
124
124
|
describe '.create_all' do
|
125
125
|
def worker_double(override = {})
|
126
|
-
stubs = {
|
126
|
+
stubs = {resolve_used_bins!: nil, run_order: 0}.merge(override)
|
127
127
|
instance_double(Worker, stubs)
|
128
128
|
end
|
129
129
|
|
130
130
|
def worker_class_doubles(workers)
|
131
|
-
workers.map{ |worker| class_double(Worker, :
|
131
|
+
workers.map{ |worker| class_double(Worker, init: worker) }
|
132
132
|
end
|
133
133
|
|
134
|
-
let(:image_optim){ double(:
|
134
|
+
let(:image_optim){ double(allow_lossy: false) }
|
135
135
|
|
136
136
|
it 'creates all workers for which options_proc returns true' do
|
137
137
|
workers = Array.new(3){ worker_double }
|
138
138
|
klasses = worker_class_doubles(workers)
|
139
139
|
options_proc = proc do |klass|
|
140
|
-
klass == klasses[1] ? {:
|
140
|
+
klass == klasses[1] ? {disable: true} : {}
|
141
141
|
end
|
142
142
|
|
143
143
|
allow(Worker).to receive(:klasses).and_return(klasses)
|
@@ -206,7 +206,7 @@ describe ImageOptim::Worker do
|
|
206
206
|
it 'orders workers by run_order' do
|
207
207
|
run_orders = [10, -10, 0, 0, 0, 10, -10]
|
208
208
|
workers = run_orders.map do |run_order|
|
209
|
-
worker_double(:
|
209
|
+
worker_double(run_order: run_order)
|
210
210
|
end
|
211
211
|
klasses_list = worker_class_doubles(workers)
|
212
212
|
|
@@ -243,16 +243,16 @@ describe ImageOptim::Worker do
|
|
243
243
|
it 'allows overriding per worker' do
|
244
244
|
klasses = worker_class_doubles([worker_double, worker_double])
|
245
245
|
options_proc = proc do |klass|
|
246
|
-
klass == klasses[1] ? {:
|
246
|
+
klass == klasses[1] ? {allow_lossy: :b} : {}
|
247
247
|
end
|
248
248
|
|
249
249
|
allow(Worker).to receive(:klasses).and_return(klasses)
|
250
250
|
|
251
251
|
klasses.each{ |klass| klass.send(:attr_reader, :allow_lossy) }
|
252
252
|
expect(klasses[0]).to receive(:init).
|
253
|
-
with(image_optim, hash_including(:
|
253
|
+
with(image_optim, hash_including(allow_lossy: false))
|
254
254
|
expect(klasses[1]).to receive(:init).
|
255
|
-
with(image_optim, hash_including(:
|
255
|
+
with(image_optim, hash_including(allow_lossy: :b))
|
256
256
|
|
257
257
|
Worker.create_all(image_optim, &options_proc)
|
258
258
|
end
|