durran-carrierwave 0.3.2.3 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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