jnicklas-carrierwave 0.2.2 → 0.2.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 (46) hide show
  1. data/README.rdoc +35 -20
  2. data/Rakefile +1 -1
  3. data/lib/carrierwave/compatibility/paperclip.rb +91 -0
  4. data/lib/carrierwave/core_ext/inheritable_attributes.rb +102 -0
  5. data/lib/carrierwave/core_ext/module_setup.rb +49 -0
  6. data/lib/carrierwave/mount.rb +119 -103
  7. data/lib/carrierwave/orm/activerecord.rb +6 -1
  8. data/lib/carrierwave/orm/sequel.rb +15 -2
  9. data/lib/carrierwave/processing/rmagick.rb +8 -7
  10. data/lib/carrierwave/storage/abstract.rb +16 -1
  11. data/lib/carrierwave/storage/file.rb +20 -1
  12. data/lib/carrierwave/uploader/cache.rb +114 -0
  13. data/lib/carrierwave/uploader/callbacks.rb +40 -0
  14. data/lib/carrierwave/uploader/default_path.rb +21 -0
  15. data/lib/carrierwave/uploader/extension_whitelist.rb +35 -0
  16. data/lib/carrierwave/uploader/mountable.rb +37 -0
  17. data/lib/carrierwave/uploader/paths.rb +25 -0
  18. data/lib/carrierwave/uploader/processing.rb +79 -0
  19. data/lib/carrierwave/uploader/proxy.rb +60 -0
  20. data/lib/carrierwave/uploader/remove.rb +21 -0
  21. data/lib/carrierwave/uploader/store.rb +154 -0
  22. data/lib/carrierwave/uploader/url.rb +22 -0
  23. data/lib/carrierwave/uploader/versions.rb +145 -0
  24. data/lib/carrierwave/uploader.rb +31 -593
  25. data/lib/carrierwave.rb +55 -7
  26. data/lib/generators/uploader_generator.rb +1 -1
  27. data/rails_generators/uploader/templates/uploader.rb +12 -8
  28. data/spec/compatibility/paperclip_spec.rb +41 -0
  29. data/spec/mount_spec.rb +88 -25
  30. data/spec/orm/activerecord_spec.rb +7 -9
  31. data/spec/orm/datamapper_spec.rb +7 -9
  32. data/spec/orm/sequel_spec.rb +47 -32
  33. data/spec/spec_helper.rb +13 -0
  34. data/spec/uploader/cache_spec.rb +194 -0
  35. data/spec/uploader/default_path_spec.rb +66 -0
  36. data/spec/uploader/extension_whitelist_spec.rb +42 -0
  37. data/spec/uploader/mountable_spec.rb +31 -0
  38. data/spec/uploader/paths_spec.rb +20 -0
  39. data/spec/uploader/processing_spec.rb +60 -0
  40. data/spec/uploader/proxy_spec.rb +52 -0
  41. data/spec/uploader/remove_spec.rb +65 -0
  42. data/spec/uploader/store_spec.rb +260 -0
  43. data/spec/uploader/url_spec.rb +85 -0
  44. data/spec/uploader/versions_spec.rb +275 -0
  45. metadata +34 -3
  46. data/spec/uploader_spec.rb +0 -887
@@ -11,13 +11,26 @@ module CarrierWave
11
11
  alias_method :read_uploader, :[]
12
12
  alias_method :write_uploader, :[]=
13
13
 
14
- before_save do
14
+ after_create do
15
15
  send("store_#{column}!")
16
16
  end
17
+
18
+ before_destroy do
19
+ send("remove_#{column}!")
20
+ end
21
+ end
22
+
23
+ # Determine if we're using Sequel > 2.12
24
+ #
25
+ # ==== Returns
26
+ # Bool:: True if Sequel 2.12 or higher False otherwise
27
+ def self.new_sequel?
28
+ !!(/^(2.12|3)/ =~ ::Sequel.version)
17
29
  end
18
30
 
19
31
  end # Sequel
20
32
  end # CarrierWave
21
33
 
34
+ # Sequel 3.x.x removed class hook methods and moved them to the plugin
35
+ Sequel::Model.plugin(:hook_class_methods) if CarrierWave::Sequel.new_sequel?
22
36
  Sequel::Model.send(:extend, CarrierWave::Sequel)
23
-
@@ -1,4 +1,8 @@
1
- require 'rmagick'
1
+ begin
2
+ require 'rmagick'
3
+ rescue LoadError
4
+ require 'RMagick'
5
+ end
2
6
 
3
7
  module CarrierWave
4
8
 
@@ -11,15 +15,13 @@ module CarrierWave
11
15
  #
12
16
  # And then include it in your uploader:
13
17
  #
14
- # class MyUploader
15
- # include CarrierWave::Uploader
18
+ # class MyUploader < CarrierWave::Uploader::Base
16
19
  # include CarrierWave::RMagick
17
20
  # end
18
21
  #
19
22
  # You can now use the provided helpers:
20
23
  #
21
- # class MyUploader
22
- # include CarrierWave::Uploader
24
+ # class MyUploader < CarrierWave::Uploader::Base
23
25
  # include CarrierWave::RMagick
24
26
  #
25
27
  # process :resize_to_fit => [200, 200]
@@ -29,8 +31,7 @@ module CarrierWave
29
31
  # out the RMagick docs at http://www.imagemagick.org/RMagick/doc/ for more
30
32
  # info
31
33
  #
32
- # class MyUploader
33
- # include CarrierWave::Uploader
34
+ # class MyUploader < CarrierWave::Uploader::Base
34
35
  # include CarrierWave::RMagick
35
36
  #
36
37
  # process :do_stuff => 10.0
@@ -18,6 +18,21 @@ module CarrierWave
18
18
  # to retrieve it later.
19
19
  #
20
20
  class Abstract
21
+
22
+ # Do something to destroy the file
23
+ #
24
+ # === Parameters
25
+ #
26
+ # [uploader (CarrierWave::Uploader)] an uploader object
27
+ # [identifier (String)] uniquely identifies the file
28
+ #
29
+ # === Returns
30
+ #
31
+ # [bool] True if file was remove or false
32
+ #
33
+ def self.destroy!(uploader, identifier)
34
+ false
35
+ end
21
36
 
22
37
  ##
23
38
  # Do setup specific for this storage engine
@@ -92,4 +107,4 @@ module CarrierWave
92
107
 
93
108
  end # Abstract
94
109
  end # Storage
95
- end # CarrierWave
110
+ end # CarrierWave
@@ -12,6 +12,25 @@ module CarrierWave
12
12
  @uploader = uploader
13
13
  end
14
14
 
15
+ ##
16
+ # Delete the file to the uploader's store path.
17
+ #
18
+ # === Parameters
19
+ #
20
+ # [uploader (CarrierWave::Uploader)] an uploader object
21
+ # [file (CarrierWave::SanitizedFile)] the file to store
22
+ #
23
+ # === Returns
24
+ #
25
+ # [bool] True if file was removed or false
26
+ #
27
+ def self.destroy!(uploader, file)
28
+ unless file.blank?
29
+ CarrierWave.logger.info "CarrierWave::Storage::File: removing file #{file.path}"
30
+ file.delete
31
+ end
32
+ end
33
+
15
34
  ##
16
35
  # Move the file to the uploader's store path.
17
36
  #
@@ -51,4 +70,4 @@ module CarrierWave
51
70
 
52
71
  end # File
53
72
  end # Storage
54
- end # CarrierWave
73
+ end # CarrierWave
@@ -0,0 +1,114 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Cache
4
+
5
+ depends_on CarrierWave::Uploader::Paths
6
+ depends_on CarrierWave::Uploader::Callbacks
7
+
8
+ ##
9
+ # Returns true if the uploader has been cached
10
+ #
11
+ # === Returns
12
+ #
13
+ # [Bool] whether the current file is cached
14
+ #
15
+ def cached?
16
+ @cache_id
17
+ end
18
+
19
+ ##
20
+ # Override this in your Uploader to change the directory where files are cached.
21
+ #
22
+ # === Returns
23
+ #
24
+ # [String] a directory
25
+ #
26
+ def cache_dir
27
+ CarrierWave.config[:cache_dir]
28
+ end
29
+
30
+ ##
31
+ # Returns a String which uniquely identifies the currently cached file for later retrieval
32
+ #
33
+ # === Returns
34
+ #
35
+ # [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
36
+ #
37
+ def cache_name
38
+ File.join(cache_id, full_original_filename) if cache_id and original_filename
39
+ end
40
+
41
+ ##
42
+ # Caches the given file. Calls process! to trigger any process callbacks.
43
+ #
44
+ # === Parameters
45
+ #
46
+ # [new_file (File, IOString, Tempfile)] any kind of file object
47
+ #
48
+ # === Raises
49
+ #
50
+ # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
51
+ #
52
+ def cache!(new_file)
53
+ new_file = CarrierWave::SanitizedFile.new(new_file)
54
+ raise CarrierWave::FormNotMultipart if new_file.is_path?
55
+
56
+ unless new_file.empty?
57
+ with_callbacks(:cache, new_file) do
58
+ self.cache_id = CarrierWave.generate_cache_id unless cache_id
59
+
60
+ @filename = new_file.filename
61
+ self.original_filename = new_file.filename
62
+
63
+ if CarrierWave.config[:cache_to_cache_dir]
64
+ @file = new_file.copy_to(cache_path, CarrierWave.config[:permissions])
65
+ else
66
+ @file = new_file
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ ##
73
+ # Retrieves the file with the given cache_name from the cache.
74
+ #
75
+ # === Parameters
76
+ #
77
+ # [cache_name (String)] uniquely identifies a cache file
78
+ #
79
+ # === Raises
80
+ #
81
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
82
+ #
83
+ def retrieve_from_cache!(cache_name)
84
+ with_callbacks(:retrieve_from_cache, cache_name) do
85
+ self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
86
+ @filename = original_filename
87
+ @file = CarrierWave::SanitizedFile.new(cache_path)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def cache_path
94
+ File.expand_path(File.join(cache_dir, cache_name), public)
95
+ end
96
+
97
+ attr_reader :cache_id, :original_filename
98
+
99
+ # We can override the full_original_filename method in other modules
100
+ alias_method :full_original_filename, :original_filename
101
+
102
+ def cache_id=(cache_id)
103
+ raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
104
+ @cache_id = cache_id
105
+ end
106
+
107
+ def original_filename=(filename)
108
+ raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /\A[a-z0-9\.\-\+_]+\z/i
109
+ @original_filename = filename
110
+ end
111
+
112
+ end # Cache
113
+ end # Uploader
114
+ end # CarrierWave
@@ -0,0 +1,40 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Callbacks
4
+
5
+ setup do
6
+ extlib_inheritable_accessor :_before_callbacks, :_after_callbacks
7
+ end
8
+
9
+ def with_callbacks(kind, *args)
10
+ self.class._before_callback(kind).each { |callback| self.send(callback, *args) }
11
+ yield
12
+ self.class._after_callback(kind).each { |callback| self.send(callback, *args) }
13
+ end
14
+
15
+ module ClassMethods
16
+
17
+ def _before_callback(kind) #:nodoc:
18
+ self._before_callbacks ||= {}
19
+ self._before_callbacks[kind] ||= []
20
+ self._before_callbacks[kind]
21
+ end
22
+
23
+ def _after_callback(kind) #:nodoc:
24
+ self._after_callbacks ||= {}
25
+ self._after_callbacks[kind] ||= []
26
+ self._after_callbacks[kind]
27
+ end
28
+
29
+ def before(kind, callback)
30
+ _before_callback(kind) << callback
31
+ end
32
+
33
+ def after(kind, callback)
34
+ _after_callback(kind) << callback
35
+ end
36
+ end # ClassMethods
37
+
38
+ end # Callbacks
39
+ end # Uploader
40
+ end # CarrierWave
@@ -0,0 +1,21 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module DefaultPath
4
+
5
+ def initialize(*args)
6
+ super
7
+ if default_path
8
+ @file = CarrierWave::SanitizedFile.new(File.expand_path(default_path, public))
9
+ def @file.blank?; true; end
10
+ end
11
+ end
12
+
13
+ ##
14
+ # Override this method in your uploader to provide a default path
15
+ # in case no file has been cached/stored yet.
16
+ #
17
+ def default_path; end
18
+
19
+ end # DefaultPath
20
+ end # Uploader
21
+ end # CarrierWave
@@ -0,0 +1,35 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module ExtensionWhitelist
4
+
5
+ setup do
6
+ before :cache, :check_whitelist!
7
+ end
8
+
9
+ ##
10
+ # Override this method in your uploader to provide a white list of extensions which
11
+ # are allowed to be uploaded.
12
+ #
13
+ # === Returns
14
+ #
15
+ # [NilClass, Array[String]] a white list of extensions which are allowed to be uploaded
16
+ #
17
+ # === Examples
18
+ #
19
+ # def extension_white_list
20
+ # %w(jpg jpeg gif png)
21
+ # end
22
+ #
23
+ def extension_white_list; end
24
+
25
+ private
26
+
27
+ def check_whitelist!(new_file)
28
+ if extension_white_list and not extension_white_list.include?(new_file.extension.to_s)
29
+ raise CarrierWave::IntegrityError, "You are not allowed to upload #{new_file.extension.inspect} files, allowed types: #{extension_white_list.inspect}"
30
+ end
31
+ end
32
+
33
+ end # ExtensionWhitelist
34
+ end # Uploader
35
+ end # CarrierWave
@@ -0,0 +1,37 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Mountable
4
+
5
+ attr_reader :model, :mounted_as
6
+
7
+ ##
8
+ # If a model is given as the first parameter, it will stored in the uploader, and
9
+ # available throught +#model+. Likewise, mounted_as stores the name of the column
10
+ # where this instance of the uploader is mounted. These values can then be used inside
11
+ # your uploader.
12
+ #
13
+ # If you do not wish to mount your uploaders with the ORM extensions in -more then you
14
+ # can override this method inside your uploader. Just be sure to call +super+
15
+ #
16
+ # === Parameters
17
+ #
18
+ # [model (Object)] Any kind of model object
19
+ # [mounted_as (Symbol)] The name of the column where this uploader is mounted
20
+ #
21
+ # === Examples
22
+ #
23
+ # class MyUploader < CarrierWave::Uploader::Base
24
+ #
25
+ # def store_dir
26
+ # File.join('public', 'files', mounted_as, model.permalink)
27
+ # end
28
+ # end
29
+ #
30
+ def initialize(model=nil, mounted_as=nil)
31
+ @model = model
32
+ @mounted_as = mounted_as
33
+ end
34
+
35
+ end # Mountable
36
+ end # Uploader
37
+ end # CarrierWave
@@ -0,0 +1,25 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Paths
4
+
5
+ ##
6
+ # === Returns
7
+ #
8
+ # [String] the directory that is the root of the application
9
+ #
10
+ def root
11
+ CarrierWave.config[:root]
12
+ end
13
+
14
+ ##
15
+ # === Returns
16
+ #
17
+ # [String] the directory where files will be publically accessible
18
+ #
19
+ def public
20
+ CarrierWave.config[:public]
21
+ end
22
+
23
+ end # Paths
24
+ end # Uploader
25
+ end # CarrierWave
@@ -0,0 +1,79 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Processing
4
+
5
+ depends_on CarrierWave::Uploader::Callbacks
6
+
7
+ setup do
8
+ after :cache, :process!
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ ##
14
+ # Lists processor callbacks declared
15
+ #
16
+ # === Returns
17
+ #
18
+ # [Array[Array[Symbol, Array]]] a list of processor callbacks which have been declared for this uploader
19
+ #
20
+ def processors
21
+ @processors ||= []
22
+ end
23
+
24
+ ##
25
+ # Adds a processor callback which applies operations as a file is uploaded.
26
+ # The argument may be the name of any method of the uploader, expressed as a symbol,
27
+ # or a list of such methods, or a hash where the key is a method and the value is
28
+ # an array of arguments to call the method with
29
+ #
30
+ # === Parameters
31
+ #
32
+ # args (*Symbol, Hash{Symbol => Array[]})
33
+ #
34
+ # === Examples
35
+ #
36
+ # class MyUploader < CarrierWave::Uploader::Base
37
+ #
38
+ # process :sepiatone, :vignette
39
+ # process :scale => [200, 200]
40
+ #
41
+ # def sepiatone
42
+ # ...
43
+ # end
44
+ #
45
+ # def vignette
46
+ # ...
47
+ # end
48
+ #
49
+ # def scale(height, width)
50
+ # ...
51
+ # end
52
+ # end
53
+ #
54
+ def process(*args)
55
+ args.each do |arg|
56
+ if arg.is_a?(Hash)
57
+ arg.each do |method, args|
58
+ processors.push([method, args])
59
+ end
60
+ else
61
+ processors.push([arg, []])
62
+ end
63
+ end
64
+ end
65
+
66
+ end # ClassMethods
67
+
68
+ ##
69
+ # Apply all process callbacks added through CarrierWave.process
70
+ #
71
+ def process!(new_file=nil)
72
+ self.class.processors.each do |method, args|
73
+ self.send(method, *args)
74
+ end
75
+ end
76
+
77
+ end # Processing
78
+ end # Uploader
79
+ end # CarrierWave
@@ -0,0 +1,60 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Proxy
4
+
5
+ ##
6
+ # === Returns
7
+ #
8
+ # [Boolean] Whether the uploaded file is blank
9
+ #
10
+ def blank?
11
+ file.blank?
12
+ end
13
+
14
+ ##
15
+ # === Returns
16
+ #
17
+ # [String] the path where the file is currently located.
18
+ #
19
+ def current_path
20
+ file.path if file.respond_to?(:path)
21
+ end
22
+
23
+ alias_method :path, :current_path
24
+
25
+ ##
26
+ # Returns a string that uniquely identifies the last stored file
27
+ #
28
+ # === Returns
29
+ #
30
+ # [String] uniquely identifies a file
31
+ #
32
+ def identifier
33
+ file.identifier if file.respond_to?(:identifier)
34
+ end
35
+
36
+ ##
37
+ # Read the contents of the file
38
+ #
39
+ # === Returns
40
+ #
41
+ # [String] contents of the file
42
+ #
43
+ def read
44
+ file.read if file.respond_to?(:read)
45
+ end
46
+
47
+ ##
48
+ # Fetches the size of the currently stored/cached file
49
+ #
50
+ # === Returns
51
+ #
52
+ # [Integer] size of the file
53
+ #
54
+ def size
55
+ file.respond_to?(:size) ? file.size : 0
56
+ end
57
+
58
+ end # Proxy
59
+ end # Uploader
60
+ end # CarrierWave
@@ -0,0 +1,21 @@
1
+ module CarrierWave
2
+ module Uploader
3
+ module Remove
4
+
5
+ depends_on CarrierWave::Uploader::Callbacks
6
+
7
+ ##
8
+ # Removes the file and reset it
9
+ #
10
+ def remove!
11
+ with_callbacks(:remove) do
12
+ CarrierWave.logger.info 'CarrierWave: removing file'
13
+ storage.destroy!(self, file)
14
+ @file = nil
15
+ @cache_id = nil
16
+ end
17
+ end
18
+
19
+ end # Remove
20
+ end # Uploader
21
+ end # CarrierWave