image_optim 0.26.5 → 0.27.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/.rubocop.yml +28 -12
- data/.travis.yml +16 -13
- data/CHANGELOG.markdown +5 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +6 -2
- data/image_optim.gemspec +3 -3
- data/lib/image_optim/bin_resolver/bin.rb +1 -0
- data/lib/image_optim/bin_resolver/comparable_condition.rb +1 -0
- data/lib/image_optim/cache_path.rb +5 -2
- data/lib/image_optim/optimized_path.rb +1 -1
- data/lib/image_optim/path.rb +20 -5
- data/lib/image_optim/worker/class_methods.rb +2 -0
- data/script/worker_analysis +4 -1
- data/spec/image_optim/cache_path_spec.rb +49 -25
- data/spec/image_optim/cache_spec.rb +2 -0
- data/spec/image_optim/path_spec.rb +49 -25
- data/spec/images/quant/generate +2 -2
- metadata +15 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2761c4a4a3488017b46d04acf157daa592537169ea05fcbeaf865928b0457618
|
|
4
|
+
data.tar.gz: 89c7fbe11f6b99cf3f1e8c4f3336fd122c1b16afd71fd56b1d0cbd6ab88c52c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: facf38c901cbbd1ba0b8222637845b2e96dc8491e4a55b20a779be53e9ff6e14e561b2ab056aa9182205dd96df20ed0b25c8d8b5a1b3ebe721344ef5384bc7fc
|
|
7
|
+
data.tar.gz: f2d2f1d4179cce616a1024445d8a30b15367a4a156a0a085fa0d8b177f38e44aaff930788b90de6e8226e7b4c022eb1877794aceee5e62cd7e7c1153554238e3
|
data/.rubocop.yml
CHANGED
|
@@ -2,6 +2,7 @@ AllCops:
|
|
|
2
2
|
Exclude:
|
|
3
3
|
- '*.gemspec'
|
|
4
4
|
- 'vendor/**/*'
|
|
5
|
+
NewCops: enable
|
|
5
6
|
|
|
6
7
|
Bundler/OrderedGems:
|
|
7
8
|
Enabled: false
|
|
@@ -9,6 +10,9 @@ Bundler/OrderedGems:
|
|
|
9
10
|
Layout/AccessModifierIndentation:
|
|
10
11
|
EnforcedStyle: outdent
|
|
11
12
|
|
|
13
|
+
Layout/AssignmentIndentation:
|
|
14
|
+
Enabled: false
|
|
15
|
+
|
|
12
16
|
Layout/CaseIndentation:
|
|
13
17
|
EnforcedStyle: end
|
|
14
18
|
|
|
@@ -18,18 +22,18 @@ Layout/DotPosition:
|
|
|
18
22
|
Layout/EndAlignment:
|
|
19
23
|
EnforcedStyleAlignWith: variable
|
|
20
24
|
|
|
21
|
-
Layout/
|
|
25
|
+
Layout/FirstArrayElementIndentation:
|
|
22
26
|
EnforcedStyle: consistent
|
|
23
27
|
|
|
24
|
-
Layout/
|
|
25
|
-
Enabled: false
|
|
26
|
-
|
|
27
|
-
Layout/IndentFirstHashElement:
|
|
28
|
+
Layout/FirstHashElementIndentation:
|
|
28
29
|
EnforcedStyle: consistent
|
|
29
30
|
|
|
30
|
-
Layout/
|
|
31
|
+
Layout/HeredocIndentation:
|
|
31
32
|
Enabled: false
|
|
32
33
|
|
|
34
|
+
Layout/LineLength:
|
|
35
|
+
Max: 120
|
|
36
|
+
|
|
33
37
|
Layout/RescueEnsureAlignment:
|
|
34
38
|
Enabled: false
|
|
35
39
|
|
|
@@ -47,10 +51,10 @@ Lint/AmbiguousBlockAssociation:
|
|
|
47
51
|
Lint/NestedPercentLiteral:
|
|
48
52
|
Enabled: false
|
|
49
53
|
|
|
50
|
-
Lint/
|
|
54
|
+
Lint/RedundantRequireStatement:
|
|
51
55
|
Enabled: false
|
|
52
56
|
|
|
53
|
-
Lint/
|
|
57
|
+
Lint/RedundantSplatExpansion:
|
|
54
58
|
Enabled: false
|
|
55
59
|
|
|
56
60
|
Metrics/AbcSize:
|
|
@@ -68,19 +72,19 @@ Metrics/ClassLength:
|
|
|
68
72
|
Metrics/CyclomaticComplexity:
|
|
69
73
|
Max: 11
|
|
70
74
|
|
|
71
|
-
Metrics/LineLength:
|
|
72
|
-
Max: 120
|
|
73
|
-
|
|
74
75
|
Metrics/MethodLength:
|
|
75
76
|
Max: 25
|
|
76
77
|
|
|
77
78
|
Metrics/PerceivedComplexity:
|
|
78
|
-
Max:
|
|
79
|
+
Max: 10
|
|
79
80
|
|
|
80
81
|
Security/MarshalLoad:
|
|
81
82
|
Exclude:
|
|
82
83
|
- 'script/worker_analysis'
|
|
83
84
|
|
|
85
|
+
Style/AccessorGrouping:
|
|
86
|
+
Enabled: false
|
|
87
|
+
|
|
84
88
|
Style/Alias:
|
|
85
89
|
EnforcedStyle: prefer_alias_method
|
|
86
90
|
|
|
@@ -99,15 +103,27 @@ Style/ExpandPathArguments:
|
|
|
99
103
|
Style/FormatStringToken:
|
|
100
104
|
Enabled: false
|
|
101
105
|
|
|
106
|
+
Style/HashEachMethods:
|
|
107
|
+
Enabled: true
|
|
108
|
+
|
|
102
109
|
Style/HashSyntax:
|
|
103
110
|
EnforcedStyle: hash_rockets
|
|
104
111
|
|
|
112
|
+
Style/HashTransformKeys:
|
|
113
|
+
Enabled: false
|
|
114
|
+
|
|
115
|
+
Style/HashTransformValues:
|
|
116
|
+
Enabled: false
|
|
117
|
+
|
|
105
118
|
Style/IfUnlessModifier:
|
|
106
119
|
Enabled: false
|
|
107
120
|
|
|
108
121
|
Style/NumericPredicate:
|
|
109
122
|
EnforcedStyle: comparison
|
|
110
123
|
|
|
124
|
+
Style/OptionalBooleanParameter:
|
|
125
|
+
Enabled: false
|
|
126
|
+
|
|
111
127
|
Style/ParallelAssignment:
|
|
112
128
|
Enabled: false
|
|
113
129
|
|
data/.travis.yml
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
sudo: false
|
|
2
|
+
dist: trusty
|
|
2
3
|
language: ruby
|
|
3
4
|
cache:
|
|
4
5
|
bundler: true
|
|
@@ -6,38 +7,40 @@ cache:
|
|
|
6
7
|
- $(npm root)
|
|
7
8
|
- ~/bin
|
|
8
9
|
rvm:
|
|
9
|
-
- '1.8.7-
|
|
10
|
+
- '1.8.7-p374'
|
|
10
11
|
- '1.9.3-p551'
|
|
11
12
|
- '2.0.0-p648'
|
|
12
13
|
- '2.1.10'
|
|
13
14
|
- '2.2.10'
|
|
14
15
|
- '2.3.8'
|
|
15
|
-
- '2.4.
|
|
16
|
-
- '2.5.
|
|
17
|
-
- '2.6.
|
|
18
|
-
- '
|
|
16
|
+
- '2.4.10'
|
|
17
|
+
- '2.5.8'
|
|
18
|
+
- '2.6.6'
|
|
19
|
+
- '2.7.1'
|
|
20
|
+
- 'jruby-9.2.11.1'
|
|
19
21
|
script:
|
|
20
22
|
- bundle exec image_optim --info
|
|
21
23
|
- bundle exec rspec
|
|
22
24
|
before_install:
|
|
25
|
+
- 'echo "gem: --no-ri --no-rdoc --no-document" > ~/.gemrc'
|
|
23
26
|
- gem install rubygems-update || gem install rubygems-update --version '< 3'
|
|
24
|
-
-
|
|
27
|
+
- update_rubygems
|
|
25
28
|
- gem install bundler || gem install bundler --version '< 2'
|
|
26
29
|
- nvm install stable
|
|
27
30
|
- mkdir -p ~/bin
|
|
28
31
|
- command -v svgo || npm install -g svgo
|
|
29
|
-
- command -v pngout || curl -L "
|
|
32
|
+
- command -v pngout || curl -L "https://www.jonof.id.au/files/kenutils/pngout-20200115-linux.tar.gz" | tar -xz -C ~/bin --strip-components 2 --wildcards '*/amd64/pngout'
|
|
30
33
|
matrix:
|
|
31
34
|
include:
|
|
32
|
-
- env: CODECLIMATE
|
|
33
|
-
rvm: '2.4.
|
|
35
|
+
- env: CODECLIMATE=1
|
|
36
|
+
rvm: '2.4.10'
|
|
34
37
|
after_success: bundle exec codeclimate-test-reporter
|
|
35
|
-
- env: RUBOCOP
|
|
36
|
-
rvm: '2.4.
|
|
38
|
+
- env: RUBOCOP=1
|
|
39
|
+
rvm: '2.4.10'
|
|
37
40
|
script: bundle exec rubocop
|
|
38
41
|
before_install: gem update --system && gem install bundler
|
|
39
|
-
- env: CHECK_RUBIES
|
|
40
|
-
rvm: '2.4.
|
|
42
|
+
- env: CHECK_RUBIES=1
|
|
43
|
+
rvm: '2.4.10'
|
|
41
44
|
script: bundle exec travis_check_rubies
|
|
42
45
|
before_install: gem update --system && gem install bundler
|
|
43
46
|
addons:
|
data/CHANGELOG.markdown
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## unreleased
|
|
4
4
|
|
|
5
|
+
## v0.27.0 (2020-08-27)
|
|
6
|
+
|
|
7
|
+
* Use `.tmp` as the extension for temporary file if it needs to be created for atomic replacement [#178](https://github.com/toy/image_optim/issues/178) [@toy](https://github.com/toy)
|
|
8
|
+
* Don't create a temporary file in destination directory for atomic replacement if temporary directory is on same device as destination [#178](https://github.com/toy/image_optim/issues/178) [@toy](https://github.com/toy)
|
|
9
|
+
|
|
5
10
|
## v0.26.5 (2019-07-14)
|
|
6
11
|
|
|
7
12
|
* Remove deprecated `rubyforge_project` attribute from gemspec [rubygems/rubygems#2436](https://github.com/rubygems/rubygems/pull/2436) [@toy](https://github.com/toy)
|
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
|
@@ -60,7 +60,7 @@ With version:
|
|
|
60
60
|
|
|
61
61
|
<!---<update-version>-->
|
|
62
62
|
```ruby
|
|
63
|
-
gem 'image_optim', '~> 0.
|
|
63
|
+
gem 'image_optim', '~> 0.27'
|
|
64
64
|
```
|
|
65
65
|
<!---</update-version>-->
|
|
66
66
|
|
|
@@ -277,6 +277,10 @@ optipng:
|
|
|
277
277
|
level: 5
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
+
### Temporary directory
|
|
281
|
+
|
|
282
|
+
`image_optim` uses standard ruby library for creating temporary files. Temporary directory can be changed using one of `TMPDIR`, `TMP` or `TEMP` environment variables.
|
|
283
|
+
|
|
280
284
|
## Options
|
|
281
285
|
|
|
282
286
|
* `:nice` — Nice level, priority of all used tools with higher value meaning lower priority, in range `-20..19`, negative values can be set only if run by root user *(defaults to `10`)*
|
|
@@ -357,4 +361,4 @@ In separate file [CHANGELOG.markdown](CHANGELOG.markdown).
|
|
|
357
361
|
|
|
358
362
|
## Copyright
|
|
359
363
|
|
|
360
|
-
Copyright (c) 2012-
|
|
364
|
+
Copyright (c) 2012-2020 Ivan Kuchin. See [LICENSE.txt](LICENSE.txt) for details.
|
data/image_optim.gemspec
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'image_optim'
|
|
5
|
-
s.version = '0.
|
|
5
|
+
s.version = '0.27.0'
|
|
6
6
|
s.summary = %q{Command line tool and ruby interface to optimize (lossless compress, optionally lossy) jpeg, png, gif and svg images using external utilities (advpng, gifsicle, jhead, jpeg-recompress, jpegoptim, jpegrescan, jpegtran, optipng, pngcrush, pngout, pngquant, svgo)}
|
|
7
|
-
s.homepage = "
|
|
7
|
+
s.homepage = "https://github.com/toy/#{s.name}"
|
|
8
8
|
s.authors = ['Ivan Kuchin']
|
|
9
9
|
s.license = 'MIT'
|
|
10
10
|
|
|
@@ -34,6 +34,6 @@ EOF
|
|
|
34
34
|
s.add_development_dependency 'image_optim_pack', '~> 0.2', '>= 0.2.2'
|
|
35
35
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
36
36
|
if RUBY_VERSION >= '2.2' && !Gem.win_platform? && !defined?(JRUBY_VERSION)
|
|
37
|
-
s.add_development_dependency 'rubocop', '~> 0.59'
|
|
37
|
+
s.add_development_dependency 'rubocop', '~> 0.59', '!= 0.78.0'
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -7,8 +7,11 @@ class ImageOptim
|
|
|
7
7
|
class CachePath < Path
|
|
8
8
|
# Atomic replace dst with self
|
|
9
9
|
def replace(dst)
|
|
10
|
-
dst = self.class.
|
|
11
|
-
|
|
10
|
+
dst = self.class.convert(dst)
|
|
11
|
+
tmpdir = [dirname, Path.new(Dir.tmpdir)].find do |dir|
|
|
12
|
+
dir.same_dev?(dst.dirname)
|
|
13
|
+
end
|
|
14
|
+
dst.temp_path_with_tmp_ext(tmpdir || dst.dirname) do |temp|
|
|
12
15
|
copy(temp)
|
|
13
16
|
dst.copy_metadata(temp)
|
|
14
17
|
temp.rename(dst.to_s)
|
|
@@ -7,7 +7,7 @@ class ImageOptim
|
|
|
7
7
|
class OptimizedPath < DelegateClass(Path)
|
|
8
8
|
def initialize(path, original_or_size = nil)
|
|
9
9
|
path = Path.convert(path)
|
|
10
|
-
|
|
10
|
+
super(path)
|
|
11
11
|
if original_or_size.is_a?(Integer)
|
|
12
12
|
@original = path
|
|
13
13
|
@original_size = original_or_size
|
data/lib/image_optim/path.rb
CHANGED
|
@@ -50,11 +50,16 @@ class ImageOptim
|
|
|
50
50
|
|
|
51
51
|
# Atomic replace dst with self
|
|
52
52
|
def replace(dst)
|
|
53
|
-
dst = self.class.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
dst.
|
|
57
|
-
|
|
53
|
+
dst = self.class.convert(dst)
|
|
54
|
+
if same_dev?(dst.dirname)
|
|
55
|
+
dst.copy_metadata(self)
|
|
56
|
+
rename(dst.to_s)
|
|
57
|
+
else
|
|
58
|
+
dst.temp_path_with_tmp_ext(dst.dirname) do |temp|
|
|
59
|
+
move(temp)
|
|
60
|
+
dst.copy_metadata(temp)
|
|
61
|
+
temp.rename(dst.to_s)
|
|
62
|
+
end
|
|
58
63
|
end
|
|
59
64
|
end
|
|
60
65
|
|
|
@@ -68,5 +73,15 @@ class ImageOptim
|
|
|
68
73
|
def self.convert(path)
|
|
69
74
|
path.is_a?(self) ? path : new(path)
|
|
70
75
|
end
|
|
76
|
+
|
|
77
|
+
protected
|
|
78
|
+
|
|
79
|
+
def same_dev?(other)
|
|
80
|
+
stat.dev == other.stat.dev
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def temp_path_with_tmp_ext(*args, &block)
|
|
84
|
+
self.class.temp_file_path([basename.to_s, '.tmp'], *args, &block)
|
|
85
|
+
end
|
|
71
86
|
end
|
|
72
87
|
end
|
|
@@ -18,6 +18,7 @@ class ImageOptim
|
|
|
18
18
|
|
|
19
19
|
# Remember all classes inheriting from this one
|
|
20
20
|
def inherited(base)
|
|
21
|
+
super
|
|
21
22
|
@klasses << base
|
|
22
23
|
end
|
|
23
24
|
|
|
@@ -36,6 +37,7 @@ class ImageOptim
|
|
|
36
37
|
|
|
37
38
|
def option(name, default, type, description = nil, &proc)
|
|
38
39
|
attr_reader name
|
|
40
|
+
|
|
39
41
|
OptionDefinition.new(name, default, type, description, &proc).
|
|
40
42
|
tap{ |option_definition| option_definitions << option_definition }
|
|
41
43
|
end
|
data/script/worker_analysis
CHANGED
|
@@ -137,13 +137,14 @@ class Analyser
|
|
|
137
137
|
# Delegate to worker with short id
|
|
138
138
|
class WorkerVariant < DelegateClass(ImageOptim::Worker)
|
|
139
139
|
attr_reader :name, :id, :cons_id, :required
|
|
140
|
+
|
|
140
141
|
def initialize(klass, image_optim, options)
|
|
141
142
|
@required = options.delete(:required)
|
|
142
143
|
@run_order = options.delete(:run_order)
|
|
143
144
|
allow_consecutive_on = Array(options.delete(:allow_consecutive_on))
|
|
144
145
|
@image_optim = image_optim
|
|
145
146
|
@name = klass.bin_sym.to_s + options_string(options)
|
|
146
|
-
|
|
147
|
+
super(klass.new(image_optim, options))
|
|
147
148
|
@id = klass.bin_sym.to_s + options_string(self.options)
|
|
148
149
|
@cons_id = [klass, allow_consecutive_on.map{ |key| [key, send(key)] }]
|
|
149
150
|
end
|
|
@@ -452,6 +453,7 @@ class Analyser
|
|
|
452
453
|
attr_reader :name
|
|
453
454
|
attr_reader :success_count
|
|
454
455
|
attr_reader :time, :avg_time
|
|
456
|
+
|
|
455
457
|
def initialize(name, steps)
|
|
456
458
|
@name = name
|
|
457
459
|
@success_count = steps.count(&:success)
|
|
@@ -465,6 +467,7 @@ class Analyser
|
|
|
465
467
|
end
|
|
466
468
|
|
|
467
469
|
attr_reader :name, :results, :ids2names
|
|
470
|
+
|
|
468
471
|
def initialize(name, results, ids2names)
|
|
469
472
|
@name = name.to_s
|
|
470
473
|
@results = results
|
|
@@ -15,45 +15,69 @@ describe ImageOptim::CachePath do
|
|
|
15
15
|
let(:src){ CachePath.temp_file_path }
|
|
16
16
|
let(:dst){ CachePath.temp_file_path }
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
shared_examples 'replaces file' do
|
|
19
|
+
it 'moves data to destination' do
|
|
20
|
+
src.write('src')
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
src.replace(dst)
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
expect(dst.read).to eq('src')
|
|
25
|
+
end
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
it 'does not remove original file' do
|
|
28
|
+
src.replace(dst)
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
expect(src).to exist
|
|
31
|
+
end
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
it 'preserves attributes of destination file' do
|
|
34
|
+
skip 'full file modes are not support' unless any_file_modes_allowed?
|
|
35
|
+
mode = 0o666
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
dst.chmod(mode)
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
src.replace(dst)
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
got = dst.stat.mode & 0o777
|
|
42
|
+
expect(got).to eq(mode), format('expected %04o, got %04o', mode, got)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'does not preserve mtime of destination file' do
|
|
46
|
+
time = src.mtime
|
|
47
|
+
|
|
48
|
+
dst.utime(time - 1000, time - 1000)
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
time = src.mtime
|
|
50
|
+
src.replace(dst)
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
expect(dst.mtime).to be >= time
|
|
53
|
+
end
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
it 'changes inode of destination' do
|
|
56
|
+
skip 'inodes are not supported' unless inodes_supported?
|
|
57
|
+
expect{ src.replace(dst) }.to change{ dst.stat.ino }
|
|
58
|
+
end
|
|
50
59
|
|
|
51
|
-
|
|
60
|
+
it 'is using temporary file with .tmp extension' do
|
|
61
|
+
expect(src).to receive(:copy).with(having_attributes(:extname => '.tmp'))
|
|
62
|
+
|
|
63
|
+
src.replace(dst)
|
|
64
|
+
end
|
|
52
65
|
end
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
context 'when src and dst are on same device' do
|
|
68
|
+
before do
|
|
69
|
+
allow_any_instance_of(File::Stat).to receive(:dev).and_return(0)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
include_examples 'replaces file'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when src and dst are on different devices' do
|
|
76
|
+
before do
|
|
77
|
+
allow_any_instance_of(File::Stat).to receive(:dev, &:__id__)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
include_examples 'replaces file'
|
|
57
81
|
end
|
|
58
82
|
end
|
|
59
83
|
end
|
|
@@ -64,6 +64,7 @@ describe ImageOptim::Cache do
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# rubocop:disable Style/RedundantFetchBlock
|
|
67
68
|
shared_examples 'an enabled cache' do
|
|
68
69
|
context 'when cached file does not exist' do
|
|
69
70
|
describe :fetch do
|
|
@@ -116,6 +117,7 @@ describe ImageOptim::Cache do
|
|
|
116
117
|
end
|
|
117
118
|
end
|
|
118
119
|
end
|
|
120
|
+
# rubocop:enable Style/RedundantFetchBlock
|
|
119
121
|
|
|
120
122
|
context 'when cache is enabled (without worker digests)' do
|
|
121
123
|
let(:image_optim) do
|
|
@@ -61,45 +61,69 @@ describe ImageOptim::Path do
|
|
|
61
61
|
let(:src){ Path.temp_file_path }
|
|
62
62
|
let(:dst){ Path.temp_file_path }
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
shared_examples 'replaces file' do
|
|
65
|
+
it 'moves data to destination' do
|
|
66
|
+
src.write('src')
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
src.replace(dst)
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
expect(dst.read).to eq('src')
|
|
71
|
+
end
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
it 'removes original file' do
|
|
74
|
+
src.replace(dst)
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
expect(src).to_not exist
|
|
77
|
+
end
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
it 'preserves attributes of destination file' do
|
|
80
|
+
skip 'full file modes are not support' unless any_file_modes_allowed?
|
|
81
|
+
mode = 0o666
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
dst.chmod(mode)
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
src.replace(dst)
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
got = dst.stat.mode & 0o777
|
|
88
|
+
expect(got).to eq(mode), format('expected %04o, got %04o', mode, got)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'does not preserve mtime of destination file' do
|
|
92
|
+
time = src.mtime
|
|
93
|
+
|
|
94
|
+
dst.utime(time - 1000, time - 1000)
|
|
95
|
+
|
|
96
|
+
src.replace(dst)
|
|
89
97
|
|
|
90
|
-
|
|
91
|
-
|
|
98
|
+
expect(dst.mtime).to be >= time
|
|
99
|
+
end
|
|
92
100
|
|
|
93
|
-
|
|
101
|
+
it 'changes inode of destination' do
|
|
102
|
+
skip 'inodes are not supported' unless inodes_supported?
|
|
103
|
+
expect{ src.replace(dst) }.to change{ dst.stat.ino }
|
|
104
|
+
end
|
|
105
|
+
end
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
context 'when src and dst are on same device' do
|
|
108
|
+
before do
|
|
109
|
+
allow_any_instance_of(File::Stat).to receive(:dev).and_return(0)
|
|
110
|
+
end
|
|
96
111
|
|
|
97
|
-
|
|
112
|
+
include_examples 'replaces file'
|
|
98
113
|
end
|
|
99
114
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
115
|
+
context 'when src and dst are on different devices' do
|
|
116
|
+
before do
|
|
117
|
+
allow_any_instance_of(File::Stat).to receive(:dev, &:__id__)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
include_examples 'replaces file'
|
|
121
|
+
|
|
122
|
+
it 'is using temporary file with .tmp extension' do
|
|
123
|
+
expect(src).to receive(:move).with(having_attributes(:extname => '.tmp'))
|
|
124
|
+
|
|
125
|
+
src.replace(dst)
|
|
126
|
+
end
|
|
103
127
|
end
|
|
104
128
|
end
|
|
105
129
|
end
|
data/spec/images/quant/generate
CHANGED
|
@@ -17,8 +17,8 @@ palettes.each do |palette|
|
|
|
17
17
|
rgb:-
|
|
18
18
|
PNG24:#{palette}.png
|
|
19
19
|
].shelljoin, 'w') do |f|
|
|
20
|
-
(side
|
|
21
|
-
color = i * palette / (side
|
|
20
|
+
(side**2).times do |i|
|
|
21
|
+
color = i * palette / (side**2) * 0x10000 / palette
|
|
22
22
|
f << [color / 0x100, color % 0x100, 0].pack('C*')
|
|
23
23
|
end
|
|
24
24
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: image_optim
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Kuchin
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-08-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: fspath
|
|
@@ -139,6 +139,9 @@ dependencies:
|
|
|
139
139
|
- - "~>"
|
|
140
140
|
- !ruby/object:Gem::Version
|
|
141
141
|
version: '0.59'
|
|
142
|
+
- - "!="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: 0.78.0
|
|
142
145
|
type: :development
|
|
143
146
|
prerelease: false
|
|
144
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -146,8 +149,11 @@ dependencies:
|
|
|
146
149
|
- - "~>"
|
|
147
150
|
- !ruby/object:Gem::Version
|
|
148
151
|
version: '0.59'
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
- - "!="
|
|
153
|
+
- !ruby/object:Gem::Version
|
|
154
|
+
version: 0.78.0
|
|
155
|
+
description:
|
|
156
|
+
email:
|
|
151
157
|
executables:
|
|
152
158
|
- image_optim
|
|
153
159
|
extensions: []
|
|
@@ -257,13 +263,13 @@ files:
|
|
|
257
263
|
- spec/spec_helper.rb
|
|
258
264
|
- vendor/jpegrescan
|
|
259
265
|
- vendor/jpegrescan.bat
|
|
260
|
-
homepage:
|
|
266
|
+
homepage: https://github.com/toy/image_optim
|
|
261
267
|
licenses:
|
|
262
268
|
- MIT
|
|
263
269
|
metadata:
|
|
264
270
|
bug_tracker_uri: https://github.com/toy/image_optim/issues
|
|
265
271
|
changelog_uri: https://github.com/toy/image_optim/blob/master/CHANGELOG.markdown
|
|
266
|
-
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.
|
|
272
|
+
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.27.0
|
|
267
273
|
source_code_uri: https://github.com/toy/image_optim
|
|
268
274
|
post_install_message: |
|
|
269
275
|
Rails image assets optimization is extracted into image_optim_rails gem
|
|
@@ -282,8 +288,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
282
288
|
- !ruby/object:Gem::Version
|
|
283
289
|
version: '0'
|
|
284
290
|
requirements: []
|
|
285
|
-
rubygems_version: 3.
|
|
286
|
-
signing_key:
|
|
291
|
+
rubygems_version: 3.1.4
|
|
292
|
+
signing_key:
|
|
287
293
|
specification_version: 4
|
|
288
294
|
summary: Command line tool and ruby interface to optimize (lossless compress, optionally
|
|
289
295
|
lossy) jpeg, png, gif and svg images using external utilities (advpng, gifsicle,
|