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.
Files changed (44) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +56 -0
  3. data/.travis.yml +3 -1
  4. data/README.markdown +23 -10
  5. data/bin/image_optim +25 -15
  6. data/image_optim.gemspec +5 -2
  7. data/lib/image_optim.rb +47 -37
  8. data/lib/image_optim/bin_resolver.rb +17 -12
  9. data/lib/image_optim/bin_resolver/comparable_condition.rb +23 -7
  10. data/lib/image_optim/bin_resolver/simple_version.rb +2 -0
  11. data/lib/image_optim/config.rb +21 -13
  12. data/lib/image_optim/handler.rb +18 -12
  13. data/lib/image_optim/hash_helpers.rb +23 -13
  14. data/lib/image_optim/image_meta.rb +1 -0
  15. data/lib/image_optim/image_path.rb +14 -13
  16. data/lib/image_optim/option_definition.rb +11 -9
  17. data/lib/image_optim/option_helpers.rb +1 -2
  18. data/lib/image_optim/railtie.rb +18 -15
  19. data/lib/image_optim/runner.rb +67 -61
  20. data/lib/image_optim/space.rb +29 -0
  21. data/lib/image_optim/true_false_nil.rb +9 -1
  22. data/lib/image_optim/worker.rb +40 -16
  23. data/lib/image_optim/worker/advpng.rb +8 -1
  24. data/lib/image_optim/worker/gifsicle.rb +13 -1
  25. data/lib/image_optim/worker/jhead.rb +5 -0
  26. data/lib/image_optim/worker/jpegoptim.rb +17 -4
  27. data/lib/image_optim/worker/jpegtran.rb +9 -1
  28. data/lib/image_optim/worker/optipng.rb +13 -2
  29. data/lib/image_optim/worker/pngcrush.rb +14 -5
  30. data/lib/image_optim/worker/pngout.rb +10 -2
  31. data/lib/image_optim/worker/svgo.rb +1 -0
  32. data/script/update_worker_options_in_readme +42 -27
  33. data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +13 -13
  34. data/spec/image_optim/bin_resolver/simple_version_spec.rb +4 -4
  35. data/spec/image_optim/bin_resolver_spec.rb +65 -37
  36. data/spec/image_optim/config_spec.rb +121 -110
  37. data/spec/image_optim/handler_spec.rb +29 -18
  38. data/spec/image_optim/hash_helpers_spec.rb +29 -27
  39. data/spec/image_optim/image_path_spec.rb +17 -17
  40. data/spec/image_optim/space_spec.rb +24 -0
  41. data/spec/image_optim/worker_spec.rb +18 -0
  42. data/spec/image_optim_spec.rb +134 -74
  43. metadata +27 -7
  44. data/script/update_instructions_in_readme +0 -44
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTMzMWQ1ZjgyYzJkMmM5NzJmZmU2MDc2YTVhMmUxYTU0MTY2MWY1NA==
4
+ MDYzNDg2MTY5NjdlNGIyY2U3NzY0Mzc5MTc1YzA3N2I3MGRmNDQ0Yw==
5
5
  data.tar.gz: !binary |-
6
- NGYzYjFlY2IyOTBjNjI1OTRkNWY2Y2EyMDg2NzYwMWRhODRkNDBhZQ==
6
+ OTcyM2IxMWJjOTA4NDYyYTVkMjcwNTI4MDI5NzE0OTVmYjI5MzE0NQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NDU2NmJlMzZkYjE5YjRiMjNlN2EzNGVmNjJjMmZjNjkyMGRhZDMzYjM3ZmJl
10
- YWNlY2ZmZWU0YTY3YmJhZThiMmI1NjU5YTM1OTA4Yzk4YWQyOWNjNjVjMThk
11
- M2ZhNmQ0MTI3ZDkwMjc4OGU5YzJiMTkxYzM0ZThlN2Q1ZTQ1NWE=
9
+ N2ViYzljYTU3OGVkMzQ5OTNmNmYyM2RmZjdmZDZmN2E4MDA0MmJmNGI5MjFk
10
+ Yzc1NDFjYWM0NjgxZTU0ZWQwMjc0MmVjNGM1MjEyYmQ3MzhmNTlmYWNkZjU3
11
+ Mzc1Mjc2Y2M0NWNkZGM3OTFlN2ZjZDNiM2EwOGRmNjY0MmIxM2M=
12
12
  data.tar.gz: !binary |-
13
- OWEzOTM2ZmY5ODIwMmUzNjg3NmEzYjFmZmJmODQ5Nzc2MTA1MmE0YTcxMzdl
14
- MTY5YWI5Nzc4MDYwMTFlODZjOWI4NDM5MzFjZjA4ZTY1NzRlY2VkYzAyN2Mx
15
- ZTZiNzUyNzQ4ODNiODZjM2RlYjAxZmUzYWVlNjcxNzEzMGMzY2Y=
13
+ Y2M4Y2I4ZTNiYjZhYThmYThhNTQxYjQ4N2UxZDhhNmU4NjQ1MmI2NmY1YTdh
14
+ MGI3YTI1YjRiZmIyYmQ5NGE4MDI2NmVjNGY1YWNmNmRkMDM3MzZhMGY3ZjQ5
15
+ MjYwZmJhOWNkYTM3YWU3NTc4OTQwMThiZjhmY2RkY2Y5ZTc3ZmY=
data/.rubocop.yml ADDED
@@ -0,0 +1,56 @@
1
+ AllCops:
2
+ Exclude:
3
+ - '*.gemspec'
4
+
5
+ Lint/EndAlignment:
6
+ AlignWith: variable
7
+
8
+ Style/AccessModifierIndentation:
9
+ EnforcedStyle: outdent
10
+
11
+ Style/CaseIndentation:
12
+ IndentWhenRelativeTo: end
13
+
14
+ Style/ClassLength:
15
+ Max: 120
16
+
17
+ Style/CyclomaticComplexity:
18
+ Max: 8
19
+
20
+ Style/DotPosition:
21
+ EnforcedStyle: trailing
22
+
23
+ Style/DoubleNegation:
24
+ Enabled: false
25
+
26
+ Style/Encoding:
27
+ EnforcedStyle: when_needed
28
+
29
+ Style/HashSyntax:
30
+ EnforcedStyle: hash_rockets
31
+
32
+ Style/IfUnlessModifier:
33
+ MaxLineLength: 40
34
+
35
+ Style/IndentHash:
36
+ EnforcedStyle: consistent
37
+
38
+ Style/MethodLength:
39
+ Max: 20
40
+
41
+ Style/PercentLiteralDelimiters:
42
+ PreferredDelimiters:
43
+ '%w': '[]'
44
+ '%W': '[]'
45
+
46
+ Style/Semicolon:
47
+ AllowAsExpressionSeparator: true
48
+
49
+ Style/SpaceBeforeBlockBraces:
50
+ EnforcedStyle: no_space
51
+
52
+ Style/SpaceInsideHashLiteralBraces:
53
+ EnforcedStyle: no_space
54
+
55
+ Style/TrailingComma:
56
+ EnforcedStyleForMultiline: comma
data/.travis.yml CHANGED
@@ -11,7 +11,9 @@ rvm:
11
11
  - jruby-19mode
12
12
  - jruby-head
13
13
  - ree
14
- script: bundle exec rspec
14
+ script:
15
+ - bundle exec rspec
16
+ - '! bundle show rubocop || bundle exec rubocop' # run rubocop only if it is bundled
15
17
  before_install:
16
18
  - sudo apt-get update -qq
17
19
  - sudo apt-get install -qq advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
data/README.markdown CHANGED
@@ -1,3 +1,10 @@
1
+ [![Gem Version](https://img.shields.io/gem/v/image_optim.svg)](https://rubygems.org/gems/image_optim)
2
+ [![Build Status](https://img.shields.io/travis/toy/image_optim/master.svg)](https://travis-ci.org/toy/image_optim)
3
+ [![Code Climate](https://img.shields.io/codeclimate/github/toy/image_optim.svg)](https://codeclimate.com/github/toy/image_optim)
4
+ [![Dependency Status](https://img.shields.io/gemnasium/toy/image_optim.svg)](https://gemnasium.com/toy/image_optim)
5
+ [![Inch CI](http://inch-ci.org/github/toy/image_optim.svg?branch=master)](http://inch-ci.org/github/toy/image_optim)
6
+ [![Gittip](https://img.shields.io/gittip/toy.svg)](https://www.gittip.com/toy/)
7
+
1
8
  # image_optim
2
9
 
3
10
  Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities:
@@ -15,10 +22,7 @@ Optimize (lossless compress) images (jpeg, png, gif, svg) using external utiliti
15
22
 
16
23
  Based on [ImageOptim.app](http://imageoptim.com/).
17
24
 
18
- [![Gem Version](https://badge.fury.io/rb/image_optim.png)](http://badge.fury.io/rb/image_optim)
19
- [![Build Status](https://travis-ci.org/toy/image_optim.png?branch=master)](https://travis-ci.org/toy/image_optim)
20
- [![Code Climate](https://codeclimate.com/github/toy/image_optim.png)](https://codeclimate.com/github/toy/image_optim)
21
- [![Dependency Status](https://gemnasium.com/toy/image_optim.png)](https://gemnasium.com/toy/image_optim)
25
+ Documentation for [latest version](http://rubydoc.info/gems/image_optim/frames) and [master](http://rubydoc.info/github/toy/image_optim/master/frames).
22
26
 
23
27
  ## Gem installation
24
28
 
@@ -29,16 +33,19 @@ gem install image_optim
29
33
  ### Bundler
30
34
 
31
35
  Add to your `Gemfile`:
36
+
32
37
  ```ruby
33
38
  gem 'image_optim'
34
39
  ```
35
40
 
36
41
  With version:
42
+
37
43
  ```ruby
38
44
  gem 'image_optim', '~> 0.11'
39
45
  ```
40
46
 
41
47
  If you want to check latest changes:
48
+
42
49
  ```ruby
43
50
  gem 'image_optim', :git => 'git://github.com/toy/image_optim.git'
44
51
  ```
@@ -93,21 +100,27 @@ You will also need to install `jpegoptim` and `pngcrush` from source:
93
100
 
94
101
  #### jpegoptim
95
102
 
103
+ Replace `X.Y.Z` with latest version number from http://www.kokkonen.net/tjko/projects.html#jpegoptim.
104
+
96
105
  ```bash
106
+ JPEGOPTIM_VERSION=X.Y.Z
97
107
  cd /tmp
98
- curl -O http://www.kokkonen.net/tjko/src/jpegoptim-1.4.0.tar.gz
99
- tar zxf jpegoptim-1.4.0.tar.gz
100
- cd jpegoptim-1.4.0
108
+ curl -O http://www.kokkonen.net/tjko/src/jpegoptim-$JPEGOPTIM_VERSION.tar.gz
109
+ tar zxf jpegoptim-$JPEGOPTIM_VERSION.tar.gz
110
+ cd jpegoptim-$JPEGOPTIM_VERSION
101
111
  ./configure && make && make install
102
112
  ```
103
113
 
104
114
  #### pngcrush
105
115
 
116
+ Replace `X.Y.Z` with latest version number from http://sourceforge.net/projects/pmt/files/pngcrush/.
117
+
106
118
  ```bash
119
+ PNGCRUSH_VERSION=X.Y.Z
107
120
  cd /tmp
108
- curl -O http://iweb.dl.sourceforge.net/project/pmt/pngcrush/1.7.70/pngcrush-1.7.73.tar.gz
109
- tar zxf pngcrush-1.7.73.tar.gz
110
- cd pngcrush-1.7.73
121
+ curl -O http://iweb.dl.sourceforge.net/project/pmt/pngcrush/$PNGCRUSH_VERSION/pngcrush-$PNGCRUSH_VERSION.tar.gz
122
+ tar zxf pngcrush-$PNGCRUSH_VERSION.tar.gz
123
+ cd pngcrush-$PNGCRUSH_VERSION
111
124
  make && cp -f pngcrush /usr/local/bin
112
125
  ```
113
126
 
data/bin/image_optim CHANGED
@@ -6,7 +6,7 @@ require 'image_optim/runner'
6
6
  options = {}
7
7
 
8
8
  option_parser = OptionParser.new do |op|
9
- op.accept(ImageOptim::TrueFalseNil, OptionParser.top.atype[TrueClass][0].merge('nil' => nil)){ |arg, val| val }
9
+ ImageOptim::TrueFalseNil.add_to_option_parser(op)
10
10
 
11
11
  op.banner = <<-TEXT.gsub(/^\s*\|/, '')
12
12
  |#{ImageOptim.full_version}
@@ -16,17 +16,19 @@ option_parser = OptionParser.new do |op|
16
16
  |
17
17
  |Configuration will be read and prepanded to options from two paths:
18
18
  | #{ImageOptim::Config::GLOBAL_CONFIG_PATH}
19
- | #{ImageOptim::Config::LOCAL_CONFIG_PATH} (in current working directory)
19
+ | #{ImageOptim::Config::LOCAL_CONFIG_PATH}
20
20
  |
21
21
  TEXT
22
22
 
23
- op.on('-r', '-R', '--recursive', 'Recurively scan directories for images') do |recursive|
23
+ op.on('-r', '-R', '--recursive', 'Recurively scan directories '\
24
+ 'for images') do |recursive|
24
25
  options[:recursive] = recursive
25
26
  end
26
27
 
27
28
  op.separator nil
28
29
 
29
- op.on('--[no-]threads N', Integer, 'Number of threads or disable (defaults to number of processors)') do |threads|
30
+ op.on('--[no-]threads N', Integer, 'Number of threads or disable '\
31
+ '(defaults to number of processors)') do |threads|
30
32
  options[:threads] = threads
31
33
  end
32
34
 
@@ -64,13 +66,18 @@ option_parser = OptionParser.new do |op|
64
66
  when Array >= type
65
67
  [Array, 'a,b,c']
66
68
  else
67
- raise "Unknown type #{type}"
69
+ fail "Unknown type #{type}"
68
70
  end
69
71
 
70
- description = "#{option_definition.description.gsub(' - ', ' - ')} (defaults to #{default})"
71
- description = description.scan(/(.*?.{1,60})(?:\s|\z)/).flatten.join("\n ").split("\n")
72
+ description_lines = %W[
73
+ #{option_definition.description.gsub(' - ', ' - ')}
74
+ (defaults to #{default})
75
+ ].join(' ').
76
+ scan(/.*?.{1,60}(?:\s|\z)/).
77
+ join("\n ").
78
+ split("\n")
72
79
 
73
- op.on("--#{bin}-#{name} #{marking}", type, *description) do |value|
80
+ op.on("--#{bin}-#{name} #{marking}", type, *description_lines) do |value|
74
81
  options[bin] = {} unless options[bin].is_a?(Hash)
75
82
  options[bin][option_definition.name.to_sym] = value
76
83
  end
@@ -98,18 +105,21 @@ end
98
105
  begin
99
106
  args = ARGV.dup
100
107
 
101
- if args == %w[-v]
102
- args = %w[--version]
103
- end
108
+ # assume -v to be request to print version if it is the only argument
109
+ args = %w[--version] if args == %w[-v]
104
110
 
105
111
  option_parser.parse!(args)
106
- $stderr.puts ImageOptim.full_version if options[:verbose]
107
- ImageOptim::Runner.run!(args, options) or exit 1
112
+ if options[:verbose]
113
+ $stderr.puts ImageOptim.full_version
114
+ end
115
+ unless ImageOptim::Runner.run!(args, options)
116
+ abort
117
+ end
108
118
  rescue OptionParser::ParseError => e
109
- abort "#{e.to_s}\n\n#{option_parser.help}"
119
+ abort "#{e}\n\n#{option_parser.help}"
110
120
  rescue => e
111
121
  if options[:verbose]
112
- abort "#{e.to_s}\n#{e.backtrace.join("\n")}"
122
+ abort "#{e}\n#{e.backtrace.join("\n")}"
113
123
  else
114
124
  abort e.to_s
115
125
  end
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.13.3'
5
+ s.version = '0.14.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']
@@ -20,5 +20,8 @@ Gem::Specification.new do |s|
20
20
  s.add_dependency 'exifr', '~> 1.1.3'
21
21
  s.add_dependency 'progress', '~> 3.0.0'
22
22
  s.add_dependency 'in_threads', '~> 1.2.0'
23
- s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'rspec', '~> 3.0'
24
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.2')
25
+ s.add_development_dependency 'rubocop', '~> 0.24.1'
26
+ end
24
27
  end
data/lib/image_optim.rb CHANGED
@@ -7,6 +7,7 @@ require 'image_optim/worker'
7
7
  require 'in_threads'
8
8
  require 'shellwords'
9
9
 
10
+ # Main interface
10
11
  class ImageOptim
11
12
  # Nice level
12
13
  attr_reader :nice
@@ -15,9 +16,7 @@ class ImageOptim
15
16
  attr_reader :threads
16
17
 
17
18
  # Verbose output?
18
- def verbose?
19
- @verbose
20
- end
19
+ attr_reader :verbose
21
20
 
22
21
  # Initialize workers, specify options using worker underscored name:
23
22
  #
@@ -29,11 +28,13 @@ class ImageOptim
29
28
  #
30
29
  # ImageOptim.new(:advpng => {:level => 3}, :optipng => {:level => 2})
31
30
  #
32
- # use :threads to set number of parallel optimizers to run (passing true or nil determines number of processors, false disables parallel processing)
31
+ # use :threads to set number of parallel optimizers to run (passing true or
32
+ # nil determines number of processors, false disables parallel processing)
33
33
  #
34
34
  # ImageOptim.new(:threads => 8)
35
35
  #
36
- # use :nice to specify optimizers nice level (true or nil makes it 10, false makes it 0)
36
+ # use :nice to specify optimizers nice level (true or nil makes it 10, false
37
+ # makes it 0)
37
38
  #
38
39
  # ImageOptim.new(:nice => 20)
39
40
  def initialize(options = {})
@@ -42,7 +43,7 @@ class ImageOptim
42
43
  @threads = config.threads
43
44
  @verbose = config.verbose
44
45
 
45
- if verbose?
46
+ if verbose
46
47
  $stderr << config
47
48
  $stderr << "Nice level: #{nice}\n"
48
49
  $stderr << "Using threads: #{threads}\n"
@@ -50,17 +51,9 @@ class ImageOptim
50
51
 
51
52
  @bin_resolver = BinResolver.new(self)
52
53
 
53
- @workers_by_format = {}
54
- Worker.klasses.each do |klass|
55
- if worker_options = config.for_worker(klass)
56
- worker = klass.new(self, worker_options)
57
- worker.image_formats.each do |format|
58
- @workers_by_format[format] ||= []
59
- @workers_by_format[format] << worker
60
- end
61
- end
54
+ @workers_by_format = create_workers_by_format do |klass|
55
+ config.for_worker(klass)
62
56
  end
63
- @workers_by_format.values.each(&:sort!)
64
57
 
65
58
  config.assert_no_unused_options!
66
59
  end
@@ -70,30 +63,29 @@ class ImageOptim
70
63
  @workers_by_format[ImagePath.convert(path).format]
71
64
  end
72
65
 
73
- # Optimize one file, return new path as OptimizedImagePath or nil if optimization failed
66
+ # Optimize one file, return new path as OptimizedImagePath or nil if
67
+ # optimization failed
74
68
  def optimize_image(original)
75
69
  original = ImagePath.convert(original)
76
- if workers = workers_for_image(original)
77
- handler = Handler.new(original)
78
- workers.each do |worker|
79
- handler.process do |src, dst|
80
- worker.optimize(src, dst)
81
- end
82
- end
83
- handler.cleanup
84
- if handler.result
85
- ImagePath::Optimized.new(handler.result, original)
70
+ return unless (workers = workers_for_image(original))
71
+ handler = Handler.new(original)
72
+ workers.each do |worker|
73
+ handler.process do |src, dst|
74
+ worker.optimize(src, dst)
86
75
  end
87
76
  end
77
+ handler.cleanup
78
+ return unless handler.result
79
+ ImagePath::Optimized.new(handler.result, original)
88
80
  end
89
81
 
90
- # Optimize one file in place, return original as OptimizedImagePath or nil if optimization failed
82
+ # Optimize one file in place, return original as OptimizedImagePath or nil if
83
+ # optimization failed
91
84
  def optimize_image!(original)
92
85
  original = ImagePath.convert(original)
93
- if result = optimize_image(original)
94
- result.replace(original)
95
- ImagePath::Optimized.new(original, result.original_size)
96
- end
86
+ return unless (result = optimize_image(original))
87
+ result.replace(original)
88
+ ImagePath::Optimized.new(original, result.original_size)
97
89
  end
98
90
 
99
91
  # Optimize image data, return new data or nil if optimization failed
@@ -105,28 +97,31 @@ class ImageOptim
105
97
  temp.write(original_data)
106
98
  temp.close
107
99
 
108
- if result = optimize_image(temp.path)
100
+ if (result = optimize_image(temp.path))
109
101
  result.open('rb', &:read)
110
102
  end
111
103
  end
112
104
  end
113
105
 
114
106
  # Optimize multiple images
115
- # if block given yields path and result for each image and returns array of yield results
107
+ # if block given yields path and result for each image and returns array of
108
+ # yield results
116
109
  # else return array of results
117
110
  def optimize_images(paths, &block)
118
111
  run_method_for(paths, :optimize_image, &block)
119
112
  end
120
113
 
121
114
  # Optimize multiple images in place
122
- # if block given yields path and result for each image and returns array of yield results
115
+ # if block given yields path and result for each image and returns array of
116
+ # yield results
123
117
  # else return array of results
124
118
  def optimize_images!(paths, &block)
125
119
  run_method_for(paths, :optimize_image!, &block)
126
120
  end
127
121
 
128
122
  # Optimize multiple image datas
129
- # if block given yields original and result for each image data and returns array of yield results
123
+ # if block given yields original and result for each image data and returns
124
+ # array of yield results
130
125
  # else return array of results
131
126
  def optimize_images_data(datas, &block)
132
127
  run_method_for(datas, :optimize_image_data, &block)
@@ -156,7 +151,8 @@ class ImageOptim
156
151
  !!workers_for_image(path)
157
152
  end
158
153
 
159
- # Check existance of binary, create symlink if ENV contains path for key XXX_BIN where XXX is upper case bin name
154
+ # Check existance of binary, create symlink if ENV contains path for key
155
+ # XXX_BIN where XXX is upper case bin name
160
156
  def resolve_bin!(bin)
161
157
  @bin_resolver.resolve!(bin)
162
158
  end
@@ -168,6 +164,20 @@ class ImageOptim
168
164
 
169
165
  private
170
166
 
167
+ # Create hash with format mapped to list of workers sorted by run order
168
+ def create_workers_by_format(&options_proc)
169
+ by_format = {}
170
+ Worker.klasses.each do |klass|
171
+ next unless (options = options_proc[klass])
172
+ worker = klass.new(self, options)
173
+ worker.image_formats.each do |format|
174
+ by_format[format] ||= []
175
+ by_format[format] << worker
176
+ end
177
+ end
178
+ by_format.each{ |_format, workers| workers.sort! }
179
+ end
180
+
171
181
  # Run method for each path and yield each path and result if block given
172
182
  def run_method_for(paths, method_name, &block)
173
183
  apply_threading(paths).map do |path|
@@ -7,7 +7,13 @@ class ImageOptim
7
7
  class BinNotFoundError < StandardError; end
8
8
  class BadBinVersion < StandardError; end
9
9
 
10
+ # Handles resolving binaries and checking versions
11
+ #
12
+ # If there is an environment variable XXX_BIN when resolbing xxx, then a
13
+ # symlink to binary will be created in a temporary directory which will be
14
+ # added to PATH
10
15
  class BinResolver
16
+ # Holds name and version of an executable
11
17
  class Bin
12
18
  attr_reader :name, :version
13
19
  def initialize(name, version)
@@ -31,8 +37,9 @@ class ImageOptim
31
37
  name = name.to_sym
32
38
 
33
39
  resolving(name) do
34
- if bin = resolve?(name) && Bin.new(name, version(name))
35
- $stderr << "Resolved #{bin}\n" if @image_optim.verbose?
40
+ bin = Bin.new(name, version(name)) if resolve?(name)
41
+ if bin && @image_optim.verbose
42
+ $stderr << "Resolved #{bin}\n"
36
43
  end
37
44
  @bins[name] = bin
38
45
  end
@@ -40,7 +47,7 @@ class ImageOptim
40
47
  if @bins[name]
41
48
  check!(@bins[name])
42
49
  else
43
- raise BinNotFoundError, "`#{name}` not found"
50
+ fail BinNotFoundError, "`#{name}` not found"
44
51
  end
45
52
  end
46
53
 
@@ -53,17 +60,14 @@ class ImageOptim
53
60
  private
54
61
 
55
62
  def resolving(name)
56
- unless @bins.include?(name)
57
- @lock.synchronize do
58
- unless @bins.include?(name)
59
- yield
60
- end
61
- end
63
+ return if @bins.include?(name)
64
+ @lock.synchronize do
65
+ yield unless @bins.include?(name)
62
66
  end
63
67
  end
64
68
 
65
69
  def resolve?(name)
66
- if path = ENV["#{name}_bin".upcase]
70
+ if (path = ENV["#{name}_bin".upcase])
67
71
  unless @dir
68
72
  @dir = FSPath.temp_dir
69
73
  at_exit{ FileUtils.remove_entry_secure @dir }
@@ -91,7 +95,8 @@ class ImageOptim
91
95
  when :pngcrush
92
96
  capture_output("#{name} -version 2>&1")[/\d+(\.\d+){1,}/]
93
97
  when :pngout
94
- date_str = capture_output("#{name} 2>&1")[/[A-Z][a-z]{2} (?: |\d)\d \d{4}/]
98
+ date_regexp = /[A-Z][a-z]{2} (?: |\d)\d \d{4}/
99
+ date_str = capture_output("#{name} 2>&1")[date_regexp]
95
100
  Date.parse(date_str).strftime('%Y%m%d')
96
101
  end
97
102
  end
@@ -102,7 +107,7 @@ class ImageOptim
102
107
  when :pngcrush
103
108
  case bin.version
104
109
  when c = is.between?('1.7.60', '1.7.65')
105
- raise BadBinVersion, "`#{bin}` (#{c}) is known to produce broken pngs"
110
+ fail BadBinVersion, "`#{bin}` (#{c}) is known to produce broken pngs"
106
111
  end
107
112
  when :advpng
108
113
  case bin.version