jmcnevin-paperclip 2.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +414 -0
  3. data/Rakefile +86 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +4 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip.rb +480 -0
  12. data/lib/paperclip/attachment.rb +520 -0
  13. data/lib/paperclip/callback_compatibility.rb +61 -0
  14. data/lib/paperclip/geometry.rb +155 -0
  15. data/lib/paperclip/interpolations.rb +171 -0
  16. data/lib/paperclip/iostream.rb +45 -0
  17. data/lib/paperclip/matchers.rb +33 -0
  18. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  19. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  20. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  21. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  22. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  23. data/lib/paperclip/options.rb +78 -0
  24. data/lib/paperclip/processor.rb +58 -0
  25. data/lib/paperclip/railtie.rb +26 -0
  26. data/lib/paperclip/storage.rb +3 -0
  27. data/lib/paperclip/storage/filesystem.rb +81 -0
  28. data/lib/paperclip/storage/fog.rb +163 -0
  29. data/lib/paperclip/storage/s3.rb +270 -0
  30. data/lib/paperclip/style.rb +95 -0
  31. data/lib/paperclip/thumbnail.rb +105 -0
  32. data/lib/paperclip/upfile.rb +62 -0
  33. data/lib/paperclip/version.rb +3 -0
  34. data/lib/tasks/paperclip.rake +101 -0
  35. data/rails/init.rb +2 -0
  36. data/shoulda_macros/paperclip.rb +124 -0
  37. data/test/attachment_test.rb +1161 -0
  38. data/test/database.yml +4 -0
  39. data/test/fixtures/12k.png +0 -0
  40. data/test/fixtures/50x50.png +0 -0
  41. data/test/fixtures/5k.png +0 -0
  42. data/test/fixtures/animated.gif +0 -0
  43. data/test/fixtures/bad.png +1 -0
  44. data/test/fixtures/double spaces in name.png +0 -0
  45. data/test/fixtures/fog.yml +8 -0
  46. data/test/fixtures/s3.yml +8 -0
  47. data/test/fixtures/spaced file.png +0 -0
  48. data/test/fixtures/text.txt +1 -0
  49. data/test/fixtures/twopage.pdf +0 -0
  50. data/test/fixtures/uppercase.PNG +0 -0
  51. data/test/fog_test.rb +192 -0
  52. data/test/geometry_test.rb +206 -0
  53. data/test/helper.rb +158 -0
  54. data/test/integration_test.rb +781 -0
  55. data/test/interpolations_test.rb +202 -0
  56. data/test/iostream_test.rb +71 -0
  57. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  58. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  59. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  60. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  61. data/test/options_test.rb +75 -0
  62. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  63. data/test/paperclip_test.rb +340 -0
  64. data/test/processor_test.rb +10 -0
  65. data/test/storage/filesystem_test.rb +56 -0
  66. data/test/storage/s3_live_test.rb +88 -0
  67. data/test/storage/s3_test.rb +689 -0
  68. data/test/style_test.rb +180 -0
  69. data/test/thumbnail_test.rb +383 -0
  70. data/test/upfile_test.rb +53 -0
  71. metadata +294 -0
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ This is not an image.
@@ -0,0 +1,8 @@
1
+ development:
2
+ provider: AWS
3
+ aws_access_key_id: AWS_ID
4
+ aws_secret_access_key: AWS_SECRET
5
+ test:
6
+ provider: AWS
7
+ aws_access_key_id: AWS_ID
8
+ aws_secret_access_key: AWS_SECRET
@@ -0,0 +1,8 @@
1
+ development:
2
+ key: 54321
3
+ production:
4
+ key: 12345
5
+ test:
6
+ bucket: <%= ENV['S3_BUCKET'] %>
7
+ access_key_id: <%= ENV['S3_KEY'] %>
8
+ secret_access_key: <%= ENV['S3_SECRET'] %>
@@ -0,0 +1 @@
1
+ paperclip!
Binary file
@@ -0,0 +1,192 @@
1
+ require './test/helper'
2
+ require 'fog'
3
+
4
+ Fog.mock!
5
+
6
+ class FogTest < Test::Unit::TestCase
7
+ context "" do
8
+
9
+ context "with credentials provided in a path string" do
10
+ setup do
11
+ rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
12
+ :storage => :fog,
13
+ :url => '/:attachment/:filename',
14
+ :fog_directory => "paperclip",
15
+ :fog_credentials => File.join(File.dirname(__FILE__), 'fixtures', 'fog.yml')
16
+ @dummy = Dummy.new
17
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
18
+ end
19
+
20
+ should "have the proper information loading credentials from a file" do
21
+ assert_equal @dummy.avatar.fog_credentials[:provider], 'AWS'
22
+ end
23
+ end
24
+
25
+ context "with credentials provided in a File object" do
26
+ setup do
27
+ rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
28
+ :storage => :fog,
29
+ :url => '/:attachment/:filename',
30
+ :fog_directory => "paperclip",
31
+ :fog_credentials => File.open(File.join(File.dirname(__FILE__), 'fixtures', 'fog.yml'))
32
+ @dummy = Dummy.new
33
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
34
+ end
35
+
36
+ should "have the proper information loading credentials from a file" do
37
+ assert_equal @dummy.avatar.fog_credentials[:provider], 'AWS'
38
+ end
39
+ end
40
+
41
+ context "with default values for path and url" do
42
+ setup do
43
+ rebuild_model :styles => { :medium => "300x300>", :thumb => "100x100>" },
44
+ :storage => :fog,
45
+ :url => '/:attachment/:filename',
46
+ :fog_directory => "paperclip",
47
+ :fog_credentials => {
48
+ :provider => 'AWS',
49
+ :aws_access_key_id => 'AWS_ID',
50
+ :aws_secret_access_key => 'AWS_SECRET'
51
+ }
52
+ @dummy = Dummy.new
53
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
54
+ end
55
+ should "be able to interpolate the path without blowing up" do
56
+ assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../public/avatars/5k.png")),
57
+ @dummy.avatar.path
58
+ end
59
+
60
+ should "clean up file objects" do
61
+ File.stubs(:exist?).returns(true)
62
+ Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
63
+ Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
64
+
65
+ @dummy.save!
66
+ end
67
+ end
68
+
69
+ setup do
70
+ @fog_directory = 'papercliptests'
71
+
72
+ @credentials = {
73
+ :provider => 'AWS',
74
+ :aws_access_key_id => 'ID',
75
+ :aws_secret_access_key => 'SECRET'
76
+ }
77
+
78
+ @connection = Fog::Storage.new(@credentials)
79
+ @connection.directories.create(
80
+ :key => @fog_directory
81
+ )
82
+
83
+ @options = {
84
+ :fog_directory => @fog_directory,
85
+ :fog_credentials => @credentials,
86
+ :fog_host => nil,
87
+ :fog_file => {:cache_control => 1234},
88
+ :path => ":attachment/:basename.:extension",
89
+ :storage => :fog
90
+ }
91
+
92
+ rebuild_model(@options)
93
+ end
94
+
95
+ should "be extended by the Fog module" do
96
+ assert Dummy.new.avatar.is_a?(Paperclip::Storage::Fog)
97
+ end
98
+
99
+ context "when assigned" do
100
+ setup do
101
+ @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
102
+ @dummy = Dummy.new
103
+ @dummy.avatar = @file
104
+ end
105
+
106
+ teardown do
107
+ @file.close
108
+ directory = @connection.directories.new(:key => @fog_directory)
109
+ directory.files.each {|file| file.destroy}
110
+ directory.destroy
111
+ end
112
+
113
+ context "without a bucket" do
114
+ setup do
115
+ @connection.directories.get(@fog_directory).destroy
116
+ end
117
+
118
+ should "create the bucket" do
119
+ assert @dummy.save
120
+ assert @connection.directories.get(@fog_directory)
121
+ end
122
+ end
123
+
124
+ context "with a bucket" do
125
+ should "succeed" do
126
+ assert @dummy.save
127
+ end
128
+ end
129
+
130
+ context "without a fog_host" do
131
+ setup do
132
+ rebuild_model(@options.merge(:fog_host => nil))
133
+ @dummy = Dummy.new
134
+ @dummy.avatar = StringIO.new('.')
135
+ @dummy.save
136
+ end
137
+
138
+ should "provide a public url" do
139
+ assert !@dummy.avatar.url.nil?
140
+ end
141
+ end
142
+
143
+ context "with a fog_host" do
144
+ setup do
145
+ rebuild_model(@options.merge(:fog_host => 'http://example.com'))
146
+ @dummy = Dummy.new
147
+ @dummy.avatar = StringIO.new('.')
148
+ @dummy.save
149
+ end
150
+
151
+ should "provide a public url" do
152
+ assert @dummy.avatar.url =~ /^http:\/\/example\.com\/avatars\/stringio\.txt\?\d*$/
153
+ end
154
+ end
155
+
156
+ context "with a fog_host that includes a wildcard placeholder" do
157
+ setup do
158
+ rebuild_model(
159
+ :fog_directory => @fog_directory,
160
+ :fog_credentials => @credentials,
161
+ :fog_host => 'http://img%d.example.com',
162
+ :path => ":attachment/:basename.:extension",
163
+ :storage => :fog
164
+ )
165
+ @dummy = Dummy.new
166
+ @dummy.avatar = StringIO.new('.')
167
+ @dummy.save
168
+ end
169
+
170
+ should "provide a public url" do
171
+ assert @dummy.avatar.url =~ /^http:\/\/img[0123]\.example\.com\/avatars\/stringio\.txt\?\d*$/
172
+ end
173
+ end
174
+
175
+ context "with fog_public set to false" do
176
+ setup do
177
+ rebuild_model(@options.merge(:fog_public => false))
178
+ @dummy = Dummy.new
179
+ @dummy.avatar = StringIO.new('.')
180
+ @dummy.save
181
+ end
182
+
183
+ should 'set the @fog_public instance variable to false' do
184
+ assert_equal false, @dummy.avatar.options.fog_public
185
+ assert_equal false, @dummy.avatar.fog_public
186
+ end
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+ end
@@ -0,0 +1,206 @@
1
+ require './test/helper'
2
+
3
+ class GeometryTest < Test::Unit::TestCase
4
+ context "Paperclip::Geometry" do
5
+ should "correctly report its given dimensions" do
6
+ assert @geo = Paperclip::Geometry.new(1024, 768)
7
+ assert_equal 1024, @geo.width
8
+ assert_equal 768, @geo.height
9
+ end
10
+
11
+ should "set height to 0 if height dimension is missing" do
12
+ assert @geo = Paperclip::Geometry.new(1024)
13
+ assert_equal 1024, @geo.width
14
+ assert_equal 0, @geo.height
15
+ end
16
+
17
+ should "set width to 0 if width dimension is missing" do
18
+ assert @geo = Paperclip::Geometry.new(nil, 768)
19
+ assert_equal 0, @geo.width
20
+ assert_equal 768, @geo.height
21
+ end
22
+
23
+ should "be generated from a WxH-formatted string" do
24
+ assert @geo = Paperclip::Geometry.parse("800x600")
25
+ assert_equal 800, @geo.width
26
+ assert_equal 600, @geo.height
27
+ end
28
+
29
+ should "be generated from a xH-formatted string" do
30
+ assert @geo = Paperclip::Geometry.parse("x600")
31
+ assert_equal 0, @geo.width
32
+ assert_equal 600, @geo.height
33
+ end
34
+
35
+ should "be generated from a Wx-formatted string" do
36
+ assert @geo = Paperclip::Geometry.parse("800x")
37
+ assert_equal 800, @geo.width
38
+ assert_equal 0, @geo.height
39
+ end
40
+
41
+ should "be generated from a W-formatted string" do
42
+ assert @geo = Paperclip::Geometry.parse("800")
43
+ assert_equal 800, @geo.width
44
+ assert_equal 0, @geo.height
45
+ end
46
+
47
+ should "ensure the modifier is nil if not present" do
48
+ assert @geo = Paperclip::Geometry.parse("123x456")
49
+ assert_nil @geo.modifier
50
+ end
51
+
52
+ should "treat x and X the same in geometries" do
53
+ @lower = Paperclip::Geometry.parse("123x456")
54
+ @upper = Paperclip::Geometry.parse("123X456")
55
+ assert_equal 123, @lower.width
56
+ assert_equal 123, @upper.width
57
+ assert_equal 456, @lower.height
58
+ assert_equal 456, @upper.height
59
+ end
60
+
61
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
62
+ should "ensure the modifier #{mod.inspect} is preserved" do
63
+ assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
64
+ assert_equal mod, @geo.modifier
65
+ assert_equal "123x456#{mod}", @geo.to_s
66
+ end
67
+ end
68
+
69
+ ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod|
70
+ should "ensure the modifier #{mod.inspect} is preserved with no height" do
71
+ assert @geo = Paperclip::Geometry.parse("123x#{mod}")
72
+ assert_equal mod, @geo.modifier
73
+ assert_equal "123#{mod}", @geo.to_s
74
+ end
75
+ end
76
+
77
+ should "make sure the modifier gets passed during transformation_to" do
78
+ assert @src = Paperclip::Geometry.parse("123x456")
79
+ assert @dst = Paperclip::Geometry.parse("123x456>")
80
+ assert_equal ["123x456>", nil], @src.transformation_to(@dst)
81
+ end
82
+
83
+ should "generate correct ImageMagick formatting string for W-formatted string" do
84
+ assert @geo = Paperclip::Geometry.parse("800")
85
+ assert_equal "800", @geo.to_s
86
+ end
87
+
88
+ should "generate correct ImageMagick formatting string for Wx-formatted string" do
89
+ assert @geo = Paperclip::Geometry.parse("800x")
90
+ assert_equal "800", @geo.to_s
91
+ end
92
+
93
+ should "generate correct ImageMagick formatting string for xH-formatted string" do
94
+ assert @geo = Paperclip::Geometry.parse("x600")
95
+ assert_equal "x600", @geo.to_s
96
+ end
97
+
98
+ should "generate correct ImageMagick formatting string for WxH-formatted string" do
99
+ assert @geo = Paperclip::Geometry.parse("800x600")
100
+ assert_equal "800x600", @geo.to_s
101
+ end
102
+
103
+ should "be generated from a file" do
104
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
105
+ file = File.new(file, 'rb')
106
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
107
+ assert @geo.height > 0
108
+ assert @geo.width > 0
109
+ end
110
+
111
+ should "be generated from a file path" do
112
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
113
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
114
+ assert @geo.height > 0
115
+ assert @geo.width > 0
116
+ end
117
+
118
+ should "not generate from a bad file" do
119
+ file = "/home/This File Does Not Exist.omg"
120
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
121
+ end
122
+
123
+ should "not generate from a blank filename" do
124
+ file = ""
125
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
126
+ end
127
+
128
+ should "not generate from a nil file" do
129
+ file = nil
130
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
131
+ end
132
+
133
+ should "not generate from a file with no path" do
134
+ file = mock("file", :path => "")
135
+ file.stubs(:respond_to?).with(:path).returns(true)
136
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
137
+ end
138
+
139
+ should "let us know when a command isn't found versus a processing error" do
140
+ old_path = ENV['PATH']
141
+ begin
142
+ ENV['PATH'] = ''
143
+ assert_raises(Paperclip::CommandNotFoundError) do
144
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
145
+ @geo = Paperclip::Geometry.from_file(file)
146
+ end
147
+ ensure
148
+ ENV['PATH'] = old_path
149
+ end
150
+ end
151
+
152
+ [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
153
+ ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
154
+ ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
155
+ context "performing calculations on a #{args[0]} viewport" do
156
+ setup do
157
+ @geo = Paperclip::Geometry.new(args[1], args[2])
158
+ end
159
+
160
+ should "#{args[3] ? "" : "not"} be vertical" do
161
+ assert_equal args[3], @geo.vertical?
162
+ end
163
+
164
+ should "#{args[4] ? "" : "not"} be horizontal" do
165
+ assert_equal args[4], @geo.horizontal?
166
+ end
167
+
168
+ should "#{args[5] ? "" : "not"} be square" do
169
+ assert_equal args[5], @geo.square?
170
+ end
171
+
172
+ should "report that #{args[6]} is the larger dimension" do
173
+ assert_equal args[6], @geo.larger
174
+ end
175
+
176
+ should "report that #{args[7]} is the smaller dimension" do
177
+ assert_equal args[7], @geo.smaller
178
+ end
179
+
180
+ should "have an aspect ratio of #{args[8]}" do
181
+ assert_in_delta args[8], @geo.aspect, 0.0001
182
+ end
183
+ end
184
+ end
185
+
186
+ [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
187
+ [ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
188
+ [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
189
+ context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
190
+ setup do
191
+ @geo = Paperclip::Geometry.new(*args[0])
192
+ @dst = Paperclip::Geometry.new(*args[1])
193
+ @scale, @crop = @geo.transformation_to @dst, true
194
+ end
195
+
196
+ should "be able to return the correct scaling transformation geometry #{args[2]}" do
197
+ assert_equal args[2], @scale
198
+ end
199
+
200
+ should "be able to return the correct crop transformation geometry #{args[3]}" do
201
+ assert_equal args[3], @crop
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,158 @@
1
+ require 'rubygems'
2
+ require 'tempfile'
3
+ require 'pathname'
4
+ require 'test/unit'
5
+
6
+ require 'shoulda'
7
+ require 'mocha'
8
+
9
+ require 'active_record'
10
+ require 'active_record/version'
11
+ require 'active_support'
12
+ require 'mime/types'
13
+ require 'pry'
14
+ require 'pathname'
15
+
16
+ puts "Testing against version #{ActiveRecord::VERSION::STRING}"
17
+
18
+ `ruby -e 'exit 0'` # Prime $? with a value.
19
+
20
+ begin
21
+ require 'ruby-debug'
22
+ rescue LoadError => e
23
+ puts "debugger disabled"
24
+ end
25
+
26
+ ROOT = Pathname(File.expand_path(File.join(File.dirname(__FILE__), '..')))
27
+
28
+ def silence_warnings
29
+ old_verbose, $VERBOSE = $VERBOSE, nil
30
+ yield
31
+ ensure
32
+ $VERBOSE = old_verbose
33
+ end
34
+
35
+ class Test::Unit::TestCase
36
+ def setup
37
+ silence_warnings do
38
+ Object.const_set(:Rails, stub('Rails', :root => ROOT, :env => 'test'))
39
+ end
40
+ end
41
+ end
42
+
43
+ $LOAD_PATH << File.join(ROOT, 'lib')
44
+ $LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
45
+
46
+ require File.join(ROOT, 'lib', 'paperclip.rb')
47
+
48
+ require './shoulda_macros/paperclip'
49
+
50
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
51
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
52
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
53
+ ActiveRecord::Base.establish_connection(config['test'])
54
+ Paperclip.options[:logger] = ActiveRecord::Base.logger
55
+
56
+ def reset_class class_name
57
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
58
+ Object.send(:remove_const, class_name) rescue nil
59
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
60
+ klass.class_eval{ include Paperclip::Glue }
61
+ klass
62
+ end
63
+
64
+ def reset_table table_name, &block
65
+ block ||= lambda { |table| true }
66
+ ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
67
+ end
68
+
69
+ def modify_table table_name, &block
70
+ ActiveRecord::Base.connection.change_table :dummies, &block
71
+ end
72
+
73
+ def rebuild_model options = {}
74
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
75
+ table.column :title, :string
76
+ table.column :other, :string
77
+ table.column :avatar_file_name, :string
78
+ table.column :avatar_content_type, :string
79
+ table.column :avatar_file_size, :integer
80
+ table.column :avatar_updated_at, :datetime
81
+ table.column :avatar_fingerprint, :string
82
+ if options.delete(:with_dimensions)
83
+ table.column :avatar_width, :integer
84
+ table.column :avatar_height, :integer
85
+ end
86
+ end
87
+ rebuild_class options
88
+ end
89
+
90
+ def rebuild_class options = {}
91
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
92
+ Object.send(:remove_const, "Dummy") rescue nil
93
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
94
+ Paperclip.reset_duplicate_clash_check!
95
+ Dummy.class_eval do
96
+ include Paperclip::Glue
97
+ has_attached_file :avatar, options
98
+ end
99
+ Dummy.reset_column_information
100
+ end
101
+
102
+ class FakeModel
103
+ attr_accessor :avatar_file_name,
104
+ :avatar_file_size,
105
+ :avatar_updated_at,
106
+ :avatar_content_type,
107
+ :avatar_fingerprint,
108
+ :id
109
+
110
+ def errors
111
+ @errors ||= []
112
+ end
113
+
114
+ def run_paperclip_callbacks name, *args
115
+ end
116
+
117
+ end
118
+
119
+ def attachment options
120
+ Paperclip::Attachment.new(:avatar, FakeModel.new, options)
121
+ end
122
+
123
+ def silence_warnings
124
+ old_verbose, $VERBOSE = $VERBOSE, nil
125
+ yield
126
+ ensure
127
+ $VERBOSE = old_verbose
128
+ end
129
+
130
+ def should_accept_dummy_class
131
+ should "accept the class" do
132
+ assert_accepts @matcher, @dummy_class
133
+ end
134
+
135
+ should "accept an instance of that class" do
136
+ assert_accepts @matcher, @dummy_class.new
137
+ end
138
+ end
139
+
140
+ def should_reject_dummy_class
141
+ should "reject the class" do
142
+ assert_rejects @matcher, @dummy_class
143
+ end
144
+
145
+ should "reject an instance of that class" do
146
+ assert_rejects @matcher, @dummy_class.new
147
+ end
148
+ end
149
+
150
+ def with_exitstatus_returning(code)
151
+ saved_exitstatus = $?.nil? ? 0 : $?.exitstatus
152
+ begin
153
+ `ruby -e 'exit #{code.to_i}'`
154
+ yield
155
+ ensure
156
+ `ruby -e 'exit #{saved_exitstatus.to_i}'`
157
+ end
158
+ end