image_optim 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,153 @@
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'rspec'
3
+ require 'image_optim/config'
4
+
5
+ class ImageOptim
6
+ describe Config do
7
+ before do
8
+ Config.stub(:global => {}, :local => {})
9
+ end
10
+
11
+ describe "assert_no_unused_options!" do
12
+ it "should not raise when no unused options" do
13
+ config = Config.new({})
14
+ config.assert_no_unused_options!
15
+ end
16
+
17
+ it "should raise when there are unused options" do
18
+ config = Config.new({:unused => true})
19
+ proc {
20
+ config.assert_no_unused_options!
21
+ }.should raise_error(ConfigurationError)
22
+ end
23
+ end
24
+
25
+ describe "nice" do
26
+ it "should be 10 by default" do
27
+ config = Config.new({})
28
+ config.nice.should == 10
29
+ end
30
+
31
+ it "should be 0 if disabled" do
32
+ config = Config.new({:nice => false})
33
+ config.nice.should == 0
34
+ end
35
+
36
+ it "should convert value to number" do
37
+ config = Config.new({:nice => '13'})
38
+ config.nice.should == 13
39
+ end
40
+ end
41
+
42
+ describe "threads" do
43
+ it "should be processor_count by default" do
44
+ config = Config.new({})
45
+ config.stub(:processor_count).and_return(13)
46
+ config.threads.should == 13
47
+ end
48
+
49
+ it "should be 1 if disabled" do
50
+ config = Config.new({:threads => false})
51
+ config.threads.should == 1
52
+ end
53
+
54
+ it "should convert value to number and limit to 1..16" do
55
+ config = Config.new({:threads => '616'})
56
+ config.threads.should == 16
57
+ end
58
+ end
59
+
60
+ describe "for_worker" do
61
+ class Abc < Worker
62
+ def image_formats; []; end
63
+ end
64
+
65
+ it "should return empty hash by default" do
66
+ config = Config.new({})
67
+ config.for_worker(Abc).should == {}
68
+ end
69
+
70
+ it "should return passed hash" do
71
+ config = Config.new({:abc => {:option => true}})
72
+ config.for_worker(Abc).should == {:option => true}
73
+ end
74
+
75
+ it "should return passed false" do
76
+ config = Config.new({:abc => false})
77
+ config.for_worker(Abc).should == false
78
+ end
79
+
80
+ it "should raise on unknown optino" do
81
+ config = Config.new({:abc => 13})
82
+ proc {
83
+ config.for_worker(Abc)
84
+ }.should raise_error(ConfigurationError)
85
+ end
86
+ end
87
+
88
+ describe 'class methods' do
89
+ before do
90
+ Config.unstub(:global)
91
+ Config.unstub(:local)
92
+ end
93
+
94
+ describe 'global' do
95
+ it "should return empty hash for global config if it does not exists" do
96
+ File.should_receive(:file?).with(Config::GLOBAL_CONFIG_PATH).and_return(false)
97
+ Config.should_not_receive(:read)
98
+
99
+ Config.global.should == {}
100
+ end
101
+
102
+ it "should read global config if it exists" do
103
+ File.should_receive(:file?).with(Config::GLOBAL_CONFIG_PATH).and_return(true)
104
+ Config.should_receive(:read).with(Config::GLOBAL_CONFIG_PATH).and_return({:config => true})
105
+
106
+ Config.global.should == {:config => true}
107
+ end
108
+ end
109
+
110
+ describe 'local' do
111
+ it "should return empty hash for local config if it does not exists" do
112
+ File.should_receive(:file?).with(Config::LOCAL_CONFIG_PATH).and_return(false)
113
+ Config.should_not_receive(:read)
114
+
115
+ Config.local.should == {}
116
+ end
117
+
118
+ it "should read local config if it exists" do
119
+ File.should_receive(:file?).with(Config::LOCAL_CONFIG_PATH).and_return(true)
120
+ Config.should_receive(:read).with(Config::LOCAL_CONFIG_PATH).and_return({:config => true})
121
+
122
+ Config.local.should == {:config => true}
123
+ end
124
+ end
125
+
126
+ describe 'read' do
127
+ it "should return hash with deep symbolised keys from yaml file reader" do
128
+ path = double(:path)
129
+ YAML.should_receive(:load_file).with(path).and_return({'config' => {'this' => true}})
130
+
131
+ Config.instance_eval{ read(path) }.should == {:config => {:this => true}}
132
+ end
133
+
134
+ it "should warn and return an empty hash if yaml file reader returns non hash" do
135
+ path = double(:path)
136
+ YAML.should_receive(:load_file).with(path).and_return([:config])
137
+ Config.should_receive(:warn)
138
+
139
+ Config.instance_eval{ read(path) }.should == {}
140
+ end
141
+
142
+ it "should warn and return an empty hash if yaml file reader raises exception" do
143
+ path = double(:path)
144
+ YAML.should_receive(:load_file).with(path).and_raise
145
+ Config.should_receive(:warn)
146
+
147
+ Config.instance_eval{ read(path) }.should == {}
148
+ end
149
+ end
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,44 @@
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'rspec'
3
+ require 'image_optim/handler'
4
+
5
+ describe ImageOptim::Handler do
6
+ it "should use original as source for first conversion and two temp files for further conversions" do
7
+ original = double(:original)
8
+ original.stub(:temp_path){ raise 'temp_path called unexpectedly' }
9
+
10
+ handler = ImageOptim::Handler.new(original)
11
+
12
+ original.should_receive(:temp_path).once.and_return(temp_a = double(:temp_a))
13
+ handler.process do |src, dst|
14
+ [src, dst].should == [original, temp_a]; false
15
+ end
16
+ handler.result.should == nil
17
+
18
+ handler.process do |src, dst|
19
+ [src, dst].should == [original, temp_a]; true
20
+ end
21
+ handler.result.should == temp_a
22
+
23
+ original.should_receive(:temp_path).once.and_return(temp_b = double(:temp_b))
24
+ handler.process do |src, dst|
25
+ [src, dst].should == [temp_a, temp_b]; false
26
+ end
27
+ handler.result.should == temp_a
28
+
29
+ handler.process do |src, dst|
30
+ [src, dst].should == [temp_a, temp_b]; true
31
+ end
32
+ handler.result.should == temp_b
33
+
34
+ handler.process do |src, dst|
35
+ [src, dst].should == [temp_b, temp_a]; true
36
+ end
37
+ handler.result.should == temp_a
38
+
39
+ handler.process do |src, dst|
40
+ [src, dst].should == [temp_a, temp_b]; true
41
+ end
42
+ handler.result.should == temp_b
43
+ end
44
+ end
@@ -0,0 +1,74 @@
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'rspec'
3
+ require 'image_optim/hash_helpers'
4
+
5
+ describe ImageOptim::HashHelpers do
6
+ HH = ImageOptim::HashHelpers
7
+
8
+ it "should deep stringify hash keys" do
9
+ HH.deep_stringify_keys({
10
+ :a => 1,
11
+ :b => {
12
+ :c => :a,
13
+ :d => {},
14
+ },
15
+ }).should == {
16
+ 'a' => 1,
17
+ 'b' => {
18
+ 'c' => :a,
19
+ 'd' => {},
20
+ },
21
+ }
22
+ end
23
+
24
+ it "should deep symbolise hash keys" do
25
+ HH.deep_symbolise_keys({
26
+ 'a' => 1,
27
+ 'b' => {
28
+ 'c' => 'a',
29
+ 'd' => {},
30
+ },
31
+ }).should == {
32
+ :a => 1,
33
+ :b => {
34
+ :c => 'a',
35
+ :d => {},
36
+ },
37
+ }
38
+ end
39
+
40
+ it "should deep merge hashes" do
41
+ HH.deep_merge({
42
+ :a => {
43
+ :b => 1,
44
+ :c => {
45
+ :d => 2,
46
+ :e => {
47
+ :f => true
48
+ },
49
+ },
50
+ },
51
+ :y => 10,
52
+ }, {
53
+ :a => {
54
+ :b => 2,
55
+ :c => {
56
+ :d => 3,
57
+ :e => false,
58
+ },
59
+ },
60
+ :z => 20,
61
+ }).should == {
62
+ :a => {
63
+ :b => 2,
64
+ :c => {
65
+ :d => 3,
66
+ :e => false,
67
+ },
68
+ },
69
+ :y => 10,
70
+ :z => 20,
71
+ }
72
+ end
73
+
74
+ end
@@ -0,0 +1,39 @@
1
+ $:.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'rspec'
3
+ require 'image_optim/image_path'
4
+
5
+ describe ImageOptim::ImagePath do
6
+ ImagePath = ImageOptim::ImagePath
7
+
8
+ describe "convert" do
9
+ it "should return ImagePath for string" do
10
+ path = 'a'
11
+
12
+ ImagePath.convert(path).should be_a(ImageOptim::ImagePath)
13
+ ImagePath.convert(path).should eq(ImageOptim::ImagePath.new(path))
14
+
15
+ ImagePath.convert(path).should_not eq(path)
16
+ ImagePath.convert(path).should_not be(path)
17
+ end
18
+
19
+ it "should return ImagePath for Pathname" do
20
+ pathname = Pathname.new('a')
21
+
22
+ ImagePath.convert(pathname).should be_a(ImageOptim::ImagePath)
23
+ ImagePath.convert(pathname).should eq(ImageOptim::ImagePath.new(pathname))
24
+
25
+ ImagePath.convert(pathname).should eq(pathname)
26
+ ImagePath.convert(pathname).should_not be(pathname)
27
+ end
28
+
29
+ it "should return same instance for ImagePath" do
30
+ image_path = ImageOptim::ImagePath.new('a')
31
+
32
+ ImagePath.convert(image_path).should be_a(ImageOptim::ImagePath)
33
+ ImagePath.convert(image_path).should eq(ImageOptim::ImagePath.new(image_path))
34
+
35
+ ImagePath.convert(image_path).should eq(image_path)
36
+ ImagePath.convert(image_path).should be(image_path)
37
+ end
38
+ end
39
+ end
@@ -1,4 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'rspec'
3
3
  require 'image_optim'
4
4
  require 'tempfile'
@@ -39,14 +39,11 @@ ImageOptim::ImagePath.class_eval do
39
39
  end
40
40
  end
41
41
 
42
- def with_env(key, value)
43
- saved, ENV[key] = ENV[key], value
44
- yield
45
- ensure
46
- ENV[key] = saved
47
- end
48
-
49
42
  describe ImageOptim do
43
+ before do
44
+ ImageOptim::Config.stub(:global => {}, :local => {})
45
+ end
46
+
50
47
  describe "isolated" do
51
48
  describe "optimize" do
52
49
  TEST_IMAGES.each do |original|
@@ -56,7 +53,7 @@ describe ImageOptim do
56
53
  Tempfile.reset_init_count
57
54
  image_optim = ImageOptim.new
58
55
  optimized_image = image_optim.optimize_image(copy)
59
- optimized_image.should be_a(ImageOptim::ImagePath)
56
+ expect(optimized_image).to be_a(ImageOptim::ImagePath::Optimized)
60
57
  optimized_image.size.should be_in_range(1...original.size)
61
58
  optimized_image.read.should_not == original.read
62
59
  copy.read.should == original.read
@@ -90,6 +87,18 @@ describe ImageOptim do
90
87
  end
91
88
  end
92
89
 
90
+ describe "optimize image data" do
91
+ TEST_IMAGES.each do |original|
92
+ it "should optimize #{original}" do
93
+ image_optim = ImageOptim.new
94
+ optimized_data = image_optim.optimize_image_data(original.read)
95
+ optimized_data.should == image_optim.optimize_image(original.temp_copy).read
96
+
97
+ image_optim.optimize_image_data(optimized_data).should be_nil
98
+ end
99
+ end
100
+ end
101
+
93
102
  describe "stop optimizing" do
94
103
  TEST_IMAGES.each do |original|
95
104
  it "should stop optimizing #{original}" do
@@ -111,7 +120,7 @@ describe ImageOptim do
111
120
  copies = TEST_IMAGES.map(&:temp_copy)
112
121
  optimized_images = ImageOptim.optimize_images(copies)
113
122
  TEST_IMAGES.zip(copies, optimized_images).each do |original, copy, optimized_image|
114
- optimized_image.should be_a(ImageOptim::ImagePath)
123
+ expect(optimized_image).to be_a(ImageOptim::ImagePath::Optimized)
115
124
  optimized_image.size.should be_in_range(1...original.size)
116
125
  optimized_image.read.should_not == original.read
117
126
  copy.read.should == original.read
@@ -126,6 +135,13 @@ describe ImageOptim do
126
135
  copy.read.should_not == original.read
127
136
  end
128
137
  end
138
+
139
+ it "should optimize datas" do
140
+ optimized_images_datas = ImageOptim.optimize_images_data(TEST_IMAGES.map(&:read))
141
+ TEST_IMAGES.zip(optimized_images_datas).each do |original, optimized_image_data|
142
+ optimized_image_data.should == ImageOptim.optimize_image(original.temp_copy).read
143
+ end
144
+ end
129
145
  end
130
146
 
131
147
  describe "unsupported" do
@@ -192,90 +208,6 @@ describe ImageOptim do
192
208
  end
193
209
  end
194
210
 
195
- describe "resolve bin" do
196
- it "should resolve bin in path" do
197
- with_env 'LS_BIN', nil do
198
- image_optim = ImageOptim.new
199
- image_optim.should_receive(:bin_accessible?).with(:ls).once.and_return(true)
200
- FSPath.should_not_receive(:temp_dir)
201
-
202
- 5.times do
203
- image_optim.resolve_bin!(:ls).should be_true
204
- end
205
- end
206
- end
207
-
208
- it "should resolve bin specified in ENV" do
209
- path = (FSPath(__FILE__).dirname / '../bin/image_optim').relative_path_from(Dir.pwd).to_s
210
- with_env 'IMAGE_OPTIM_BIN', path do
211
- tmpdir = double(:tmpdir)
212
- symlink = double(:symlink)
213
-
214
- image_optim = ImageOptim.new
215
- image_optim.should_receive(:bin_accessible?).with(symlink).once.and_return(true)
216
- FSPath.should_receive(:temp_dir).once.and_return(tmpdir)
217
- tmpdir.should_receive(:/).with(:image_optim).once.and_return(symlink)
218
- symlink.should_receive(:make_symlink).with(File.expand_path(path)).once
219
-
220
- at_exit_blocks = []
221
- image_optim.should_receive(:at_exit).twice do |&block|
222
- at_exit_blocks.unshift(block)
223
- end
224
-
225
- 5.times do
226
- image_optim.resolve_bin!(:image_optim).should be_true
227
- end
228
-
229
- FileUtils.should_receive(:remove_entry_secure).with(tmpdir)
230
- symlink.should_receive(:unlink)
231
- at_exit_blocks.each(&:call)
232
- end
233
- end
234
-
235
- it "should raise on failure to resolve bin" do
236
- with_env 'SHOULD_NOT_EXIST_BIN', nil do
237
- image_optim = ImageOptim.new
238
- image_optim.should_receive(:bin_accessible?).with(:should_not_exist).once.and_return(false)
239
- FSPath.should_not_receive(:temp_dir)
240
-
241
- 5.times do
242
- expect do
243
- image_optim.resolve_bin!(:should_not_exist)
244
- end.to raise_error ImageOptim::BinNotFoundError
245
- end
246
- end
247
- end
248
-
249
- it "should raise on failure to resolve bin specified in ENV" do
250
- path = (FSPath(__FILE__).dirname / '../bin/should_not_exist_bin').relative_path_from(Dir.pwd).to_s
251
- with_env 'SHOULD_NOT_EXIST_BIN', path do
252
- tmpdir = double(:tmpdir)
253
- symlink = double(:symlink)
254
-
255
- image_optim = ImageOptim.new
256
- image_optim.should_receive(:bin_accessible?).with(symlink).once.and_return(false)
257
- FSPath.should_receive(:temp_dir).once.and_return(tmpdir)
258
- tmpdir.should_receive(:/).with(:should_not_exist).once.and_return(symlink)
259
- symlink.should_receive(:make_symlink).with(File.expand_path(path)).once
260
-
261
- at_exit_blocks = []
262
- image_optim.should_receive(:at_exit).twice do |&block|
263
- at_exit_blocks.unshift(block)
264
- end
265
-
266
- 5.times do
267
- expect do
268
- image_optim.resolve_bin!(:should_not_exist)
269
- end.to raise_error ImageOptim::BinNotFoundError
270
- end
271
-
272
- FileUtils.should_receive(:remove_entry_secure).with(tmpdir)
273
- symlink.should_receive(:unlink)
274
- at_exit_blocks.each(&:call)
275
- end
276
- end
277
- end
278
-
279
211
  describe "auto orienting" do
280
212
  original = ImageOptim::ImagePath.new(__FILE__).dirname / 'images/orient/original.jpg'
281
213
  ImageOptim::ImagePath.new(__FILE__).dirname.glob('images/orient/?.jpg').each do |jpg|
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.9.1
4
+ version: 0.10.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: 2013-08-20 00:00:00.000000000 Z
11
+ date: 2013-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.5
19
+ version: 2.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.5
26
+ version: 2.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: image_size
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -106,13 +106,21 @@ files:
106
106
  - Gemfile
107
107
  - LICENSE.txt
108
108
  - README.markdown
109
- - TODO
110
109
  - bin/image_optim
111
110
  - image_optim.gemspec
112
111
  - lib/image_optim.rb
112
+ - lib/image_optim/bin_not_found_error.rb
113
+ - lib/image_optim/bin_resolver.rb
114
+ - lib/image_optim/config.rb
115
+ - lib/image_optim/configuration_error.rb
116
+ - lib/image_optim/handler.rb
117
+ - lib/image_optim/hash_helpers.rb
113
118
  - lib/image_optim/image_path.rb
114
119
  - lib/image_optim/option_definition.rb
115
120
  - lib/image_optim/option_helpers.rb
121
+ - lib/image_optim/railtie.rb
122
+ - lib/image_optim/runner.rb
123
+ - lib/image_optim/true_false_nil.rb
116
124
  - lib/image_optim/worker.rb
117
125
  - lib/image_optim/worker/advpng.rb
118
126
  - lib/image_optim/worker/gifsicle.rb
@@ -122,7 +130,12 @@ files:
122
130
  - lib/image_optim/worker/optipng.rb
123
131
  - lib/image_optim/worker/pngcrush.rb
124
132
  - lib/image_optim/worker/pngout.rb
125
- - script/options_for_readme
133
+ - script/update_worker_options_in_readme
134
+ - spec/image_optim/bin_resolver_spec.rb
135
+ - spec/image_optim/config_spec.rb
136
+ - spec/image_optim/handler_spec.rb
137
+ - spec/image_optim/hash_helpers_spec.rb
138
+ - spec/image_optim/image_path_spec.rb
126
139
  - spec/image_optim_spec.rb
127
140
  - spec/images/comparison.png
128
141
  - spec/images/decompressed.jpeg
@@ -170,6 +183,11 @@ specification_version: 4
170
183
  summary: Optimize (lossless compress) images (jpeg, png, gif) using external utilities
171
184
  (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout)
172
185
  test_files:
186
+ - spec/image_optim/bin_resolver_spec.rb
187
+ - spec/image_optim/config_spec.rb
188
+ - spec/image_optim/handler_spec.rb
189
+ - spec/image_optim/hash_helpers_spec.rb
190
+ - spec/image_optim/image_path_spec.rb
173
191
  - spec/image_optim_spec.rb
174
192
  - spec/images/comparison.png
175
193
  - spec/images/decompressed.jpeg
data/TODO DELETED
@@ -1,12 +0,0 @@
1
- preserve color (leave_color branch)
2
- preserve all extra stuff
3
- global level of optimization #10
4
- timeout workers?
5
- based on file size?
6
- fail worker instead of process on bin not present?
7
- preserve time/attrs option?
8
- file based config
9
- http://www.erickcantwell.com/code/config.rb
10
- https://github.com/derks/ruby-parseconfig
11
- http://stick.gk2.sk/2009/03/the-ugly-duckling-called-xdg_config_home/
12
- http://css-ig.net/png-tools-overview
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- $: << File.expand_path('../../lib', __FILE__)
5
-
6
- require 'image_optim'
7
-
8
- ImageOptim::Worker.klasses.each_with_index do |klass, i|
9
- puts "### #{klass.bin_sym}"
10
- klass.option_definitions.each do |option_definition|
11
- puts "* `:#{option_definition.name}` — #{option_definition.description} *(defaults to #{option_definition.default})*"
12
- end
13
- puts
14
- end