jnicklas-carrierwave 0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -4,7 +4,13 @@ This plugin for Merb and Rails provides a simple and extremely flexible way to u
4
4
 
5
5
  ## Getting Started
6
6
 
7
- At the moment you are going to have to grab it here from github and install it yourself.
7
+ Install the latest stable release:
8
+
9
+ [sudo] gem install carrierwave
10
+
11
+ Or the cutting edge development version:
12
+
13
+ [sudo] gem install jnicklas-carrierwave --source http://gems.github.com
8
14
 
9
15
  In Merb, add it as a dependency to your config/dependencies.rb:
10
16
 
@@ -20,6 +26,10 @@ Start off by generating an uploader:
20
26
 
21
27
  merb-gen uploader Avatar
22
28
 
29
+ or in Rails:
30
+
31
+ script/generate uploader Avatar
32
+
23
33
  this should give you a file in:
24
34
 
25
35
  app/uploaders/avatar_uploader.rb
@@ -127,6 +137,33 @@ When this uploader is used, an uploaded image would be scaled to be no larger th
127
137
 
128
138
  One important thing to remember is that process is called *before* versions are created. This can cut down on processing cost.
129
139
 
140
+ ## Making uploads work across form redisplays
141
+
142
+ Often you'll notice that uploaded files disappear when a validation
143
+ fails. CarrierWave has a feature that makes it easy to remember the
144
+ uploaded file even in that case. Suppose your `user` model has an uploader mounted on `avatar` file, just add a hidden field called `avatar_cache`.
145
+ In Rails, this would look like this:
146
+
147
+ <% form_for @user do |f| %>
148
+ <p>
149
+ <label>My Avatar</label>
150
+ <%= f.file_field :avatar %>
151
+ <%= f.hidden_field :avatar_cache %>
152
+ </p>
153
+ <% end %>
154
+
155
+ It might be a good idea to show th user that a file has been uploaded,
156
+ in the case of images, a small thumbnail would be a good indicator:
157
+
158
+ <% form_for @user do |f| %>
159
+ <p>
160
+ <label>My Avatar</label>
161
+ <%= image_tag(@user.avatar.url) if @user.avatar %>
162
+ <%= f.file_field :avatar %>
163
+ <%= f.hidden_field :avatar_cache %>
164
+ </p>
165
+ <% end %>
166
+
130
167
  ## What's in that uploader file?
131
168
 
132
169
  The fact that uploaders are separate classes in CarrierWave is a big advantage. What this means for you is:
@@ -206,6 +243,10 @@ And then include it in your model:
206
243
  process :crop_resized => [200, 200]
207
244
  end
208
245
 
246
+ ## Documentation
247
+
248
+ Full YARD documentation is [available at Rubyforge](http://carrierwave.rubyforge.org/).
249
+
209
250
  ## Read the source
210
251
 
211
- CarrierWave is still young, but most of it is pretty well documented. Just dig in and look at the source for more in-depth explanation of what things are doing.
252
+ CarrierWave is still young, but most of it is pretty well documented. It is also extensively specced, and there are cucumber features for some common use cases. Just dig in and look at the source for more in-depth explanation of what things are doing.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'spec/rake/spectask'
6
6
  require 'cucumber/rake/task'
7
7
 
8
8
  NAME = "carrierwave"
9
- GEM_VERSION = "0.1"
9
+ GEM_VERSION = "0.1.1"
10
10
  AUTHOR = "Jonas Nicklas"
11
11
  EMAIL = "jonas.nicklas@gmail.com"
12
12
  HOMEPAGE = "http://www.example.com"
@@ -25,7 +25,7 @@ spec = Gem::Specification.new do |s|
25
25
  s.email = EMAIL
26
26
  s.homepage = HOMEPAGE
27
27
  s.require_path = 'lib'
28
- s.files = %w(LICENSE Generators README.md Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
28
+ s.files = %w(LICENSE Generators README.md Rakefile TODO) + Dir.glob("{lib,spec,rails_generators}/**/*")
29
29
 
30
30
  end
31
31
 
@@ -7,7 +7,12 @@ module CarrierWave
7
7
 
8
8
  class UploadError < StandardError; end
9
9
  class NoFileError < UploadError; end
10
- class FormNotMultipart < UploadError; end
10
+ class FormNotMultipart < UploadError
11
+ def message
12
+ "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."
13
+ end
14
+ end
15
+ class IntegrityError < UploadError; end
11
16
  class InvalidParameter < UploadError; end
12
17
  # Should be used by methods used as process callbacks.
13
18
  class ProcessingError < UploadError; end
@@ -32,8 +37,8 @@ CarrierWave.config = {
32
37
  :s3 => {
33
38
  :access => :public_read
34
39
  },
35
- :store_dir => 'public/uploads',
36
- :cache_dir => 'public/uploads/tmp'
40
+ :store_dir => 'uploads',
41
+ :cache_dir => 'uploads/tmp'
37
42
  }
38
43
 
39
44
  if defined?(Merb)
@@ -43,7 +48,7 @@ if defined?(Merb)
43
48
  orm_path = File.dirname(__FILE__) / 'carrierwave' / 'orm' / Merb.orm
44
49
  require orm_path if File.exist?(orm_path + '.rb')
45
50
 
46
- Merb.push_path(:model, Merb.root / "app" / "uploaders")
51
+ Merb.push_path(:uploader, Merb.root / "app" / "uploaders")
47
52
 
48
53
  Merb.add_generators File.dirname(__FILE__) / 'generators' / 'uploader_generator'
49
54
  end
@@ -1,23 +1,124 @@
1
1
  module CarrierWave
2
2
 
3
+ ##
4
+ # If a Class is extended with this module, it gains the mount_uploader
5
+ # method, which is used for mapping attributes to uploaders and allowing
6
+ # easy assignment.
7
+ #
8
+ # You can use mount_uploader with pretty much any class, however it is
9
+ # intended to be used with some kind of persistent storage, like an ORM.
10
+ # If you want to persist the uploaded files in a particular Class, it
11
+ # needs to implement a `read_uploader` and a `write_uploader` method.
12
+ #
3
13
  module Mount
14
+
15
+ ##
16
+ # @return [Hash{Symbol => CarrierWave}] what uploaders are mounted on which columns
17
+ #
18
+ def uploaders
19
+ @uploaders ||= {}
20
+ end
21
+
22
+ ##
23
+ # Mounts the given uploader on the given column. This means that assigning
24
+ # and reading from the column will upload and retrieve files. Supposing
25
+ # that a User class has an uploader mounted on image, you can assign and
26
+ # retrieve files like this:
27
+ #
28
+ # @user.image # => <Uploader>
29
+ # @user.image = some_file_object
30
+ #
31
+ # @user.store_image!
32
+ #
33
+ # @user.image.url # => '/some_url.png'
34
+ #
35
+ # It is also possible (but not recommended) to ommit the uploader, which
36
+ # will create an anonymous uploader class. Passing a block to this method
37
+ # makes it possible to customize it. This can be convenient for brevity,
38
+ # but if there is any significatnt logic in the uploader, you should do
39
+ # the right thing and have it in its own file.
40
+ #
41
+ # @param [Symbol] column the attribute to mount this uploader on
42
+ # @param [CarrierWave::Uploader] uploader the uploader class to mount
43
+ # @param [Proc] &block customize anonymous uploaders
44
+ # @example
45
+ # class Song
46
+ # mount_uploader :lyrics, LyricsUploader
47
+ # mount_uploader :file, SongUploader
48
+ # end
49
+ # @example
50
+ # class Data
51
+ # # this will add an anonymous uploader with only
52
+ # # the default settings
53
+ # mount_uploader :csv
54
+ # end
55
+ # @example
56
+ # class Product
57
+ # # this will add an anonymous uploader overriding
58
+ # # the store_dir
59
+ # mount_uploader :blueprint do
60
+ # def store_dir
61
+ # 'blueprints'
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ def mount_uploader(column, uploader=nil, &block)
67
+ unless uploader
68
+ uploader = Class.new(CarrierWave::Uploader)
69
+ uploader.class_eval(&block)
70
+ end
71
+
72
+ uploaders[column.to_sym] = uploader
73
+
74
+ include CarrierWave::Mount::Extension
75
+
76
+ class_eval <<-EOF, __FILE__, __LINE__+1
77
+ def #{column} # def image
78
+ get_uploader(:#{column}) # get_uploader(:image)
79
+ end # end
80
+ #
81
+ def #{column}=(new_file) # def image=(new_file)
82
+ set_uploader(:#{column}, new_file) # set_uploader(:image, new_file)
83
+ end # end
84
+ #
85
+ def #{column}_cache # def image_cache
86
+ get_uploader_cache(:#{column}) # get_uploader_cache(:image)
87
+ end # end
88
+ #
89
+ def #{column}_cache=(cache_name) # def image_cache=(cache_name)
90
+ set_uploader_cache(:#{column}, cache_name) # set_uploader_cache(:image, cache_name)
91
+ end # end
92
+ #
93
+ def store_#{column}! # def store_image!
94
+ store_uploader!(:#{column}) # store_uploader!(:image)
95
+ end # end
96
+ EOF
97
+ end
98
+
4
99
  module Extension
5
100
 
6
101
  private
102
+
103
+ # overwrite this to read from a serialized attribute
104
+ def read_uploader(column); end
105
+
106
+ # overwrite this to write to a serialized attribute
107
+ def write_uploader(column, identifier); end
7
108
 
8
109
  def uploaders
9
110
  @uploaders ||= {}
10
111
  end
11
112
 
12
113
  def store_uploader!(column)
13
- if uploaders[column]
114
+ unless uploaders[column].blank?
14
115
  uploaders[column].store!
15
116
  write_uploader(column, uploaders[column].identifier)
16
117
  end
17
118
  end
18
119
 
19
120
  def get_uploader(column)
20
- return uploaders[column] if uploaders[column]
121
+ return uploaders[column] unless uploaders[column].blank?
21
122
 
22
123
  identifier = read_uploader(column)
23
124
 
@@ -29,16 +130,12 @@ module CarrierWave
29
130
  end
30
131
 
31
132
  def set_uploader(column, new_file)
32
- new_file = CarrierWave::SanitizedFile.new(new_file)
33
-
34
- unless new_file.empty?
35
- uploaders[column] ||= self.class.uploaders[column].new(self, column)
36
- uploaders[column].cache!(new_file)
37
- end
133
+ uploaders[column] ||= self.class.uploaders[column].new(self, column)
134
+ uploaders[column].cache!(new_file)
38
135
  end
39
136
 
40
137
  def get_uploader_cache(column)
41
- uploaders[column].cache_name if uploaders[column]
138
+ uploaders[column].cache_name unless uploaders[column].blank?
42
139
  end
43
140
 
44
141
  def set_uploader_cache(column, cache_name)
@@ -50,44 +147,5 @@ module CarrierWave
50
147
 
51
148
  end # Extension
52
149
 
53
- def uploaders
54
- @uploaders ||= {}
55
- end
56
-
57
- def mount_uploader(column, uploader=nil, &block)
58
- unless uploader
59
- uploader = Class.new(CarrierWave::Uploader)
60
- uploader.class_eval(&block)
61
- end
62
-
63
- uploaders[column.to_sym] = uploader
64
-
65
- include CarrierWave::Mount::Extension
66
-
67
- class_eval <<-EOF, __FILE__, __LINE__+1
68
- def #{column} # def image
69
- get_uploader(:#{column}) # get_uploader(:image)
70
- end # end
71
- #
72
- def #{column}=(new_file) # def image=(new_file)
73
- set_uploader(:#{column}, new_file) # set_uploader(:image, new_file)
74
- end # end
75
- #
76
- def #{column}_cache # def image_cache
77
- get_uploader_cache(:#{column}) # get_uploader_cache(:image)
78
- end # end
79
- #
80
- def #{column}_cache=(cache_name) # def image_cache=(cache_name)
81
- set_uploader_cache(:#{column}, cache_name) # set_uploader_cache(:image, cache_name)
82
- end # end
83
- #
84
- def store_#{column}! # def store_image!
85
- store_uploader!(:#{column}) # store_uploader!(:image)
86
- end # end
87
- EOF
88
-
89
- after_mount(column, uploader) if respond_to?(:after_mount)
90
- end
91
-
92
150
  end # Mount
93
151
  end # CarrierWave
@@ -5,7 +5,9 @@ module CarrierWave
5
5
 
6
6
  include CarrierWave::Mount
7
7
 
8
- def after_mount(column, uploader)
8
+ def mount_uploader(column, uploader)
9
+ super
10
+
9
11
  alias_method :read_uploader, :read_attribute
10
12
  alias_method :write_uploader, :write_attribute
11
13
 
@@ -5,7 +5,9 @@ module CarrierWave
5
5
 
6
6
  include CarrierWave::Mount
7
7
 
8
- def after_mount(column, uploader)
8
+ def mount_uploader(column, uploader)
9
+ super
10
+
9
11
  alias_method :read_uploader, :attribute_get
10
12
  alias_method :write_uploader, :attribute_set
11
13
 
@@ -1,5 +1,14 @@
1
1
  module CarrierWave
2
- class SanitizedFile
2
+
3
+ ##
4
+ # SanitizedFile is a base class which provides a common API around all
5
+ # the different quirky Ruby File libraries. It has support for Tempfile,
6
+ # File, StringIO, Merb-style upload Hashes, as well as paths given as
7
+ # Strings and Pathnames.
8
+ #
9
+ # It's probably needlessly comprehensive and complex. Help is appreciated.
10
+ #
11
+ class SanitizedFile
3
12
 
4
13
  attr_accessor :file, :options
5
14
 
@@ -58,10 +67,12 @@ module CarrierWave
58
67
  # @return [Integer] the file's size in bytes.
59
68
  #
60
69
  def size
61
- if @file.respond_to?(:size)
70
+ if string?
71
+ exists? ? File.size(path) : 0
72
+ elsif @file.respond_to?(:size)
62
73
  @file.size
63
74
  elsif path
64
- File.size(path)
75
+ exists? ? File.size(path) : 0
65
76
  else
66
77
  0
67
78
  end
@@ -97,7 +108,7 @@ module CarrierWave
97
108
  # @return [Boolean]
98
109
  #
99
110
  def empty?
100
- (@file.nil? && @path.nil?) || self.size.nil? || self.size.zero?
111
+ @file.nil? || self.size.nil? || self.size.zero?
101
112
  end
102
113
 
103
114
  ##
@@ -208,7 +219,7 @@ module CarrierWave
208
219
  name = name.gsub("\\", "/") # work-around for IE
209
220
  name = File.basename(name)
210
221
  name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
211
- name = "_#{name}" if name =~ /^\.+$/
222
+ name = "_#{name}" if name =~ /\A\.+\z/
212
223
  name = "unnamed" if name.size == 0
213
224
  return name.downcase
214
225
  end
@@ -216,8 +227,8 @@ module CarrierWave
216
227
  def split_extension(fn)
217
228
  # regular expressions to try for identifying extensions
218
229
  ext_regexps = [
219
- /^(.+)\.([^\.]{1,3}\.[^\.]{1,4})$/, # matches "something.tar.gz"
220
- /^(.+)\.([^\.]+)$/ # matches "something.jpg"
230
+ /\A(.+)\.([^\.]{1,3}\.[^\.]{1,4})\z/, # matches "something.tar.gz"
231
+ /\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
221
232
  ]
222
233
  ext_regexps.each do |regexp|
223
234
  if fn =~ regexp
@@ -1,5 +1,6 @@
1
1
  module CarrierWave
2
2
  module Storage
3
+
3
4
  ##
4
5
  # This file serves mostly as a specification for Storage engines. There is no requirement
5
6
  # that storage engines must be a subclass of this class. However, any storage engine must
@@ -1,5 +1,11 @@
1
1
  module CarrierWave
2
2
  module Storage
3
+
4
+ ##
5
+ # File storage stores file to the Filesystem (surprising, no?). There's really not much
6
+ # to it, it uses the store_dir defined on the uploader as the storage location. That's
7
+ # pretty much it.
8
+ #
3
9
  class File < Abstract
4
10
 
5
11
  def initialize(uploader)
@@ -16,7 +22,7 @@ module CarrierWave
16
22
  #
17
23
  def self.store!(uploader, file)
18
24
  path = ::File.join(uploader.store_dir, uploader.filename)
19
- path = ::File.expand_path(path, uploader.root)
25
+ path = ::File.expand_path(path, uploader.public)
20
26
  file.move_to(path)
21
27
  file
22
28
  end
@@ -31,7 +37,7 @@ module CarrierWave
31
37
  #
32
38
  def self.retrieve!(uploader, identifier)
33
39
  path = ::File.join(uploader.store_dir, identifier)
34
- path = ::File.expand_path(path, uploader.root)
40
+ path = ::File.expand_path(path, uploader.public)
35
41
  CarrierWave::SanitizedFile.new(path)
36
42
  end
37
43
 
@@ -1,7 +1,31 @@
1
1
  module CarrierWave
2
2
  module Storage
3
+
3
4
  ##
4
- # Uploads things to Amazon S3 webservices
5
+ # Uploads things to Amazon S3 webservices. It requies the aws/s3 gem. In order for
6
+ # CarrierWave to connect to Amazon S3, you'll need to specify an access key id, secret key
7
+ # and bucket
8
+ #
9
+ # CarrierWave.config[:s3][:access_key_id] = "xxxxxx"
10
+ # CarrierWave.config[:s3][:secret_access_key] = "xxxxxx"
11
+ # CarrierWave.config[:s3][:bucket] = "my_bucket_name"
12
+ #
13
+ # You can also set the access policy for the uploaded files:
14
+ #
15
+ # CarrierWave.config[:s3][:access] = :public_read
16
+ #
17
+ # Possible values are the 'canned access control policies' provided in the aws/s3 gem,
18
+ # they are:
19
+ #
20
+ # :private No one else has any access rights.
21
+ # :public_read The anonymous principal is granted READ access.
22
+ # If this policy is used on an object, it can be read from a
23
+ # browser with no authentication.
24
+ # :public_read_write The anonymous principal is granted READ and WRITE access.
25
+ # :authenticated_read Any principal authenticated as a registered Amazon S3 user
26
+ # is granted READ access.
27
+ #
28
+ # The default is :public_read, it should work in most cases.
5
29
  #
6
30
  class S3 < Abstract
7
31
 
@@ -75,7 +99,7 @@ module CarrierWave
75
99
  # @return [String] file's url
76
100
  #
77
101
  def url
78
- "http://s3.amazonaws.com/#{self.class.bucket}/#{@store_dir}/#{@identifier}"
102
+ ["http://s3.amazonaws.com", self.class.bucket, @store_dir, @identifier].compact.join('/')
79
103
  end
80
104
 
81
105
  end # S3
@@ -1,6 +1,22 @@
1
1
  module CarrierWave
2
+
3
+ ##
4
+ # An uploader is a class that allows you to easily handle the caching and storage of
5
+ # uploaded files. Please refer to the README for configuration options.
6
+ #
7
+ # Once you have an uploader you can use it in isolation:
8
+ #
9
+ # my_uploader = MyUploader.new
10
+ # my_uploader.cache!(File.open(path_to_file))
11
+ # my_uploader.retrieve_from_store!('monkey.png')
12
+ #
13
+ # Alternatively, you can mount it on an ORM or other persistence layer, with
14
+ # +CarrierWave::Mount#mount_uploader+. There are extensions for activerecord and datamapper
15
+ # these are *very* simple (they are only a dozen lines of code), so adding your own should
16
+ # be trivial.
17
+ #
2
18
  class Uploader
3
-
19
+
4
20
  class << self
5
21
 
6
22
  ##
@@ -157,7 +173,14 @@ module CarrierWave
157
173
  end
158
174
 
159
175
  ##
160
- # Apply all process callbacks added through CarrierWaveer.process
176
+ # @return [Boolean] Whether the uploaded file is blank
177
+ #
178
+ def blank?
179
+ !file or file.empty?
180
+ end
181
+
182
+ ##
183
+ # Apply all process callbacks added through CarrierWave.process
161
184
  #
162
185
  def process!
163
186
  self.class.processors.each do |method, args|
@@ -193,7 +216,7 @@ module CarrierWave
193
216
  if file.respond_to?(:url) and not file.url.blank?
194
217
  file.url
195
218
  elsif current_path
196
- File.expand_path(current_path).gsub(File.expand_path(CarrierWave.config[:public]), '')
219
+ File.expand_path(current_path).gsub(File.expand_path(public), '')
197
220
  end
198
221
  end
199
222
 
@@ -232,11 +255,30 @@ module CarrierWave
232
255
  end
233
256
 
234
257
  ##
235
- # @return [String] the directory relative to which we will upload
258
+ # @return [String] the directory that is the root of the application
236
259
  #
237
260
  def root
238
261
  CarrierWave.config[:root]
239
262
  end
263
+
264
+ ##
265
+ # @return [String] the directory where files will be publically accessible
266
+ #
267
+ def public
268
+ CarrierWave.config[:public]
269
+ end
270
+
271
+ ##
272
+ # Override this method in your uploader to provide a white list of extensions which
273
+ # are allowed to be uploaded.
274
+ #
275
+ # @return [NilClass, Array[String]] a white list of extensions which are allowed to be uploaded
276
+ # @example
277
+ # def extension_white_list
278
+ # %w(jpg jpeg gif png)
279
+ # end
280
+ #
281
+ def extension_white_list; end
240
282
 
241
283
  ####################
242
284
  ## Cache
@@ -277,21 +319,28 @@ module CarrierWave
277
319
  # @raise [CarrierWave::FormNotMultipart] if the assigned parameter is a string
278
320
  #
279
321
  def cache!(new_file)
280
- self.cache_id = CarrierWave::Uploader.generate_cache_id unless cache_id
281
322
  new_file = CarrierWave::SanitizedFile.new(new_file)
282
- raise CarrierWave::FormNotMultipart, "check that your upload form is multipart encoded" if new_file.string?
323
+ raise CarrierWave::FormNotMultipart if new_file.string?
283
324
 
284
- @file = new_file
325
+ unless new_file.empty?
326
+ if extension_white_list and not extension_white_list.include?(new_file.extension.to_s)
327
+ raise CarrierWave::IntegrityError, "You are not allowed to upload #{new_file.extension.inspect} files, allowed types: #{extension_white_list.inspect}"
328
+ end
285
329
 
286
- @filename = new_file.filename
287
- self.original_filename = new_file.filename
330
+ self.cache_id = CarrierWave::Uploader.generate_cache_id unless cache_id
331
+
332
+ @file = new_file
333
+
334
+ @filename = new_file.filename
335
+ self.original_filename = new_file.filename
288
336
 
289
- @file = @file.copy_to(cache_path)
290
- process!
337
+ @file = @file.copy_to(cache_path)
338
+ process!
291
339
 
292
- versions.each do |name, v|
293
- v.send(:cache_id=, cache_id)
294
- v.cache!(new_file)
340
+ versions.each do |name, v|
341
+ v.send(:cache_id=, cache_id)
342
+ v.cache!(new_file)
343
+ end
295
344
  end
296
345
  end
297
346
 
@@ -352,35 +401,25 @@ module CarrierWave
352
401
  #
353
402
  # If new_file is omitted, a previously cached file will be stored.
354
403
  #
355
- # If CarrierWave.config[:use_cache] is true, it will first cache the file
356
- # and apply any process callbacks before uploading it.
357
- #
358
404
  # @param [File, IOString, Tempfile] new_file any kind of file object
359
405
  #
360
406
  def store!(new_file=nil)
361
- if CarrierWave.config[:use_cache]
362
- cache!(new_file) if new_file
407
+ cache!(new_file) if new_file
408
+ if @file
363
409
  @file = storage.store!(self, @file)
364
410
  @cache_id = nil
365
- else
366
- new_file = CarrierWave::SanitizedFile.new(new_file)
367
-
368
- @filename = new_file.filename
369
- self.original_filename = filename
370
-
371
- @file = storage.store!(self, new_file)
411
+ versions.each { |name, v| v.store!(new_file) }
372
412
  end
373
- versions.each { |name, v| v.store!(new_file) }
374
413
  end
375
414
 
376
415
  ##
377
416
  # Retrieves the file from the storage, unless a file has
378
417
  # already been cached, stored or retrieved.
379
418
  #
380
- # @param [String] filename uniquely identifies the file to retrieve
419
+ # @param [String] identifier uniquely identifies the file to retrieve
381
420
  #
382
- def retrieve_from_store(filename)
383
- retrieve_from_store!(filename) unless file
421
+ def retrieve_from_store(identifier)
422
+ retrieve_from_store!(identifier) unless file
384
423
  rescue CarrierWave::InvalidParameter
385
424
  end
386
425
 
@@ -397,7 +436,7 @@ module CarrierWave
397
436
  private
398
437
 
399
438
  def cache_path
400
- File.expand_path(File.join(cache_dir, cache_name), root)
439
+ File.expand_path(File.join(cache_dir, cache_name), public)
401
440
  end
402
441
 
403
442
  def storage
@@ -407,12 +446,12 @@ module CarrierWave
407
446
  attr_reader :cache_id, :original_filename
408
447
 
409
448
  def cache_id=(cache_id)
410
- raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /^[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}$/
449
+ raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
411
450
  @cache_id = cache_id
412
451
  end
413
452
 
414
453
  def original_filename=(filename)
415
- raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /^[a-z0-9\.\-\+_]+$/i
454
+ raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /\A[a-z0-9\.\-\+_]+\z/i
416
455
  @original_filename = filename
417
456
  end
418
457
 
@@ -3,13 +3,13 @@ module Merb
3
3
  class UploaderGenerator < NamedGenerator
4
4
 
5
5
  def self.source_root
6
- File.join(File.dirname(__FILE__), 'templates')
6
+ File.join(File.dirname(__FILE__), '..', '..', 'rails_generators', 'uploader', 'templates')
7
7
  end
8
8
 
9
9
  first_argument :name, :required => true, :desc => "The name of this uploader"
10
10
 
11
11
  template :uploader do |t|
12
- t.source = 'uploader.rbt'
12
+ t.source = 'uploader.rb'
13
13
  t.destination = "app/uploaders/#{file_name}_uploader.rb"
14
14
  end
15
15
  end
@@ -0,0 +1,2 @@
1
+ Description:
2
+ Generates a skeleton for a new uploader.
@@ -6,6 +6,7 @@ class <%= class_name %>Uploader < CarrierWave::Uploader
6
6
 
7
7
  # Choose what kind of storage to use for this uploader
8
8
  storage :file
9
+ # storage :s3
9
10
 
10
11
  # Process files as they are uploaded.
11
12
  # process :scale => [200, 300]
@@ -14,14 +15,14 @@ class <%= class_name %>Uploader < CarrierWave::Uploader
14
15
  # # do something
15
16
  # end
16
17
 
17
- # Create different verions of your uploaded files
18
+ # Create different versions of your uploaded files
18
19
  # version :thumb do
19
20
  # process :scale => [50, 50]
20
21
  # end
21
22
 
22
23
  # Override the filename of the uploaded files
23
24
  # def filename
24
- # "something"
25
+ # "something.jpg"
25
26
  # end
26
27
 
27
28
  # Override the directory where uploaded files will be stored
@@ -0,0 +1,19 @@
1
+ class UploaderGenerator < Rails::Generator::NamedBase
2
+
3
+ def manifest
4
+ record do |m|
5
+ m.directory 'app/uploaders'
6
+ m.template 'uploader.rb', "app/uploaders/#{name.underscore}_uploader.rb"
7
+ end
8
+ end
9
+
10
+ def class_name
11
+ name.camelize
12
+ end
13
+
14
+ protected
15
+
16
+ def banner
17
+ "Usage: #{$0} uploader UploaderName"
18
+ end
19
+ end
@@ -97,6 +97,7 @@ describe CarrierWave::Mount do
97
97
  before do
98
98
  @instance.stub!(:write_uploader)
99
99
  @instance.stub!(:read_uploader).and_return(nil)
100
+ CarrierWave::SanitizedFile.new(file_path('test.jpg')).copy_to(public_path('uploads/tmp/19990512-1202-123-1234/test.jpg'))
100
101
  end
101
102
 
102
103
  it "should do nothing when nil is assigned" do
@@ -168,6 +168,12 @@ describe CarrierWave::SanitizedFile do
168
168
  end
169
169
  end
170
170
 
171
+ describe "#size" do
172
+ it "should return the size of the file" do
173
+ @sanitized_file.size.should == 13
174
+ end
175
+ end
176
+
171
177
  describe '#move_to' do
172
178
 
173
179
  after do
@@ -29,8 +29,6 @@ end
29
29
 
30
30
  CarrierWave.config[:public] = public_path
31
31
  CarrierWave.config[:root] = File.expand_path(File.dirname(__FILE__))
32
- CarrierWave.config[:store_dir] = 'public/uploads'
33
- CarrierWave.config[:cache_dir] = 'public/uploads/tmp'
34
32
 
35
33
  module SanitizedFileSpecHelper
36
34
  def stub_merb_tempfile(filename)
@@ -55,7 +55,7 @@ describe CarrierWave::Uploader do
55
55
  public_path('monkey/apache')
56
56
  end
57
57
  end
58
- @uploader.store_dir.should == 'public/uploads'
58
+ @uploader.store_dir.should == 'uploads'
59
59
  @uploader.thumb.store_dir.should == public_path('monkey/apache')
60
60
  end
61
61
 
@@ -133,15 +133,31 @@ describe CarrierWave::Uploader do
133
133
  end
134
134
  end
135
135
 
136
+ describe '#blank' do
137
+ it "should be true when nothing has been done" do
138
+ @uploader.should be_blank
139
+ end
140
+
141
+ it "should not be true when the file is empty" do
142
+ @uploader.retrieve_from_cache!('20071201-1234-345-2255/test.jpeg')
143
+ @uploader.should be_blank
144
+ end
145
+
146
+ it "should not be true when a file has been cached" do
147
+ @uploader.cache!(File.open(file_path('test.jpg')))
148
+ @uploader.should_not be_blank
149
+ end
150
+ end
151
+
136
152
  describe '#store_dir' do
137
153
  it "should default to the config option" do
138
- @uploader.store_dir.should == 'public/uploads'
154
+ @uploader.store_dir.should == 'uploads'
139
155
  end
140
156
  end
141
157
 
142
158
  describe '#cache_dir' do
143
159
  it "should default to the config option" do
144
- @uploader.cache_dir.should == 'public/uploads/tmp'
160
+ @uploader.cache_dir.should == 'uploads/tmp'
145
161
  end
146
162
  end
147
163
 
@@ -258,6 +274,43 @@ describe CarrierWave::Uploader do
258
274
  @uploader.should_receive(:process!)
259
275
  @uploader.cache!(File.open(file_path('test.jpg')))
260
276
  end
277
+
278
+ it "should raise an error when trying to cache a string" do
279
+ running {
280
+ @uploader.cache!(file_path('test.jpg'))
281
+ }.should raise_error(CarrierWave::FormNotMultipart)
282
+ end
283
+
284
+ it "should raise an error when trying to cache a pathname" do
285
+ running {
286
+ @uploader.cache!(Pathname.new(file_path('test.jpg')))
287
+ }.should raise_error(CarrierWave::FormNotMultipart)
288
+ end
289
+
290
+ it "should do nothing when trying to cache an empty file" do
291
+ @uploader.cache!(nil)
292
+ end
293
+
294
+ it "should not raise an integiry error if there is no white list" do
295
+ @uploader.stub!(:extension_white_list).and_return(nil)
296
+ running {
297
+ @uploader.cache!(File.open(file_path('test.jpg')))
298
+ }.should_not raise_error(CarrierWave::IntegrityError)
299
+ end
300
+
301
+ it "should not raise an integiry error if there is a white list and the file is on it" do
302
+ @uploader.stub!(:extension_white_list).and_return(%w(jpg gif png))
303
+ running {
304
+ @uploader.cache!(File.open(file_path('test.jpg')))
305
+ }.should_not raise_error(CarrierWave::IntegrityError)
306
+ end
307
+
308
+ it "should raise an integiry error if there is a white list and the file is not on it" do
309
+ @uploader.stub!(:extension_white_list).and_return(%w(txt doc xls))
310
+ running {
311
+ @uploader.cache!(File.open(file_path('test.jpg')))
312
+ }.should raise_error(CarrierWave::IntegrityError)
313
+ end
261
314
  end
262
315
 
263
316
  describe '#retrieve_from_cache!' do
@@ -375,14 +428,8 @@ describe CarrierWave::Uploader do
375
428
  @uploader.store!(@file)
376
429
  end
377
430
 
378
- it "should, if a files is given as an argument and use_cache is false, not cache that file" do
379
- CarrierWave.config[:use_cache] = false
380
- @uploader.should_not_receive(:cache!)
381
- @uploader.store!(@file)
382
- CarrierWave.config[:use_cache] = true
383
- end
384
-
385
431
  it "should use a previously cached file if no argument is given" do
432
+ @uploader.cache!(File.open(file_path('test.jpg')))
386
433
  @uploader.should_not_receive(:cache!)
387
434
  @uploader.store!
388
435
  end
@@ -403,6 +450,10 @@ describe CarrierWave::Uploader do
403
450
  @uploader.store!(@file)
404
451
  @uploader.file.should == @stored_file
405
452
  end
453
+
454
+ it "should do nothing when trying to store an empty file" do
455
+ @uploader.store!(nil)
456
+ end
406
457
  end
407
458
 
408
459
  describe '#retrieve_from_store!' do
@@ -494,8 +545,8 @@ describe CarrierWave::Uploader do
494
545
 
495
546
  it "should suffix the version's store_dir" do
496
547
  @uploader.cache!(File.open(file_path('test.jpg')))
497
- @uploader.store_dir.should == 'public/uploads'
498
- @uploader.thumb.store_dir.should == 'public/uploads/thumb'
548
+ @uploader.store_dir.should == 'uploads'
549
+ @uploader.thumb.store_dir.should == 'uploads/thumb'
499
550
  end
500
551
 
501
552
  it "should move it to the tmp dir with the filename prefixed" do
@@ -516,8 +567,8 @@ describe CarrierWave::Uploader do
516
567
 
517
568
  it "should suffix the version's store_dir" do
518
569
  @uploader.retrieve_from_cache!('20071201-1234-345-2255/test.jpg')
519
- @uploader.store_dir.should == 'public/uploads'
520
- @uploader.thumb.store_dir.should == 'public/uploads/thumb'
570
+ @uploader.store_dir.should == 'uploads'
571
+ @uploader.thumb.store_dir.should == 'uploads/thumb'
521
572
  end
522
573
  end
523
574
 
@@ -551,15 +602,15 @@ describe CarrierWave::Uploader do
551
602
 
552
603
  it "should, if a file is given as argument, suffix the version's store_dir" do
553
604
  @uploader.store!(@file)
554
- @uploader.store_dir.should == 'public/uploads'
555
- @uploader.thumb.store_dir.should == 'public/uploads/thumb'
605
+ @uploader.store_dir.should == 'uploads'
606
+ @uploader.thumb.store_dir.should == 'uploads/thumb'
556
607
  end
557
608
 
558
609
  it "should, if a files is given as an argument and use_cache is false, suffix the version's store_dir" do
559
610
  CarrierWave.config[:use_cache] = false
560
611
  @uploader.store!(@file)
561
- @uploader.store_dir.should == 'public/uploads'
562
- @uploader.thumb.store_dir.should == 'public/uploads/thumb'
612
+ @uploader.store_dir.should == 'uploads'
613
+ @uploader.thumb.store_dir.should == 'uploads/thumb'
563
614
  end
564
615
 
565
616
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jnicklas-carrierwave
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-02 00:00:00 -08:00
12
+ date: 2009-03-13 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -45,8 +45,6 @@ files:
45
45
  - lib/carrierwave/uploader.rb
46
46
  - lib/carrierwave.rb
47
47
  - lib/generators
48
- - lib/generators/templates
49
- - lib/generators/templates/uploader.rbt
50
48
  - lib/generators/uploader_generator.rb
51
49
  - spec/fixtures
52
50
  - spec/fixtures/bork.txt
@@ -59,6 +57,11 @@ files:
59
57
  - spec/sanitized_file_spec.rb
60
58
  - spec/spec_helper.rb
61
59
  - spec/uploader_spec.rb
60
+ - rails_generators/uploader
61
+ - rails_generators/uploader/templates
62
+ - rails_generators/uploader/templates/uploader.rb
63
+ - rails_generators/uploader/uploader_generator.rb
64
+ - rails_generators/uploader/USAGE
62
65
  has_rdoc: true
63
66
  homepage: http://www.example.com
64
67
  post_install_message: