jnicklas-carrierwave 0.2.2 → 0.2.3

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