durran-carrierwave 0.3.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/Generators +4 -0
  2. data/History.txt +66 -0
  3. data/LICENSE +8 -0
  4. data/Manifest.txt +89 -0
  5. data/README.rdoc +342 -0
  6. data/Rakefile +30 -0
  7. data/carrierwave.gemspec +57 -0
  8. data/cucumber.yml +2 -0
  9. data/features/caching.feature +28 -0
  10. data/features/file_storage.feature +37 -0
  11. data/features/file_storage_overridden_filename.feature +38 -0
  12. data/features/file_storage_overridden_store_dir.feature +38 -0
  13. data/features/file_storage_reversing_processor.feature +43 -0
  14. data/features/fixtures/bork.txt +1 -0
  15. data/features/fixtures/monkey.txt +1 -0
  16. data/features/mount_activerecord.feature +46 -0
  17. data/features/mount_datamapper.feature +46 -0
  18. data/features/step_definitions/activerecord_steps.rb +22 -0
  19. data/features/step_definitions/caching_steps.rb +14 -0
  20. data/features/step_definitions/datamapper_steps.rb +29 -0
  21. data/features/step_definitions/file_steps.rb +42 -0
  22. data/features/step_definitions/general_steps.rb +80 -0
  23. data/features/step_definitions/mount_steps.rb +19 -0
  24. data/features/step_definitions/store_steps.rb +18 -0
  25. data/features/support/activerecord.rb +30 -0
  26. data/features/support/datamapper.rb +7 -0
  27. data/features/support/env.rb +35 -0
  28. data/features/versions_basics.feature +50 -0
  29. data/features/versions_nested_versions.feature +70 -0
  30. data/features/versions_overridden_filename.feature +51 -0
  31. data/features/versions_overriden_store_dir.feature +41 -0
  32. data/lib/carrierwave.rb +145 -0
  33. data/lib/carrierwave/compatibility/paperclip.rb +95 -0
  34. data/lib/carrierwave/core_ext/blank.rb +46 -0
  35. data/lib/carrierwave/core_ext/inheritable_attributes.rb +104 -0
  36. data/lib/carrierwave/core_ext/module_setup.rb +51 -0
  37. data/lib/carrierwave/mount.rb +332 -0
  38. data/lib/carrierwave/orm/activerecord.rb +73 -0
  39. data/lib/carrierwave/orm/datamapper.rb +27 -0
  40. data/lib/carrierwave/orm/mongomapper.rb +27 -0
  41. data/lib/carrierwave/orm/sequel.rb +57 -0
  42. data/lib/carrierwave/processing/image_science.rb +72 -0
  43. data/lib/carrierwave/processing/rmagick.rb +286 -0
  44. data/lib/carrierwave/sanitized_file.rb +272 -0
  45. data/lib/carrierwave/storage/abstract.rb +32 -0
  46. data/lib/carrierwave/storage/file.rb +50 -0
  47. data/lib/carrierwave/storage/s3.rb +215 -0
  48. data/lib/carrierwave/test/matchers.rb +114 -0
  49. data/lib/carrierwave/uploader.rb +43 -0
  50. data/lib/carrierwave/uploader/cache.rb +116 -0
  51. data/lib/carrierwave/uploader/callbacks.rb +42 -0
  52. data/lib/carrierwave/uploader/default_path.rb +23 -0
  53. data/lib/carrierwave/uploader/extension_whitelist.rb +37 -0
  54. data/lib/carrierwave/uploader/mountable.rb +39 -0
  55. data/lib/carrierwave/uploader/paths.rb +27 -0
  56. data/lib/carrierwave/uploader/processing.rb +81 -0
  57. data/lib/carrierwave/uploader/proxy.rb +62 -0
  58. data/lib/carrierwave/uploader/remove.rb +23 -0
  59. data/lib/carrierwave/uploader/store.rb +156 -0
  60. data/lib/carrierwave/uploader/url.rb +24 -0
  61. data/lib/carrierwave/uploader/versions.rb +147 -0
  62. data/lib/generators/uploader_generator.rb +22 -0
  63. data/rails_generators/uploader/USAGE +2 -0
  64. data/rails_generators/uploader/templates/uploader.rb +47 -0
  65. data/rails_generators/uploader/uploader_generator.rb +21 -0
  66. data/script/console +10 -0
  67. data/script/destroy +14 -0
  68. data/script/generate +14 -0
  69. data/spec/compatibility/paperclip_spec.rb +43 -0
  70. data/spec/fixtures/bork.txt +1 -0
  71. data/spec/fixtures/test.jpeg +1 -0
  72. data/spec/fixtures/test.jpg +1 -0
  73. data/spec/mount_spec.rb +517 -0
  74. data/spec/orm/activerecord_spec.rb +271 -0
  75. data/spec/orm/datamapper_spec.rb +161 -0
  76. data/spec/orm/mongomapper_spec.rb +184 -0
  77. data/spec/orm/sequel_spec.rb +192 -0
  78. data/spec/sanitized_file_spec.rb +612 -0
  79. data/spec/spec_helper.rb +99 -0
  80. data/spec/uploader/cache_spec.rb +196 -0
  81. data/spec/uploader/default_path_spec.rb +68 -0
  82. data/spec/uploader/extension_whitelist_spec.rb +44 -0
  83. data/spec/uploader/mountable_spec.rb +33 -0
  84. data/spec/uploader/paths_spec.rb +22 -0
  85. data/spec/uploader/processing_spec.rb +62 -0
  86. data/spec/uploader/proxy_spec.rb +54 -0
  87. data/spec/uploader/remove_spec.rb +70 -0
  88. data/spec/uploader/store_spec.rb +274 -0
  89. data/spec/uploader/url_spec.rb +87 -0
  90. data/spec/uploader/versions_spec.rb +306 -0
  91. metadata +228 -0
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Test
5
+
6
+ ##
7
+ # These are some matchers that can be used in RSpec specs, to simplify the testing
8
+ # of uploaders.
9
+ #
10
+ module Matchers
11
+
12
+ class BeIdenticalTo # :nodoc:
13
+ def initialize(expected)
14
+ @expected = expected
15
+ end
16
+ def matches?(actual)
17
+ @actual = actual
18
+ FileUtils.identical?(@actual, @expected)
19
+ end
20
+ def failure_message
21
+ "expected #{@actual.inspect} to be identical to #{@expected.inspect}"
22
+ end
23
+ def negative_failure_message
24
+ "expected #{@actual.inspect} to not be identical to #{@expected.inspect}"
25
+ end
26
+ end
27
+
28
+ def be_identical_to(expected)
29
+ BeIdenticalTo.new(expected)
30
+ end
31
+
32
+ class HavePermissions # :nodoc:
33
+ def initialize(expected)
34
+ @expected = expected
35
+ end
36
+
37
+ def matches?(actual)
38
+ @actual = actual
39
+ # Satisfy expectation here. Return false or raise an error if it's not met.
40
+ (File.stat(@actual.path).mode & 0777) == @expected
41
+ end
42
+
43
+ def failure_message
44
+ "expected #{@actual.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
45
+ end
46
+
47
+ def negative_failure_message
48
+ "expected #{@actual.inspect} not to have permissions #{@expected.to_s(8)}, but it did"
49
+ end
50
+ end
51
+
52
+ def have_permissions(expected)
53
+ HavePermissions.new(expected)
54
+ end
55
+
56
+ class BeNoLargerThan # :nodoc:
57
+ def initialize(width, height)
58
+ @width, @height = width, height
59
+ end
60
+
61
+ def matches?(actual)
62
+ @actual = actual
63
+ # Satisfy expectation here. Return false or raise an error if it's not met.
64
+ require 'RMagick'
65
+ img = ::Magick::Image.read(@actual.path).first
66
+ @actual_width = img.columns
67
+ @actual_height = img.rows
68
+ @actual_width <= @width && @actual_height <= @height
69
+ end
70
+
71
+ def failure_message
72
+ "expected #{@actual.inspect} to be no larger than #{@width} by #{@height}, but it was #{@actual_height} by #{@actual_width}."
73
+ end
74
+
75
+ def negative_failure_message
76
+ "expected #{@actual.inspect} to be larger than #{@width} by #{@height}, but it wasn't."
77
+ end
78
+ end
79
+
80
+ def be_no_larger_than(width, height)
81
+ BeNoLargerThan.new(width, height)
82
+ end
83
+
84
+ class HaveDimensions # :nodoc:
85
+ def initialize(width, height)
86
+ @width, @height = width, height
87
+ end
88
+
89
+ def matches?(actual)
90
+ @actual = actual
91
+ # Satisfy expectation here. Return false or raise an error if it's not met.
92
+ require 'RMagick'
93
+ img = ::Magick::Image.read(@actual.path).first
94
+ @actual_width = img.columns
95
+ @actual_height = img.rows
96
+ @actual_width == @width && @actual_height == @height
97
+ end
98
+
99
+ def failure_message
100
+ "expected #{@actual.inspect} to have an exact size of #{@width} by #{@height}, but it was #{@actual_height} by #{@actual_width}."
101
+ end
102
+
103
+ def negative_failure_message
104
+ "expected #{@actual.inspect} not to have an exact size of #{@width} by #{@height}, but it did."
105
+ end
106
+ end
107
+
108
+ def have_dimensions(width, height)
109
+ HaveDimensions.new(width, height)
110
+ end
111
+
112
+ end # SpecHelper
113
+ end # Test
114
+ end # CarrierWave
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+
5
+ ##
6
+ # See CarrierWave::Uploader::Base
7
+ #
8
+ module Uploader
9
+
10
+ ##
11
+ # An uploader is a class that allows you to easily handle the caching and storage of
12
+ # uploaded files. Please refer to the README for configuration options.
13
+ #
14
+ # Once you have an uploader you can use it in isolation:
15
+ #
16
+ # my_uploader = MyUploader.new
17
+ # my_uploader.cache!(File.open(path_to_file))
18
+ # my_uploader.retrieve_from_store!('monkey.png')
19
+ #
20
+ # Alternatively, you can mount it on an ORM or other persistence layer, with
21
+ # +CarrierWave::Mount#mount_uploader+. There are extensions for activerecord and datamapper
22
+ # these are *very* simple (they are only a dozen lines of code), so adding your own should
23
+ # be trivial.
24
+ #
25
+ class Base
26
+ attr_reader :file
27
+
28
+ use CarrierWave::Uploader::Paths
29
+ use CarrierWave::Uploader::Callbacks
30
+ use CarrierWave::Uploader::Proxy
31
+ use CarrierWave::Uploader::Url
32
+ use CarrierWave::Uploader::Mountable
33
+ use CarrierWave::Uploader::Cache
34
+ use CarrierWave::Uploader::Store
35
+ use CarrierWave::Uploader::Remove
36
+ use CarrierWave::Uploader::ExtensionWhitelist
37
+ use CarrierWave::Uploader::DefaultPath
38
+ use CarrierWave::Uploader::Processing
39
+ use CarrierWave::Uploader::Versions
40
+ end # Base
41
+
42
+ end # Uploader
43
+ end # CarrierWave
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Cache
6
+
7
+ depends_on CarrierWave::Uploader::Paths
8
+ depends_on CarrierWave::Uploader::Callbacks
9
+
10
+ ##
11
+ # Returns true if the uploader has been cached
12
+ #
13
+ # === Returns
14
+ #
15
+ # [Bool] whether the current file is cached
16
+ #
17
+ def cached?
18
+ @cache_id
19
+ end
20
+
21
+ ##
22
+ # Override this in your Uploader to change the directory where files are cached.
23
+ #
24
+ # === Returns
25
+ #
26
+ # [String] a directory
27
+ #
28
+ def cache_dir
29
+ CarrierWave.config[:cache_dir]
30
+ end
31
+
32
+ ##
33
+ # Returns a String which uniquely identifies the currently cached file for later retrieval
34
+ #
35
+ # === Returns
36
+ #
37
+ # [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
38
+ #
39
+ def cache_name
40
+ File.join(cache_id, full_original_filename) if cache_id and original_filename
41
+ end
42
+
43
+ ##
44
+ # Caches the given file. Calls process! to trigger any process callbacks.
45
+ #
46
+ # === Parameters
47
+ #
48
+ # [new_file (File, IOString, Tempfile)] any kind of file object
49
+ #
50
+ # === Raises
51
+ #
52
+ # [CarrierWave::FormNotMultipart] if the assigned parameter is a string
53
+ #
54
+ def cache!(new_file)
55
+ new_file = CarrierWave::SanitizedFile.new(new_file)
56
+ raise CarrierWave::FormNotMultipart if new_file.is_path?
57
+
58
+ unless new_file.empty?
59
+ with_callbacks(:cache, new_file) do
60
+ self.cache_id = CarrierWave.generate_cache_id unless cache_id
61
+
62
+ @filename = new_file.filename
63
+ self.original_filename = new_file.filename
64
+
65
+ if CarrierWave.config[:cache_to_cache_dir]
66
+ @file = new_file.copy_to(cache_path, CarrierWave.config[:permissions])
67
+ else
68
+ @file = new_file
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ ##
75
+ # Retrieves the file with the given cache_name from the cache.
76
+ #
77
+ # === Parameters
78
+ #
79
+ # [cache_name (String)] uniquely identifies a cache file
80
+ #
81
+ # === Raises
82
+ #
83
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
84
+ #
85
+ def retrieve_from_cache!(cache_name)
86
+ with_callbacks(:retrieve_from_cache, cache_name) do
87
+ self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
88
+ @filename = original_filename
89
+ @file = CarrierWave::SanitizedFile.new(cache_path)
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def cache_path
96
+ File.expand_path(File.join(cache_dir, cache_name), public)
97
+ end
98
+
99
+ attr_reader :cache_id, :original_filename
100
+
101
+ # We can override the full_original_filename method in other modules
102
+ alias_method :full_original_filename, :original_filename
103
+
104
+ def cache_id=(cache_id)
105
+ raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
106
+ @cache_id = cache_id
107
+ end
108
+
109
+ def original_filename=(filename)
110
+ raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /\A[a-z0-9\.\-\+_]+\z/i
111
+ @original_filename = filename
112
+ end
113
+
114
+ end # Cache
115
+ end # Uploader
116
+ end # CarrierWave
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Callbacks
6
+
7
+ setup do
8
+ extlib_inheritable_accessor :_before_callbacks, :_after_callbacks
9
+ end
10
+
11
+ def with_callbacks(kind, *args)
12
+ self.class._before_callbacks_for(kind).each { |callback| self.send(callback, *args) }
13
+ yield
14
+ self.class._after_callbacks_for(kind).each { |callback| self.send(callback, *args) }
15
+ end
16
+
17
+ module ClassMethods
18
+
19
+ def _before_callbacks_for(kind) #:nodoc:
20
+ self._before_callbacks ||= {}
21
+ self._before_callbacks[kind] ||= []
22
+ self._before_callbacks[kind]
23
+ end
24
+
25
+ def _after_callbacks_for(kind) #:nodoc:
26
+ self._after_callbacks ||= {}
27
+ self._after_callbacks[kind] ||= []
28
+ self._after_callbacks[kind]
29
+ end
30
+
31
+ def before(kind, callback)
32
+ _before_callbacks_for(kind) << callback
33
+ end
34
+
35
+ def after(kind, callback)
36
+ _after_callbacks_for(kind) << callback
37
+ end
38
+ end # ClassMethods
39
+
40
+ end # Callbacks
41
+ end # Uploader
42
+ end # CarrierWave
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module DefaultPath
6
+
7
+ def initialize(*args)
8
+ super
9
+ if default_path
10
+ @file = CarrierWave::SanitizedFile.new(File.expand_path(default_path, public))
11
+ def @file.blank?; true; end
12
+ end
13
+ end
14
+
15
+ ##
16
+ # Override this method in your uploader to provide a default path
17
+ # in case no file has been cached/stored yet.
18
+ #
19
+ def default_path; end
20
+
21
+ end # DefaultPath
22
+ end # Uploader
23
+ end # CarrierWave
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module ExtensionWhitelist
6
+
7
+ setup do
8
+ before :cache, :check_whitelist!
9
+ end
10
+
11
+ ##
12
+ # Override this method in your uploader to provide a white list of extensions which
13
+ # are allowed to be uploaded.
14
+ #
15
+ # === Returns
16
+ #
17
+ # [NilClass, Array[String]] a white list of extensions which are allowed to be uploaded
18
+ #
19
+ # === Examples
20
+ #
21
+ # def extension_white_list
22
+ # %w(jpg jpeg gif png)
23
+ # end
24
+ #
25
+ def extension_white_list; end
26
+
27
+ private
28
+
29
+ def check_whitelist!(new_file)
30
+ if extension_white_list and not extension_white_list.include?(new_file.extension.to_s)
31
+ raise CarrierWave::IntegrityError, "You are not allowed to upload #{new_file.extension.inspect} files, allowed types: #{extension_white_list.inspect}"
32
+ end
33
+ end
34
+
35
+ end # ExtensionWhitelist
36
+ end # Uploader
37
+ end # CarrierWave
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Mountable
6
+
7
+ attr_reader :model, :mounted_as
8
+
9
+ ##
10
+ # If a model is given as the first parameter, it will stored in the uploader, and
11
+ # available throught +#model+. Likewise, mounted_as stores the name of the column
12
+ # where this instance of the uploader is mounted. These values can then be used inside
13
+ # your uploader.
14
+ #
15
+ # If you do not wish to mount your uploaders with the ORM extensions in -more then you
16
+ # can override this method inside your uploader. Just be sure to call +super+
17
+ #
18
+ # === Parameters
19
+ #
20
+ # [model (Object)] Any kind of model object
21
+ # [mounted_as (Symbol)] The name of the column where this uploader is mounted
22
+ #
23
+ # === Examples
24
+ #
25
+ # class MyUploader < CarrierWave::Uploader::Base
26
+ #
27
+ # def store_dir
28
+ # File.join('public', 'files', mounted_as, model.permalink)
29
+ # end
30
+ # end
31
+ #
32
+ def initialize(model=nil, mounted_as=nil)
33
+ @model = model
34
+ @mounted_as = mounted_as
35
+ end
36
+
37
+ end # Mountable
38
+ end # Uploader
39
+ end # CarrierWave
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Uploader
5
+ module Paths
6
+
7
+ ##
8
+ # === Returns
9
+ #
10
+ # [String] the directory that is the root of the application
11
+ #
12
+ def root
13
+ CarrierWave.config[:root]
14
+ end
15
+
16
+ ##
17
+ # === Returns
18
+ #
19
+ # [String] the directory where files will be publically accessible
20
+ #
21
+ def public
22
+ CarrierWave.config[:public]
23
+ end
24
+
25
+ end # Paths
26
+ end # Uploader
27
+ end # CarrierWave