image_resizer 0.1.4

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.
Files changed (43) hide show
  1. data/.rspec +1 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +45 -0
  5. data/LICENSE +22 -0
  6. data/README.md +56 -0
  7. data/Rakefile +53 -0
  8. data/VERSION +1 -0
  9. data/image_resizer.gemspec +93 -0
  10. data/lib/image_resizer/analyzer.rb +51 -0
  11. data/lib/image_resizer/configurable.rb +206 -0
  12. data/lib/image_resizer/encoder.rb +55 -0
  13. data/lib/image_resizer/has_filename.rb +24 -0
  14. data/lib/image_resizer/loggable.rb +28 -0
  15. data/lib/image_resizer/processor.rb +220 -0
  16. data/lib/image_resizer/shell.rb +48 -0
  17. data/lib/image_resizer/temp_object.rb +216 -0
  18. data/lib/image_resizer/utils.rb +44 -0
  19. data/lib/image_resizer.rb +10 -0
  20. data/samples/DSC02119.JPG +0 -0
  21. data/samples/a.jp2 +0 -0
  22. data/samples/beach.jpg +0 -0
  23. data/samples/beach.png +0 -0
  24. data/samples/egg.png +0 -0
  25. data/samples/landscape.png +0 -0
  26. data/samples/round.gif +0 -0
  27. data/samples/sample.docx +0 -0
  28. data/samples/taj.jpg +0 -0
  29. data/samples/white pixel.png +0 -0
  30. data/spec/image_resizer/analyzer_spec.rb +78 -0
  31. data/spec/image_resizer/configurable_spec.rb +479 -0
  32. data/spec/image_resizer/encoder_spec.rb +41 -0
  33. data/spec/image_resizer/has_filename_spec.rb +88 -0
  34. data/spec/image_resizer/loggable_spec.rb +80 -0
  35. data/spec/image_resizer/processor_spec.rb +590 -0
  36. data/spec/image_resizer/shell_spec.rb +34 -0
  37. data/spec/image_resizer/temp_object_spec.rb +442 -0
  38. data/spec/spec_helper.rb +61 -0
  39. data/spec/support/argument_matchers.rb +19 -0
  40. data/spec/support/image_matchers.rb +58 -0
  41. data/spec/support/simple_matchers.rb +53 -0
  42. data/tmp/test_file +1 -0
  43. metadata +147 -0
@@ -0,0 +1,479 @@
1
+ require 'spec_helper'
2
+
3
+ describe ImageResizer::Configurable do
4
+
5
+ before(:each) do
6
+ class Car
7
+ include ImageResizer::Configurable
8
+ configurable_attr :colour
9
+ configurable_attr :top_speed, 216
10
+ def self.other_thing=(thing); end
11
+ end
12
+ @car = Car.new
13
+ end
14
+
15
+ describe "setup" do
16
+ it "should provide attr_readers for configurable attributes" do
17
+ @car.should respond_to(:colour)
18
+ end
19
+
20
+ it "should provide attr_writers for configurable attributes" do
21
+ @car.colour = 'verde'
22
+ @car.colour.should == 'verde'
23
+ end
24
+
25
+ it "should set default values for configurable attributes" do
26
+ @car.top_speed.should == 216
27
+ end
28
+
29
+ it "should set the default as nil if not specified" do
30
+ @car.colour.should be_nil
31
+ end
32
+
33
+ it "should allow setting to nil" do
34
+ @car.top_speed = nil
35
+ @car.top_speed.should be_nil
36
+ end
37
+
38
+ it "should allow specifying configurable attrs as strings" do
39
+ class Bike
40
+ include ImageResizer::Configurable
41
+ configurable_attr 'colour', 'rude'
42
+ end
43
+ Bike.new.colour.should == 'rude'
44
+ end
45
+ end
46
+
47
+ describe "configuring" do
48
+ it "should allow you to change values" do
49
+ @car.configure do |c|
50
+ c.colour = 'red'
51
+ end
52
+ @car.colour.should == 'red'
53
+ end
54
+
55
+ it "should not allow you to call other methods on the object via the configuration" do
56
+ lambda{
57
+ @car.configure do |c|
58
+ c.other_thing = 5
59
+ end
60
+ }.should raise_error(ImageResizer::Configurable::BadConfigAttribute)
61
+ end
62
+
63
+ it "should return itself" do
64
+ @car.configure{|c|}.should == @car
65
+ end
66
+ end
67
+
68
+ describe "getting configuration" do
69
+ it "should return the configuration when nothing is set" do
70
+ @car.configuration.should == {}
71
+ end
72
+ it "should return the configuration when something is set" do
73
+ @car.top_speed = 10
74
+ @car.configuration.should == {:top_speed => 10}
75
+ end
76
+ end
77
+
78
+ describe "multiple objects" do
79
+ it "should return the default configuration" do
80
+ Car.default_configuration.should == {:colour => nil, :top_speed => 216}
81
+ end
82
+ it "should allow instances to be configured differently" do
83
+ car1 = Car.new
84
+ car1.configure{|c| c.colour = 'green'}
85
+ car2 = Car.new
86
+ car2.configure{|c| c.colour = 'yellow'}
87
+ car1.configuration.should == {:colour => 'green'}
88
+ car2.configuration.should == {:colour => 'yellow'}
89
+ end
90
+ end
91
+
92
+ describe "lazy attributes" do
93
+ before(:each) do
94
+ cow = @cow = mock('cow')
95
+ class Lazy; end
96
+ Lazy.class_eval do
97
+ include ImageResizer::Configurable
98
+ configurable_attr(:sound){ cow.moo }
99
+ end
100
+ @lazy = Lazy.new
101
+ end
102
+ it "should not call the block if the configurable attribute is set to something else" do
103
+ @cow.should_not_receive(:moo)
104
+ @lazy.configure{|c| c.sound = 'baa' }
105
+ @lazy.sound.should == 'baa'
106
+ end
107
+ it "should call the block if it's not been changed, once it's accessed" do
108
+ @cow.should_receive(:moo).and_return('mooo!')
109
+ @lazy.sound.should == 'mooo!'
110
+ end
111
+ it "should not call the block when accessed again" do
112
+ @cow.should_receive(:moo).exactly(:once).and_return('mooo!')
113
+ @lazy.sound.should == 'mooo!'
114
+ @lazy.sound.should == 'mooo!'
115
+ end
116
+ it "should not call an explicitly passed in proc" do
117
+ @lazy.configure{|c| c.sound = lambda{ @cow.fart }}
118
+ @lazy.sound.should be_a(Proc)
119
+ end
120
+ end
121
+
122
+ describe "configuration method" do
123
+
124
+ before(:each) do
125
+ class ClassWithMethod
126
+ include ImageResizer::Configurable
127
+ def add_thing(thing)
128
+ 'poo'
129
+ end
130
+ def remove_thing(thing)
131
+ 'bum'
132
+ end
133
+ configuration_method :add_thing, :remove_thing
134
+ end
135
+ @thing = ClassWithMethod.new
136
+ end
137
+
138
+ it "should allow calling the method through 'configure'" do
139
+ @thing.configure do |c|
140
+ c.add_thing('duck')
141
+ c.remove_thing('dog')
142
+ end
143
+ end
144
+
145
+ end
146
+
147
+ describe "nested configurable objects" do
148
+
149
+ before(:each) do
150
+ class NestedThing
151
+ include ImageResizer::Configurable
152
+ configurable_attr :age, 29
153
+ def some_method(val)
154
+ @some_thing = val
155
+ end
156
+ configuration_method :some_method
157
+ attr_reader :some_thing
158
+ end
159
+
160
+ class Car
161
+ def nested_thing
162
+ @nested_thing ||= NestedThing.new
163
+ end
164
+ nested_configurable :nested_thing
165
+ end
166
+
167
+ @car.configure do |c|
168
+ c.nested_thing.configure do |nt|
169
+ nt.age = 50
170
+ nt.some_method('yo')
171
+ end
172
+ end
173
+ end
174
+
175
+ it "should allow configuring nested configurable accessors" do
176
+ @car.nested_thing.age.should == 50
177
+ end
178
+
179
+ it "should allow configuring nested configurable normal methods" do
180
+ @car.nested_thing.some_thing.should == 'yo'
181
+ end
182
+
183
+ it "should not allow configuring directly on the config object" do
184
+ expect{
185
+ @car.configure do |c|
186
+ c.some_method('other')
187
+ end
188
+ }.to raise_error(ImageResizer::Configurable::BadConfigAttribute)
189
+ end
190
+ end
191
+
192
+ describe "configuring with a saved config" do
193
+ before(:each) do
194
+ @cool_configuration = Object.new
195
+ def @cool_configuration.apply_configuration(car, colour=nil)
196
+ car.configure do |c|
197
+ c.colour = (colour || 'vermelho')
198
+ end
199
+ end
200
+ end
201
+
202
+ it "should allow configuration by a saved config" do
203
+ @car.configure_with(@cool_configuration)
204
+ @car.colour.should == 'vermelho'
205
+ @car.top_speed.should == 216
206
+ end
207
+
208
+ it "should pass any args through to the saved config" do
209
+ @car.configure_with(@cool_configuration, 'preto')
210
+ @car.colour.should == 'preto'
211
+ end
212
+
213
+ it "should yield a block for any extra configuration" do
214
+ @car.configure_with(@cool_configuration) do |c|
215
+ c.colour = 'branco'
216
+ end
217
+ @car.colour.should == 'branco'
218
+ end
219
+
220
+ it "should return itself" do
221
+ @car.configure_with(@cool_configuration).should == @car
222
+ end
223
+
224
+ describe "using a symbol to specify the config" do
225
+
226
+ before(:all) do
227
+ @rally_config = Object.new
228
+ Car.register_configuration(:rally, @rally_config)
229
+ @long_journey_config = Object.new
230
+ Car.register_configuration(:long_journey){ @long_journey_config }
231
+ Car.register_configuration(:some_library){ SomeLibrary }
232
+ end
233
+
234
+ it "should map the symbol to the correct configuration" do
235
+ @rally_config.should_receive(:apply_configuration).with(@car)
236
+ @car.configure_with(:rally)
237
+ end
238
+
239
+ it "should map the symbol to the correct configuration lazily" do
240
+ @long_journey_config.should_receive(:apply_configuration).with(@car)
241
+ @car.configure_with(:long_journey)
242
+ end
243
+
244
+ it "should throw an error if an unknown symbol is passed in" do
245
+ lambda {
246
+ @car.configure_with(:eggs)
247
+ }.should raise_error(ArgumentError)
248
+ end
249
+
250
+ it "should only try to load the library when asked to" do
251
+ lambda{
252
+ @car.configure_with(:some_library)
253
+ }.should raise_error(NameError, /uninitialized constant.*SomeLibrary/)
254
+ end
255
+ end
256
+
257
+ end
258
+
259
+ describe "falling back to another config" do
260
+ before(:each) do
261
+ class Garage
262
+ include ImageResizer::Configurable
263
+ configurable_attr :top_speed, 100
264
+ end
265
+ @garage = Garage.new
266
+ @car.use_as_fallback_config(@garage)
267
+ end
268
+
269
+ describe "when nothing set" do
270
+ it "should use its default" do
271
+ @car.top_speed.should == 216
272
+ end
273
+ it "shouldn't affect the fallback config object" do
274
+ @garage.top_speed.should == 100
275
+ end
276
+ end
277
+
278
+ describe "if set" do
279
+ before(:each) do
280
+ @car.top_speed = 444
281
+ end
282
+ it "should work normally" do
283
+ @car.top_speed.should == 444
284
+ end
285
+ it "shouldn't affect the fallback config object" do
286
+ @garage.top_speed.should == 100
287
+ end
288
+ end
289
+
290
+ describe "both set" do
291
+ before(:each) do
292
+ @car.top_speed = 444
293
+ @garage.top_speed = 3000
294
+ end
295
+ it "should prefer its own setting" do
296
+ @car.top_speed.should == 444
297
+ end
298
+ it "shouldn't affect the fallback config object" do
299
+ @garage.top_speed.should == 3000
300
+ end
301
+ end
302
+
303
+ describe "the fallback config is set" do
304
+ before(:each) do
305
+ @garage.top_speed = 3000
306
+ end
307
+ it "should use the fallback config" do
308
+ @car.top_speed.should == 3000
309
+ end
310
+ it "shouldn't affect the fallback config object" do
311
+ @garage.top_speed.should == 3000
312
+ end
313
+ end
314
+
315
+ describe "falling back multiple levels" do
316
+ before(:each) do
317
+ @klass = Class.new
318
+ @klass.class_eval do
319
+ include ImageResizer::Configurable
320
+ configurable_attr :veg, 'carrot'
321
+ end
322
+ @a = @klass.new
323
+ @b = @klass.new
324
+ @b.use_as_fallback_config(@a)
325
+ @c = @klass.new
326
+ @c.use_as_fallback_config(@b)
327
+ end
328
+
329
+ it "should be the default if nothing set" do
330
+ @c.veg.should == 'carrot'
331
+ end
332
+
333
+ it "should fall all the way back to the top one if necessary" do
334
+ @a.veg = 'turnip'
335
+ @c.veg.should == 'turnip'
336
+ end
337
+
338
+ it "should prefer the closer one over the further away one" do
339
+ @b.veg = 'tatty'
340
+ @a.veg = 'turnip'
341
+ @c.veg.should == 'tatty'
342
+ end
343
+
344
+ it "should work properly with nils" do
345
+ @a.veg = nil
346
+ @c.veg = 'broc'
347
+ @a.veg.should be_nil
348
+ @b.veg.should be_nil
349
+ @c.veg.should == 'broc'
350
+ end
351
+ end
352
+
353
+ describe "objects with different methods" do
354
+ before(:each) do
355
+ class Dad
356
+ include ImageResizer::Configurable
357
+ end
358
+ @dad = Dad.new
359
+ class Kid
360
+ include ImageResizer::Configurable
361
+ configurable_attr :lug, 'default-lug'
362
+ end
363
+ @kid = Kid.new
364
+ @kid.use_as_fallback_config(@dad)
365
+ end
366
+
367
+ it "should not allow setting on the fallback obj directly" do
368
+ lambda{
369
+ @dad.lug = 'leg'
370
+ }.should raise_error(NoMethodError)
371
+ end
372
+
373
+ it "should not have the fallback obj respond to the method" do
374
+ @dad.should_not respond_to(:lug=)
375
+ end
376
+
377
+ it "should allow configuring through the fallback object even if it doesn't have that method" do
378
+ @dad.configure do |c|
379
+ c.lug = 'leg'
380
+ end
381
+ @kid.lug.should == 'leg'
382
+ end
383
+
384
+ it "should work when a grandchild config is added later" do
385
+ class Grandkid
386
+ include ImageResizer::Configurable
387
+ configurable_attr :oogie, 'boogie'
388
+ end
389
+ grandkid = Grandkid.new
390
+ grandkid.use_as_fallback_config(@kid)
391
+ @dad.configure{|c| c.oogie = 'duggen' }
392
+ grandkid.oogie.should == 'duggen'
393
+ end
394
+
395
+ it "should allow configuring twice through the fallback object" do
396
+ @dad.configure{|c| c.lug = 'leg' }
397
+ @dad.configure{|c| c.lug = 'blug' }
398
+ @kid.lug.should == 'blug'
399
+ end
400
+ end
401
+
402
+ describe "clashing with configurable modules" do
403
+ before(:each) do
404
+ @mod = mod = Module.new
405
+ @mod.module_eval do
406
+ include ImageResizer::Configurable
407
+ configurable_attr :team, 'spurs'
408
+ end
409
+ @class = Class.new
410
+ @class.class_eval do
411
+ include mod
412
+ include ImageResizer::Configurable
413
+ configurable_attr :tree, 'elm'
414
+ end
415
+ end
416
+
417
+ it "should not override the defaults from the module" do
418
+ obj = @class.new
419
+ obj.team.should == 'spurs'
420
+ end
421
+
422
+ it "should still use its own defaults" do
423
+ obj = @class.new
424
+ obj.tree.should == 'elm'
425
+ end
426
+
427
+ describe "when the configurable_attr is specified in a subclass that doesn't include Configurable" do
428
+ before(:each) do
429
+ @subclass = Class.new(@class)
430
+ @subclass.class_eval do
431
+ configurable_attr :car, 'mazda'
432
+ configurable_attr :tree, 'oak'
433
+ end
434
+ @obj = @subclass.new
435
+ end
436
+
437
+ it "should still work with default values" do
438
+ @obj.car.should == 'mazda'
439
+ end
440
+
441
+ it "should override the default from the parent" do
442
+ @obj.tree.should == 'oak'
443
+ end
444
+ end
445
+
446
+ end
447
+
448
+ end
449
+
450
+ describe "inheriting configurable_attrs from multiple places" do
451
+ before(:each) do
452
+ module A
453
+ include ImageResizer::Configurable
454
+ configurable_attr :a
455
+ end
456
+ module B
457
+ include ImageResizer::Configurable
458
+ configurable_attr :b
459
+ end
460
+ class K
461
+ include ImageResizer::Configurable
462
+ include A
463
+ include B
464
+ configurable_attr :c
465
+ end
466
+ class L < K
467
+ end
468
+ end
469
+
470
+ it "should include configuration from all of its mixins" do
471
+ l = L.new
472
+ l.configure do |c|
473
+ c.a = 'something'
474
+ c.b = 'something'
475
+ c.c = 'something'
476
+ end
477
+ end
478
+ end
479
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe ImageResizer::Encoder do
4
+
5
+ before(:all) do
6
+ sample_file = SAMPLES_DIR.join('beach.png') # 280x355, 135KB
7
+ @image = ImageResizer::TempObject.new(File.new(sample_file))
8
+ @encoder = ImageResizer::Encoder.new
9
+ end
10
+
11
+ describe "#encode" do
12
+
13
+ it "should encode the image to the correct format" do
14
+ image = @encoder.encode(@image, :gif)
15
+ image.should have_format('gif')
16
+ end
17
+
18
+ it "should throw :unable_to_handle if the format is not handleable" do
19
+ lambda{
20
+ @encoder.encode(@image, :goofy)
21
+ }.should throw_symbol(:unable_to_handle)
22
+ end
23
+
24
+ it "should do nothing if the image is already in the correct format" do
25
+ image = @encoder.encode(@image, :png)
26
+ image.should == @image
27
+ end
28
+
29
+ it "should allow for extra args" do
30
+ image = @encoder.encode(@image, :jpg, '-quality 1')
31
+ image.should have_format('jpeg')
32
+ image.should have_size('1.45KB')
33
+ end
34
+
35
+ it "should still work even if the image is already in the correct format and args are given" do
36
+ image = @encoder.encode(@image, :png, '-quality 1')
37
+ image.should_not == @image
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe ImageResizer::HasFilename do
4
+
5
+ before(:each) do
6
+ @obj = Object.new
7
+ class << @obj
8
+ include ImageResizer::HasFilename
9
+ attr_accessor :name
10
+ end
11
+ end
12
+
13
+ describe "basename" do
14
+ it "should define basename" do
15
+ @obj.name = 'meat.balls'
16
+ @obj.basename.should == 'meat'
17
+ end
18
+ it "should all but the last bit" do
19
+ @obj.name = 'tooting.meat.balls'
20
+ @obj.basename.should == 'tooting.meat'
21
+ end
22
+ it "should be nil if name not set" do
23
+ @obj.basename.should be_nil
24
+ end
25
+ it "should be the whole name if it has no ext" do
26
+ @obj.name = 'eggs'
27
+ @obj.basename.should == 'eggs'
28
+ end
29
+ end
30
+
31
+ describe "basename=" do
32
+ it "should set the whole name if there isn't one" do
33
+ @obj.basename = 'doog'
34
+ @obj.name.should == 'doog'
35
+ end
36
+ it "should replace the whole name if there's no ext" do
37
+ @obj.name = 'lungs'
38
+ @obj.basename = 'doog'
39
+ @obj.name.should == 'doog'
40
+ end
41
+ it "should replace all but the last bit" do
42
+ @obj.name = 'bong.lungs.pig'
43
+ @obj.basename = 'smeeg'
44
+ @obj.name.should == 'smeeg.pig'
45
+ end
46
+ end
47
+
48
+ describe "ext" do
49
+ it "should define ext" do
50
+ @obj.name = 'meat.balls'
51
+ @obj.ext.should == 'balls'
52
+ end
53
+ it "should only use the last bit" do
54
+ @obj.name = 'tooting.meat.balls'
55
+ @obj.ext.should == 'balls'
56
+ end
57
+ it "should be nil if name not set" do
58
+ @obj.ext.should be_nil
59
+ end
60
+ it "should be nil if name has no ext" do
61
+ @obj.name = 'eggs'
62
+ @obj.ext.should be_nil
63
+ end
64
+ end
65
+
66
+ describe "ext=" do
67
+ it "should use a default basename if there is no name" do
68
+ @obj.ext = 'doog'
69
+ @obj.name.should == 'file.doog'
70
+ end
71
+ it "should append the ext if name has none already" do
72
+ @obj.name = 'lungs'
73
+ @obj.ext = 'doog'
74
+ @obj.name.should == 'lungs.doog'
75
+ end
76
+ it "should replace the ext if name has one already" do
77
+ @obj.name = 'lungs.pig'
78
+ @obj.ext = 'doog'
79
+ @obj.name.should == 'lungs.doog'
80
+ end
81
+ it "should only replace the last bit" do
82
+ @obj.name = 'long.lungs.pig'
83
+ @obj.ext = 'doog'
84
+ @obj.name.should == 'long.lungs.doog'
85
+ end
86
+ end
87
+
88
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ class Testoast
4
+ include ImageResizer::Loggable
5
+ end
6
+
7
+ describe ImageResizer::Loggable do
8
+
9
+ before(:each) do
10
+ @object = Testoast.new
11
+ end
12
+
13
+ shared_examples_for "common" do
14
+ it "should return a log" do
15
+ @object.log.should be_a(Logger)
16
+ end
17
+ it "should cache the log" do
18
+ @object.log.should == @object.log
19
+ end
20
+ end
21
+
22
+ describe "without being set" do
23
+ it "should return the log object as nil" do
24
+ @object.log_object.should be_nil
25
+ end
26
+ it_should_behave_like 'common'
27
+ end
28
+
29
+ describe "when set" do
30
+ before(:each) do
31
+ @log = Logger.new($stdout)
32
+ @object.log = @log
33
+ end
34
+ it "should return the new log" do
35
+ @object.log.should == @log
36
+ end
37
+ it "should return the log object" do
38
+ @object.log_object.should == @log
39
+ end
40
+ it_should_behave_like 'common'
41
+ end
42
+
43
+ describe "when set as a proc" do
44
+ before(:each) do
45
+ @log = Logger.new($stdout)
46
+ @object.log = proc{ @log }
47
+ end
48
+ it "should return the new log" do
49
+ @object.log.should == @log
50
+ end
51
+ it "should return the log object" do
52
+ @object.log_object.should be_a(Proc)
53
+ end
54
+ it "should allow for changing logs" do
55
+ logs = [@log]
56
+ @object.log = proc{ logs[0] }
57
+ @object.log.should == @log
58
+
59
+ new_log = Logger.new($stdout)
60
+ logs[0] = new_log
61
+
62
+ @object.log.should == new_log
63
+ end
64
+ it_should_behave_like 'common'
65
+ end
66
+
67
+ describe "sharing logs" do
68
+ before(:each) do
69
+ @log = Logger.new($stdout)
70
+ @obj1 = Testoast.new
71
+ @obj2 = Testoast.new
72
+ end
73
+ it "should enable sharing logs" do
74
+ @obj1.log = proc{ @log }
75
+ @obj2.use_same_log_as(@obj1)
76
+ @obj2.log.should == @log
77
+ end
78
+ end
79
+
80
+ end