insano_image_resizer 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ require 'shellwords'
2
+
3
+ module ImageResizer
4
+ module Shell
5
+
6
+ include Configurable
7
+ configurable_attr :log_commands, true
8
+
9
+ # Exceptions
10
+ class CommandFailed < RuntimeError; end
11
+
12
+ def run(command, args="")
13
+ full_command = "#{command} #{escape_args(args)}"
14
+ log.debug("Running command: #{full_command}") if log_commands
15
+ begin
16
+ result = `#{full_command}`
17
+ rescue Errno::ENOENT
18
+ raise_shell_command_failed(full_command)
19
+ end
20
+ if $?.exitstatus == 1
21
+ throw :unable_to_handle
22
+ elsif !$?.success?
23
+ raise_shell_command_failed(full_command)
24
+ end
25
+ result
26
+ end
27
+
28
+ def raise_shell_command_failed(command)
29
+ raise CommandFailed, "Command failed (#{command}) with exit status #{$?.exitstatus}"
30
+ end
31
+
32
+ def escape_args(args)
33
+ args.shellsplit.map do |arg|
34
+ quote arg.gsub(/\\?'/, %q('\\\\''))
35
+ end.join(' ')
36
+ end
37
+
38
+ def quote(string)
39
+ q = running_on_windows? ? '"' : "'"
40
+ q + string + q
41
+ end
42
+
43
+ def running_on_windows?
44
+ ENV['OS'] && ENV['OS'].downcase == 'windows_nt'
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+
2
+ require 'image_resizer/loggable'
3
+ require 'image_resizer/configurable'
4
+ require 'image_resizer/shell'
5
+ require 'image_resizer/processor'
Binary file
data/samples/test.jpg ADDED
Binary file
data/samples/test.png ADDED
Binary file
@@ -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,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