durran-carrierwave 0.3.2.3 → 0.4.3

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 (67) hide show
  1. data/Generators +1 -1
  2. data/History.txt +39 -2
  3. data/Manifest.txt +19 -5
  4. data/README.rdoc +180 -55
  5. data/Rakefile +11 -4
  6. data/features/grid_fs_storage.feature +32 -0
  7. data/features/step_definitions/general_steps.rb +6 -1
  8. data/features/support/activerecord.rb +1 -1
  9. data/features/support/env.rb +3 -16
  10. data/lib/carrierwave.rb +19 -74
  11. data/lib/carrierwave/compatibility/paperclip.rb +2 -2
  12. data/lib/carrierwave/core_ext/inheritable_attributes.rb +3 -3
  13. data/lib/carrierwave/mount.rb +36 -27
  14. data/lib/carrierwave/orm/activerecord.rb +3 -3
  15. data/lib/carrierwave/orm/datamapper.rb +2 -2
  16. data/lib/carrierwave/orm/mongoid.rb +23 -0
  17. data/lib/carrierwave/orm/mongomapper.rb +1 -1
  18. data/lib/carrierwave/orm/sequel.rb +4 -16
  19. data/lib/carrierwave/processing/image_science.rb +54 -25
  20. data/lib/carrierwave/processing/mini_magick.rb +269 -0
  21. data/lib/carrierwave/processing/rmagick.rb +4 -6
  22. data/lib/carrierwave/sanitized_file.rb +7 -6
  23. data/lib/carrierwave/storage/abstract.rb +0 -2
  24. data/lib/carrierwave/storage/file.rb +3 -5
  25. data/lib/carrierwave/storage/grid_fs.rb +92 -0
  26. data/lib/carrierwave/storage/right_s3.rb +183 -0
  27. data/lib/carrierwave/storage/s3.rb +37 -69
  28. data/lib/carrierwave/test/matchers.rb +22 -8
  29. data/lib/carrierwave/uploader.rb +2 -2
  30. data/lib/carrierwave/uploader/cache.rb +21 -18
  31. data/lib/carrierwave/uploader/configuration.rb +122 -0
  32. data/lib/carrierwave/uploader/default_url.rb +19 -0
  33. data/lib/carrierwave/uploader/processing.rb +4 -2
  34. data/lib/carrierwave/uploader/remove.rb +0 -1
  35. data/lib/carrierwave/uploader/store.rb +1 -68
  36. data/lib/carrierwave/uploader/url.rb +1 -1
  37. data/lib/carrierwave/uploader/versions.rb +3 -4
  38. data/{lib/generators → merb_generators}/uploader_generator.rb +0 -0
  39. data/rails_generators/uploader/templates/uploader.rb +4 -4
  40. data/spec/compatibility/paperclip_spec.rb +11 -2
  41. data/spec/fixtures/landscape.jpg +0 -0
  42. data/spec/fixtures/portrait.jpg +0 -0
  43. data/spec/mount_spec.rb +0 -25
  44. data/spec/orm/datamapper_spec.rb +55 -48
  45. data/spec/orm/mongoid_spec.rb +206 -0
  46. data/spec/orm/mongomapper_spec.rb +19 -1
  47. data/spec/orm/sequel_spec.rb +3 -12
  48. data/spec/processing/image_science_spec.rb +56 -0
  49. data/spec/processing/mini_magick_spec.rb +76 -0
  50. data/spec/processing/rmagick_spec.rb +68 -0
  51. data/spec/sanitized_file_spec.rb +84 -74
  52. data/spec/spec_helper.rb +1 -3
  53. data/spec/storage/grid_fs_spec.rb +78 -0
  54. data/spec/storage/right_s3_spec.rb +75 -0
  55. data/spec/storage/s3_spec.rb +83 -0
  56. data/spec/uploader/cache_spec.rb +1 -13
  57. data/spec/uploader/configuration_spec.rb +105 -0
  58. data/spec/uploader/{default_path_spec.rb → default_url_spec.rb} +22 -5
  59. data/spec/uploader/paths_spec.rb +1 -1
  60. data/spec/uploader/processing_spec.rb +11 -0
  61. data/spec/uploader/store_spec.rb +21 -47
  62. data/spec/uploader/versions_spec.rb +0 -8
  63. metadata +105 -17
  64. data/LICENSE +0 -8
  65. data/carrierwave.gemspec +0 -57
  66. data/lib/carrierwave/uploader/default_path.rb +0 -23
  67. data/lib/carrierwave/uploader/paths.rb +0 -27
data/Rakefile CHANGED
@@ -2,26 +2,33 @@ require 'rubygems'
2
2
  gem 'hoe', '>= 2.1.0'
3
3
  require 'hoe'
4
4
  require 'fileutils'
5
- require './lib/carrierwave'
5
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
6
+ require 'carrierwave'
6
7
 
7
8
  Hoe.plugin :newgem
8
9
  # Hoe.plugin :website
9
10
  Hoe.plugin :cucumberfeatures
10
11
 
11
- $hoe = Hoe.spec 'carrierwave' do
12
+ $hoe = Hoe.spec 'durran-carrierwave' do
12
13
  self.developer 'Jonas Nicklas', 'jonas.nicklas@gmail.com'
13
14
  self.rubyforge_name = self.name
14
15
  self.readme_file = 'README.rdoc'
15
16
  self.version = CarrierWave::VERSION
17
+ self.extra_dev_deps << ['newgem', '>=1.5.2']
16
18
  self.extra_dev_deps << ['rspec', '>=1.2.8']
17
19
  self.extra_dev_deps << ['cucumber', '>=0.3.96']
18
20
  self.extra_dev_deps << ['activerecord', '>=2.3.3']
21
+ self.extra_dev_deps << ['sqlite3-ruby', '>=1.2.5']
19
22
  self.extra_dev_deps << ['dm-core', '>=0.9.11']
23
+ self.extra_dev_deps << ['data_objects', '>=0.9.12']
24
+ self.extra_dev_deps << ['do_sqlite3', '>=0.9.11']
20
25
  self.extra_dev_deps << ['sequel', '>=3.2.0']
21
26
  self.extra_dev_deps << ['rmagick', '>=2.10.0']
22
- self.extra_dev_deps << ['mongomapper', '>=0.3.3']
27
+ self.extra_dev_deps << ['mini_magick', '>=1.2.5']
28
+ self.extra_dev_deps << ['mongo_mapper', '>=0.6.8']
29
+ self.extra_dev_deps << ['mongoid', '>=0.10.4']
30
+ self.extra_dev_deps << ['aws-s3', '>=0.6.2']
23
31
  self.extra_rdoc_files << 'README.rdoc'
24
- self.extra_rdoc_files << 'LICENSE'
25
32
  end
26
33
 
27
34
  require 'newgem/tasks'
@@ -0,0 +1,32 @@
1
+ Feature: uploader with file storage
2
+ In order to be awesome
3
+ As a developer using CarrierWave
4
+ I want to upload files to the filesystem
5
+
6
+ Background:
7
+ Given an uploader class that uses the 'grid_fs' storage
8
+ And an instance of that class
9
+
10
+ Scenario: store a file
11
+ When I store the file 'fixtures/bork.txt'
12
+ Then the contents of the file should be 'this is a file'
13
+
14
+ Scenario: store two files in succession
15
+ When I store the file 'fixtures/bork.txt'
16
+ Then the contents of the file should be 'this is a file'
17
+ When I store the file 'fixtures/monkey.txt'
18
+ Then the contents of the file should be 'this is another file'
19
+
20
+ Scenario: cache a file and then store it
21
+ When I cache the file 'fixtures/bork.txt'
22
+ Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
23
+ And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
24
+ And there should not be a file at 'public/uploads/bork.txt'
25
+ When I store the file
26
+ Then the contents of the file should be 'this is a file'
27
+
28
+ Scenario: retrieving a file from cache then storing
29
+ Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
30
+ When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
31
+ And I store the file
32
+ Then the contents of the file should be 'this is a file'
@@ -1,13 +1,18 @@
1
1
  # encoding: utf-8
2
2
 
3
- Given /^an uploader class that uses the 'file' storage$/ do
3
+ Given /^an uploader class that uses the '(.*?)' storage$/ do |kind|
4
4
  @klass = Class.new(CarrierWave::Uploader::Base)
5
+ @klass.storage = kind.to_sym
5
6
  end
6
7
 
7
8
  Given /^an instance of that class$/ do
8
9
  @uploader = @klass.new
9
10
  end
10
11
 
12
+ Then /^the contents of the file should be '(.*?)'$/ do |contents|
13
+ @uploader.read.chomp.should == contents
14
+ end
15
+
11
16
  Given /^that the uploader reverses the filename$/ do
12
17
  @klass.class_eval do
13
18
  def filename
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'activerecord'
3
+ require 'active_record'
4
4
  require 'carrierwave/mount'
5
5
  require 'carrierwave/orm/activerecord'
6
6
 
@@ -1,34 +1,21 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  $TESTING=true
4
- $:.push File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $:.unshift File.expand_path(File.join('..', '..', 'lib'), File.dirname(__FILE__))
5
5
 
6
- require 'rubygems'
7
6
  require File.join(File.dirname(__FILE__), 'activerecord')
8
7
  require File.join(File.dirname(__FILE__), 'datamapper')
9
8
 
10
- if ENV["AS"]
11
- puts "--> using ActiveSupport"
12
- require 'activesupport'
13
- elsif ENV["EXTLIB"]
14
- puts "--> using Extlib"
15
- require 'extlib'
16
- end
17
-
18
- require 'tempfile'
19
- #require 'ruby-debug'
20
9
  require 'spec'
21
-
22
10
  require 'carrierwave'
23
11
 
24
12
  alias :running :lambda
25
13
 
26
14
  def file_path( *paths )
27
- File.expand_path(File.join(File.dirname(__FILE__), '..', *paths))
15
+ File.expand_path(File.join('..', *paths), File.dirname(__FILE__))
28
16
  end
29
17
 
30
- CarrierWave.config[:public] = file_path('public')
31
- CarrierWave.config[:root] = file_path
18
+ CarrierWave.root = file_path('public')
32
19
 
33
20
  After do
34
21
  FileUtils.rm_rf(file_path("public"))
@@ -7,50 +7,33 @@ require 'carrierwave/core_ext/inheritable_attributes'
7
7
 
8
8
  module CarrierWave
9
9
 
10
- VERSION = "0.3.2.3"
10
+ VERSION = "0.4.3"
11
11
 
12
12
  class << self
13
- attr_accessor :config, :logger
13
+ attr_accessor :root
14
14
 
15
- def logger
16
- return @logger if @logger
17
- require 'logger'
18
- @logger = Logger.new(STDOUT)
19
- end
20
-
21
- ##
22
- # Generates a unique cache id for use in the caching system
23
- #
24
- # === Returns
25
- #
26
- # [String] a cache id in the format YYYYMMDD-HHMM-PID-RND
27
- #
28
- def generate_cache_id
29
- Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
15
+ def configure(&block)
16
+ CarrierWave::Uploader::Base.configure(&block)
30
17
  end
31
18
  end
32
19
 
33
20
  class UploadError < StandardError; end
34
- class NoFileError < UploadError; end
35
- class FormNotMultipart < UploadError
36
- def message
37
- "You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.\n\n If this is a file upload, please check that your upload form is multipart encoded."
38
- end
39
- end
40
21
  class IntegrityError < UploadError; end
41
22
  class InvalidParameter < UploadError; end
42
- # Should be used by methods used as process callbacks.
43
23
  class ProcessingError < UploadError; end
44
24
 
45
25
  autoload :SanitizedFile, 'carrierwave/sanitized_file'
46
26
  autoload :Mount, 'carrierwave/mount'
47
27
  autoload :RMagick, 'carrierwave/processing/rmagick'
48
28
  autoload :ImageScience, 'carrierwave/processing/image_science'
29
+ autoload :MiniMagick, 'carrierwave/processing/mini_magick'
49
30
 
50
31
  module Storage
51
32
  autoload :Abstract, 'carrierwave/storage/abstract'
52
33
  autoload :File, 'carrierwave/storage/file'
53
34
  autoload :S3, 'carrierwave/storage/s3'
35
+ autoload :GridFS, 'carrierwave/storage/grid_fs'
36
+ autoload :RightS3, 'carrierwave/storage/right_s3'
54
37
  end
55
38
 
56
39
  module Uploader
@@ -61,12 +44,12 @@ module CarrierWave
61
44
  autoload :Processing, 'carrierwave/uploader/processing'
62
45
  autoload :Versions, 'carrierwave/uploader/versions'
63
46
  autoload :Remove, 'carrierwave/uploader/remove'
64
- autoload :Paths, 'carrierwave/uploader/paths'
65
47
  autoload :ExtensionWhitelist, 'carrierwave/uploader/extension_whitelist'
66
- autoload :DefaultPath, 'carrierwave/uploader/default_path'
48
+ autoload :DefaultUrl, 'carrierwave/uploader/default_url'
67
49
  autoload :Proxy, 'carrierwave/uploader/proxy'
68
50
  autoload :Url, 'carrierwave/uploader/url'
69
51
  autoload :Mountable, 'carrierwave/uploader/mountable'
52
+ autoload :Configuration, 'carrierwave/uploader/configuration'
70
53
  end
71
54
 
72
55
  module Compatibility
@@ -79,67 +62,29 @@ module CarrierWave
79
62
 
80
63
  end
81
64
 
82
- CarrierWave.config = {
83
- :permissions => 0644,
84
- :storage => :file,
85
- :use_cache => true,
86
- :storage_engines => {
87
- :file => "CarrierWave::Storage::File",
88
- :s3 => "CarrierWave::Storage::S3"
89
- },
90
- :s3 => {
91
- :access => :public_read
92
- },
93
- :store_dir => 'uploads',
94
- :cache_dir => 'uploads/tmp',
95
- :cache_to_cache_dir => true,
96
- :mount => {
97
- :ignore_integrity_errors => true,
98
- :ignore_processing_errors => true,
99
- :validate_integrity => true,
100
- :validate_processing => true
101
- }
102
- }
103
-
104
- if defined?(Merb::Plugins)
105
- CarrierWave.config[:root] = Merb.root
106
- CarrierWave.config[:public] = Merb.dir_for(:public)
65
+ if defined?(Merb)
107
66
 
67
+ CarrierWave.root = Merb.dir_for(:public)
108
68
  Merb::BootLoader.before_app_loads do
109
- # Set logger
110
- CarrierWave.logger ||= Merb.logger
111
69
  # Setup path for uploaders and load all of them before classes are loaded
112
70
  Merb.push_path(:uploaders, Merb.root / 'app' / 'uploaders', '*.rb')
113
71
  Dir.glob(File.join(Merb.load_paths[:uploaders])).each {|f| require f }
114
72
  end
115
73
 
116
- orm_path = File.dirname(__FILE__) / 'carrierwave' / 'orm' / Merb.orm
117
- require orm_path if File.exist?(orm_path + '.rb')
118
-
119
- Merb.add_generators File.dirname(__FILE__) / 'generators' / 'uploader_generator'
120
-
121
74
  elsif defined?(Rails)
122
- begin
123
- CarrierWave.logger = Rails.logger
124
- rescue
125
- # Rails < 2.1
126
- CarrierWave.logger = RAILS_DEFAULT_LOGGER
127
- end
128
- CarrierWave.config[:root] = Rails.root
129
- CarrierWave.config[:public] = File.join(Rails.root, 'public')
130
-
131
- require File.join(File.dirname(__FILE__), "carrierwave", "orm", 'activerecord')
132
75
 
76
+ CarrierWave.root = File.join(Rails.root, 'public')
133
77
  ActiveSupport::Dependencies.load_paths << File.join(Rails.root, "app", "uploaders")
134
78
 
135
79
  elsif defined?(Sinatra)
136
80
 
137
- CarrierWave.config[:root] = Sinatra::Application.root
138
- CarrierWave.config[:public] = Sinatra::Application.public
81
+ CarrierWave.root = Sinatra::Application.public
139
82
 
140
83
  end
141
84
 
142
- # MongoMapper is framework agnostic so we could need this in any environment.
143
- if defined?(MongoMapper)
144
- require File.join(File.dirname(__FILE__), "carrierwave", "orm", "mongomapper")
145
- end
85
+
86
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", 'activerecord') if defined?(ActiveRecord)
87
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", 'datamapper') if defined?(DataMapper)
88
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", 'sequel') if defined?(Sequel)
89
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", "mongomapper") if defined?(MongoMapper)
90
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", "mongoid") if defined?(Mongoid)
@@ -78,8 +78,8 @@ module CarrierWave
78
78
 
79
79
  def mappings
80
80
  {
81
- :rails_root => lambda{|u, f| CarrierWave.config[:root] },
82
- :rails_env => lambda{|u, f| CarrierWave.config[:env] },
81
+ :rails_root => lambda{|u, f| Rails.root },
82
+ :rails_env => lambda{|u, f| Rails.env },
83
83
  :class => lambda{|u, f| u.model.class.name.underscore.pluralize},
84
84
  :id => lambda{|u, f| u.model.id },
85
85
  :id_partition => lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")},
@@ -58,7 +58,7 @@ class Class
58
58
  RUBY
59
59
  end
60
60
  end
61
- end
61
+ end unless Class.respond_to?(:extlib_inheritable_reader)
62
62
 
63
63
  # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
64
64
  # each subclass has a copy of parent's attribute.
@@ -86,7 +86,7 @@ class Class
86
86
  RUBY
87
87
  end
88
88
  end
89
- end
89
+ end unless Class.respond_to?(:extlib_inheritable_writer)
90
90
 
91
91
  # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
92
92
  # each subclass has a copy of parent's attribute.
@@ -100,5 +100,5 @@ class Class
100
100
  def extlib_inheritable_accessor(*syms)
101
101
  extlib_inheritable_reader(*syms)
102
102
  extlib_inheritable_writer(*syms)
103
- end
103
+ end unless Class.respond_to?(:extlib_inheritable_accessor)
104
104
  end
@@ -26,11 +26,6 @@ module CarrierWave
26
26
  @uploaders
27
27
  end
28
28
 
29
- ##
30
- # === Returns
31
- #
32
- # [Hash{Symbol => Hash}] options for mounted uploaders
33
- #
34
29
  def uploader_options
35
30
  @uploader_options ||= {}
36
31
  @uploader_options = superclass.uploader_options.merge(@uploader_options)
@@ -38,6 +33,26 @@ module CarrierWave
38
33
  @uploader_options
39
34
  end
40
35
 
36
+ ##
37
+ # Return a particular option for a particular uploader
38
+ #
39
+ # === Parameters
40
+ #
41
+ # [column (Symbol)] The column the uploader is mounted at
42
+ # [option (Symbol)] The option, e.g. validate_integrity
43
+ #
44
+ # === Returns
45
+ #
46
+ # [Object] The option value
47
+ #
48
+ def uploader_option(column, option)
49
+ if uploader_options[column].has_key?(option)
50
+ uploader_options[column][option]
51
+ else
52
+ uploaders[column].send(option)
53
+ end
54
+ end
55
+
41
56
  ##
42
57
  # Mounts the given uploader on the given column. This means that assigning
43
58
  # and reading from the column will upload and retrieve files. Supposing
@@ -70,9 +85,6 @@ module CarrierWave
70
85
  # [image_cache] Returns a string that identifies the cache location of the file
71
86
  # [image_cache=] Retrieves the file from the cache based on the given cache name
72
87
  #
73
- # [image_uploader] Returns an instance of the uploader
74
- # [image_uploader=] Sets the uploader (be careful!)
75
- #
76
88
  # [remove_image] An attribute reader that can be used with a checkbox to mark a file for removal
77
89
  # [remove_image=] An attribute writer that can be used with a checkbox to mark a file for removal
78
90
  # [remove_image?] Whether the file should be removed when store_image! is called.
@@ -131,7 +143,7 @@ module CarrierWave
131
143
  end
132
144
 
133
145
  uploaders[column.to_sym] = uploader
134
- uploader_options[column.to_sym] = CarrierWave.config[:mount].merge(options)
146
+ uploader_options[column.to_sym] = options
135
147
 
136
148
  include CarrierWave::Mount::Extension
137
149
 
@@ -165,14 +177,6 @@ module CarrierWave
165
177
  _mounter(:#{column}).url(*args)
166
178
  end
167
179
 
168
- def #{column}_uploader
169
- _mounter(:#{column}).uploader
170
- end
171
-
172
- def #{column}_uploader=(uploader)
173
- _mounter(:#{column}).uploader = uploader
174
- end
175
-
176
180
  def #{column}_cache
177
181
  _mounter(:#{column}).cache_name
178
182
  end
@@ -232,6 +236,8 @@ module CarrierWave
232
236
  private
233
237
 
234
238
  def _mounter(column)
239
+ # We cannot memoize in frozen objects :(
240
+ return Mounter.new(self, column) if frozen?
235
241
  @_mounters ||= {}
236
242
  @_mounters[column] ||= Mounter.new(self, column)
237
243
  end
@@ -242,9 +248,8 @@ module CarrierWave
242
248
  # we don't pollute the model with a lot of methods.
243
249
  class Mounter #:nodoc:
244
250
 
245
- attr_reader :column, :record, :options
246
-
247
- attr_accessor :uploader, :integrity_error, :processing_error, :remove
251
+ attr_reader :column, :record, :integrity_error, :processing_error
252
+ attr_accessor :remove
248
253
 
249
254
  def initialize(record, column, options={})
250
255
  @record = record
@@ -275,14 +280,14 @@ module CarrierWave
275
280
 
276
281
  def cache(new_file)
277
282
  uploader.cache!(new_file)
278
- self.integrity_error = nil
279
- self.processing_error = nil
283
+ @integrity_error = nil
284
+ @processing_error = nil
280
285
  rescue CarrierWave::IntegrityError => e
281
- self.integrity_error = e
282
- raise e unless options[:ignore_integrity_errors]
286
+ @integrity_error = e
287
+ raise e unless option(:ignore_integrity_errors)
283
288
  rescue CarrierWave::ProcessingError => e
284
- self.processing_error = e
285
- raise e unless options[:ignore_processing_errors]
289
+ @processing_error = e
290
+ raise e unless option(:ignore_processing_errors)
286
291
  end
287
292
 
288
293
  def cache_name
@@ -321,9 +326,13 @@ module CarrierWave
321
326
  end
322
327
 
323
328
  private
329
+
330
+ def option(name)
331
+ record.class.uploader_option(column, name)
332
+ end
324
333
 
325
334
  def serialization_column
326
- options[:mount_on] || column
335
+ option(:mount_on) || column
327
336
  end
328
337
 
329
338
  end # Mounter