attachment_saver 1.0.0

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 (41) hide show
  1. data/.gitignore +3 -0
  2. data/MIT-LICENSE +19 -0
  3. data/README +137 -0
  4. data/Rakefile +16 -0
  5. data/attachment_saver.gemspec +41 -0
  6. data/init.rb +1 -0
  7. data/lib/attachment_saver.rb +171 -0
  8. data/lib/attachment_saver/version.rb +3 -0
  9. data/lib/attachment_saver_errors.rb +3 -0
  10. data/lib/datastores/file_system.rb +189 -0
  11. data/lib/datastores/in_column.rb +49 -0
  12. data/lib/misc/extended_tempfile.rb +12 -0
  13. data/lib/misc/file_size.rb +5 -0
  14. data/lib/misc/image_science_extensions.rb +102 -0
  15. data/lib/misc/mini_magick_extensions.rb +89 -0
  16. data/lib/processors/image.rb +187 -0
  17. data/lib/processors/image_science.rb +94 -0
  18. data/lib/processors/mini_magick.rb +103 -0
  19. data/lib/processors/r_magick.rb +120 -0
  20. data/test/attachment_saver_test.rb +162 -0
  21. data/test/database.yml +3 -0
  22. data/test/file_system_datastore_test.rb +468 -0
  23. data/test/fixtures/broken.jpg +1 -0
  24. data/test/fixtures/emptyextension. +0 -0
  25. data/test/fixtures/noextension +0 -0
  26. data/test/fixtures/test.jpg +0 -0
  27. data/test/fixtures/test.js +1 -0
  28. data/test/fixtures/wrongextension.png +0 -0
  29. data/test/image_fixtures.rb +69 -0
  30. data/test/image_operations.rb +114 -0
  31. data/test/image_processor_test.rb +67 -0
  32. data/test/image_processor_test_common.rb +81 -0
  33. data/test/image_science_processor_test.rb +20 -0
  34. data/test/in_column_datastore_test.rb +115 -0
  35. data/test/mini_magick_processor_test.rb +20 -0
  36. data/test/model_test.rb +205 -0
  37. data/test/public/.empty +0 -0
  38. data/test/rmagick_processor_test.rb +20 -0
  39. data/test/schema.rb +41 -0
  40. data/test/test_helper.rb +49 -0
  41. metadata +223 -0
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'image_processor_test_common'))
2
+ require 'processors/mini_magick'
3
+
4
+ class MiniMagickProcessorTest < Test::Unit::TestCase
5
+ class MiniMagickTestModel
6
+ include AttachmentSaver::InstanceMethods
7
+ include AttachmentSaver::Processors::MiniMagick
8
+ include ImageProcessorTestModel
9
+ end
10
+
11
+ def processor_model
12
+ MiniMagickTestModel
13
+ end
14
+
15
+ def processor_exception
16
+ MiniMagickProcessorError
17
+ end
18
+
19
+ include ImageProcessorTests
20
+ end
@@ -0,0 +1,205 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'image_fixtures'))
3
+
4
+ class DerivedImage < ActiveRecord::Base
5
+ saves_attachment
6
+ end
7
+
8
+ class Image < ActiveRecord::Base
9
+ FORMATS = {:thumb => [:cover_and_crop, 50, 50],
10
+ :medium => [:shrink_to_fit, 500, 500],
11
+ :big => [:shrink_to_fit, 1024, 1024]}
12
+ saves_attachment :formats => FORMATS
13
+ end
14
+
15
+ class OtherImage < ActiveRecord::Base
16
+ saves_attachment :formats => {:small => [:shrink_to_fit, 200, 200], :normal => [:shrink_to_fit, 400, 300]}
17
+ cattr_accessor :want_smalls
18
+
19
+ protected
20
+ def want_format?(format_name, width, height)
21
+ format_name != :small || self.class.want_smalls
22
+ end
23
+ end
24
+
25
+ class Unprocessed < ActiveRecord::Base
26
+ saves_attachment
27
+ validates_presence_of :original_filename, :content_type, :size
28
+ end
29
+
30
+ class LoadedImage < ActiveRecord::Base
31
+ set_table_name 'images'
32
+ saves_attachment :processor => 'image_science' # don't create any derived images, but still process the image to get the attributes
33
+ end
34
+
35
+ class AllInOneTableImages < ActiveRecord::Base
36
+ saves_attachment :formats => {:small => '200x200', :normal => '400x'},
37
+ :derived_class => 'AllInOneTableImages'
38
+ end
39
+
40
+ class ImageScienceImage < ActiveRecord::Base
41
+ set_table_name 'images'
42
+ saves_attachment :processor => 'ImageScience', :formats => {:small => '200x200'}
43
+ end
44
+
45
+ class RMagickImage < ActiveRecord::Base
46
+ set_table_name 'images'
47
+ saves_attachment :processor => 'RMagick', :formats => {:small => '200x200'}
48
+ end
49
+
50
+ class MiniMagickImage < ActiveRecord::Base
51
+ set_table_name 'images'
52
+ saves_attachment :processor => 'RMagick', :formats => {:small => '200x200'}
53
+ end
54
+
55
+ class ModelTest < Test::Unit::TestCase
56
+ module ValidUploadedFileAttributes
57
+ def fixture=(value)
58
+ @fixture = value
59
+ end
60
+
61
+ def original_filename
62
+ @fixture[:original_filename]
63
+ end
64
+
65
+ def content_type
66
+ @fixture[:content_type]
67
+ end
68
+
69
+ def size
70
+ stat.size
71
+ end
72
+ end
73
+
74
+ def uploaded_file_from(fixture)
75
+ f = File.open(fixture[:path])
76
+ f.extend ValidUploadedFileAttributes
77
+ f.fixture = fixture
78
+ f
79
+ end
80
+
81
+ def test_unprocessed_attachment
82
+ model = Unprocessed.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
83
+ assert_equal ImageFixtures::valid[:expected_content_type], model.content_type
84
+ assert_equal ImageFixtures::valid[:expected_extension], model.file_extension
85
+ assert_equal ImageFixtures::valid[:expected_extension], AttachmentSaver::split_filename(model.storage_filename).last
86
+ assert File.read(ImageFixtures::valid[:path]) == File.read(model.storage_filename), "stored data doesn't match!"
87
+ end
88
+
89
+ def test_underived_but_processed_attachment
90
+ model = LoadedImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
91
+ assert_equal ImageFixtures::valid[:expected_content_type], model.content_type
92
+ assert_equal ImageFixtures::valid[:expected_extension], model.file_extension
93
+ assert_equal ImageFixtures::valid[:expected_extension], AttachmentSaver::split_filename(model.storage_filename).last
94
+ assert File.read(ImageFixtures::valid[:path]) == File.read(model.storage_filename), "stored data doesn't match!"
95
+ assert_equal ImageFixtures::valid[:width], model.width
96
+ assert_equal ImageFixtures::valid[:height], model.height
97
+ assert_equal "#{ImageFixtures::valid[:width]}x#{ImageFixtures::valid[:height]}", model.image_size
98
+ end
99
+
100
+ def test_extension_and_type_correction
101
+ model = LoadedImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::wrong_extension))
102
+ assert_equal ImageFixtures::wrong_extension[:expected_content_type], model.content_type
103
+ assert_equal ImageFixtures::wrong_extension[:expected_extension], model.file_extension
104
+ assert_equal ImageFixtures::wrong_extension[:expected_extension], AttachmentSaver::split_filename(model.storage_filename).last
105
+ assert File.read(ImageFixtures::wrong_extension[:path]) == File.read(model.storage_filename), "stored data doesn't match!"
106
+ assert_equal ImageFixtures::wrong_extension[:width], model.width
107
+ assert_equal ImageFixtures::wrong_extension[:height], model.height
108
+ assert_equal "#{ImageFixtures::wrong_extension[:width]}x#{ImageFixtures::wrong_extension[:height]}", model.image_size
109
+ end
110
+
111
+ def test_image_resizing
112
+ model = Image.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
113
+ assert_equal ImageFixtures::valid[:expected_content_type], model.content_type
114
+ assert_equal ImageFixtures::valid[:expected_extension], model.file_extension
115
+ assert_equal ImageFixtures::valid[:expected_extension], AttachmentSaver::split_filename(model.storage_filename).last
116
+ assert File.read(ImageFixtures::valid[:path]) == File.read(model.storage_filename), "stored data doesn't match!"
117
+ assert_equal ImageFixtures::valid[:width], model.width
118
+ assert_equal ImageFixtures::valid[:height], model.height
119
+ assert_equal "#{ImageFixtures::valid[:width]}x#{ImageFixtures::valid[:height]}", model.image_size
120
+
121
+ # full resize operation tests are performed in image_*_processor_test, here we just check enough to ensure that they were executed
122
+
123
+ assert_equal Image::FORMATS.keys.collect(&:to_s).sort, model.formats.collect(&:format_name).sort
124
+ model.formats.each {|size| assert !size.new_record?}
125
+
126
+ thumb = model.formats.find_by_format_name('thumb')
127
+ assert_equal Image::FORMATS[:thumb][1], thumb.width
128
+ assert_equal Image::FORMATS[:thumb][1], thumb.height
129
+
130
+ medium = model.formats.find_by_format_name('medium')
131
+ assert medium.width <= Image::FORMATS[:medium][1]
132
+ assert medium.height <= Image::FORMATS[:medium][2]
133
+ assert medium.width == Image::FORMATS[:medium][1] || medium.height == Image::FORMATS[:medium][2]
134
+ end
135
+
136
+ def test_image_science
137
+ model = ImageScienceImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
138
+ assert_equal ['small'], model.formats.collect(&:format_name)
139
+ end
140
+
141
+ def test_rmagick
142
+ model = RMagickImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
143
+ assert_equal ['small'], model.formats.collect(&:format_name)
144
+ end
145
+
146
+ def test_mini_magick
147
+ model = MiniMagickImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
148
+ assert_equal ['small'], model.formats.collect(&:format_name)
149
+ end
150
+
151
+ def test_image_rebuilding
152
+ model = Image.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
153
+ old_storage_filenames = [model.storage_filename] + model.formats.sort_by(&:format_name).collect(&:storage_filename)
154
+ model.update_attributes(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
155
+ new_storage_filenames = [model.storage_filename] + model.formats.sort_by(&:format_name).collect(&:storage_filename)
156
+ model.reload
157
+ model.formats(true)
158
+ reloaded_storage_filenames = [model.storage_filename] + model.formats.sort_by(&:format_name).collect(&:storage_filename)
159
+
160
+ assert_equal Image::FORMATS.size, model.formats.size
161
+ assert_equal Image::FORMATS.keys.collect(&:to_s).sort, model.formats.collect(&:format_name).sort
162
+
163
+ assert_equal old_storage_filenames.size, new_storage_filenames.size
164
+ assert_equal old_storage_filenames.size, reloaded_storage_filenames.size
165
+ old_storage_filenames.each_with_index do |f, i|
166
+ assert_not_equal f, new_storage_filenames[i]
167
+ assert_not_equal f, reloaded_storage_filenames[i]
168
+ assert_equal new_storage_filenames[i], reloaded_storage_filenames[i]
169
+ end
170
+ end
171
+
172
+ def test_want_format?
173
+ OtherImage.want_smalls = false
174
+ model = OtherImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
175
+ assert_equal ["normal"], model.formats.collect(&:format_name).sort
176
+
177
+ OtherImage.want_smalls = true
178
+ model = OtherImage.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
179
+ assert_equal ["normal", "small"], model.formats.collect(&:format_name).sort
180
+
181
+ OtherImage.want_smalls = false
182
+ model.update_attributes!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
183
+ #assert_equal ["normal"], model.formats.collect(&:format_name).sort # because we use formats.destroy(..ids..), they really should be removed from the formats collection in memory, but aren't in Rails 1.2.3 :/. so the normal, expected semantics is that apps must reload to see collection changes.
184
+ assert_equal ["normal"], model.formats(true).collect(&:format_name).sort
185
+ # note that the small size has not only been not regenerated, it's been deleted
186
+ end
187
+
188
+ def test_all_in_one_table
189
+ model = AllInOneTableImages.create!(:uploaded_data => uploaded_file_from(ImageFixtures::valid))
190
+ assert_equal ImageFixtures::valid[:expected_content_type], model.content_type
191
+ assert_equal ImageFixtures::valid[:expected_extension], model.file_extension
192
+ assert_equal ImageFixtures::valid[:expected_extension], AttachmentSaver::split_filename(model.storage_filename).last
193
+ assert File.read(ImageFixtures::valid[:path]) == File.read(model.storage_filename), "stored data doesn't match!"
194
+ assert_equal ImageFixtures::valid[:width], model.width
195
+ assert_equal ImageFixtures::valid[:height], model.height
196
+ assert_equal "#{ImageFixtures::valid[:width]}x#{ImageFixtures::valid[:height]}", model.image_size
197
+
198
+ assert !model.formats.empty?
199
+ model.formats.each do |size|
200
+ assert_equal AllInOneTableImages, size.class
201
+ assert !size.new_record?
202
+ assert size.formats.empty?
203
+ end
204
+ end
205
+ end
File without changes
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'image_processor_test_common'))
2
+ require 'processors/r_magick'
3
+
4
+ class RMagickProcessorTest < Test::Unit::TestCase
5
+ class RMagickTestModel
6
+ include AttachmentSaver::InstanceMethods
7
+ include AttachmentSaver::Processors::RMagick
8
+ include ImageProcessorTestModel
9
+ end
10
+
11
+ def processor_model
12
+ RMagickTestModel
13
+ end
14
+
15
+ def processor_exception
16
+ RMagickProcessorError
17
+ end
18
+
19
+ include ImageProcessorTests
20
+ end
@@ -0,0 +1,41 @@
1
+ def add_generic_attachment_columns(t, want_image_columns)
2
+ t.string :storage_key, :null => false
3
+ t.string :content_type, :null => false
4
+ t.integer :size, :null => false
5
+ t.datetime :created_at, :null => false
6
+ t.datetime :updated_at
7
+ t.integer :width, :null => false if want_image_columns
8
+ t.integer :height, :null => false if want_image_columns
9
+ end
10
+
11
+ ActiveRecord::Schema.define(:version => 0) do
12
+ create_table :unprocesseds, :force => true do |t|
13
+ t.string :original_filename, :null => false
14
+ add_generic_attachment_columns(t, false)
15
+ end
16
+
17
+ create_table :images, :force => true do |t|
18
+ t.string :original_filename, :null => false
19
+ add_generic_attachment_columns(t, true)
20
+ end
21
+
22
+ create_table :derived_images, :force => true do |t|
23
+ t.string :original_type, :null => false
24
+ t.integer :original_id, :null => false
25
+ t.string :format_name, :null => false
26
+ add_generic_attachment_columns(t, true)
27
+ end
28
+
29
+ create_table :other_images, :force => true do |t| # for testing derived_image owner polymorphism
30
+ t.string :original_filename, :null => false
31
+ add_generic_attachment_columns(t, true)
32
+ end
33
+
34
+ create_table :all_in_one_table_images, :force => true do |t|
35
+ t.string :original_filename # will be null for deriveds
36
+ t.string :original_type # will be null for originals
37
+ t.integer :original_id # ditto
38
+ t.string :format_name # ditto
39
+ add_generic_attachment_columns(t, true)
40
+ end
41
+ end
@@ -0,0 +1,49 @@
1
+ if File.exist?("../../../config/boot.rb")
2
+ require "../../../config/boot.rb"
3
+ else
4
+ require 'rubygems'
5
+ end
6
+
7
+ gem 'activesupport', ENV['RAILS_VERSION']
8
+ gem 'activerecord', ENV['RAILS_VERSION']
9
+
10
+ require 'test/unit'
11
+ require 'active_support'
12
+ require 'active_support/test_case'
13
+ require 'active_record'
14
+ require 'active_record/fixtures'
15
+
16
+ begin
17
+ require 'ruby-debug'
18
+ Debugger.start
19
+ rescue LoadError
20
+ # ruby-debug not installed, no debugging for you
21
+ end
22
+
23
+ RAILS_ROOT = File.dirname(__FILE__)
24
+ RAILS_ENV = ENV['RAILS_ENV'] ||= 'test'
25
+ TEST_TEMP_DIR = File.join(File.dirname(__FILE__), 'tmp', 'attachment_saver_test')
26
+
27
+ class Rails
28
+ def self.root; RAILS_ROOT; end
29
+ def self.env; RAILS_ENV; end
30
+ end
31
+
32
+ class DummyLogger
33
+ def method_missing(*args)
34
+ end
35
+ end
36
+
37
+ ActiveRecord::Base.logger = DummyLogger.new
38
+
39
+ ActiveRecord::Base.configurations = YAML::load(IO.read(File.join(File.dirname(__FILE__), "database.yml")))
40
+ ActiveRecord::Base.establish_connection ActiveRecord::Base.configurations[ENV['RAILS_ENV']]
41
+ load(File.join(File.dirname(__FILE__), "/schema.rb"))
42
+
43
+ require File.expand_path(File.join(File.dirname(__FILE__), '../init')) # load the plugin
44
+
45
+ at_exit do # at_exits are run in reverse of declaration order, and Test::Unit runs from an at_exit, so we must declare ours before that require below
46
+ FileUtils.rm_rf(File.join(File.dirname(__FILE__), 'tmp'))
47
+ end
48
+
49
+ require 'test/unit'
metadata ADDED
@@ -0,0 +1,223 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attachment_saver
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Will Bryant
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-04-21 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activerecord
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rake
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: image_science
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rmagick
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: mini_magick
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ type: :development
89
+ version_requirements: *id005
90
+ - !ruby/object:Gem::Dependency
91
+ name: sqlite3
92
+ prerelease: false
93
+ requirement: &id006 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ type: :development
103
+ version_requirements: *id006
104
+ description: |
105
+ This plugin implements attachment storage and processing, integrated with
106
+ ActiveRecord models and Ruby CGI/Rails-style uploads. Image processing
107
+ operations including a number of different resizing & thumbnailing modes are
108
+ provided, and the architecture simplifies clean implementation of other types
109
+ of processing. Errors are carefully handled to minimize the possibility of
110
+ broken uploads leaving incomplete or corrupt data.
111
+
112
+ RMagick, MiniMagick, and ImageScience image processors are supported.
113
+
114
+
115
+ Compatibility
116
+ =============
117
+
118
+ Currently tested against Rails 3.2.13 and 3.1.8, on Ruby 1.8.7 and 2.0.0p0.
119
+ Was also tested compatible with 2.3.14 and 3.0.17.
120
+
121
+ email: will.bryant@gmail.com
122
+ executables: []
123
+
124
+ extensions: []
125
+
126
+ extra_rdoc_files: []
127
+
128
+ files:
129
+ - .gitignore
130
+ - MIT-LICENSE
131
+ - README
132
+ - Rakefile
133
+ - attachment_saver.gemspec
134
+ - init.rb
135
+ - lib/attachment_saver.rb
136
+ - lib/attachment_saver/version.rb
137
+ - lib/attachment_saver_errors.rb
138
+ - lib/datastores/file_system.rb
139
+ - lib/datastores/in_column.rb
140
+ - lib/misc/extended_tempfile.rb
141
+ - lib/misc/file_size.rb
142
+ - lib/misc/image_science_extensions.rb
143
+ - lib/misc/mini_magick_extensions.rb
144
+ - lib/processors/image.rb
145
+ - lib/processors/image_science.rb
146
+ - lib/processors/mini_magick.rb
147
+ - lib/processors/r_magick.rb
148
+ - test/attachment_saver_test.rb
149
+ - test/database.yml
150
+ - test/file_system_datastore_test.rb
151
+ - test/fixtures/broken.jpg
152
+ - test/fixtures/emptyextension.
153
+ - test/fixtures/noextension
154
+ - test/fixtures/test.jpg
155
+ - test/fixtures/test.js
156
+ - test/fixtures/wrongextension.png
157
+ - test/image_fixtures.rb
158
+ - test/image_operations.rb
159
+ - test/image_processor_test.rb
160
+ - test/image_processor_test_common.rb
161
+ - test/image_science_processor_test.rb
162
+ - test/in_column_datastore_test.rb
163
+ - test/mini_magick_processor_test.rb
164
+ - test/model_test.rb
165
+ - test/public/.empty
166
+ - test/rmagick_processor_test.rb
167
+ - test/schema.rb
168
+ - test/test_helper.rb
169
+ homepage: http://github.com/willbryant/attachment_saver
170
+ licenses: []
171
+
172
+ post_install_message:
173
+ rdoc_options: []
174
+
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ hash: 3
183
+ segments:
184
+ - 0
185
+ version: "0"
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
194
+ version: "0"
195
+ requirements: []
196
+
197
+ rubyforge_project:
198
+ rubygems_version: 1.8.15
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: Saves attachments in files, models, or columns.
202
+ test_files:
203
+ - test/attachment_saver_test.rb
204
+ - test/database.yml
205
+ - test/file_system_datastore_test.rb
206
+ - test/fixtures/broken.jpg
207
+ - test/fixtures/emptyextension.
208
+ - test/fixtures/noextension
209
+ - test/fixtures/test.jpg
210
+ - test/fixtures/test.js
211
+ - test/fixtures/wrongextension.png
212
+ - test/image_fixtures.rb
213
+ - test/image_operations.rb
214
+ - test/image_processor_test.rb
215
+ - test/image_processor_test_common.rb
216
+ - test/image_science_processor_test.rb
217
+ - test/in_column_datastore_test.rb
218
+ - test/mini_magick_processor_test.rb
219
+ - test/model_test.rb
220
+ - test/public/.empty
221
+ - test/rmagick_processor_test.rb
222
+ - test/schema.rb
223
+ - test/test_helper.rb