image_optim 0.11.2 → 0.12.0

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