oahu-dragonfly 0.8.2
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.
- data/.rspec +1 -0
- data/.yardopts +24 -0
- data/Gemfile +30 -0
- data/History.md +323 -0
- data/LICENSE +20 -0
- data/README.md +88 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/config.ru +14 -0
- data/docs.watchr +1 -0
- data/dragonfly.gemspec +297 -0
- data/extra_docs/Analysers.md +66 -0
- data/extra_docs/Caching.md +23 -0
- data/extra_docs/Configuration.md +124 -0
- data/extra_docs/Couch.md +49 -0
- data/extra_docs/DataStorage.md +153 -0
- data/extra_docs/Encoding.md +67 -0
- data/extra_docs/GeneralUsage.md +121 -0
- data/extra_docs/Generators.md +60 -0
- data/extra_docs/Heroku.md +50 -0
- data/extra_docs/ImageMagick.md +125 -0
- data/extra_docs/Index.md +33 -0
- data/extra_docs/MimeTypes.md +40 -0
- data/extra_docs/Models.md +272 -0
- data/extra_docs/Mongo.md +45 -0
- data/extra_docs/Processing.md +77 -0
- data/extra_docs/Rack.md +52 -0
- data/extra_docs/Rails2.md +57 -0
- data/extra_docs/Rails3.md +62 -0
- data/extra_docs/Sinatra.md +25 -0
- data/extra_docs/URLs.md +169 -0
- data/features/images.feature +47 -0
- data/features/no_processing.feature +14 -0
- data/features/rails_3.0.5.feature +8 -0
- data/features/steps/common_steps.rb +8 -0
- data/features/steps/dragonfly_steps.rb +66 -0
- data/features/steps/rails_steps.rb +28 -0
- data/features/support/env.rb +13 -0
- data/features/support/setup.rb +32 -0
- data/fixtures/rails_3.0.5/files/app/models/album.rb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/new.html.erb +7 -0
- data/fixtures/rails_3.0.5/files/app/views/albums/show.html.erb +6 -0
- data/fixtures/rails_3.0.5/files/config/initializers/dragonfly.rb +4 -0
- data/fixtures/rails_3.0.5/files/features/manage_album_images.feature +38 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/helper_steps.rb +7 -0
- data/fixtures/rails_3.0.5/files/features/step_definitions/image_steps.rb +25 -0
- data/fixtures/rails_3.0.5/files/features/support/paths.rb +17 -0
- data/fixtures/rails_3.0.5/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.5/template.rb +20 -0
- data/irbrc.rb +18 -0
- data/lib/dragonfly.rb +55 -0
- data/lib/dragonfly/active_model_extensions.rb +13 -0
- data/lib/dragonfly/active_model_extensions/attachment.rb +250 -0
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +148 -0
- data/lib/dragonfly/active_model_extensions/class_methods.rb +95 -0
- data/lib/dragonfly/active_model_extensions/instance_methods.rb +28 -0
- data/lib/dragonfly/active_model_extensions/validations.rb +41 -0
- data/lib/dragonfly/analyser.rb +58 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +32 -0
- data/lib/dragonfly/analysis/image_magick_analyser.rb +6 -0
- data/lib/dragonfly/app.rb +172 -0
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/image_magick.rb +6 -0
- data/lib/dragonfly/config/rails.rb +20 -0
- data/lib/dragonfly/configurable.rb +207 -0
- data/lib/dragonfly/core_ext/array.rb +7 -0
- data/lib/dragonfly/core_ext/hash.rb +7 -0
- data/lib/dragonfly/core_ext/object.rb +12 -0
- data/lib/dragonfly/core_ext/string.rb +9 -0
- data/lib/dragonfly/core_ext/symbol.rb +9 -0
- data/lib/dragonfly/data_storage.rb +9 -0
- data/lib/dragonfly/data_storage/couch_data_store.rb +64 -0
- data/lib/dragonfly/data_storage/file_data_store.rb +141 -0
- data/lib/dragonfly/data_storage/mongo_data_store.rb +86 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +145 -0
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/image_magick_encoder.rb +6 -0
- data/lib/dragonfly/function_manager.rb +71 -0
- data/lib/dragonfly/generation/image_magick_generator.rb +6 -0
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/hash_with_css_style_keys.rb +21 -0
- data/lib/dragonfly/image_magick/analyser.rb +51 -0
- data/lib/dragonfly/image_magick/config.rb +41 -0
- data/lib/dragonfly/image_magick/encoder.rb +57 -0
- data/lib/dragonfly/image_magick/generator.rb +145 -0
- data/lib/dragonfly/image_magick/processor.rb +99 -0
- data/lib/dragonfly/image_magick/utils.rb +72 -0
- data/lib/dragonfly/image_magick_utils.rb +4 -0
- data/lib/dragonfly/job.rb +451 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +15 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +20 -0
- data/lib/dragonfly/processing/image_magick_processor.rb +6 -0
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/rails/images.rb +27 -0
- data/lib/dragonfly/response.rb +97 -0
- data/lib/dragonfly/routed_endpoint.rb +40 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/server.rb +113 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/temp_object.rb +175 -0
- data/lib/dragonfly/url_mapper.rb +78 -0
- data/samples/beach.png +0 -0
- data/samples/egg.png +0 -0
- data/samples/round.gif +0 -0
- data/samples/sample.docx +0 -0
- data/samples/taj.jpg +0 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +1426 -0
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +91 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +48 -0
- data/spec/dragonfly/app_spec.rb +135 -0
- data/spec/dragonfly/configurable_spec.rb +461 -0
- data/spec/dragonfly/core_ext/array_spec.rb +19 -0
- data/spec/dragonfly/core_ext/hash_spec.rb +19 -0
- data/spec/dragonfly/core_ext/string_spec.rb +17 -0
- data/spec/dragonfly/core_ext/symbol_spec.rb +17 -0
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +76 -0
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +296 -0
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +57 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +258 -0
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +77 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/hash_with_css_style_keys_spec.rb +24 -0
- data/spec/dragonfly/image_magick/analyser_spec.rb +64 -0
- data/spec/dragonfly/image_magick/encoder_spec.rb +41 -0
- data/spec/dragonfly/image_magick/generator_spec.rb +172 -0
- data/spec/dragonfly/image_magick/processor_spec.rb +233 -0
- data/spec/dragonfly/image_magick/utils_spec.rb +18 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +173 -0
- data/spec/dragonfly/job_spec.rb +1046 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +47 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/server_spec.rb +278 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/temp_object_spec.rb +306 -0
- data/spec/dragonfly/url_mapper_spec.rb +126 -0
- data/spec/functional/deprecations_spec.rb +51 -0
- data/spec/functional/image_magick_app_spec.rb +27 -0
- data/spec/functional/model_urls_spec.rb +85 -0
- data/spec/functional/remote_on_the_fly_spec.rb +51 -0
- data/spec/functional/to_response_spec.rb +31 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/argument_matchers.rb +19 -0
- data/spec/support/image_matchers.rb +47 -0
- data/spec/support/simple_matchers.rb +53 -0
- data/yard/handlers/configurable_attr_handler.rb +38 -0
- data/yard/setup.rb +15 -0
- data/yard/templates/default/fulldoc/html/css/common.css +107 -0
- data/yard/templates/default/layout/html/layout.erb +89 -0
- data/yard/templates/default/module/html/configuration_summary.erb +31 -0
- data/yard/templates/default/module/setup.rb +17 -0
- metadata +544 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'dragonfly/active_model_extensions/attachment_class_methods'
|
|
3
|
+
|
|
4
|
+
module Dragonfly
|
|
5
|
+
module ActiveModelExtensions
|
|
6
|
+
|
|
7
|
+
class Attachment
|
|
8
|
+
|
|
9
|
+
# Exceptions
|
|
10
|
+
class BadAssignmentKey < RuntimeError; end
|
|
11
|
+
|
|
12
|
+
extend Forwardable
|
|
13
|
+
def_delegators :job,
|
|
14
|
+
:data, :to_file, :file, :tempfile, :path,
|
|
15
|
+
:process, :encode, :analyse,
|
|
16
|
+
:meta, :meta=,
|
|
17
|
+
:name, :basename, :ext, :size,
|
|
18
|
+
:url
|
|
19
|
+
|
|
20
|
+
def initialize(model)
|
|
21
|
+
@model = model
|
|
22
|
+
self.uid = model_uid
|
|
23
|
+
update_from_uid if uid
|
|
24
|
+
@should_run_callbacks = true
|
|
25
|
+
self.class.ensure_uses_cached_magic_attributes
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def app
|
|
29
|
+
self.class.app
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def attribute
|
|
33
|
+
self.class.attribute
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def assign(value)
|
|
37
|
+
self.changed = true
|
|
38
|
+
destroy_retained! if retained?
|
|
39
|
+
set_uid_and_model_uid(nil)
|
|
40
|
+
if value.nil?
|
|
41
|
+
self.job = nil
|
|
42
|
+
reset_magic_attributes
|
|
43
|
+
self.class.run_callbacks(:after_unassign, model, self) if should_run_callbacks?
|
|
44
|
+
else
|
|
45
|
+
self.job = case value
|
|
46
|
+
when Job then value.dup
|
|
47
|
+
when self.class then value.job.dup
|
|
48
|
+
else app.new_job(value)
|
|
49
|
+
end
|
|
50
|
+
set_magic_attributes
|
|
51
|
+
update_meta
|
|
52
|
+
self.class.run_callbacks(:after_assign, model, self) if should_run_callbacks?
|
|
53
|
+
end
|
|
54
|
+
value
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def changed?
|
|
58
|
+
!!@changed
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def destroy!
|
|
62
|
+
destroy_previous!
|
|
63
|
+
destroy_content(uid) if uid
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def save!
|
|
67
|
+
sync_with_model
|
|
68
|
+
store_job! if job && !uid
|
|
69
|
+
destroy_previous!
|
|
70
|
+
self.changed = false
|
|
71
|
+
self.retained = false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_value
|
|
75
|
+
self if job
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def name=(name)
|
|
79
|
+
job.name = name
|
|
80
|
+
set_magic_attribute(:name, name) if has_magic_attribute_for?(:name)
|
|
81
|
+
name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def process!(*args)
|
|
85
|
+
assign(process(*args))
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def encode!(*args)
|
|
90
|
+
assign(encode(*args))
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def remote_url(opts={})
|
|
95
|
+
app.remote_url_for(uid, opts) if uid
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def apply
|
|
99
|
+
job.apply
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
attr_writer :should_run_callbacks
|
|
104
|
+
|
|
105
|
+
def should_run_callbacks?
|
|
106
|
+
@should_run_callbacks
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Retaining for avoiding uploading more than once
|
|
110
|
+
|
|
111
|
+
def retain!
|
|
112
|
+
if changed?
|
|
113
|
+
store_job!
|
|
114
|
+
self.retained = true
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def retained?
|
|
119
|
+
!!@retained
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def destroy_retained!
|
|
123
|
+
destroy_content(retained_attrs[:uid])
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def retained_attrs
|
|
127
|
+
attribute_keys.inject({}) do |hash, key|
|
|
128
|
+
hash[key] = send(key)
|
|
129
|
+
hash
|
|
130
|
+
end if retained?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def retained_attrs=(attrs)
|
|
134
|
+
if changed? # if already set, ignore and destroy this retained content
|
|
135
|
+
destroy_content(attrs[:uid])
|
|
136
|
+
else
|
|
137
|
+
attrs.each do |key, value|
|
|
138
|
+
unless attribute_keys.include?(key)
|
|
139
|
+
raise BadAssignmentKey, "trying to call #{attribute}_#{key} = #{value.inspect} via retained_#{attribute} but this is not allowed!"
|
|
140
|
+
end
|
|
141
|
+
model.send("#{attribute}_#{key}=", value)
|
|
142
|
+
end
|
|
143
|
+
sync_with_model
|
|
144
|
+
update_from_uid
|
|
145
|
+
self.retained = true
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def inspect
|
|
150
|
+
"<Dragonfly Attachment uid=#{uid.inspect}, app=#{app.inspect}>"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
protected
|
|
154
|
+
|
|
155
|
+
attr_reader :job
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
attr_writer :changed, :retained
|
|
160
|
+
|
|
161
|
+
def attribute_keys
|
|
162
|
+
[:uid] + magic_attributes
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def store_job!
|
|
166
|
+
opts = self.class.evaluate_storage_opts(model, self)
|
|
167
|
+
set_uid_and_model_uid job.store(opts)
|
|
168
|
+
self.job = job.to_fetched_job(uid)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def destroy_content(uid)
|
|
172
|
+
app.datastore.destroy(uid)
|
|
173
|
+
rescue DataStorage::DataNotFound => e
|
|
174
|
+
app.log.warn("*** WARNING ***: tried to destroy data with uid #{uid}, but got error: #{e}")
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def destroy_previous!
|
|
178
|
+
if previous_uid
|
|
179
|
+
destroy_content(previous_uid)
|
|
180
|
+
self.previous_uid = nil
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def sync_with_model
|
|
185
|
+
# If the model uid has been set manually
|
|
186
|
+
if uid != model_uid
|
|
187
|
+
self.uid = model_uid
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def set_uid_and_model_uid(uid)
|
|
192
|
+
self.uid = uid
|
|
193
|
+
self.model_uid = uid
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def model_uid=(uid)
|
|
197
|
+
model.send("#{attribute}_uid=", uid)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def model_uid
|
|
201
|
+
model.send("#{attribute}_uid")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
attr_reader :model, :uid
|
|
205
|
+
attr_writer :job
|
|
206
|
+
attr_accessor :previous_uid
|
|
207
|
+
|
|
208
|
+
def uid=(uid)
|
|
209
|
+
self.previous_uid = @uid if @uid
|
|
210
|
+
@uid = uid
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def update_meta
|
|
214
|
+
magic_attributes.each{|property| meta[property] = model.send("#{attribute}_#{property}") }
|
|
215
|
+
meta[:model_class] = model.class.name
|
|
216
|
+
meta[:model_attachment] = attribute
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def update_from_uid
|
|
220
|
+
self.job = app.fetch(uid)
|
|
221
|
+
update_meta
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def magic_attributes
|
|
225
|
+
self.class.magic_attributes
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def set_magic_attribute(property, value)
|
|
229
|
+
model.send("#{attribute}_#{property}=", value)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def set_magic_attributes
|
|
233
|
+
magic_attributes.each{|property| set_magic_attribute(property, job.send(property)) }
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def reset_magic_attributes
|
|
237
|
+
magic_attributes.each{|property| set_magic_attribute(property, nil) }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def has_magic_attribute_for?(property)
|
|
241
|
+
magic_attributes.include?(property.to_sym)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def magic_attribute_for(property)
|
|
245
|
+
model.send("#{attribute}_#{property}")
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module ActiveModelExtensions
|
|
3
|
+
class Attachment
|
|
4
|
+
class << self
|
|
5
|
+
|
|
6
|
+
class ConfigProxy
|
|
7
|
+
|
|
8
|
+
def initialize(spec, block)
|
|
9
|
+
@spec = spec
|
|
10
|
+
instance_eval(&block)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
attr_reader :spec
|
|
16
|
+
|
|
17
|
+
def after_assign(*callbacks, &block)
|
|
18
|
+
add_callbacks(:after_assign, *callbacks, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def after_unassign(*callbacks, &block)
|
|
22
|
+
add_callbacks(:after_unassign, *callbacks, &block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def copy_to(accessor, &block)
|
|
26
|
+
after_assign do |a|
|
|
27
|
+
self.send "#{accessor}=", (block_given? ? instance_exec(a, &block) : a)
|
|
28
|
+
end
|
|
29
|
+
after_unassign{|a| self.send("#{accessor}=", nil) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def retain
|
|
33
|
+
after_assign{|a| a.retain! }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def storage_opts(opts=nil, &block)
|
|
37
|
+
spec.storage_opts_specs << (opts || block)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def storage_opt(key, value, &block)
|
|
41
|
+
if value.is_a? Symbol
|
|
42
|
+
storage_opts{|a| {key => send(value)} }
|
|
43
|
+
elsif block_given?
|
|
44
|
+
storage_opts{|a| {key => instance_exec(a, &block)} }
|
|
45
|
+
else
|
|
46
|
+
storage_opts{|a| {key => value} }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def add_callbacks(name, *callbacks, &block)
|
|
51
|
+
if block_given?
|
|
52
|
+
spec.callbacks[name] << block
|
|
53
|
+
else
|
|
54
|
+
spec.callbacks[name].push(*callbacks)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def method_missing(meth, *args, &block)
|
|
59
|
+
if meth.to_s =~ /^storage_(.*)$/
|
|
60
|
+
storage_opt($1.to_sym, args.first, &block)
|
|
61
|
+
else
|
|
62
|
+
super
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def init(model_class, attribute, app, config_block)
|
|
69
|
+
@model_class, @attribute, @app, @config_block = model_class, attribute, app, config_block
|
|
70
|
+
include app.analyser.analysis_methods
|
|
71
|
+
include app.job_definitions
|
|
72
|
+
define_method :format do
|
|
73
|
+
job.format
|
|
74
|
+
end
|
|
75
|
+
define_method :mime_type do
|
|
76
|
+
job.mime_type
|
|
77
|
+
end
|
|
78
|
+
ConfigProxy.new(self, config_block) if config_block
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
attr_reader :model_class, :attribute, :app, :config_block
|
|
83
|
+
|
|
84
|
+
# Callbacks
|
|
85
|
+
def callbacks
|
|
86
|
+
@callbacks ||= Hash.new{|h,k| h[k] = [] }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def run_callbacks(name, model, attachment)
|
|
90
|
+
attachment.should_run_callbacks = false
|
|
91
|
+
callbacks[name].each do |callback|
|
|
92
|
+
case callback
|
|
93
|
+
when Symbol then model.send(callback)
|
|
94
|
+
when Proc then model.instance_exec(attachment, &callback)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
attachment.should_run_callbacks = true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Magic attributes
|
|
101
|
+
def allowed_magic_attributes
|
|
102
|
+
app.analyser.analysis_method_names + [:size, :basename, :name, :ext, :meta]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def magic_attributes
|
|
106
|
+
@magic_attributes ||= begin
|
|
107
|
+
prefix = attribute.to_s + '_'
|
|
108
|
+
model_class.public_instance_methods.inject([]) do |attrs, name|
|
|
109
|
+
_, __, suffix = name.to_s.partition(prefix)
|
|
110
|
+
if !suffix.empty? && allowed_magic_attributes.include?(suffix.to_sym)
|
|
111
|
+
attrs << suffix.to_sym
|
|
112
|
+
end
|
|
113
|
+
attrs
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def ensure_uses_cached_magic_attributes
|
|
119
|
+
return if @uses_cached_magic_attributes
|
|
120
|
+
magic_attributes.each do |attr|
|
|
121
|
+
define_method attr do
|
|
122
|
+
magic_attribute_for(attr)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
@uses_cached_magic_attributes = true
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Storage options
|
|
129
|
+
def storage_opts_specs
|
|
130
|
+
@storage_opts_specs ||= []
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def evaluate_storage_opts(model, attachment)
|
|
134
|
+
storage_opts_specs.inject({}) do |opts, spec|
|
|
135
|
+
options = case spec
|
|
136
|
+
when Proc then model.instance_exec(attachment, &spec)
|
|
137
|
+
when Symbol then model.send(spec)
|
|
138
|
+
else spec
|
|
139
|
+
end
|
|
140
|
+
opts.merge!(options)
|
|
141
|
+
opts
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Dragonfly
|
|
2
|
+
module ActiveModelExtensions
|
|
3
|
+
module ClassMethods
|
|
4
|
+
|
|
5
|
+
include Validations
|
|
6
|
+
|
|
7
|
+
def register_dragonfly_app(macro_name, app)
|
|
8
|
+
(class << self; self; end).class_eval do
|
|
9
|
+
|
|
10
|
+
# Defines e.g. 'image_accessor' for any activemodel class body
|
|
11
|
+
define_method macro_name do |attribute, &config_block|
|
|
12
|
+
|
|
13
|
+
# Add callbacks
|
|
14
|
+
before_save :save_dragonfly_attachments
|
|
15
|
+
before_destroy :destroy_dragonfly_attachments
|
|
16
|
+
|
|
17
|
+
# Register the new attribute
|
|
18
|
+
dragonfly_attachment_classes << new_dragonfly_attachment_class(attribute, app, config_block)
|
|
19
|
+
|
|
20
|
+
# Define the setter for the attribute
|
|
21
|
+
define_method "#{attribute}=" do |value|
|
|
22
|
+
dragonfly_attachments[attribute].assign(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Define the getter for the attribute
|
|
26
|
+
define_method attribute do
|
|
27
|
+
dragonfly_attachments[attribute].to_value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Define the URL setter
|
|
31
|
+
define_method "#{attribute}_url=" do |url|
|
|
32
|
+
unless url.blank?
|
|
33
|
+
dragonfly_attachments[attribute].assign(app.fetch_url(url))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Define the URL getter
|
|
38
|
+
define_method "#{attribute}_url" do
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Define the remove setter
|
|
43
|
+
define_method "remove_#{attribute}=" do |value|
|
|
44
|
+
unless [0, "0", false, "false", "", nil].include?(value)
|
|
45
|
+
dragonfly_attachments[attribute].assign(nil)
|
|
46
|
+
instance_variable_set("@remove_#{attribute}", true)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Define the remove getter
|
|
51
|
+
attr_reader "remove_#{attribute}"
|
|
52
|
+
|
|
53
|
+
# Define the retained setter
|
|
54
|
+
define_method "retained_#{attribute}=" do |string|
|
|
55
|
+
unless string.blank?
|
|
56
|
+
begin
|
|
57
|
+
dragonfly_attachments[attribute].retained_attrs = Serializer.marshal_decode(string)
|
|
58
|
+
rescue Serializer::BadString => e
|
|
59
|
+
app.log.warn("*** WARNING ***: couldn't update attachment with serialized retained_#{attribute} string #{string.inspect}")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Define the retained getter
|
|
65
|
+
define_method "retained_#{attribute}" do
|
|
66
|
+
attrs = dragonfly_attachments[attribute].retained_attrs
|
|
67
|
+
Serializer.marshal_encode(attrs) if attrs
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
app
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def dragonfly_attachment_classes
|
|
77
|
+
@dragonfly_attachment_classes ||= begin
|
|
78
|
+
parent_class = ancestors.select{|a| a.is_a?(Class) }[1]
|
|
79
|
+
if parent_class.respond_to?(:dragonfly_attachment_classes)
|
|
80
|
+
parent_class.dragonfly_attachment_classes.map do |klass|
|
|
81
|
+
new_dragonfly_attachment_class(klass.attribute, klass.app, klass.config_block)
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
[]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def new_dragonfly_attachment_class(attribute, app, config_block)
|
|
90
|
+
Class.new(Attachment).init(self, attribute, app, config_block)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|