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,442 @@
1
+ require 'spec_helper'
2
+
3
+ describe ImageResizer::TempObject do
4
+
5
+ ####### Helper Methods #######
6
+
7
+ def sample_path(filename)
8
+ SAMPLES_DIR.join(filename)
9
+ end
10
+
11
+ def new_tempfile(data='HELLO')
12
+ tempfile = Tempfile.new('test')
13
+ tempfile.write(data)
14
+ tempfile.rewind
15
+ tempfile
16
+ end
17
+
18
+ def new_file(data='HELLO', path="tmp/test_file")
19
+ File.open(path, 'w') do |f|
20
+ f.write(data)
21
+ end
22
+ File.new(path)
23
+ end
24
+
25
+ def new_pathname(data='HELLO', path="tmp/test_file")
26
+ File.open(path, 'w') do |f|
27
+ f.write(data)
28
+ end
29
+ Pathname.new(path)
30
+ end
31
+
32
+ def new_temp_object(data, klass=ImageResizer::TempObject)
33
+ klass.new(initialization_object(data))
34
+ end
35
+
36
+ def initialization_object(data)
37
+ raise NotImplementedError, "This should be implemented in the describe block!"
38
+ end
39
+
40
+ def get_parts(temp_object)
41
+ parts = []
42
+ temp_object.each do |bytes|
43
+ parts << bytes
44
+ end
45
+ parts.length.should >= 2 # Sanity check to check that the sample file is adequate for this test
46
+ parts
47
+ end
48
+
49
+ ###############################
50
+
51
+ it "should raise an error if initialized with a non-string/file/tempfile" do
52
+ lambda{
53
+ ImageResizer::TempObject.new(3)
54
+ }.should raise_error(ArgumentError)
55
+ end
56
+
57
+ shared_examples_for "common behaviour" do
58
+
59
+ describe "simple initialization" do
60
+
61
+ before(:each) do
62
+ @temp_object = new_temp_object('HELLO')
63
+ end
64
+
65
+ describe "data" do
66
+ it "should return the data correctly" do
67
+ @temp_object.data.should == 'HELLO'
68
+ end
69
+ end
70
+
71
+ describe "file" do
72
+ it "should return a readable file" do
73
+ @temp_object.file.should be_a(File)
74
+ end
75
+ it "should contain the correct data" do
76
+ @temp_object.file.read.should == 'HELLO'
77
+ end
78
+ it "should yield a file then close it if a block is given" do
79
+ @temp_object.file do |f|
80
+ f.read.should == 'HELLO'
81
+ f.should_receive :close
82
+ end
83
+ end
84
+ it "should return whatever is returned from the block if a block is given" do
85
+ @temp_object.file do |f|
86
+ 'doogie'
87
+ end.should == 'doogie'
88
+ end
89
+ it "should enable reading the file twice" do
90
+ @temp_object.file{|f| f.read }.should == "HELLO"
91
+ @temp_object.file{|f| f.read }.should == "HELLO"
92
+ end
93
+ end
94
+
95
+ describe "tempfile" do
96
+ it "should create a closed tempfile" do
97
+ @temp_object.tempfile.should be_a(Tempfile)
98
+ @temp_object.tempfile.should be_closed
99
+ end
100
+ it "should contain the correct data" do
101
+ @temp_object.tempfile.open.read.should == 'HELLO'
102
+ end
103
+ end
104
+
105
+ describe "path" do
106
+ it "should return an absolute file path" do
107
+ if running_on_windows?
108
+ @temp_object.path.should =~ %r{^[a-zA-Z]:/\w+}
109
+ else
110
+ @temp_object.path.should =~ %r{^/\w+}
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "size" do
116
+ it "should return the size in bytes" do
117
+ @temp_object.size.should == 5
118
+ end
119
+ end
120
+
121
+ describe "to_file" do
122
+ before(:each) do
123
+ @filename = 'tmp/eggnog.txt'
124
+ FileUtils.rm_f(@filename) if File.exists?(@filename)
125
+ end
126
+ after(:each) do
127
+ FileUtils.rm_f(@filename) if File.exists?(@filename)
128
+ end
129
+ it "should write to a file" do
130
+ @temp_object.to_file(@filename)
131
+ File.exists?(@filename).should be_true
132
+ end
133
+ it "should write the correct data to the file" do
134
+ @temp_object.to_file(@filename)
135
+ File.read(@filename).should == 'HELLO'
136
+ end
137
+ it "should return a readable file" do
138
+ file = @temp_object.to_file(@filename)
139
+ file.should be_a(File)
140
+ file.read.should == 'HELLO'
141
+ end
142
+ it "should have 644 permissions" do
143
+ @temp_object.to_file(@filename)
144
+ File::Stat.new(@filename).mode.to_s(8).should =~ /644$/
145
+ end
146
+ it "should allow setting different permissions" do
147
+ @temp_object.to_file(@filename, :mode => 0755)
148
+ File::Stat.new(@filename).mode.to_s(8).should =~ /755$/
149
+ end
150
+ it "should create intermediate subdirs" do
151
+ filename = 'tmp/gog/mcgee'
152
+ @temp_object.to_file(filename)
153
+ File.exists?(filename).should be_true
154
+ FileUtils.rm_rf('tmp/gog')
155
+ end
156
+ it "should allow not creating intermediate subdirs" do
157
+ filename = 'tmp/gog/mcgee'
158
+ expect{ @temp_object.to_file(filename, :mkdirs => false) }.to raise_error()
159
+ end
160
+ end
161
+
162
+ end
163
+
164
+ describe "each" do
165
+ it "should yield 8192 bytes each time" do
166
+ temp_object = new_temp_object(File.read(sample_path('round.gif')))
167
+ parts = get_parts(temp_object)
168
+ parts[0...-1].each do |part|
169
+ part.bytesize.should == 8192
170
+ end
171
+ parts.last.bytesize.should <= 8192
172
+ end
173
+ end
174
+
175
+ describe "closing" do
176
+ before(:each) do
177
+ @temp_object = new_temp_object("wassup")
178
+ end
179
+ it "should delete its tempfile" do
180
+ tempfile = @temp_object.tempfile
181
+ path = tempfile.path
182
+ path.should_not be_empty
183
+ @temp_object.close
184
+ File.exist?(path).should be_false
185
+ end
186
+ %w(tempfile file data).each do |method|
187
+ it "should raise error when calling #{method}" do
188
+ @temp_object.close
189
+ expect{
190
+ @temp_object.send(method)
191
+ }.to raise_error(ImageResizer::TempObject::Closed)
192
+ end
193
+ end
194
+ it "should not report itself as closed to begin with" do
195
+ @temp_object.should_not be_closed
196
+ end
197
+ it "should report itself as closed after closing" do
198
+ @temp_object.close
199
+ @temp_object.should be_closed
200
+ end
201
+ end
202
+
203
+ end
204
+
205
+ describe "initializing from a string" do
206
+
207
+ def initialization_object(data)
208
+ data
209
+ end
210
+
211
+ it_should_behave_like "common behaviour"
212
+
213
+ it "should not create a file when calling each" do
214
+ temp_object = new_temp_object('HELLO')
215
+ temp_object.should_not_receive(:tempfile)
216
+ temp_object.each{}
217
+ end
218
+
219
+ it "should use set the file extension in path from the name" do
220
+ temp_object = ImageResizer::TempObject.new("hi", :name => 'dark.cloud')
221
+ temp_object.path.should =~ /\.cloud$/
222
+ end
223
+ end
224
+
225
+ describe "initializing from a tempfile" do
226
+
227
+ def initialization_object(data)
228
+ new_tempfile(data)
229
+ end
230
+
231
+ it_should_behave_like "common behaviour"
232
+
233
+ it "should not create a data string when calling each" do
234
+ temp_object = new_temp_object('HELLO')
235
+ temp_object.should_not_receive(:data)
236
+ temp_object.each{}
237
+ end
238
+
239
+ it "should return the tempfile's path" do
240
+ temp_object = new_temp_object('HELLO')
241
+ temp_object.path.should == temp_object.tempfile.path
242
+ end
243
+ end
244
+
245
+ describe "initializing from a file" do
246
+
247
+ def initialization_object(data)
248
+ new_file(data)
249
+ end
250
+
251
+ it_should_behave_like "common behaviour"
252
+
253
+ it "should not create a data string when calling each" do
254
+ temp_object = new_temp_object('HELLO')
255
+ temp_object.should_not_receive(:data)
256
+ temp_object.each{}
257
+ end
258
+
259
+ it "should return the file's path" do
260
+ file = new_file('HELLO')
261
+ temp_object = ImageResizer::TempObject.new(file)
262
+ temp_object.path.should == File.expand_path(file.path)
263
+ end
264
+
265
+ it "should return an absolute path even if the file wasn't instantiated like that" do
266
+ file = new_file('HELLO', 'tmp/bongo')
267
+ temp_object = ImageResizer::TempObject.new(file)
268
+ if running_on_windows?
269
+ temp_object.path.should =~ %r{^[a-zA-Z]:/\w.*bongo}
270
+ else
271
+ temp_object.path.should =~ %r{^/\w.*bongo}
272
+ end
273
+ file.close
274
+ FileUtils.rm(file.path)
275
+ end
276
+ end
277
+
278
+ describe "initializing from a pathname" do
279
+
280
+ def initialization_object(data)
281
+ new_pathname(data)
282
+ end
283
+
284
+ it_should_behave_like "common behaviour"
285
+
286
+ it "should not create a data string when calling each" do
287
+ temp_object = new_temp_object('HELLO')
288
+ temp_object.should_not_receive(:data)
289
+ temp_object.each{}
290
+ end
291
+
292
+ it "should return the file's path" do
293
+ pathname = new_pathname('HELLO')
294
+ temp_object = ImageResizer::TempObject.new(pathname)
295
+ temp_object.path.should == File.expand_path(pathname.to_s)
296
+ end
297
+
298
+ it "should return an absolute path even if the pathname is relative" do
299
+ pathname = new_pathname('HELLO', 'tmp/bingo')
300
+ temp_object = ImageResizer::TempObject.new(pathname)
301
+ if running_on_windows?
302
+ temp_object.path.should =~ %r{^[a-zA-Z]:/\w.*bingo}
303
+ else
304
+ temp_object.path.should =~ %r{^/\w.*bingo}
305
+ end
306
+ pathname.delete
307
+ end
308
+ end
309
+
310
+ describe "initializing from another temp object" do
311
+
312
+ def initialization_object(data)
313
+ ImageResizer::TempObject.new(data)
314
+ end
315
+
316
+ before(:each) do
317
+ @temp_object1 = ImageResizer::TempObject.new(new_tempfile('hello'))
318
+ @temp_object2 = ImageResizer::TempObject.new(@temp_object1)
319
+ end
320
+
321
+ it_should_behave_like "common behaviour"
322
+
323
+ it "should not be the same object" do
324
+ @temp_object1.should_not == @temp_object2
325
+ end
326
+ it "should have the same data" do
327
+ @temp_object1.data.should == @temp_object2.data
328
+ end
329
+ it "should have the same file path" do
330
+ @temp_object1.path.should == @temp_object2.path
331
+ end
332
+ end
333
+
334
+ describe "initialize from a Rack::Test::UploadedFile" do
335
+ def initialization_object(data)
336
+ # The criteria we're using to determine if an object is a
337
+ # Rack::Test::UploadedFile is if it responds to path
338
+ #
339
+ # We can't just check if it is_a?(Rack::Test::UploadedFile) because that
340
+ # class may not always be present.
341
+ uploaded_file = mock("mock_uploadedfile")
342
+ uploaded_file.stub!(:path).and_return File.expand_path('tmp/test_file')
343
+ uploaded_file.stub!(:original_filename).and_return('foo.jpg')
344
+
345
+ # Create a real file with the contents required at the correct path
346
+ new_file(data, 'tmp/test_file')
347
+
348
+ uploaded_file
349
+ end
350
+
351
+ it_should_behave_like "common behaviour"
352
+ end
353
+
354
+ describe "original_filename" do
355
+ before(:each) do
356
+ @obj = new_tempfile
357
+ end
358
+ it "should set the original_filename if the initial object responds to 'original filename'" do
359
+ def @obj.original_filename
360
+ 'jimmy.page'
361
+ end
362
+ ImageResizer::TempObject.new(@obj).original_filename.should == 'jimmy.page'
363
+ end
364
+ it "should not set the name if the initial object doesn't respond to 'original filename'" do
365
+ ImageResizer::TempObject.new(@obj).original_filename.should be_nil
366
+ end
367
+ it "should set the name if the initial object is a file object" do
368
+ file = File.new(SAMPLES_DIR.join('round.gif'))
369
+ temp_object = ImageResizer::TempObject.new(file)
370
+ temp_object.original_filename.should == 'round.gif'
371
+ end
372
+ it "should set the name if the initial object is a pathname" do
373
+ pathname = Pathname.new(SAMPLES_DIR + '/round.gif')
374
+ temp_object = ImageResizer::TempObject.new(pathname)
375
+ temp_object.original_filename.should == 'round.gif'
376
+ end
377
+ end
378
+
379
+ describe "meta" do
380
+ it "should default to an empty hash" do
381
+ ImageResizer::TempObject.new('sdf').meta.should == {}
382
+ end
383
+ it "should allow setting on initialize" do
384
+ ImageResizer::TempObject.new('sdf', :dub => 'wub').meta.should == {:dub => 'wub'}
385
+ end
386
+ it "should allow setting" do
387
+ temp_object = ImageResizer::TempObject.new('boo')
388
+ temp_object.meta = {:far => 'gone'}
389
+ temp_object.meta.should == {:far => 'gone'}
390
+ end
391
+ end
392
+
393
+ describe "name" do
394
+ it "should default to nil" do
395
+ ImageResizer::TempObject.new("HELLO").name.should be_nil
396
+ end
397
+ it "should allow setting the name via the meta" do
398
+ ImageResizer::TempObject.new("HELLO", :name => 'gosh.pig').name.should == "gosh.pig"
399
+ end
400
+ it "should fallback to the original filename if not set" do
401
+ content = "HELLO"
402
+ content.should_receive(:original_filename).and_return("some.egg")
403
+ temp_object = ImageResizer::TempObject.new(content)
404
+ temp_object.name.should == "some.egg"
405
+ end
406
+ it "should prefer the specified name to the original filename" do
407
+ content = "HELLO"
408
+ content.stub!(:original_filename).and_return("brase.nose")
409
+ temp_object = ImageResizer::TempObject.new("HELLO", :name => 'some.gug')
410
+ temp_object.name.should == "some.gug"
411
+ end
412
+ it "should allow setting with a setter" do
413
+ temp_object = ImageResizer::TempObject.new("HELLO")
414
+ temp_object.name = 'bugs'
415
+ temp_object.name.should == "bugs"
416
+ end
417
+ end
418
+
419
+ describe "sanity check for using HasFilename" do
420
+ it "should act like ImageResizer::HasFilename" do
421
+ temp_object = ImageResizer::TempObject.new('h', :name => 'one.big.park')
422
+ temp_object.ext = 'smeagol'
423
+ temp_object.name.should == 'one.big.smeagol'
424
+ end
425
+ end
426
+
427
+ describe "unique_id" do
428
+ before(:each) do
429
+ @temp_object = ImageResizer::TempObject.new('hello')
430
+ end
431
+ it "should return a unique id" do
432
+ @temp_object.unique_id.should =~ /^\d+$/
433
+ end
434
+ it "should be unique" do
435
+ @temp_object.unique_id.should_not == ImageResizer::TempObject.new('hello').unique_id
436
+ end
437
+ it "should not change" do
438
+ @temp_object.unique_id.should == @temp_object.unique_id
439
+ end
440
+ end
441
+
442
+ end
@@ -0,0 +1,61 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup(:default, :test)
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'rspec'
8
+ require 'image_resizer'
9
+ require 'fileutils'
10
+ require 'pry'
11
+ require 'pry-nav'
12
+ require 'pry-stack_explorer'
13
+
14
+ # Requires supporting files with custom matchers and macros, etc,
15
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
16
+
17
+ SAMPLES_DIR = Pathname.new(File.expand_path(File.dirname(__FILE__) + '/../samples')) unless defined?(SAMPLES_DIR)
18
+
19
+ def todo
20
+ raise "TODO"
21
+ end
22
+
23
+
24
+ # require 'logger'
25
+ # LOG_FILE = 'tmp/test.log' unless defined?(LOG_FILE)
26
+ # FileUtils.rm_rf(LOG_FILE)
27
+ # def mock_app(extra_stubs={})
28
+ # mock('app', {
29
+ # :datastore => mock('datastore', :store => 'some_uid', :retrieve => ["SOME_DATA", {}], :destroy => nil),
30
+ # :processor => mock('processor', :process => "SOME_PROCESSED_DATA"),
31
+ # :encoder => mock('encoder', :encode => "SOME_ENCODED_DATA"),
32
+ # :analyzer => mock('analyzer', :analyse => "some_result", :analysis_methods => Module.new),
33
+ # :generator => mock('generator', :generate => "SOME_GENERATED_DATA"),
34
+ # :log => Logger.new(LOG_FILE),
35
+ # :cache_duration => 10000,
36
+ # :job_definitions => Module.new
37
+ # }.merge(extra_stubs)
38
+ # )
39
+ # end
40
+
41
+ # def test_app
42
+ # time = Time.now
43
+ # app = ImageResizer::App.send(:new, "test_#{time.sec}_#{time.usec}".to_sym)
44
+ # app.log = Logger.new(LOG_FILE)
45
+ # app.datastore.root_path = 'tmp/file_data_store_test'
46
+ # app
47
+ # end
48
+
49
+ def suppressing_stderr
50
+ original_stderr = $stderr.dup
51
+ tempfile = Tempfile.new('stderr')
52
+ $stderr.reopen(tempfile) rescue
53
+ yield
54
+ ensure
55
+ tempfile.close!
56
+ $stderr.reopen(original_stderr)
57
+ end
58
+
59
+ def running_on_windows?
60
+ ENV['OS'] && ENV['OS'].downcase == 'windows_nt'
61
+ end
@@ -0,0 +1,19 @@
1
+ def string_matching(regexp)
2
+ Spec::Mocks::ArgumentMatchers::RegexpMatcher.new(regexp)
3
+ end
4
+
5
+ class TempObjectArgumentMatcher
6
+ def initialize(data, opts)
7
+ @data = data
8
+ @opts = opts
9
+ end
10
+ def ==(actual)
11
+ actual.is_a?(ImageResizer::TempObject) &&
12
+ actual.data == @data &&
13
+ @opts.all?{|k,v| actual.send(k) == v }
14
+ end
15
+ end
16
+
17
+ def a_temp_object_with_data(data, opts={})
18
+ TempObjectArgumentMatcher.new(data, opts)
19
+ end
@@ -0,0 +1,58 @@
1
+ def image_properties(image)
2
+ if image.is_a?(Tempfile)
3
+ tempfile = image
4
+ else
5
+ tempfile = Tempfile.new('image')
6
+ tempfile.binmode
7
+ tempfile.write(image.is_a?(ImageResizer::TempObject) ? image.data : image)
8
+ tempfile.close
9
+ end
10
+ details = `identify #{tempfile.path}`
11
+ # example of details string:
12
+ # myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
13
+ filename, format, geometry, geometry_2, depth, image_class, size = details.split(' ')
14
+ width, height = geometry.split('x')
15
+ {
16
+ :filename => filename,
17
+ :format => format.downcase,
18
+ :width => width,
19
+ :height => height,
20
+ :depth => depth,
21
+ :image_class => image_class,
22
+ :size => size
23
+ }
24
+ end
25
+
26
+ RSpec::Matchers.define :have_width do |width|
27
+ match do |given|
28
+ width.should === image_properties(given)[:width].to_i
29
+ end
30
+ end
31
+
32
+ RSpec::Matchers.define :have_height do |height|
33
+ match do |given|
34
+ height.should === image_properties(given)[:height].to_i
35
+ end
36
+ end
37
+
38
+ RSpec::Matchers.define :have_format do |format|
39
+ match do |given|
40
+ image_properties(given)[:format].should == format
41
+ end
42
+ end
43
+
44
+ RSpec::Matchers.define :have_size do |size|
45
+ match do |given|
46
+ image_properties(given)[:size].should == size
47
+ end
48
+ end
49
+
50
+ RSpec::Matchers.define :equal_image do |other|
51
+ match do |given|
52
+ image_data = given.open.read
53
+ other_image_data = other.open.read
54
+ given.close
55
+ other.close
56
+ image_data == other_image_data
57
+ end
58
+ end
@@ -0,0 +1,53 @@
1
+ RSpec::Matchers.define :match_url do |url|
2
+ match do |given|
3
+ given_path, given_query_string = given.split('?')
4
+ path, query_string = url.split('?')
5
+
6
+ path == given_path && given_query_string.split('&').sort == query_string.split('&').sort
7
+ end
8
+ end
9
+
10
+ RSpec::Matchers.define :be_an_empty_directory do
11
+ match do |given|
12
+ Dir.entries(given) == ['.','..']
13
+ end
14
+ end
15
+
16
+ RSpec::Matchers.define :include_hash do |hash|
17
+ match do |given|
18
+ given.merge(hash) == given
19
+ end
20
+ end
21
+
22
+ def memory_usage
23
+ GC.start # Garbage collect
24
+ `ps -o rss= -p #{$$}`.strip.to_i
25
+ end
26
+
27
+ RSpec::Matchers.define :leak_memory do
28
+ match do |given|
29
+ memory_before = memory_usage
30
+ given.call
31
+ memory_after = memory_usage
32
+ result = memory_after > memory_before
33
+ puts "#{memory_after} > #{memory_before}" if result
34
+ result
35
+ end
36
+ end
37
+
38
+ RSpec::Matchers.define :match_attachment_classes do |classes|
39
+ match do |given_classes|
40
+ given_classes.length == classes.length &&
41
+ classes.zip(given_classes).all? do |(klass, given)|
42
+ given.model_class == klass[0] && given.attribute == klass[1] && given.app == klass[2]
43
+ end
44
+ end
45
+ end
46
+
47
+ RSpec::Matchers.define :be_a_text_response do
48
+ match do |given_response|
49
+ given_response.status.should == 200
50
+ given_response.body.length.should > 0
51
+ given_response.content_type.should == 'text/plain'
52
+ end
53
+ end
data/tmp/test_file ADDED
@@ -0,0 +1 @@
1
+ wassup