durran-carrierwave 0.3.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 (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