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.
- data/README.rdoc +35 -20
- data/Rakefile +1 -1
- data/lib/carrierwave.rb +55 -7
- data/lib/carrierwave/compatibility/paperclip.rb +91 -0
- data/lib/carrierwave/core_ext/inheritable_attributes.rb +102 -0
- data/lib/carrierwave/core_ext/module_setup.rb +49 -0
- data/lib/carrierwave/mount.rb +119 -103
- data/lib/carrierwave/orm/activerecord.rb +6 -1
- data/lib/carrierwave/orm/sequel.rb +15 -2
- data/lib/carrierwave/processing/rmagick.rb +8 -7
- data/lib/carrierwave/storage/abstract.rb +16 -1
- data/lib/carrierwave/storage/file.rb +20 -1
- data/lib/carrierwave/uploader.rb +31 -593
- data/lib/carrierwave/uploader/cache.rb +114 -0
- data/lib/carrierwave/uploader/callbacks.rb +40 -0
- data/lib/carrierwave/uploader/default_path.rb +21 -0
- data/lib/carrierwave/uploader/extension_whitelist.rb +35 -0
- data/lib/carrierwave/uploader/mountable.rb +37 -0
- data/lib/carrierwave/uploader/paths.rb +25 -0
- data/lib/carrierwave/uploader/processing.rb +79 -0
- data/lib/carrierwave/uploader/proxy.rb +60 -0
- data/lib/carrierwave/uploader/remove.rb +21 -0
- data/lib/carrierwave/uploader/store.rb +154 -0
- data/lib/carrierwave/uploader/url.rb +22 -0
- data/lib/carrierwave/uploader/versions.rb +145 -0
- data/lib/generators/uploader_generator.rb +1 -1
- data/rails_generators/uploader/templates/uploader.rb +12 -8
- data/spec/compatibility/paperclip_spec.rb +41 -0
- data/spec/mount_spec.rb +88 -25
- data/spec/orm/activerecord_spec.rb +7 -9
- data/spec/orm/datamapper_spec.rb +7 -9
- data/spec/orm/sequel_spec.rb +47 -32
- data/spec/spec_helper.rb +13 -0
- data/spec/test.log +1717 -0
- data/spec/uploader/cache_spec.rb +194 -0
- data/spec/uploader/default_path_spec.rb +66 -0
- data/spec/uploader/extension_whitelist_spec.rb +42 -0
- data/spec/uploader/mountable_spec.rb +31 -0
- data/spec/uploader/paths_spec.rb +20 -0
- data/spec/uploader/processing_spec.rb +60 -0
- data/spec/uploader/proxy_spec.rb +52 -0
- data/spec/uploader/remove_spec.rb +65 -0
- data/spec/uploader/store_spec.rb +260 -0
- data/spec/uploader/url_spec.rb +85 -0
- data/spec/uploader/versions_spec.rb +275 -0
- metadata +30 -3
- 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
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
|