image_optim 0.11.2 → 0.12.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTcxZTdkMDdlYjUwYTg1MDQ4ODcwYTU0YTk3ODUyNjVjODhkMzFhMw==
4
+ NDA2NmMyODM2ZTg1ZDUzMTA3NjBjYjIzYWIyZTEwODQyZmRmOGNmMQ==
5
5
  data.tar.gz: !binary |-
6
- MWExOGIwNzY3NGZhYjE2YTE1YmZkM2U3ODQ0YTQwYzMwMWMwZDdhMw==
6
+ MWZlMWVhNGE5MzNiOGE0YWZhODMxNWJiNzRkOGU4YTVmN2NlNWU5Yw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MDg3NmY1ZTc2MDhkY2U2MDA2ODI3MzdlZDMzODRhNjM4MGFlZDQ1YTk0YjQw
10
- NTdkNzRjNjIxZGFjNGMzYWIwOGYyOWFmOTRmMDc0NWY0ZDU1ZDM5MGQ4ZjI2
11
- ODk1M2Y4NTU5NDIzYjhhOGVjZWZjNTc4ZjdlMWI0YjU0MDRjM2M=
9
+ ZDcyMjNlNDFmNmE3ODQ5ZGEwMmE5MTk0OTc1NDkzY2FmNzY3ZjczMzA2NTEy
10
+ ZDE2Y2NhODlkMjRiYzVjYTA2OTE2NTUzYzhmODU3YWE0ZWQxMmZjNzk5YTlj
11
+ Y2JkM2ViYTMzMzVmNjNhMzFhZDQzYjU1ZjNlMWIyODdhYzFhMDE=
12
12
  data.tar.gz: !binary |-
13
- ODE4MzBjMTU2NjQyODM5MThiMmMzZGNkZDU2ZTdhN2NhNmY5OTljNzIyYWY5
14
- ZTNlOWU1NzVhNmVhNDgwODM0YWJjMGZjYWFiMzQxNThiY2U3MzUzNzJiZDhl
15
- MmVmMDRjYzYzZGVhN2EwZTBjZmU1NzM2YTJjMzMyZjI3MmQ0M2M=
13
+ MTBhMzNjMTgzZGU2NTA5NTc3ZTA1OThlODU4Yzk3OGQ3ZDE1ZDM0OTM0MDg5
14
+ ZGU4ODQwNGMyNjRhZDIwMjU5YzRlMjQ2NzZjM2I1MzhlZTNiYThmMTE5YWVk
15
+ YzFkYjllN2I1MWEzNTJjOTNjMGMwZDUxZmNkNzBiYTQ3MzQ2YmE=
data/.travis.yml CHANGED
@@ -5,8 +5,11 @@ rvm:
5
5
  - 1.9.2
6
6
  - 1.9.3
7
7
  - 2.0.0
8
+ - 2.1.0
9
+ - ruby-head
8
10
  - jruby-18mode
9
11
  - jruby-19mode
12
+ - jruby-head
10
13
  - ree
11
14
  script: bundle exec rspec
12
15
  before_install:
@@ -18,3 +21,7 @@ before_install:
18
21
  - npm install -g svgo
19
22
  env:
20
23
  - PATH=pngout-linux/x86_64:$PATH
24
+ matrix:
25
+ allow_failures:
26
+ - rvm: ruby-head
27
+ - rvm: jruby-head
data/image_optim.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_optim'
5
- s.version = '0.11.2'
5
+ s.version = '0.12.0'
6
6
  s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, svgo)}
7
7
  s.homepage = "http://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
@@ -1,23 +1,40 @@
1
- require 'image_optim/bin_not_found_error'
2
1
  require 'thread'
3
2
  require 'fspath'
4
3
 
5
4
  class ImageOptim
5
+ class BinNotFoundError < StandardError; end
6
+ class BadBinVersion < StandardError; end
7
+
6
8
  class BinResolver
9
+ class Bin
10
+ attr_reader :name, :version
11
+ def initialize(name, version)
12
+ @name, @version = name, version
13
+ end
14
+
15
+ def to_s
16
+ "#{@name} #{@version || '-'}"
17
+ end
18
+ end
19
+
7
20
  attr_reader :dir
8
21
  def initialize
9
22
  @bins = {}
10
23
  @lock = Mutex.new
11
24
  end
12
25
 
13
- def resolve!(bin)
14
- bin = bin.to_sym
15
- unless @bins.include?(bin)
16
- @lock.synchronize do
17
- @bins[bin] = resolve?(bin) unless @bins.include?(bin)
18
- end
26
+ def resolve!(name)
27
+ name = name.to_sym
28
+
29
+ resolving(name) do
30
+ @bins[name] = resolve?(name) && Bin.new(name, version(name))
31
+ end
32
+
33
+ if @bins[name]
34
+ check!(@bins[name])
35
+ else
36
+ raise BinNotFoundError, "`#{name}` not found"
19
37
  end
20
- @bins[bin] or raise BinNotFoundError, "`#{bin}` not found"
21
38
  end
22
39
 
23
40
  VENDOR_PATH = File.expand_path('../../../vendor', __FILE__)
@@ -28,20 +45,62 @@ class ImageOptim
28
45
 
29
46
  private
30
47
 
31
- def resolve?(bin)
32
- if path = ENV["#{bin}_bin".upcase]
48
+ def resolving(name)
49
+ unless @bins.include?(name)
50
+ @lock.synchronize do
51
+ unless @bins.include?(name)
52
+ yield
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ def resolve?(name)
59
+ if path = ENV["#{name}_bin".upcase]
33
60
  unless @dir
34
61
  @dir = FSPath.temp_dir
35
62
  at_exit{ FileUtils.remove_entry_secure @dir }
36
63
  end
37
- symlink = @dir / bin
64
+ symlink = @dir / name
38
65
  symlink.make_symlink(File.expand_path(path))
39
66
  end
40
- accessible?(bin)
67
+ accessible?(name)
68
+ end
69
+
70
+ def accessible?(name)
71
+ capture_output("which #{name.to_s.shellescape}") != ''
72
+ end
73
+
74
+ def version(name)
75
+ case name.to_sym
76
+ when :advpng, :gifsicle, :jpegoptim, :optipng
77
+ capture_output("#{name} --version")[/\d+(\.\d+){1,}/]
78
+ when :svgo
79
+ capture_output("#{name} --version 2>&1")[/\d+(\.\d+){1,}/]
80
+ when :jhead
81
+ capture_output("#{name} -V")[/\d+(\.\d+){1,}/]
82
+ when :jpegtran
83
+ capture_output("#{name} -v - 2>&1")[/version (\d+\S*)/, 1]
84
+ when :pngcrush
85
+ capture_output("#{name} -version 2>&1")[/\d+(\.\d+){1,}/]
86
+ when :pngout
87
+ date_str = capture_output("#{name} 2>&1")[/[A-Z][a-z]{2} (?: |\d)\d \d{4}/]
88
+ Date.parse(date_str).strftime('%Y%m%d')
89
+ end
90
+ end
91
+
92
+ def check!(bin)
93
+ case bin.name
94
+ when :pngcrush
95
+ case bin.version
96
+ when '1.7.60'..'1.7.65'
97
+ raise BadBinVersion, "`#{bin}` is known to produce broken pngs"
98
+ end
99
+ end
41
100
  end
42
101
 
43
- def accessible?(bin)
44
- `env PATH=#{env_path.shellescape} which #{bin.to_s.shellescape}` != ''
102
+ def capture_output(command)
103
+ `env PATH=#{env_path.shellescape} #{command}`
45
104
  end
46
105
  end
47
106
  end
@@ -17,7 +17,7 @@ describe ImageOptim::BinResolver do
17
17
  FSPath.should_not_receive(:temp_dir)
18
18
 
19
19
  5.times do
20
- resolver.resolve!(:ls).should be_true
20
+ resolver.resolve!(:ls)
21
21
  end
22
22
  resolver.env_path.should == "#{ENV['PATH']}:#{ImageOptim::BinResolver::VENDOR_PATH}"
23
23
  end
@@ -41,7 +41,7 @@ describe ImageOptim::BinResolver do
41
41
  end
42
42
 
43
43
  5.times do
44
- resolver.resolve!(:image_optim).should be_true
44
+ resolver.resolve!(:image_optim)
45
45
  end
46
46
  resolver.env_path.should == "#{tmpdir.to_str}:#{ENV['PATH']}:#{ImageOptim::BinResolver::VENDOR_PATH}"
47
47
 
@@ -93,4 +93,33 @@ describe ImageOptim::BinResolver do
93
93
  at_exit_blocks.each(&:call)
94
94
  end
95
95
  end
96
+
97
+ it "should resolve bin only once" do
98
+ with_env 'LS_BIN', nil do
99
+ resolver = ImageOptim::BinResolver.new
100
+ resolver.should_receive(:resolve?).once.with(:ls){ sleep 0.1; true }
101
+
102
+ 10.times.map do
103
+ Thread.new do
104
+ resolver.resolve!(:ls)
105
+ end
106
+ end.each(&:join)
107
+ end
108
+ end
109
+
110
+ it "should raise on detection of problematic version" do
111
+ with_env 'PNGCRUSH_BIN', nil do
112
+ resolver = ImageOptim::BinResolver.new
113
+ resolver.should_receive(:accessible?).with(:pngcrush).once.and_return(true)
114
+ resolver.should_receive(:version).with(:pngcrush).once.and_return('1.7.60')
115
+ FSPath.should_not_receive(:temp_dir)
116
+
117
+ 5.times do
118
+ expect do
119
+ resolver.resolve!(:pngcrush)
120
+ end.to raise_error ImageOptim::BadBinVersion
121
+ end
122
+ resolver.env_path.should == "#{ENV['PATH']}:#{ImageOptim::BinResolver::VENDOR_PATH}"
123
+ end
124
+ end
96
125
  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.11.2
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuchin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-01 00:00:00.000000000 Z
11
+ date: 2014-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -109,7 +109,6 @@ files:
109
109
  - bin/image_optim
110
110
  - image_optim.gemspec
111
111
  - lib/image_optim.rb
112
- - lib/image_optim/bin_not_found_error.rb
113
112
  - lib/image_optim/bin_resolver.rb
114
113
  - lib/image_optim/config.rb
115
114
  - lib/image_optim/configuration_error.rb
@@ -1,3 +0,0 @@
1
- class ImageOptim
2
- class BinNotFoundError < StandardError; end
3
- end