jnicklas-carrierwave 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,39 +15,63 @@ module CarrierWave
15
15
  # these are *very* simple (they are only a dozen lines of code), so adding your own should
16
16
  # be trivial.
17
17
  #
18
- class Uploader
18
+ module Uploader
19
19
 
20
- class << self
20
+ def self.append_features(base) #:nodoc:
21
+ super
22
+ base.extend(ClassMethods)
23
+ end
21
24
 
25
+ ##
26
+ # Generates a unique cache id for use in the caching system
27
+ #
28
+ # === Returns
29
+ #
30
+ # [String] a cache id in the format YYYYMMDD-HHMM-PID-RND
31
+ #
32
+ def self.generate_cache_id
33
+ Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
34
+ end
35
+
36
+ module ClassMethods
37
+
22
38
  ##
23
- # Returns a list of processor callbacks which have been declared for this uploader
39
+ # Lists processor callbacks declared
24
40
  #
25
- # @return [String]
41
+ # === Returns
42
+ #
43
+ # [Array[Array[Symbol, Array]]] a list of processor callbacks which have been declared for this uploader
26
44
  #
27
45
  def processors
28
46
  @processors ||= []
29
47
  end
30
-
48
+
31
49
  ##
32
50
  # Adds a processor callback which applies operations as a file is uploaded.
33
51
  # The argument may be the name of any method of the uploader, expressed as a symbol,
34
52
  # or a list of such methods, or a hash where the key is a method and the value is
35
53
  # an array of arguments to call the method with
36
54
  #
37
- # @param [*Symbol, Hash{Symbol => Array[]}] args
38
- # @example
39
- # class MyUploader < CarrierWave::Uploader
55
+ # === Parameters
56
+ #
57
+ # args (*Symbol, Hash{Symbol => Array[]})
58
+ #
59
+ # === Examples
60
+ #
61
+ # class MyUploader
62
+ # include CarrierWave::Uploader
63
+ #
40
64
  # process :sepiatone, :vignette
41
65
  # process :scale => [200, 200]
42
- #
66
+ #
43
67
  # def sepiatone
44
68
  # ...
45
69
  # end
46
- #
70
+ #
47
71
  # def vignette
48
72
  # ...
49
73
  # end
50
- #
74
+ #
51
75
  # def scale(height, width)
52
76
  # ...
53
77
  # end
@@ -64,7 +88,7 @@ module CarrierWave
64
88
  end
65
89
  end
66
90
  end
67
-
91
+
68
92
  ##
69
93
  # Sets the storage engine to be used when storing files with this uploader.
70
94
  # Can be any class that implements a #store!(CarrierWave::SanitizedFile) and a #retrieve!
@@ -73,14 +97,21 @@ module CarrierWave
73
97
  # to by a symbol, which should be more convenient
74
98
  #
75
99
  # If no argument is given, it will simply return the currently used storage engine.
76
- #
77
- # @param [Symbol, Class] storage The storage engine to use for this uploader
78
- # @return [Class] the storage engine to be used with this uploader
79
- # @example
100
+ #
101
+ # === Parameters
102
+ #
103
+ # [storage (Symbol, Class)] The storage engine to use for this uploader
104
+ #
105
+ # === Returns
106
+ #
107
+ # [Class] the storage engine to be used with this uploader
108
+ #
109
+ # === Examples
110
+ #
80
111
  # storage :file
81
112
  # storage CarrierWave::Storage::File
82
113
  # storage MyCustomStorageEngine
83
- #
114
+ #
84
115
  def storage(storage = nil)
85
116
  if storage.is_a?(Symbol)
86
117
  @storage = get_storage_by_symbol(storage)
@@ -101,54 +132,54 @@ module CarrierWave
101
132
  end
102
133
 
103
134
  alias_method :storage=, :storage
104
-
105
- attr_accessor :version_name
135
+
136
+ def version_names
137
+ @version_names ||= []
138
+ end
106
139
 
107
140
  ##
108
141
  # Adds a new version to this uploader
109
142
  #
110
- # @param [#to_sym] name name of the version
111
- # @param [Proc] &block a block to eval on this version of the uploader
143
+ # === Parameters
144
+ #
145
+ # [name (#to_sym)] name of the version
146
+ # [&block (Proc)] a block to eval on this version of the uploader
112
147
  #
113
148
  def version(name, &block)
114
149
  name = name.to_sym
115
- klass = Class.new(self)
116
- klass.version_name = name
117
- klass.class_eval(&block) if block
118
- versions[name] = klass
119
- class_eval <<-RUBY
120
- def #{name}
121
- versions[:#{name}]
122
- end
123
- RUBY
150
+ unless versions[name]
151
+ versions[name] = Class.new(self)
152
+ versions[name].version_names.push(*version_names)
153
+ versions[name].version_names.push(name)
154
+ class_eval <<-RUBY
155
+ def #{name}
156
+ versions[:#{name}]
157
+ end
158
+ RUBY
159
+ end
160
+ versions[name].class_eval(&block) if block
161
+ versions[name]
124
162
  end
125
163
 
126
164
  ##
127
- # @return [Hash{Symbol => Class}] a list of versions available for this uploader
165
+ # === Returns
166
+ #
167
+ # [Hash{Symbol => Class}] a list of versions available for this uploader
128
168
  #
129
169
  def versions
130
170
  @versions ||= {}
131
171
  end
132
172
 
133
- ##
134
- # Generates a unique cache id for use in the caching system
135
- #
136
- # @return [String] a cache if in the format YYYYMMDD-HHMM-PID-RND
137
- #
138
- def generate_cache_id
139
- Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
140
- end
141
-
142
173
  private
143
-
174
+
144
175
  def get_storage_by_symbol(symbol)
145
- CarrierWave.config[:storage_engines][symbol]
176
+ eval(CarrierWave.config[:storage_engines][symbol])
146
177
  end
147
-
148
- end # class << self
149
-
178
+
179
+ end # ClassMethods
180
+
150
181
  attr_reader :file, :model, :mounted_as
151
-
182
+
152
183
  ##
153
184
  # If a model is given as the first parameter, it will stored in the uploader, and
154
185
  # available throught +#model+. Likewise, mounted_as stores the name of the column
@@ -158,10 +189,16 @@ module CarrierWave
158
189
  # If you do not wish to mount your uploaders with the ORM extensions in -more then you
159
190
  # can override this method inside your uploader.
160
191
  #
161
- # @param [Object] model Any kind of model object
162
- # @param [Symbol] mounted_as The name of the column where this uploader is mounted
163
- # @example
164
- # class MyUploader < CarrierWave::Uploader
192
+ # === Parameters
193
+ #
194
+ # [model (Object)] Any kind of model object
195
+ # [mounted_as (Symbol)] The name of the column where this uploader is mounted
196
+ #
197
+ # === Examples
198
+ #
199
+ # class MyUploader
200
+ # include CarrierWave::Uploader
201
+ #
165
202
  # def store_dir
166
203
  # File.join('public', 'files', mounted_as, model.permalink)
167
204
  # end
@@ -171,14 +208,16 @@ module CarrierWave
171
208
  @model = model
172
209
  @mounted_as = mounted_as
173
210
  end
174
-
211
+
175
212
  ##
176
- # @return [Boolean] Whether the uploaded file is blank
213
+ # === Returns
214
+ #
215
+ # [Boolean] Whether the uploaded file is blank
177
216
  #
178
217
  def blank?
179
- !file or file.empty?
218
+ !file or file.blank?
180
219
  end
181
-
220
+
182
221
  ##
183
222
  # Apply all process callbacks added through CarrierWave.process
184
223
  #
@@ -187,18 +226,24 @@ module CarrierWave
187
226
  self.send(method, *args)
188
227
  end
189
228
  end
190
-
229
+
191
230
  ##
192
- # @return [String] the path where the file is currently located.
231
+ # === Returns
232
+ #
233
+ # [String] the path where the file is currently located.
193
234
  #
194
235
  def current_path
195
236
  file.path if file.respond_to?(:path)
196
237
  end
197
-
238
+
239
+ alias_method :path, :current_path
240
+
198
241
  ##
199
242
  # Returns a hash mapping the name of each version of the uploader to an instance of it
200
243
  #
201
- # @return [Hash{Symbol => CarrierWave::Uploader}] a list of uploader instances
244
+ # === Returns
245
+ #
246
+ # [Hash{Symbol => CarrierWave::Uploader}] a list of uploader instances
202
247
  #
203
248
  def versions
204
249
  return @versions if @versions
@@ -210,7 +255,9 @@ module CarrierWave
210
255
  end
211
256
 
212
257
  ##
213
- # @return [String] the location where this file is accessible via a url
258
+ # === Returns
259
+ #
260
+ # [String] the location where this file is accessible via a url
214
261
  #
215
262
  def url
216
263
  if file.respond_to?(:url) and not file.url.blank?
@@ -219,18 +266,31 @@ module CarrierWave
219
266
  File.expand_path(current_path).gsub(File.expand_path(public), '')
220
267
  end
221
268
  end
222
-
269
+
223
270
  alias_method :to_s, :url
224
-
271
+
225
272
  ##
226
273
  # Returns a string that uniquely identifies the last stored file
227
274
  #
228
- # @return [String] uniquely identifies a file
275
+ # === Returns
276
+ #
277
+ # [String] uniquely identifies a file
229
278
  #
230
279
  def identifier
231
280
  file.identifier if file.respond_to?(:identifier)
232
281
  end
233
-
282
+
283
+ ##
284
+ # Read the contents of the file
285
+ #
286
+ # === Returns
287
+ #
288
+ # [String] contents of the file
289
+ #
290
+ def read
291
+ file.read if file.respond_to?(:read)
292
+ end
293
+
234
294
  ##
235
295
  # Override this in your Uploader to change the filename.
236
296
  #
@@ -241,28 +301,36 @@ module CarrierWave
241
301
  # Do not use the version_name in the filename, as it will prevent versions from being
242
302
  # loaded correctly.
243
303
  #
244
- # @return [String] a filename
304
+ # === Returns
305
+ #
306
+ # [String] a filename
245
307
  #
246
308
  def filename
247
309
  @filename
248
310
  end
249
311
 
250
312
  ##
251
- # @return [String] the name of this version of the uploader
313
+ # === Returns
314
+ #
315
+ # [String] the name of this version of the uploader
252
316
  #
253
317
  def version_name
254
- self.class.version_name
318
+ self.class.version_names.join('_').to_sym unless self.class.version_names.blank?
255
319
  end
256
-
320
+
257
321
  ##
258
- # @return [String] the directory that is the root of the application
322
+ # === Returns
323
+ #
324
+ # [String] the directory that is the root of the application
259
325
  #
260
326
  def root
261
327
  CarrierWave.config[:root]
262
328
  end
263
-
329
+
264
330
  ##
265
- # @return [String] the directory where files will be publically accessible
331
+ # === Returns
332
+ #
333
+ # [String] the directory where files will be publically accessible
266
334
  #
267
335
  def public
268
336
  CarrierWave.config[:public]
@@ -272,55 +340,73 @@ module CarrierWave
272
340
  # Override this method in your uploader to provide a white list of extensions which
273
341
  # are allowed to be uploaded.
274
342
  #
275
- # @return [NilClass, Array[String]] a white list of extensions which are allowed to be uploaded
276
- # @example
343
+ # === Returns
344
+ #
345
+ # [NilClass, Array[String]] a white list of extensions which are allowed to be uploaded
346
+ #
347
+ # === Examples
348
+ #
277
349
  # def extension_white_list
278
350
  # %w(jpg jpeg gif png)
279
351
  # end
280
352
  #
281
353
  def extension_white_list; end
282
-
354
+
283
355
  ####################
284
356
  ## Cache
285
357
  ####################
286
-
358
+
287
359
  ##
288
360
  # Override this in your Uploader to change the directory where files are cached.
289
361
  #
290
- # @return [String] a directory
362
+ # === Returns
363
+ #
364
+ # [String] a directory
291
365
  #
292
366
  def cache_dir
293
367
  CarrierWave.config[:cache_dir]
294
368
  end
295
-
369
+
296
370
  ##
297
371
  # Returns a String which uniquely identifies the currently cached file for later retrieval
298
372
  #
299
- # @return [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
373
+ # === Returns
374
+ #
375
+ # [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
300
376
  #
301
377
  def cache_name
302
378
  File.join(cache_id, [version_name, original_filename].compact.join('_')) if cache_id and original_filename
303
379
  end
304
-
380
+
305
381
  ##
306
382
  # Caches the given file unless a file has already been cached, stored or retrieved.
307
383
  #
308
- # @param [File, IOString, Tempfile] new_file any kind of file object
309
- # @raise [CarrierWave::FormNotMultipart] if the assigned parameter is a string
384
+ # === Parameters
385
+ #
386
+ # [new_file (File, IOString, Tempfile)] any kind of file object
387
+ #
388
+ # === Raises
389
+ #
390
+ # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
310
391
  #
311
392
  def cache(new_file)
312
393
  cache!(new_file) unless file
313
394
  end
314
-
395
+
315
396
  ##
316
397
  # Caches the given file. Calls process! to trigger any process callbacks.
317
398
  #
318
- # @param [File, IOString, Tempfile] new_file any kind of file object
319
- # @raise [CarrierWave::FormNotMultipart] if the assigned parameter is a string
399
+ # === Parameters
400
+ #
401
+ # [new_file (File, IOString, Tempfile)] any kind of file object
402
+ #
403
+ # === Raises
404
+ #
405
+ # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
320
406
  #
321
407
  def cache!(new_file)
322
408
  new_file = CarrierWave::SanitizedFile.new(new_file)
323
- raise CarrierWave::FormNotMultipart if new_file.string?
409
+ raise CarrierWave::FormNotMultipart if new_file.is_path?
324
410
 
325
411
  unless new_file.empty?
326
412
  if extension_white_list and not extension_white_list.include?(new_file.extension.to_s)
@@ -333,8 +419,8 @@ module CarrierWave
333
419
 
334
420
  @filename = new_file.filename
335
421
  self.original_filename = new_file.filename
336
-
337
- @file = @file.copy_to(cache_path)
422
+
423
+ @file = @file.copy_to(cache_path, CarrierWave.config[:permissions])
338
424
  process!
339
425
 
340
426
  versions.each do |name, v|
@@ -343,23 +429,30 @@ module CarrierWave
343
429
  end
344
430
  end
345
431
  end
346
-
432
+
347
433
  ##
348
434
  # Retrieves the file with the given cache_name from the cache, unless a file has
349
435
  # already been cached, stored or retrieved.
350
436
  #
351
- # @param [String] cache_name uniquely identifies a cache file
437
+ # === Parameters
438
+ #
439
+ # [cache_name (String)] uniquely identifies a cache file
352
440
  #
353
441
  def retrieve_from_cache(cache_name)
354
442
  retrieve_from_cache!(cache_name) unless file
355
443
  rescue CarrierWave::InvalidParameter
356
444
  end
357
-
445
+
358
446
  ##
359
447
  # Retrieves the file with the given cache_name from the cache.
360
448
  #
361
- # @param [String] cache_name uniquely identifies a cache file
362
- # @raise [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
449
+ # === Parameters
450
+ #
451
+ # [cache_name (String)] uniquely identifies a cache file
452
+ #
453
+ # === Raises
454
+ #
455
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
363
456
  #
364
457
  def retrieve_from_cache!(cache_name)
365
458
  self.cache_id, self.original_filename = cache_name.split('/', 2)
@@ -367,22 +460,40 @@ module CarrierWave
367
460
  @file = CarrierWave::SanitizedFile.new(cache_path)
368
461
  versions.each { |name, v| v.retrieve_from_cache!(cache_name) }
369
462
  end
370
-
463
+
371
464
  ####################
372
465
  ## STORE
373
466
  ####################
374
-
467
+
375
468
  ##
376
469
  # Override this in your Uploader to change the directory where the file backend stores files.
377
470
  #
378
471
  # Other backends may or may not use this method, depending on their specific needs.
379
472
  #
380
- # @return [String] a directory
473
+ # === Returns
474
+ #
475
+ # [String] a directory
381
476
  #
382
477
  def store_dir
383
- [CarrierWave.config[:store_dir], version_name].compact.join(File::Separator)
478
+ CarrierWave.config[:store_dir]
384
479
  end
385
-
480
+
481
+ ##
482
+ # Calculates the path where the file should be stored. If +for_file+ is given, it will be
483
+ # used as the filename, otherwise +CarrierWave::Uploader#filename+ is assumed.
484
+ #
485
+ # === Parameters
486
+ #
487
+ # [for_file (String)] name of the file <optional>
488
+ #
489
+ # === Returns
490
+ #
491
+ # [String] the store path
492
+ #
493
+ def store_path(for_file=filename)
494
+ File.join(store_dir, [version_name, for_file].compact.join('_'))
495
+ end
496
+
386
497
  ##
387
498
  # Stores the file by passing it to this Uploader's storage engine, unless a file has
388
499
  # already been cached, stored or retrieved.
@@ -390,18 +501,22 @@ module CarrierWave
390
501
  # If CarrierWave.config[:use_cache] is true, it will first cache the file
391
502
  # and apply any process callbacks before uploading it.
392
503
  #
393
- # @param [File, IOString, Tempfile] new_file any kind of file object
504
+ # === Parameters
505
+ #
506
+ # [new_file (File, IOString, Tempfile)] any kind of file object
394
507
  #
395
508
  def store(new_file)
396
509
  store!(new_file) unless file
397
510
  end
398
-
511
+
399
512
  ##
400
513
  # Stores the file by passing it to this Uploader's storage engine.
401
514
  #
402
515
  # If new_file is omitted, a previously cached file will be stored.
403
516
  #
404
- # @param [File, IOString, Tempfile] new_file any kind of file object
517
+ # === Parameters
518
+ #
519
+ # [new_file (File, IOString, Tempfile)] any kind of file object
405
520
  #
406
521
  def store!(new_file=nil)
407
522
  cache!(new_file) if new_file
@@ -411,49 +526,53 @@ module CarrierWave
411
526
  versions.each { |name, v| v.store!(new_file) }
412
527
  end
413
528
  end
414
-
529
+
415
530
  ##
416
531
  # Retrieves the file from the storage, unless a file has
417
532
  # already been cached, stored or retrieved.
418
- #
419
- # @param [String] identifier uniquely identifies the file to retrieve
533
+ #
534
+ # === Parameters
535
+ #
536
+ # [identifier (String)] uniquely identifies the file to retrieve
420
537
  #
421
538
  def retrieve_from_store(identifier)
422
539
  retrieve_from_store!(identifier) unless file
423
540
  rescue CarrierWave::InvalidParameter
424
541
  end
425
-
542
+
426
543
  ##
427
544
  # Retrieves the file from the storage.
428
- #
429
- # @param [String] identifier uniquely identifies the file to retrieve
545
+ #
546
+ # === Parameters
547
+ #
548
+ # [identifier (String)] uniquely identifies the file to retrieve
430
549
  #
431
550
  def retrieve_from_store!(identifier)
432
551
  @file = storage.retrieve!(self, identifier)
433
552
  versions.each { |name, v| v.retrieve_from_store!(identifier) }
434
553
  end
435
-
554
+
436
555
  private
437
-
556
+
438
557
  def cache_path
439
558
  File.expand_path(File.join(cache_dir, cache_name), public)
440
559
  end
441
-
560
+
442
561
  def storage
443
562
  self.class.storage
444
563
  end
445
-
564
+
446
565
  attr_reader :cache_id, :original_filename
447
566
 
448
567
  def cache_id=(cache_id)
449
568
  raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
450
569
  @cache_id = cache_id
451
570
  end
452
-
571
+
453
572
  def original_filename=(filename)
454
573
  raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /\A[a-z0-9\.\-\+_]+\z/i
455
574
  @original_filename = filename
456
575
  end
457
-
576
+
458
577
  end # Uploader
459
- end # CarrierWave
578
+ end # CarrierWave