paperclip-v2_7-patched-ruby-1_8_6 2.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +14 -0
  4. data/Appraisals +20 -0
  5. data/CONTRIBUTING.md +38 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE +26 -0
  8. data/NEWS +69 -0
  9. data/README.md +444 -0
  10. data/Rakefile +41 -0
  11. data/cucumber/paperclip_steps.rb +6 -0
  12. data/features/basic_integration.feature +48 -0
  13. data/features/rake_tasks.feature +68 -0
  14. data/features/step_definitions/attachment_steps.rb +65 -0
  15. data/features/step_definitions/html_steps.rb +15 -0
  16. data/features/step_definitions/rails_steps.rb +193 -0
  17. data/features/step_definitions/s3_steps.rb +14 -0
  18. data/features/step_definitions/web_steps.rb +209 -0
  19. data/features/support/env.rb +8 -0
  20. data/features/support/fakeweb.rb +3 -0
  21. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  22. data/features/support/fixtures/boot_config.txt +15 -0
  23. data/features/support/fixtures/gemfile.txt +5 -0
  24. data/features/support/fixtures/preinitializer.txt +20 -0
  25. data/features/support/paths.rb +28 -0
  26. data/features/support/rails.rb +46 -0
  27. data/features/support/selectors.rb +19 -0
  28. data/gemfiles/rails2.gemfile +9 -0
  29. data/gemfiles/rails3.gemfile +9 -0
  30. data/gemfiles/rails3_1.gemfile +9 -0
  31. data/gemfiles/rails3_2.gemfile +9 -0
  32. data/generators/paperclip/USAGE +5 -0
  33. data/generators/paperclip/paperclip_generator.rb +27 -0
  34. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  35. data/init.rb +4 -0
  36. data/lib/generators/paperclip/USAGE +8 -0
  37. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  38. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  39. data/lib/paperclip.rb +493 -0
  40. data/lib/paperclip/attachment.rb +491 -0
  41. data/lib/paperclip/attachment_options.rb +10 -0
  42. data/lib/paperclip/callback_compatibility.rb +61 -0
  43. data/lib/paperclip/geometry.rb +120 -0
  44. data/lib/paperclip/interpolations.rb +174 -0
  45. data/lib/paperclip/iostream.rb +45 -0
  46. data/lib/paperclip/matchers.rb +64 -0
  47. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  48. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  49. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  50. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  51. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  52. data/lib/paperclip/processor.rb +58 -0
  53. data/lib/paperclip/railtie.rb +35 -0
  54. data/lib/paperclip/schema.rb +39 -0
  55. data/lib/paperclip/storage.rb +3 -0
  56. data/lib/paperclip/storage/filesystem.rb +81 -0
  57. data/lib/paperclip/storage/fog.rb +191 -0
  58. data/lib/paperclip/storage/s3.rb +351 -0
  59. data/lib/paperclip/style.rb +103 -0
  60. data/lib/paperclip/thumbnail.rb +105 -0
  61. data/lib/paperclip/upfile.rb +64 -0
  62. data/lib/paperclip/url_generator.rb +64 -0
  63. data/lib/paperclip/version.rb +3 -0
  64. data/lib/tasks/paperclip.rake +101 -0
  65. data/paperclip.gemspec +41 -0
  66. data/rails/init.rb +2 -0
  67. data/shoulda_macros/paperclip.rb +124 -0
  68. data/test/attachment_options_test.rb +40 -0
  69. data/test/attachment_test.rb +1211 -0
  70. data/test/database.yml +4 -0
  71. data/test/fixtures/12k.png +0 -0
  72. data/test/fixtures/50x50.png +0 -0
  73. data/test/fixtures/5k.png +0 -0
  74. data/test/fixtures/animated.gif +0 -0
  75. data/test/fixtures/bad.png +1 -0
  76. data/test/fixtures/fog.yml +8 -0
  77. data/test/fixtures/s3.yml +8 -0
  78. data/test/fixtures/spaced file.png +0 -0
  79. data/test/fixtures/text.txt +1 -0
  80. data/test/fixtures/twopage.pdf +0 -0
  81. data/test/fixtures/uppercase.PNG +0 -0
  82. data/test/geometry_test.rb +206 -0
  83. data/test/helper.rb +181 -0
  84. data/test/integration_test.rb +652 -0
  85. data/test/interpolations_test.rb +219 -0
  86. data/test/iostream_test.rb +71 -0
  87. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  88. data/test/matchers/validate_attachment_content_type_matcher_test.rb +110 -0
  89. data/test/matchers/validate_attachment_presence_matcher_test.rb +47 -0
  90. data/test/matchers/validate_attachment_size_matcher_test.rb +72 -0
  91. data/test/paperclip_missing_attachment_styles_test.rb +96 -0
  92. data/test/paperclip_test.rb +409 -0
  93. data/test/processor_test.rb +10 -0
  94. data/test/schema_test.rb +98 -0
  95. data/test/storage/filesystem_test.rb +62 -0
  96. data/test/storage/fog_test.rb +280 -0
  97. data/test/storage/s3_live_test.rb +138 -0
  98. data/test/storage/s3_test.rb +1093 -0
  99. data/test/style_test.rb +215 -0
  100. data/test/support/mock_attachment.rb +22 -0
  101. data/test/support/mock_interpolator.rb +24 -0
  102. data/test/support/mock_model.rb +2 -0
  103. data/test/support/mock_url_generator_builder.rb +27 -0
  104. data/test/thumbnail_test.rb +396 -0
  105. data/test/upfile_test.rb +53 -0
  106. data/test/url_generator_test.rb +187 -0
  107. metadata +374 -0
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+ module Paperclip
3
+ # The Style class holds the definition of a thumbnail style, applying
4
+ # whatever processing is required to normalize the definition and delaying
5
+ # the evaluation of block parameters until useful context is available.
6
+
7
+ class Style
8
+
9
+ attr_reader :name, :attachment, :format
10
+
11
+ # Creates a Style object. +name+ is the name of the attachment,
12
+ # +definition+ is the style definition from has_attached_file, which
13
+ # can be string, array or hash
14
+ def initialize name, definition, attachment
15
+ @name = name
16
+ @attachment = attachment
17
+ if definition.is_a? Hash
18
+ @geometry = definition.delete(:geometry)
19
+ @format = definition.delete(:format)
20
+ @processors = definition.delete(:processors)
21
+ @convert_options = definition.delete(:convert_options)
22
+ @source_file_options = definition.delete(:source_file_options)
23
+ @other_args = definition
24
+ elsif definition.is_a? String
25
+ @geometry = definition
26
+ @format = nil
27
+ @other_args = {}
28
+ else
29
+ @geometry, @format = [definition, nil].flatten[0..1]
30
+ @other_args = {}
31
+ end
32
+ @format = nil if @format.blank?
33
+ end
34
+
35
+ # retrieves from the attachment the processors defined in the has_attached_file call
36
+ # (which method (in the attachment) will call any supplied procs)
37
+ # There is an important change of interface here: a style rule can set its own processors
38
+ # by default we behave as before, though.
39
+ # if a proc has been supplied, we call it here
40
+ def processors
41
+ @processors.respond_to?(:call) ? @processors.call(attachment.instance) : (@processors || attachment.processors)
42
+ end
43
+
44
+ # retrieves from the attachment the whiny setting
45
+ def whiny
46
+ attachment.whiny
47
+ end
48
+
49
+ # returns true if we're inclined to grumble
50
+ def whiny?
51
+ !!whiny
52
+ end
53
+
54
+ def convert_options
55
+ @convert_options.respond_to?(:call) ? @convert_options.call(attachment.instance) :
56
+ (@convert_options || attachment.send(:extra_options_for, name))
57
+ end
58
+
59
+ def source_file_options
60
+ @source_file_options.respond_to?(:call) ? @source_file_options.call(attachment.instance) :
61
+ (@source_file_options || attachment.send(:extra_source_file_options_for, name))
62
+ end
63
+
64
+ # returns the geometry string for this style
65
+ # if a proc has been supplied, we call it here
66
+ def geometry
67
+ @geometry.respond_to?(:call) ? @geometry.call(attachment.instance) : @geometry
68
+ end
69
+
70
+ # Supplies the hash of options that processors expect to receive as their second argument
71
+ # Arguments other than the standard geometry, format etc are just passed through from
72
+ # initialization and any procs are called here, just before post-processing.
73
+ def processor_options
74
+ args = {}
75
+ @other_args.each do |k,v|
76
+ args[k] = v.respond_to?(:call) ? v.call(attachment) : v
77
+ end
78
+ [:processors, :geometry, :format, :whiny, :convert_options, :source_file_options].each do |k|
79
+ (arg = send(k)) && args[k] = arg
80
+ end
81
+ args
82
+ end
83
+
84
+ # Supports getting and setting style properties with hash notation to ensure backwards-compatibility
85
+ # eg. @attachment.styles[:large][:geometry]@ will still work
86
+ def [](key)
87
+ if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated, :source_file_options].include?(key)
88
+ send(key)
89
+ elsif defined? @other_args[key]
90
+ @other_args[key]
91
+ end
92
+ end
93
+
94
+ def []=(key, value)
95
+ if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated, :source_file_options].include?(key)
96
+ send("#{key}=".intern, value)
97
+ else
98
+ @other_args[key] = value
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,105 @@
1
+ module Paperclip
2
+ # Handles thumbnailing images that are uploaded.
3
+ class Thumbnail < Processor
4
+
5
+ attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
6
+ :source_file_options, :animated
7
+
8
+ # List of formats that we need to preserve animation
9
+ ANIMATED_FORMATS = %w(gif)
10
+
11
+ # Creates a Thumbnail object set to work on the +file+ given. It
12
+ # will attempt to transform the image into one defined by +target_geometry+
13
+ # which is a "WxH"-style string. +format+ will be inferred from the +file+
14
+ # unless specified. Thumbnail creation will raise no errors unless
15
+ # +whiny+ is true (which it is, by default. If +convert_options+ is
16
+ # set, the options will be appended to the convert command upon image conversion
17
+ #
18
+ # Options include:
19
+ #
20
+ # +geometry+ - the desired width and height of the thumbnail (required)
21
+ # +file_geometry_parser+ - an object with a method named +from_file+ that takes an image file and produces its geometry and a +transformation_to+. Defaults to Paperclip::Geometry
22
+ # +string_geometry_parser+ - an object with a method named +parse+ that takes a string and produces an object with +width+, +height+, and +to_s+ accessors. Defaults to Paperclip::Geometry
23
+ # +source_file_options+ - flags passed to the +convert+ command that influence how the source file is read
24
+ # +convert_options+ - flags passed to the +convert+ command that influence how the image is processed
25
+ # +whiny+ - whether to raise an error when processing fails. Defaults to true
26
+ # +format+ - the desired filename extension
27
+ # +animated+ - whether to merge all the layers in the image. Defaults to true
28
+ def initialize(file, options = {}, attachment = nil)
29
+ super
30
+
31
+ geometry = options[:geometry] # this is not an option
32
+ @file = file
33
+ @crop = geometry[-1,1] == '#'
34
+ @target_geometry = (options[:string_geometry_parser] || Geometry).parse(geometry)
35
+ @current_geometry = (options[:file_geometry_parser] || Geometry).from_file(@file)
36
+ @source_file_options = options[:source_file_options]
37
+ @convert_options = options[:convert_options]
38
+ @whiny = options[:whiny].nil? ? true : options[:whiny]
39
+ @format = options[:format]
40
+ @animated = options[:animated].nil? ? true : options[:animated]
41
+
42
+ @source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
43
+ @convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
44
+
45
+ @current_format = File.extname(@file.path)
46
+ @basename = File.basename(@file.path, @current_format)
47
+
48
+ end
49
+
50
+ # Returns true if the +target_geometry+ is meant to crop.
51
+ def crop?
52
+ @crop
53
+ end
54
+
55
+ # Returns true if the image is meant to make use of additional convert options.
56
+ def convert_options?
57
+ !@convert_options.nil? && !@convert_options.empty?
58
+ end
59
+
60
+ # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
61
+ # that contains the new image.
62
+ def make
63
+ src = @file
64
+ dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
65
+ dst.binmode
66
+
67
+ begin
68
+ parameters = []
69
+ parameters << source_file_options
70
+ parameters << ":source"
71
+ parameters << transformation_command
72
+ parameters << convert_options
73
+ parameters << ":dest"
74
+
75
+ parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
76
+
77
+ success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}#{'[0]' unless animated?}", :dest => File.expand_path(dst.path))
78
+ rescue Cocaine::ExitStatusError => e
79
+ raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
80
+ rescue Cocaine::CommandNotFoundError => e
81
+ raise Paperclip::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
82
+ end
83
+
84
+ dst
85
+ end
86
+
87
+ # Returns the command ImageMagick's +convert+ needs to transform the image
88
+ # into the thumbnail.
89
+ def transformation_command
90
+ scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
91
+ trans = []
92
+ trans << "-coalesce" if animated?
93
+ trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
94
+ trans << "-crop" << %["#{crop}"] << "+repage" if crop
95
+ trans
96
+ end
97
+
98
+ protected
99
+
100
+ # Return true if the format is animated
101
+ def animated?
102
+ @animated && ANIMATED_FORMATS.include?(@current_format[1..-1]) && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,64 @@
1
+ require 'mime/types'
2
+
3
+ module Paperclip
4
+ # The Upfile module is a convenience module for adding uploaded-file-type methods
5
+ # to the +File+ class. Useful for testing.
6
+ # user.avatar = File.new("test/test_avatar.jpg")
7
+ module Upfile
8
+ # Infer the MIME-type of the file from the extension.
9
+ def content_type
10
+ types = MIME::Types.type_for(self.original_filename)
11
+ if types.length == 0
12
+ type_from_file_command
13
+ elsif types.length == 1
14
+ types.first.content_type
15
+ else
16
+ iterate_over_array_to_find_best_option(types)
17
+ end
18
+ end
19
+
20
+ def iterate_over_array_to_find_best_option(types)
21
+ types.reject {|type| type.content_type.match(/\/x-/) }.first
22
+ end
23
+
24
+ def type_from_file_command
25
+ # On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
26
+ type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
27
+ mime_type = (Paperclip.run("file", "-b --mime :file", :file => self.path).split(/[:;]\s+/)[0] rescue "application/x-#{type}")
28
+ mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
29
+ mime_type
30
+ end
31
+
32
+ # Returns the file's normal name.
33
+ def original_filename
34
+ File.basename(self.path)
35
+ end
36
+
37
+ # Returns the size of the file.
38
+ def size
39
+ File.size(self)
40
+ end
41
+ end
42
+ end
43
+
44
+ if defined? StringIO
45
+ class StringIO
46
+ attr_accessor :original_filename, :content_type, :fingerprint
47
+
48
+ def original_filename
49
+ @original_filename ||= "stringio.txt"
50
+ end
51
+
52
+ def content_type
53
+ @content_type ||= "text/plain"
54
+ end
55
+
56
+ def fingerprint
57
+ @fingerprint ||= Digest::MD5.hexdigest(self.string)
58
+ end
59
+ end
60
+ end
61
+
62
+ class File #:nodoc:
63
+ include Paperclip::Upfile
64
+ end
@@ -0,0 +1,64 @@
1
+ require 'uri'
2
+
3
+ module Paperclip
4
+ class UrlGenerator
5
+ def initialize(attachment, attachment_options)
6
+ @attachment = attachment
7
+ @attachment_options = attachment_options
8
+ end
9
+
10
+ def for(style_name, options)
11
+ escape_url_as_needed(
12
+ timestamp_as_needed(
13
+ @attachment_options[:interpolator].interpolate(most_appropriate_url, @attachment, style_name),
14
+ options
15
+ ), options)
16
+ end
17
+
18
+ private
19
+
20
+ # This method is all over the place.
21
+ def default_url
22
+ if @attachment_options[:default_url].respond_to?(:call)
23
+ @attachment_options[:default_url].call(@attachment)
24
+ elsif @attachment_options[:default_url].is_a?(Symbol)
25
+ @attachment.instance.send(@attachment_options[:default_url])
26
+ else
27
+ @attachment_options[:default_url]
28
+ end
29
+ end
30
+
31
+ def most_appropriate_url
32
+ if @attachment.original_filename.nil?
33
+ default_url
34
+ else
35
+ @attachment_options[:url]
36
+ end
37
+ end
38
+
39
+ def timestamp_as_needed(url, options)
40
+ if options[:timestamp] && timestamp_possible?
41
+ delimiter_char = url.match(/\?.+=/) ? '&' : '?'
42
+ "#{url}#{delimiter_char}#{@attachment.updated_at.to_s}"
43
+ else
44
+ url
45
+ end
46
+ end
47
+
48
+ def timestamp_possible?
49
+ @attachment.respond_to?(:updated_at) && @attachment.updated_at.present?
50
+ end
51
+
52
+ def escape_url_as_needed(url, options)
53
+ if options[:escape]
54
+ escape_url(url)
55
+ else
56
+ url
57
+ end
58
+ end
59
+
60
+ def escape_url(url)
61
+ (url.respond_to?(:escape) ? url.escape : URI.escape(url)).gsub(/(\/.+)\?(.+\.)/, '\1%3F\2')
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module Paperclip
2
+ VERSION = "2.7.5" unless defined? Paperclip::VERSION
3
+ end
@@ -0,0 +1,101 @@
1
+ module Paperclip
2
+ module Task
3
+ def self.obtain_class
4
+ class_name = ENV['CLASS'] || ENV['class']
5
+ raise "Must specify CLASS" unless class_name
6
+ class_name
7
+ end
8
+
9
+ def self.obtain_attachments(klass)
10
+ klass = Paperclip.class_for(klass.to_s)
11
+ name = ENV['ATTACHMENT'] || ENV['attachment']
12
+ raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
13
+ if !name.blank? && klass.attachment_definitions.keys.include?(name)
14
+ [ name ]
15
+ else
16
+ klass.attachment_definitions.keys
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ namespace :paperclip do
23
+ desc "Refreshes both metadata and thumbnails."
24
+ task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
25
+
26
+ namespace :refresh do
27
+ desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT and STYLES splitted by comma)."
28
+ task :thumbnails => :environment do
29
+ errors = []
30
+ klass = Paperclip::Task.obtain_class
31
+ names = Paperclip::Task.obtain_attachments(klass)
32
+ styles = (ENV['STYLES'] || ENV['styles'] || '').split(',').map(&:to_sym)
33
+ names.each do |name|
34
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
35
+ instance.send(name).reprocess!(*styles)
36
+ errors << [instance.id, instance.errors] unless instance.errors.blank?
37
+ end
38
+ end
39
+ errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" }
40
+ end
41
+
42
+ desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
43
+ task :metadata => :environment do
44
+ klass = Paperclip::Task.obtain_class
45
+ names = Paperclip::Task.obtain_attachments(klass)
46
+ names.each do |name|
47
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
48
+ if file = instance.send(name).to_file(:original)
49
+ instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
50
+ instance.send("#{name}_content_type=", file.content_type.to_s.strip)
51
+ instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
52
+ if Rails.version >= "3.0.0"
53
+ instance.save(:validate => false)
54
+ else
55
+ instance.save(false)
56
+ end
57
+ else
58
+ true
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ desc "Regenerates missing thumbnail styles for all classes using Paperclip."
65
+ task :missing_styles => :environment do
66
+ # Force loading all model classes to never miss any has_attached_file declaration:
67
+ Dir[Rails.root + 'app/models/**/*.rb'].each { |path| load path }
68
+ Paperclip.missing_attachments_styles.each do |klass, attachment_definitions|
69
+ attachment_definitions.each do |attachment_name, missing_styles|
70
+ puts "Regenerating #{klass} -> #{attachment_name} -> #{missing_styles.inspect}"
71
+ ENV['CLASS'] = klass.to_s
72
+ ENV['ATTACHMENT'] = attachment_name.to_s
73
+ ENV['STYLES'] = missing_styles.join(',')
74
+ Rake::Task['paperclip:refresh:thumbnails'].execute
75
+ end
76
+ end
77
+ Paperclip.save_current_attachments_styles!
78
+ end
79
+ end
80
+
81
+ desc "Cleans out invalid attachments. Useful after you've added new validations."
82
+ task :clean => :environment do
83
+ klass = Paperclip::Task.obtain_class
84
+ names = Paperclip::Task.obtain_attachments(klass)
85
+ names.each do |name|
86
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
87
+ unless instance.valid?
88
+ attributes = %w(file_size file_name content_type).map{ |suffix| "#{name}_#{suffix}".to_sym }
89
+ if attributes.any?{ |attribute| instance.errors[attribute].present? }
90
+ instance.send("#{name}=", nil)
91
+ if Rails.version >= "3.0.0"
92
+ instance.save(:validate => false)
93
+ else
94
+ instance.save(false)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,41 @@
1
+ $LOAD_PATH.push File.expand_path("../lib", __FILE__)
2
+ require 'paperclip/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "paperclip-v2_7-patched-ruby-1_8_6"
6
+ s.version = Paperclip::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.author = "Jon Yurek"
9
+ s.email = ["jyurek@thoughtbot.com"]
10
+ s.homepage = "https://github.com/thoughtbot/paperclip"
11
+ s.summary = "File attachments as attributes for ActiveRecord"
12
+ s.description = "Easy upload management for ActiveRecord"
13
+
14
+ s.rubyforge_project = "paperclip"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.requirements << "ImageMagick"
22
+
23
+ s.add_dependency('activerecord', '< 4.0.0')
24
+ s.add_dependency('activesupport', '< 4.0.0')
25
+ s.add_dependency('cocaine', '~> 0.3.0')
26
+ s.add_dependency('mime-types')
27
+
28
+ s.add_development_dependency('shoulda')
29
+ s.add_development_dependency('appraisal', '~> 0.4.0')
30
+ s.add_development_dependency('mocha')
31
+ s.add_development_dependency('aws-sdk')
32
+ s.add_development_dependency('sqlite3', '~> 1.3.5')
33
+ s.add_development_dependency('cucumber', '~> 1.1.0')
34
+ s.add_development_dependency('aruba')
35
+ s.add_development_dependency('capybara')
36
+ s.add_development_dependency('bundler')
37
+ # s.add_development_dependency('cocaine', '~> 0.3.0')
38
+ s.add_development_dependency('fog')
39
+ s.add_development_dependency('rake')
40
+ s.add_development_dependency('fakeweb')
41
+ end