dragonfly 0.9.8 → 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dragonfly might be problematic. Click here for more details.
- data/Gemfile +1 -1
- data/History.md +32 -0
- data/README.md +54 -32
- data/VERSION +1 -1
- data/dragonfly.gemspec +23 -21
- data/extra_docs/Configuration.md +0 -8
- data/extra_docs/DataStorage.md +13 -5
- data/extra_docs/ExampleUseCases.md +4 -1
- data/extra_docs/Heroku.md +14 -6
- data/extra_docs/Models.md +5 -1
- data/extra_docs/Rails3.md +1 -1
- data/extra_docs/URLs.md +8 -1
- data/lib/dragonfly.rb +7 -8
- data/lib/dragonfly/active_model_extensions/attachment.rb +37 -17
- data/lib/dragonfly/active_model_extensions/attachment_class_methods.rb +1 -1
- data/lib/dragonfly/active_model_extensions/validations.rb +53 -26
- data/lib/dragonfly/analyser.rb +1 -1
- data/lib/dragonfly/app.rb +1 -1
- data/lib/dragonfly/config/heroku.rb +7 -0
- data/lib/dragonfly/configurable.rb +19 -20
- data/lib/dragonfly/data_storage/couch_data_store.rb +2 -3
- data/lib/dragonfly/data_storage/file_data_store.rb +2 -9
- data/lib/dragonfly/data_storage/mongo_data_store.rb +1 -1
- data/lib/dragonfly/data_storage/s3data_store.rb +17 -10
- data/lib/dragonfly/function_manager.rb +4 -8
- data/lib/dragonfly/has_filename.rb +24 -0
- data/lib/dragonfly/image_magick/analyser.rb +1 -1
- data/lib/dragonfly/image_magick/generator.rb +1 -1
- data/lib/dragonfly/image_magick/processor.rb +5 -0
- data/lib/dragonfly/image_magick/utils.rb +1 -2
- data/lib/dragonfly/job.rb +52 -71
- data/lib/dragonfly/railtie.rb +1 -1
- data/lib/dragonfly/temp_object.rb +32 -14
- data/lib/dragonfly/url_attributes.rb +30 -0
- data/lib/dragonfly/url_mapper.rb +2 -2
- data/samples/DSC02119.JPG +0 -0
- data/samples/a.jp2 +0 -0
- data/samples/beach.jpg +0 -0
- data/spec/dragonfly/active_model_extensions/model_spec.rb +63 -40
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +4 -0
- data/spec/dragonfly/app_spec.rb +11 -3
- data/spec/dragonfly/configurable_spec.rb +38 -20
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +24 -36
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +21 -5
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +2 -2
- data/spec/dragonfly/has_filename_spec.rb +88 -0
- data/spec/dragonfly/image_magick/analyser_spec.rb +10 -0
- data/spec/dragonfly/image_magick/processor_spec.rb +11 -0
- data/spec/dragonfly/job_spec.rb +173 -167
- data/spec/dragonfly/temp_object_spec.rb +82 -10
- data/spec/dragonfly/url_attributes.rb +47 -0
- data/spec/dragonfly/url_mapper_spec.rb +9 -1
- data/spec/functional/model_urls_spec.rb +36 -1
- metadata +179 -250
- data/lib/dragonfly/core_ext/string.rb +0 -9
- data/lib/dragonfly/core_ext/symbol.rb +0 -9
- data/spec/dragonfly/core_ext/string_spec.rb +0 -17
- data/spec/dragonfly/core_ext/symbol_spec.rb +0 -17
@@ -34,7 +34,7 @@ module Dragonfly
|
|
34
34
|
content_type = opts[:content_type] || opts[:mime_type] || 'application/octet-stream'
|
35
35
|
temp_object.file do |f|
|
36
36
|
mongo_id = grid.put(f, :content_type => content_type,
|
37
|
-
:metadata => marshal_encode(
|
37
|
+
:metadata => marshal_encode(temp_object.meta))
|
38
38
|
mongo_id.to_s
|
39
39
|
end
|
40
40
|
end
|
@@ -11,15 +11,20 @@ module Dragonfly
|
|
11
11
|
configurable_attr :bucket_name
|
12
12
|
configurable_attr :access_key_id
|
13
13
|
configurable_attr :secret_access_key
|
14
|
-
configurable_attr :use_filesystem, true
|
15
14
|
configurable_attr :region
|
15
|
+
configurable_attr :use_filesystem, true
|
16
16
|
configurable_attr :storage_headers, {'x-amz-acl' => 'public-read'}
|
17
|
+
configurable_attr :url_scheme, 'http'
|
17
18
|
|
18
19
|
REGIONS = {
|
19
|
-
'us-east-1'
|
20
|
-
'
|
20
|
+
'us-east-1' => 's3.amazonaws.com', #default
|
21
|
+
'us-west-1' => 's3-us-west-1.amazonaws.com',
|
22
|
+
'us-west-2' => 's3-us-west-2.amazonaws.com',
|
23
|
+
'ap-northeast-1' => 's3-ap-northeast-1.amazonaws.com',
|
21
24
|
'ap-southeast-1' => 's3-ap-southeast-1.amazonaws.com',
|
22
|
-
'
|
25
|
+
'eu-west-1' => 's3-eu-west-1.amazonaws.com',
|
26
|
+
'sa-east-1' => 's3-sa-east-1.amazonaws.com',
|
27
|
+
'sa-east-1' => 's3-sa-east-1.amazonaws.com'
|
23
28
|
}
|
24
29
|
|
25
30
|
def initialize(opts={})
|
@@ -33,17 +38,18 @@ module Dragonfly
|
|
33
38
|
ensure_configured
|
34
39
|
ensure_bucket_initialized
|
35
40
|
|
36
|
-
meta = opts[:meta] || {}
|
37
41
|
headers = opts[:headers] || {}
|
38
|
-
|
42
|
+
mime_type = opts[:mime_type] || opts[:content_type]
|
43
|
+
headers['Content-Type'] = mime_type if mime_type
|
44
|
+
uid = opts[:path] || generate_uid(temp_object.name || 'file')
|
39
45
|
|
40
46
|
rescuing_socket_errors do
|
41
47
|
if use_filesystem
|
42
48
|
temp_object.file do |f|
|
43
|
-
storage.put_object(bucket_name, uid, f, full_storage_headers(headers, meta))
|
49
|
+
storage.put_object(bucket_name, uid, f, full_storage_headers(headers, temp_object.meta))
|
44
50
|
end
|
45
51
|
else
|
46
|
-
storage.put_object(bucket_name, uid, temp_object.data, full_storage_headers(headers, meta))
|
52
|
+
storage.put_object(bucket_name, uid, temp_object.data, full_storage_headers(headers, temp_object.meta))
|
47
53
|
end
|
48
54
|
end
|
49
55
|
|
@@ -75,7 +81,8 @@ module Dragonfly
|
|
75
81
|
storage.get_object_url(bucket_name, uid, opts[:expires])
|
76
82
|
end
|
77
83
|
else
|
78
|
-
|
84
|
+
scheme = opts[:scheme] || url_scheme
|
85
|
+
"#{scheme}://#{bucket_name}.s3.amazonaws.com/#{uid}"
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
@@ -93,7 +100,7 @@ module Dragonfly
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def bucket_exists?
|
96
|
-
rescuing_socket_errors{ storage.
|
103
|
+
rescuing_socket_errors{ storage.get_bucket(bucket_name) }
|
97
104
|
true
|
98
105
|
rescue Excon::Errors::NotFound => e
|
99
106
|
false
|
@@ -26,7 +26,7 @@ module Dragonfly
|
|
26
26
|
obj.use_same_log_as(self) if obj.is_a?(Loggable)
|
27
27
|
obj.use_as_fallback_config(self) if obj.is_a?(Configurable)
|
28
28
|
methods_to_add(obj).each do |meth|
|
29
|
-
add meth
|
29
|
+
add meth, obj.method(meth)
|
30
30
|
end
|
31
31
|
objects << obj
|
32
32
|
obj
|
@@ -58,13 +58,9 @@ module Dragonfly
|
|
58
58
|
private
|
59
59
|
|
60
60
|
def methods_to_add(obj)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
[:configured_class.to_method_name] # Hacky - there must be a better way...
|
65
|
-
else
|
66
|
-
obj.public_methods(false)
|
67
|
-
end
|
61
|
+
methods = obj.public_methods(false).map{|m| m.to_sym }
|
62
|
+
methods -= obj.config_methods if obj.is_a?(Configurable)
|
63
|
+
methods
|
68
64
|
end
|
69
65
|
|
70
66
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Dragonfly
|
2
|
+
# Convenience methods for setting basename and extension
|
3
|
+
# Including class needs to define a 'name' accessor
|
4
|
+
# which is assumed to hold a filename-style string
|
5
|
+
module HasFilename
|
6
|
+
|
7
|
+
def basename
|
8
|
+
File.basename(name, '.*') if name
|
9
|
+
end
|
10
|
+
|
11
|
+
def basename=(basename)
|
12
|
+
self.name = [basename, ext].compact.join('.')
|
13
|
+
end
|
14
|
+
|
15
|
+
def ext
|
16
|
+
File.extname(name)[/\.(.*)/, 1] if name
|
17
|
+
end
|
18
|
+
|
19
|
+
def ext=(ext)
|
20
|
+
self.name = [(basename || 'file'), ext].join('.')
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -20,12 +20,17 @@ module Dragonfly
|
|
20
20
|
CROP_GEOMETRY = /^(\d+)x(\d+)([+-]\d+)?([+-]\d+)?(\w{1,2})?$/ # e.g. '30x30+10+10'
|
21
21
|
THUMB_GEOMETRY = Regexp.union RESIZE_GEOMETRY, CROPPED_RESIZE_GEOMETRY, CROP_GEOMETRY
|
22
22
|
|
23
|
+
include Configurable
|
23
24
|
include Utils
|
24
25
|
|
25
26
|
def resize(temp_object, geometry)
|
26
27
|
convert(temp_object, "-resize #{geometry}")
|
27
28
|
end
|
28
29
|
|
30
|
+
def auto_orient(temp_object)
|
31
|
+
convert(temp_object, "-auto-orient")
|
32
|
+
end
|
33
|
+
|
29
34
|
def crop(temp_object, opts={})
|
30
35
|
width = opts[:width]
|
31
36
|
height = opts[:height]
|
@@ -21,8 +21,7 @@ module Dragonfly
|
|
21
21
|
def identify(temp_object)
|
22
22
|
# example of details string:
|
23
23
|
# myimage.png PNG 200x100 200x100+0+0 8-bit DirectClass 31.2kb
|
24
|
-
format,
|
25
|
-
width, height = geometry.split('x')
|
24
|
+
format, width, height, depth = raw_identify(temp_object).scan(/([A-Z0-9]+) (\d+)x(\d+) .+ (\d+)-bit/)[0]
|
26
25
|
{
|
27
26
|
:format => format.downcase.to_sym,
|
28
27
|
:width => width.to_i,
|
data/lib/dragonfly/job.rb
CHANGED
@@ -10,17 +10,19 @@ module Dragonfly
|
|
10
10
|
# Exceptions
|
11
11
|
class AppDoesNotMatch < StandardError; end
|
12
12
|
class JobAlreadyApplied < StandardError; end
|
13
|
+
class NoContent < StandardError; end
|
13
14
|
class NothingToProcess < StandardError; end
|
14
15
|
class NothingToEncode < StandardError; end
|
15
|
-
class NothingToAnalyse < StandardError; end
|
16
16
|
class InvalidArray < StandardError; end
|
17
17
|
class NoSHAGiven < StandardError; end
|
18
18
|
class IncorrectSHA < StandardError; end
|
19
19
|
|
20
20
|
extend Forwardable
|
21
21
|
def_delegators :result,
|
22
|
-
:data, :file, :tempfile, :path, :to_file, :size, :each
|
23
|
-
|
22
|
+
:data, :file, :tempfile, :path, :to_file, :size, :each,
|
23
|
+
:meta, :meta=, :name, :name=, :basename, :basename=, :ext, :ext=
|
24
|
+
def_delegator :app,
|
25
|
+
:server
|
24
26
|
|
25
27
|
class Step
|
26
28
|
|
@@ -81,7 +83,7 @@ module Dragonfly
|
|
81
83
|
|
82
84
|
class Encode < Step
|
83
85
|
def init
|
84
|
-
job.
|
86
|
+
job.url_attrs[:format] = format
|
85
87
|
end
|
86
88
|
def format
|
87
89
|
args.first
|
@@ -92,8 +94,7 @@ module Dragonfly
|
|
92
94
|
def apply
|
93
95
|
raise NothingToEncode, "Can't encode because temp object has not been initialized. Need to fetch first?" unless job.temp_object
|
94
96
|
content, meta = job.app.encoder.encode(job.temp_object, format, *arguments)
|
95
|
-
job.update(content, meta)
|
96
|
-
job.meta[:format] = format
|
97
|
+
job.update(content, (meta || {}).merge(:format => format))
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
@@ -106,19 +107,22 @@ module Dragonfly
|
|
106
107
|
|
107
108
|
class FetchFile < Step
|
108
109
|
def init
|
109
|
-
job.name =
|
110
|
+
job.url_attrs[:name] = filename
|
110
111
|
end
|
111
112
|
def path
|
112
|
-
File.expand_path(args.first)
|
113
|
+
@path ||= File.expand_path(args.first)
|
114
|
+
end
|
115
|
+
def filename
|
116
|
+
@filename ||= File.basename(path)
|
113
117
|
end
|
114
118
|
def apply
|
115
|
-
job.
|
119
|
+
job.update(Pathname.new(path), :name => filename)
|
116
120
|
end
|
117
121
|
end
|
118
122
|
|
119
123
|
class FetchUrl < Step
|
120
124
|
def init
|
121
|
-
job.name =
|
125
|
+
job.url_attrs[:name] = filename
|
122
126
|
end
|
123
127
|
def url
|
124
128
|
@url ||= (args.first[%r<^\w+://>] ? args.first : "http://#{args.first}")
|
@@ -126,9 +130,12 @@ module Dragonfly
|
|
126
130
|
def path
|
127
131
|
@path ||= URI.parse(url).path
|
128
132
|
end
|
133
|
+
def filename
|
134
|
+
@filename ||= File.basename(path) if path[/[^\/]$/]
|
135
|
+
end
|
129
136
|
def apply
|
130
137
|
open(url) do |f|
|
131
|
-
job.
|
138
|
+
job.update(f.read, :name => filename)
|
132
139
|
end
|
133
140
|
end
|
134
141
|
end
|
@@ -183,7 +190,7 @@ module Dragonfly
|
|
183
190
|
|
184
191
|
def format
|
185
192
|
apply
|
186
|
-
|
193
|
+
meta[:format] || (ext.to_sym if ext && app.trust_file_extensions) || analyse(:format)
|
187
194
|
end
|
188
195
|
|
189
196
|
def mime_type
|
@@ -196,13 +203,13 @@ module Dragonfly
|
|
196
203
|
|
197
204
|
end
|
198
205
|
|
199
|
-
def initialize(app, content=nil, meta={})
|
206
|
+
def initialize(app, content=nil, meta={}, url_attrs={})
|
200
207
|
@app = app
|
201
208
|
@steps = []
|
202
209
|
@next_step_index = 0
|
203
|
-
@meta = {}
|
204
210
|
@previous_temp_objects = []
|
205
|
-
update(content, meta)
|
211
|
+
update(content, meta) if content
|
212
|
+
self.url_attrs = url_attrs
|
206
213
|
end
|
207
214
|
|
208
215
|
# Used by 'dup' and 'clone'
|
@@ -237,9 +244,6 @@ module Dragonfly
|
|
237
244
|
end
|
238
245
|
|
239
246
|
def analyse(method, *args)
|
240
|
-
unless result
|
241
|
-
raise NothingToAnalyse, "Can't analyse because temp object has not been initialized. Need to fetch first?"
|
242
|
-
end
|
243
247
|
analyser.analyse(result, method, *args)
|
244
248
|
end
|
245
249
|
|
@@ -255,11 +259,6 @@ module Dragonfly
|
|
255
259
|
next_step_index == steps.length
|
256
260
|
end
|
257
261
|
|
258
|
-
def result
|
259
|
-
apply
|
260
|
-
temp_object
|
261
|
-
end
|
262
|
-
|
263
262
|
def applied_steps
|
264
263
|
steps[0...next_step_index]
|
265
264
|
end
|
@@ -309,6 +308,12 @@ module Dragonfly
|
|
309
308
|
app.url_for(self, attributes_for_url.merge(opts)) unless steps.empty?
|
310
309
|
end
|
311
310
|
|
311
|
+
def url_attrs=(hash)
|
312
|
+
@url_attrs = UrlAttributes[hash]
|
313
|
+
end
|
314
|
+
|
315
|
+
attr_reader :url_attrs
|
316
|
+
|
312
317
|
def b64_data
|
313
318
|
"data:#{mime_type};base64,#{Base64.encode64(data)}"
|
314
319
|
end
|
@@ -324,7 +329,7 @@ module Dragonfly
|
|
324
329
|
end
|
325
330
|
|
326
331
|
def to_fetched_job(uid)
|
327
|
-
new_job = self.class.new(app, temp_object, meta)
|
332
|
+
new_job = self.class.new(app, temp_object, meta, url_attrs)
|
328
333
|
new_job.fetch!(uid)
|
329
334
|
new_job.next_step_index = 1
|
330
335
|
new_job
|
@@ -368,56 +373,20 @@ module Dragonfly
|
|
368
373
|
# Misc
|
369
374
|
|
370
375
|
def store(opts={})
|
371
|
-
|
376
|
+
temp_object = result
|
377
|
+
app.store(temp_object, opts_for_store.merge(opts).merge(:meta => temp_object.meta))
|
372
378
|
end
|
373
379
|
|
374
380
|
def inspect
|
375
381
|
to_s.sub(/>$/, " app=#{app}, steps=#{steps.inspect}, temp_object=#{temp_object.inspect}, steps applied:#{applied_steps.length}/#{steps.length} >")
|
376
382
|
end
|
377
|
-
|
378
|
-
# Name and stuff
|
379
|
-
|
380
|
-
attr_reader :meta
|
381
|
-
|
382
|
-
def meta=(hash)
|
383
|
-
raise ArgumentError, "meta must be a hash, you tried setting it as #{hash.inspect}" unless hash.is_a?(Hash)
|
384
|
-
@meta = hash
|
385
|
-
end
|
386
|
-
|
387
|
-
def name
|
388
|
-
meta[:name]
|
389
|
-
end
|
390
|
-
|
391
|
-
def name=(name)
|
392
|
-
meta[:name] = name
|
393
|
-
end
|
394
383
|
|
395
|
-
def
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
def ext
|
400
|
-
meta[:ext] || (File.extname(name)[/\.(.*)/, 1] if name)
|
401
|
-
end
|
402
|
-
|
403
|
-
def attributes_for_url
|
404
|
-
attrs = meta.reject{|k, v| !server.params_in_url.include?(k.to_s) }
|
405
|
-
attrs[:basename] ||= basename if server.params_in_url.include?('basename')
|
406
|
-
attrs[:ext] ||= ext if server.params_in_url.include?('ext')
|
407
|
-
attrs[:format] = (attrs[:format] || format_from_meta).to_s if server.params_in_url.include?('format')
|
408
|
-
attrs.delete_if{|k, v| v.blank? }
|
409
|
-
attrs
|
410
|
-
end
|
411
|
-
|
412
|
-
def update(content, meta)
|
413
|
-
if meta
|
414
|
-
meta.merge!(meta.delete(:meta)) if meta[:meta] # legacy data etc. may have nested meta hash - deprecate gracefully here
|
415
|
-
self.meta.merge!(meta)
|
416
|
-
end
|
417
|
-
if content
|
418
|
-
self.temp_object = TempObject.new(content)
|
419
|
-
self.name = temp_object.original_filename if name.nil? && temp_object.original_filename
|
384
|
+
def update(content, new_meta)
|
385
|
+
if new_meta
|
386
|
+
new_meta.merge!(new_meta.delete(:meta)) if new_meta[:meta] # legacy data etc. may have nested meta hash - deprecate gracefully here
|
420
387
|
end
|
388
|
+
old_meta = temp_object ? temp_object.meta : {}
|
389
|
+
self.temp_object = TempObject.new(content, old_meta.merge(new_meta || {}))
|
421
390
|
end
|
422
391
|
|
423
392
|
def close
|
@@ -432,15 +401,27 @@ module Dragonfly
|
|
432
401
|
|
433
402
|
private
|
434
403
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
404
|
+
def result
|
405
|
+
apply
|
406
|
+
temp_object || raise(NoContent, "Job has not been initialized with content. Need to fetch first?")
|
407
|
+
end
|
408
|
+
|
409
|
+
def attributes_for_url
|
410
|
+
attrs = url_attrs.slice(*server.params_in_url)
|
411
|
+
attrs[:format] = (attrs[:format] || (url_attrs.ext if app.trust_file_extensions)).to_s if server.params_in_url.include?('format')
|
412
|
+
attrs.delete_if{|k, v| v.blank? }
|
413
|
+
attrs
|
439
414
|
end
|
415
|
+
|
416
|
+
attr_reader :previous_temp_objects
|
440
417
|
|
441
418
|
def last_step_of_type(type)
|
442
419
|
steps.select{|s| s.is_a?(type) }.last
|
443
420
|
end
|
421
|
+
|
422
|
+
def opts_for_store
|
423
|
+
{:mime_type => mime_type}
|
424
|
+
end
|
444
425
|
|
445
426
|
end
|
446
427
|
end
|
data/lib/dragonfly/railtie.rb
CHANGED
@@ -4,7 +4,7 @@ require 'rails'
|
|
4
4
|
module Dragonfly
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
initializer "dragonfly.railtie.initializer" do |app|
|
7
|
-
app.middleware.
|
7
|
+
app.middleware.insert_before 'ActionDispatch::Cookies', Dragonfly::CookieMonster
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -32,20 +32,14 @@ module Dragonfly
|
|
32
32
|
#
|
33
33
|
class TempObject
|
34
34
|
|
35
|
+
include HasFilename
|
36
|
+
|
35
37
|
# Exceptions
|
36
38
|
class Closed < RuntimeError; end
|
37
39
|
|
38
|
-
# Class configuration
|
39
|
-
class << self
|
40
|
-
|
41
|
-
include Configurable
|
42
|
-
configurable_attr :block_size, 8192
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
40
|
# Instance Methods
|
47
41
|
|
48
|
-
def initialize(obj)
|
42
|
+
def initialize(obj, meta={})
|
49
43
|
if obj.is_a? TempObject
|
50
44
|
@data = obj.get_data
|
51
45
|
@tempfile = obj.get_tempfile
|
@@ -74,9 +68,22 @@ module Dragonfly
|
|
74
68
|
elsif @pathname
|
75
69
|
@pathname.basename.to_s
|
76
70
|
end
|
71
|
+
|
72
|
+
# Meta
|
73
|
+
@meta = meta
|
74
|
+
@meta[:name] ||= @original_filename if @original_filename
|
77
75
|
end
|
78
76
|
|
79
77
|
attr_reader :original_filename
|
78
|
+
attr_accessor :meta
|
79
|
+
|
80
|
+
def name
|
81
|
+
meta[:name]
|
82
|
+
end
|
83
|
+
|
84
|
+
def name=(name)
|
85
|
+
meta[:name] = name
|
86
|
+
end
|
80
87
|
|
81
88
|
def data
|
82
89
|
raise Closed, "can't read data as TempObject has been closed" if closed?
|
@@ -124,12 +131,14 @@ module Dragonfly
|
|
124
131
|
end
|
125
132
|
end
|
126
133
|
|
127
|
-
def to_file(path)
|
134
|
+
def to_file(path, opts={})
|
135
|
+
mode = opts[:mode] || 0644
|
136
|
+
prepare_path(path) unless opts[:mkdirs] == false
|
128
137
|
if @data
|
129
|
-
File.open(path, 'wb'){|f| f.write(@data) }
|
138
|
+
File.open(path, 'wb', mode){|f| f.write(@data) }
|
130
139
|
else
|
131
140
|
FileUtils.cp(self.path, path)
|
132
|
-
File.chmod(
|
141
|
+
File.chmod(mode, path)
|
133
142
|
end
|
134
143
|
File.new(path, 'rb')
|
135
144
|
end
|
@@ -159,6 +168,10 @@ module Dragonfly
|
|
159
168
|
to_s.sub(/>$/, " #{content_string} >")
|
160
169
|
end
|
161
170
|
|
171
|
+
def unique_id
|
172
|
+
@unique_id ||= "#{object_id}#{rand(1000000)}"
|
173
|
+
end
|
174
|
+
|
162
175
|
protected
|
163
176
|
|
164
177
|
# We don't use normal accessors here because #data etc. do more than just return the instance var
|
@@ -177,7 +190,7 @@ module Dragonfly
|
|
177
190
|
private
|
178
191
|
|
179
192
|
def block_size
|
180
|
-
|
193
|
+
8192
|
181
194
|
end
|
182
195
|
|
183
196
|
def copy_to_tempfile(path)
|
@@ -187,12 +200,17 @@ module Dragonfly
|
|
187
200
|
end
|
188
201
|
|
189
202
|
def new_tempfile(content=nil)
|
190
|
-
tempfile = Tempfile.new('dragonfly')
|
203
|
+
tempfile = ext ? Tempfile.new(['dragonfly', ".#{ext}"]) : Tempfile.new('dragonfly')
|
191
204
|
tempfile.binmode
|
192
205
|
tempfile.write(content) if content
|
193
206
|
tempfile.close
|
194
207
|
tempfile
|
195
208
|
end
|
196
209
|
|
210
|
+
def prepare_path(path)
|
211
|
+
dir = File.dirname(path)
|
212
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
213
|
+
end
|
214
|
+
|
197
215
|
end
|
198
216
|
end
|