carrierwave 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

Files changed (47) hide show
  1. data/README.rdoc +35 -20
  2. data/Rakefile +1 -1
  3. data/lib/carrierwave.rb +55 -7
  4. data/lib/carrierwave/compatibility/paperclip.rb +91 -0
  5. data/lib/carrierwave/core_ext/inheritable_attributes.rb +102 -0
  6. data/lib/carrierwave/core_ext/module_setup.rb +49 -0
  7. data/lib/carrierwave/mount.rb +119 -103
  8. data/lib/carrierwave/orm/activerecord.rb +6 -1
  9. data/lib/carrierwave/orm/sequel.rb +15 -2
  10. data/lib/carrierwave/processing/rmagick.rb +8 -7
  11. data/lib/carrierwave/storage/abstract.rb +16 -1
  12. data/lib/carrierwave/storage/file.rb +20 -1
  13. data/lib/carrierwave/uploader.rb +31 -593
  14. data/lib/carrierwave/uploader/cache.rb +114 -0
  15. data/lib/carrierwave/uploader/callbacks.rb +40 -0
  16. data/lib/carrierwave/uploader/default_path.rb +21 -0
  17. data/lib/carrierwave/uploader/extension_whitelist.rb +35 -0
  18. data/lib/carrierwave/uploader/mountable.rb +37 -0
  19. data/lib/carrierwave/uploader/paths.rb +25 -0
  20. data/lib/carrierwave/uploader/processing.rb +79 -0
  21. data/lib/carrierwave/uploader/proxy.rb +60 -0
  22. data/lib/carrierwave/uploader/remove.rb +21 -0
  23. data/lib/carrierwave/uploader/store.rb +154 -0
  24. data/lib/carrierwave/uploader/url.rb +22 -0
  25. data/lib/carrierwave/uploader/versions.rb +145 -0
  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/test.log +1717 -0
  35. data/spec/uploader/cache_spec.rb +194 -0
  36. data/spec/uploader/default_path_spec.rb +66 -0
  37. data/spec/uploader/extension_whitelist_spec.rb +42 -0
  38. data/spec/uploader/mountable_spec.rb +31 -0
  39. data/spec/uploader/paths_spec.rb +20 -0
  40. data/spec/uploader/processing_spec.rb +60 -0
  41. data/spec/uploader/proxy_spec.rb +52 -0
  42. data/spec/uploader/remove_spec.rb +65 -0
  43. data/spec/uploader/store_spec.rb +260 -0
  44. data/spec/uploader/url_spec.rb +85 -0
  45. data/spec/uploader/versions_spec.rb +275 -0
  46. metadata +30 -3
  47. data/spec/uploader_spec.rb +0 -887
data/README.rdoc CHANGED
@@ -36,9 +36,7 @@ this should give you a file in:
36
36
 
37
37
  Check out this file for some hints on how you can customize your uploader. It should look something like this:
38
38
 
39
- class AvatarUploader
40
- include CarrierWave::Uploader
41
-
39
+ class AvatarUploader < CarrierWave::Uploader::Base
42
40
  storage :file
43
41
  end
44
42
 
@@ -97,9 +95,7 @@ Now you can cache files by assigning them to the attribute, they will automatica
97
95
 
98
96
  In order to change where uploaded files are put, just override the +store_dir+ method:
99
97
 
100
- class MyUploader
101
- include CarrierWave::Uploader
102
-
98
+ class MyUploader < CarrierWave::Uploader::Base
103
99
  def store_dir
104
100
  'public/my/upload/directory'
105
101
  end
@@ -111,10 +107,9 @@ This works for the file storage as well as Amazon S3.
111
107
 
112
108
  Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this:
113
109
 
114
- class MyUploader
115
- include CarrierWave::Uploader
110
+ class MyUploader < CarrierWave::Uploader::Base
116
111
  include CarrierWave::RMagick
117
-
112
+
118
113
  process :resize => [800, 800]
119
114
 
120
115
  version :thumb do
@@ -135,8 +130,7 @@ One important thing to remember is that process is called *before* versions are
135
130
 
136
131
  It is possible to nest versions within versions:
137
132
 
138
- class MyUploader
139
- include CarrierWave::Uploader
133
+ class MyUploader < CarrierWave::Uploader::Base
140
134
 
141
135
  version :animal do
142
136
  version :human
@@ -174,6 +168,16 @@ in the case of images, a small thumbnail would be a good indicator:
174
168
 
175
169
  NOTE: this feature currently requires write access to your filesystem. If write access is unavailable (e.g. Heroku) you will not be able to upload files. You can prevent CarrierWave from writing to the file system by setting `CarrierWave.config[:cache_to_cache_dir] = false`. This will however break redisplays of forms.
176
170
 
171
+ == Providing a default path
172
+
173
+ In many cases, especially when working with images, it might be a good idea to provide a default path, a fallback in case no file has been uploaded. You can do this easily by overriding the +default_path+ method in your uploader:
174
+
175
+ class MyUploader < CarrierWave::Uploader::Base
176
+ def default_path
177
+ "images/fallback/" + [version_name, "default.png"].compact.join('_')
178
+ end
179
+ end
180
+
177
181
  == Using Amazon S3
178
182
 
179
183
  You'll need to configure a bucket, access id and secret key like this:
@@ -186,9 +190,7 @@ Do this in an initializer in Rails, and in a +before_app_loads+ block in Merb.
186
190
 
187
191
  And then in your uploader, set the storage to :s3
188
192
 
189
- class AvatarUploader
190
- include CarrierWave::Uploader
191
-
193
+ class AvatarUploader <
192
194
  storage :s3
193
195
  end
194
196
 
@@ -198,15 +200,13 @@ That's it! You can still use the +CarrierWave::Uploader#url+ method to return th
198
200
 
199
201
  If you're uploading images, you'll probably want to manipulate them in some way, you might want to create thumbnail images for example. CarrierWave comes with a small library to make manipulating images with RMagick easier, you'll need to include it in your Uploader:
200
202
 
201
- class AvatarUploader
202
- include CarrierWave::Uploader
203
+ class AvatarUploader < CarrierWave::Uploader::Base
203
204
  include CarrierWave::RMagick
204
205
  end
205
206
 
206
207
  The RMagick module gives you a few methods, like +CarrierWave::RMagick#crop_resized+ which manipulate the image file in some way. You can set a +process+ callback, which will call that method any time a file is uploaded.
207
208
 
208
- class AvatarUploader
209
- include CarrierWave::Uploader
209
+ class AvatarUploader < CarrierWave::Uploader::Base
210
210
  include CarrierWave::RMagick
211
211
 
212
212
  process :crop_resized => [200, 200]
@@ -223,13 +223,28 @@ Check out the manipulate! method, which makes it easy for you to write your own
223
223
 
224
224
  ImageScience works the same way as RMagick.
225
225
 
226
- class AvatarUploader
227
- include CarrierWave::Uploader
226
+ class AvatarUploader < CarrierWave::Uploader::Base
228
227
  include CarrierWave::ImageScience
229
228
 
230
229
  process :crop_resized => [200, 200]
231
230
  end
232
231
 
232
+ == Migrating
233
+
234
+ If you are using Paperclip, you can use the provided compatibility module:
235
+
236
+ class AvatarUploader < CarrierWave::Uploader::Base
237
+ include CarrierWave::Compatibility::Paperclip
238
+ end
239
+
240
+ See the documentation for +Paperclip::Compatibility::Paperclip+ for more detaills.
241
+
242
+ Be sure to use mount_on to specify the correct column:
243
+
244
+ mount_uploader :avatar, AvatarUploader, :mount_on => :avatar_file_name
245
+
246
+ Unfortunately AttachmentFoo differs too much in philosophy for there to be a sensible compatibility mode. Patches for migrating from other solutions will be happily accepted.
247
+
233
248
  == Documentation
234
249
 
235
250
  Full rdoc documentation is {available at Rubyforge}[http://carrierwave.rubyforge.org/].
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ require 'spec/rake/spectask'
9
9
  require 'cucumber/rake/task'
10
10
 
11
11
  NAME = "carrierwave"
12
- GEM_VERSION = "0.2.1"
12
+ GEM_VERSION = "0.2.3"
13
13
  AUTHOR = "Jonas Nicklas"
14
14
  EMAIL = "jonas.nicklas@gmail.com"
15
15
  HOMEPAGE = "http://www.example.com"
data/lib/carrierwave.rb CHANGED
@@ -1,8 +1,27 @@
1
1
  require 'fileutils'
2
+ require 'carrierwave/core_ext/module_setup'
3
+ require 'carrierwave/core_ext/inheritable_attributes'
2
4
 
3
5
  module CarrierWave
4
6
  class << self
5
- attr_accessor :config
7
+ attr_accessor :config, :logger
8
+
9
+ def logger
10
+ return @logger if @logger
11
+ require 'logger'
12
+ @logger = Logger.new(STDOUT)
13
+ end
14
+
15
+ ##
16
+ # Generates a unique cache id for use in the caching system
17
+ #
18
+ # === Returns
19
+ #
20
+ # [String] a cache id in the format YYYYMMDD-HHMM-PID-RND
21
+ #
22
+ def generate_cache_id
23
+ Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
24
+ end
6
25
  end
7
26
 
8
27
  class UploadError < StandardError; end
@@ -18,7 +37,6 @@ module CarrierWave
18
37
  class ProcessingError < UploadError; end
19
38
 
20
39
  autoload :SanitizedFile, 'carrierwave/sanitized_file'
21
- autoload :Uploader, 'carrierwave/uploader'
22
40
  autoload :Mount, 'carrierwave/mount'
23
41
  autoload :RMagick, 'carrierwave/processing/rmagick'
24
42
  autoload :ImageScience, 'carrierwave/processing/image_science'
@@ -29,6 +47,26 @@ module CarrierWave
29
47
  autoload :S3, 'carrierwave/storage/s3'
30
48
  end
31
49
 
50
+ module Uploader
51
+ autoload :Base, 'carrierwave/uploader'
52
+ autoload :Cache, 'carrierwave/uploader/cache'
53
+ autoload :Store, 'carrierwave/uploader/store'
54
+ autoload :Callbacks, 'carrierwave/uploader/callbacks'
55
+ autoload :Processing, 'carrierwave/uploader/processing'
56
+ autoload :Versions, 'carrierwave/uploader/versions'
57
+ autoload :Remove, 'carrierwave/uploader/remove'
58
+ autoload :Paths, 'carrierwave/uploader/paths'
59
+ autoload :ExtensionWhitelist, 'carrierwave/uploader/extension_whitelist'
60
+ autoload :DefaultPath, 'carrierwave/uploader/default_path'
61
+ autoload :Proxy, 'carrierwave/uploader/proxy'
62
+ autoload :Url, 'carrierwave/uploader/url'
63
+ autoload :Mountable, 'carrierwave/uploader/mountable'
64
+ end
65
+
66
+ module Compatibility
67
+ autoload :Paperclip, 'carrierwave/compatibility/paperclip'
68
+ end
69
+
32
70
  module Test
33
71
  autoload :Matchers, 'carrierwave/test/matchers'
34
72
  end
@@ -57,20 +95,30 @@ CarrierWave.config = {
57
95
  }
58
96
  }
59
97
 
60
- if defined?(Merb)
61
-
98
+ if defined?(Merb::Plugins)
62
99
  CarrierWave.config[:root] = Merb.root
63
100
  CarrierWave.config[:public] = Merb.dir_for(:public)
64
101
 
102
+ Merb::BootLoader.before_app_loads do
103
+ # Set logger
104
+ CarrierWave.logger ||= Merb.logger
105
+ # Setup path for uploaders and load all of them before classes are loaded
106
+ Merb.push_path(:uploaders, Merb.root / 'app' / 'uploaders', '*.rb')
107
+ Dir.glob(File.join(Merb.load_paths[:uploaders])).each {|f| require f }
108
+ end
109
+
65
110
  orm_path = File.dirname(__FILE__) / 'carrierwave' / 'orm' / Merb.orm
66
111
  require orm_path if File.exist?(orm_path + '.rb')
67
112
 
68
- Merb.push_path(:uploader, Merb.root / "app" / "uploaders")
69
-
70
113
  Merb.add_generators File.dirname(__FILE__) / 'generators' / 'uploader_generator'
71
114
 
72
115
  elsif defined?(Rails)
73
-
116
+ begin
117
+ CarrierWave.logger = Rails.logger
118
+ rescue
119
+ # Rails < 2.1
120
+ CarrierWave.logger = RAILS_DEFAULT_LOGGER
121
+ end
74
122
  CarrierWave.config[:root] = Rails.root
75
123
  CarrierWave.config[:public] = File.join(Rails.root, 'public')
76
124
 
@@ -0,0 +1,91 @@
1
+ # This file contains code taken from Paperclip
2
+ #
3
+ # LICENSE
4
+ #
5
+ # The MIT License
6
+ #
7
+ # Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ # of this software and associated documentation files (the "Software"), to deal
11
+ # in the Software without restriction, including without limitation the rights
12
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # copies of the Software, and to permit persons to whom the Software is
14
+ # furnished to do so, subject to the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included in
17
+ # all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ # THE SOFTWARE.
26
+
27
+ module CarrierWave
28
+ module Compatibility
29
+
30
+ ##
31
+ # Mix this module into an Uploader to make it mimic Paperclip's storage paths
32
+ # This will make your Uploader use the same default storage path as paperclip
33
+ # does. If you need to override it, you can override the +paperclip_path+ method
34
+ # and provide a Paperclip style path:
35
+ #
36
+ # class MyUploader < CarrierWave::Uploader::Base
37
+ # include CarrierWave::Compatibility::Paperclip
38
+ #
39
+ # def paperclip_path
40
+ # ":rails_root/public/uploads/:id/:attachment/:style_:basename.:extension"
41
+ # end
42
+ # end
43
+ #
44
+ module Paperclip
45
+
46
+ def store_path(for_file=filename)
47
+ path = paperclip_path
48
+ path ||= File.join(*[store_dir, paperclip_style.to_s, for_file].compact)
49
+ interpolate_paperclip_path(path, for_file)
50
+ end
51
+
52
+ def store_dir
53
+ ":rails_root/public/system/:attachment/:id"
54
+ end
55
+
56
+ def paperclip_default_style
57
+ :original
58
+ end
59
+
60
+ def paperclip_path
61
+ end
62
+
63
+ def paperclip_style
64
+ version_name || paperclip_default_style
65
+ end
66
+
67
+ private
68
+
69
+ def interpolate_paperclip_path(path, filename)
70
+ mappings.inject(path) do |agg, pair|
71
+ agg.gsub(":#{pair[0]}", pair[1].call(self, filename).to_s)
72
+ end
73
+ end
74
+
75
+ def mappings
76
+ {
77
+ :rails_root => lambda{|u, f| CarrierWave.config[:root] },
78
+ :rails_env => lambda{|u, f| CarrierWave.config[:env] },
79
+ :class => lambda{|u, f| u.model.class.name.underscore.pluralize},
80
+ :id => lambda{|u, f| u.model.id },
81
+ :id_partition => lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")},
82
+ :attachment => lambda{|u, f| u.mounted_as.to_s.downcase.pluralize },
83
+ :style => lambda{|u, f| u.paperclip_style },
84
+ :basename => lambda{|u, f| f.gsub(/#{File.extname(f)}$/, "") },
85
+ :extension => lambda{|u, f| File.extname(f).gsub(/^\.+/, "")}
86
+ }
87
+ end
88
+
89
+ end # Paperclip
90
+ end # Compatibility
91
+ end # CarrierWave
@@ -0,0 +1,102 @@
1
+ # Stolen from Rails 3
2
+
3
+ # Copyright (c) 2005-2009 David Heinemeier Hansson
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ # Retain for backward compatibility. Methods are now included in Class.
25
+ class Class
26
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
27
+ # each subclass has a copy of parent's attribute.
28
+ #
29
+ # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
30
+ # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
31
+ #
32
+ # @api public
33
+ #
34
+ # @todo Do we want to block instance_reader via :instance_reader => false
35
+ # @todo It would be preferable that we do something with a Hash passed in
36
+ # (error out or do the same as other methods above) instead of silently
37
+ # moving on). In particular, this makes the return value of this function
38
+ # less useful.
39
+ def extlib_inheritable_reader(*ivars)
40
+ instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
41
+
42
+ ivars.each do |ivar|
43
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
44
+ def self.#{ivar}
45
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
46
+ ivar = superclass.#{ivar}
47
+ return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
48
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
49
+ end
50
+ RUBY
51
+ unless instance_reader == false
52
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
53
+ def #{ivar}
54
+ self.class.#{ivar}
55
+ end
56
+ RUBY
57
+ end
58
+ end
59
+ end
60
+
61
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
62
+ # each subclass has a copy of parent's attribute.
63
+ #
64
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
65
+ # define inheritable writer for.
66
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
67
+ # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
68
+ #
69
+ # @api public
70
+ #
71
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
72
+ # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
73
+ def extlib_inheritable_writer(*ivars)
74
+ instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
75
+ ivars.each do |ivar|
76
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
77
+ def self.#{ivar}=(obj)
78
+ @#{ivar} = obj
79
+ end
80
+ RUBY
81
+ unless instance_writer == false
82
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
83
+ def #{ivar}=(obj) self.class.#{ivar} = obj end
84
+ RUBY
85
+ end
86
+ end
87
+ end
88
+
89
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
90
+ # each subclass has a copy of parent's attribute.
91
+ #
92
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
93
+ # define inheritable accessor for.
94
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
95
+ # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
96
+ #
97
+ # @api public
98
+ def extlib_inheritable_accessor(*syms)
99
+ extlib_inheritable_reader(*syms)
100
+ extlib_inheritable_writer(*syms)
101
+ end
102
+ end
@@ -0,0 +1,49 @@
1
+ # Stolen from Rails 3
2
+
3
+ # Copyright (c) 2005-2009 David Heinemeier Hansson
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ class Module
25
+ attr_accessor :_setup_block
26
+ attr_accessor :_dependencies
27
+
28
+ def setup(&blk)
29
+ @_setup_block = blk
30
+ end
31
+
32
+ def use(mod)
33
+ return if self < mod
34
+
35
+ (mod._dependencies || []).each do |dep|
36
+ use dep
37
+ end
38
+ # raise "Circular dependencies" if self < mod
39
+ include mod
40
+ extend mod.const_get("ClassMethods") if mod.const_defined?("ClassMethods")
41
+ class_eval(&mod._setup_block) if mod._setup_block
42
+ end
43
+
44
+ def depends_on(mod)
45
+ return if self < mod
46
+ @_dependencies ||= []
47
+ @_dependencies << mod
48
+ end
49
+ end