upload_cache 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/upload_cache.rb +152 -60
- data/upload_cache.gemspec +28 -0
- metadata +29 -52
data/lib/upload_cache.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
require 'uuidtools'
|
2
1
|
require 'fileutils'
|
3
2
|
require 'cgi'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
require 'map'
|
4
6
|
|
5
7
|
class UploadCache
|
6
|
-
Version = '1.
|
8
|
+
Version = '1.2.0'
|
7
9
|
|
8
|
-
|
10
|
+
Readme = <<-__
|
9
11
|
NAME
|
10
12
|
upload_cache.rb
|
11
13
|
|
@@ -49,6 +51,9 @@ class UploadCache
|
|
49
51
|
|
50
52
|
UploadCache.clear! ### nuke old files once per day
|
51
53
|
|
54
|
+
upload_caches ***does this automatically*** at_exit{}, but you can still
|
55
|
+
run it manually if you like.
|
56
|
+
|
52
57
|
__
|
53
58
|
|
54
59
|
class << UploadCache
|
@@ -56,25 +61,36 @@ class UploadCache
|
|
56
61
|
UploadCache::Version
|
57
62
|
end
|
58
63
|
|
59
|
-
def
|
60
|
-
@
|
64
|
+
def url
|
65
|
+
@url ||= "file:/#{ root }"
|
61
66
|
end
|
62
67
|
|
63
|
-
def
|
64
|
-
@
|
68
|
+
def url=(url)
|
69
|
+
@url = '/' + Array(url).join('/').squeeze('/').sub(%r|^/+|, '').sub(%r|/+$|, '')
|
65
70
|
end
|
66
71
|
|
67
|
-
def
|
68
|
-
|
72
|
+
def root
|
73
|
+
@root ||= Dir.tmpdir
|
69
74
|
end
|
70
75
|
|
71
|
-
def root
|
72
|
-
@root
|
76
|
+
def root=(root)
|
77
|
+
@root = File.expand_path(root)
|
73
78
|
end
|
74
79
|
|
75
|
-
|
76
|
-
|
80
|
+
{
|
81
|
+
'ffi-uuid' => proc{|*args| FFI::UUID.generate_time.to_s},
|
82
|
+
'uuid' => proc{|*args| UUID.generate.to_s},
|
83
|
+
'uuidtools' => proc{|*args| UUIDTools::UUID.timestamp_create.to_s}
|
84
|
+
}.each do |lib, implementation|
|
85
|
+
begin
|
86
|
+
require(lib)
|
87
|
+
define_method(:uuid, &implementation)
|
88
|
+
break
|
89
|
+
rescue LoadError
|
90
|
+
nil
|
91
|
+
end
|
77
92
|
end
|
93
|
+
abort 'no suitable uuid generation library detected' unless method_defined?(:uuid)
|
78
94
|
|
79
95
|
def tmpdir(&block)
|
80
96
|
tmpdir = File.join(root, uuid)
|
@@ -93,35 +109,9 @@ class UploadCache
|
|
93
109
|
end
|
94
110
|
|
95
111
|
def cache_key_for(key)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
def for(params, key = :upload)
|
100
|
-
upload = params[key]
|
101
|
-
if upload.respond_to?(:read)
|
102
|
-
tmpdir do |tmp|
|
103
|
-
original_basename = upload.respond_to?(:original_path) ? upload.original_path : upload.original_filename
|
104
|
-
basename = cleanname(original_basename)
|
105
|
-
|
106
|
-
path = File.join(tmp, basename)
|
107
|
-
open(path, 'w'){|fd| fd.write(upload.read)}
|
108
|
-
upload_cache = new(key, path)
|
109
|
-
params[key] = upload_cache.io
|
110
|
-
return upload_cache
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
cache_key = cache_key_for(key)
|
115
|
-
upload_cache = params[cache_key]
|
116
|
-
if upload_cache
|
117
|
-
dirname, basename = File.split(upload_cache)
|
118
|
-
path = root + '/' + File.join(File.basename(dirname), basename)
|
119
|
-
upload_cache = new(key, path)
|
120
|
-
params[key] = upload_cache.io
|
121
|
-
return upload_cache
|
112
|
+
key.clone.tap do |cache_key|
|
113
|
+
cache_key[-1] = "#{ cache_key[-1] }_upload_cache"
|
122
114
|
end
|
123
|
-
|
124
|
-
return new(key, path=nil)
|
125
115
|
end
|
126
116
|
|
127
117
|
def finalizer(object_id)
|
@@ -135,6 +125,8 @@ class UploadCache
|
|
135
125
|
Age = 60 * 60 * 24
|
136
126
|
|
137
127
|
def clear!(options = {})
|
128
|
+
return if UploadCache.turd?
|
129
|
+
|
138
130
|
glob = File.join(root, '*')
|
139
131
|
age = Integer(options[:age] || options['age'] || Age)
|
140
132
|
since = options[:since] || options['since'] || Time.now
|
@@ -163,47 +155,136 @@ class UploadCache
|
|
163
155
|
end
|
164
156
|
end
|
165
157
|
end
|
158
|
+
|
159
|
+
at_exit{ UploadCache.clear! }
|
160
|
+
|
161
|
+
def turd?
|
162
|
+
@turd ||= !!ENV['UPLOAD_CACHE_TURD']
|
163
|
+
end
|
164
|
+
|
165
|
+
def name_for(key, &block)
|
166
|
+
if block
|
167
|
+
@name_for = block
|
168
|
+
else
|
169
|
+
defined?(@name_for) ? @name_for[key] : [prefix, *Array(key)].compact.join('.')
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def prefix(*value)
|
174
|
+
@prefix = value.shift if value
|
175
|
+
@prefix
|
176
|
+
end
|
177
|
+
|
178
|
+
def prefix=(value)
|
179
|
+
@prefix = value
|
180
|
+
end
|
181
|
+
|
182
|
+
def default
|
183
|
+
@default ||= Map[:url, nil, :path, nil]
|
184
|
+
end
|
185
|
+
|
186
|
+
def for(params, *args)
|
187
|
+
params = Map.for(params)
|
188
|
+
options = Map.options_for!(args)
|
189
|
+
|
190
|
+
key = Array(options[:key] || args).flatten.compact
|
191
|
+
key = [:upload] if key.empty?
|
192
|
+
|
193
|
+
upload = params.get(key)
|
194
|
+
|
195
|
+
if upload.respond_to?(:read)
|
196
|
+
tmpdir do |tmp|
|
197
|
+
original_basename =
|
198
|
+
[:path, :filename, :original_path, :original_filename].
|
199
|
+
map{|msg| upload.send(msg) if upload.respond_to?(msg)}.compact.first
|
200
|
+
basename = cleanname(original_basename)
|
201
|
+
|
202
|
+
path = File.join(tmp, basename)
|
203
|
+
open(path, 'wb'){|fd| fd.write(upload.read)}
|
204
|
+
upload_cache = UploadCache.new(key, path, options)
|
205
|
+
params.set(key, upload_cache.io)
|
206
|
+
return upload_cache
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
cache_key = cache_key_for(key)
|
211
|
+
upload_cache = params.get(cache_key)
|
212
|
+
|
213
|
+
if upload_cache
|
214
|
+
dirname, basename = File.split(upload_cache)
|
215
|
+
relative_dirname = File.expand_path(File.dirname(dirname))
|
216
|
+
relative_basename = File.join(relative_dirname, basename)
|
217
|
+
path = root + '/' + relative_basename
|
218
|
+
upload_cache = UploadCache.new(key, path, options)
|
219
|
+
params.set(key, upload_cache.io)
|
220
|
+
return upload_cache
|
221
|
+
end
|
222
|
+
|
223
|
+
upload_cache = UploadCache.new(key, options)
|
224
|
+
params.set(key, upload_cache.io) if upload_cache.io
|
225
|
+
return upload_cache
|
226
|
+
end
|
166
227
|
end
|
167
228
|
|
168
229
|
attr_accessor :key
|
169
230
|
attr_accessor :cache_key
|
231
|
+
attr_accessor :name
|
170
232
|
attr_accessor :path
|
171
233
|
attr_accessor :dirname
|
172
234
|
attr_accessor :basename
|
173
235
|
attr_accessor :value
|
174
236
|
attr_accessor :io
|
237
|
+
attr_accessor :default_url
|
238
|
+
attr_accessor :default_path
|
175
239
|
|
176
240
|
IOs = {}
|
177
241
|
|
178
|
-
def initialize(key,
|
179
|
-
|
180
|
-
|
242
|
+
def initialize(key, *args)
|
243
|
+
options = Map.options_for!(args)
|
244
|
+
|
245
|
+
@key = key
|
246
|
+
@cache_key = UploadCache.cache_key_for(@key)
|
247
|
+
@name = UploadCache.name_for(@cache_key)
|
248
|
+
|
249
|
+
path = args.shift || options[:path]
|
250
|
+
|
251
|
+
default = Map.for(options[:default])
|
252
|
+
|
253
|
+
@default_url = default[:url] || options[:default_url] || UploadCache.default.url
|
254
|
+
@default_path = default[:path] || options[:default_path] || UploadCache.default.path
|
181
255
|
|
182
256
|
if path
|
183
257
|
@path = path
|
184
258
|
@dirname, @basename = File.split(@path)
|
185
259
|
@value = File.join(File.basename(@dirname), @basename).strip
|
186
|
-
@io = open(@path)
|
187
|
-
IOs[object_id] = @io.fileno
|
188
|
-
ObjectSpace.define_finalizer(self, UploadCache.method(:finalizer).to_proc)
|
189
260
|
else
|
190
261
|
@path = nil
|
191
262
|
@value = nil
|
192
263
|
end
|
264
|
+
|
265
|
+
if @path or @default_path
|
266
|
+
@io = open(@path || @default_path, 'rb')
|
267
|
+
IOs[object_id] = @io.fileno
|
268
|
+
ObjectSpace.define_finalizer(self, UploadCache.method(:finalizer).to_proc)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def url
|
273
|
+
if @value
|
274
|
+
File.join(UploadCache.url, @value)
|
275
|
+
else
|
276
|
+
@default_url ? @default_url : nil
|
277
|
+
end
|
193
278
|
end
|
194
279
|
|
195
280
|
def hidden
|
196
|
-
raw("<input type='hidden' name='#{ @
|
281
|
+
raw("<input type='hidden' name='#{ @name }' value='#{ @value }' class='upload_cache' />") if @value
|
197
282
|
end
|
198
283
|
|
199
284
|
def to_s
|
200
285
|
hidden.to_s
|
201
286
|
end
|
202
287
|
|
203
|
-
def url
|
204
|
-
File.join(UploadCache.url, @value) if @value
|
205
|
-
end
|
206
|
-
|
207
288
|
module HtmlSafe
|
208
289
|
def html_safe() self end
|
209
290
|
def html_safe?() self end
|
@@ -218,23 +299,34 @@ class UploadCache
|
|
218
299
|
end
|
219
300
|
|
220
301
|
def clear!
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
302
|
+
return if UploadCache.turd?
|
303
|
+
|
304
|
+
begin
|
305
|
+
FileUtils.rm_rf(@dirname) if test(?d, @dirname)
|
306
|
+
rescue
|
307
|
+
nil
|
308
|
+
ensure
|
309
|
+
@io.close rescue nil
|
310
|
+
IOs.delete(object_id)
|
311
|
+
Thread.new{ UploadCache.clear! }
|
312
|
+
end
|
228
313
|
end
|
229
314
|
end
|
230
315
|
|
231
316
|
Upload_cache = UploadCache unless defined?(Upload_cache)
|
232
317
|
|
318
|
+
|
319
|
+
|
233
320
|
if defined?(Rails.env)
|
321
|
+
|
322
|
+
if defined?(Rails.root) and Rails.root
|
323
|
+
UploadCache.url = '/system/uploads/cache'
|
324
|
+
UploadCache.root = File.join(Rails.root, 'public', UploadCache.url)
|
325
|
+
end
|
326
|
+
|
234
327
|
unless Rails.env.production?
|
235
328
|
if defined?(unloadable)
|
236
329
|
unloadable(UploadCache)
|
237
|
-
unloadable(Upload_cache)
|
238
330
|
end
|
239
331
|
end
|
240
332
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
## upload_cache.gemspec
|
2
|
+
#
|
3
|
+
|
4
|
+
Gem::Specification::new do |spec|
|
5
|
+
spec.name = "upload_cache"
|
6
|
+
spec.version = "1.2.0"
|
7
|
+
spec.platform = Gem::Platform::RUBY
|
8
|
+
spec.summary = "upload_cache"
|
9
|
+
spec.description = "description: upload_cache kicks the ass"
|
10
|
+
|
11
|
+
spec.files = ["lib", "lib/upload_cache.rb", "Rakefile", "README", "upload_cache.gemspec"]
|
12
|
+
spec.executables = []
|
13
|
+
|
14
|
+
spec.require_path = "lib"
|
15
|
+
|
16
|
+
spec.has_rdoc = true
|
17
|
+
spec.test_files = nil
|
18
|
+
|
19
|
+
# spec.add_dependency 'lib', '>= version'
|
20
|
+
spec.add_dependency 'uuidtools'
|
21
|
+
|
22
|
+
spec.extensions.push(*[])
|
23
|
+
|
24
|
+
spec.rubyforge_project = "codeforpeople"
|
25
|
+
spec.author = "Ara T. Howard"
|
26
|
+
spec.email = "ara.t.howard@gmail.com"
|
27
|
+
spec.homepage = "http://github.com/ahoward/upload_cache"
|
28
|
+
end
|
metadata
CHANGED
@@ -1,82 +1,59 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: upload_cache
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 0
|
10
|
-
version: 1.0.0
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Ara T. Howard
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-12-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: uuidtools
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70226716783500 !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 0
|
32
|
-
version: "0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
33
22
|
type: :runtime
|
34
|
-
|
35
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70226716783500
|
25
|
+
description: ! 'description: upload_cache kicks the ass'
|
36
26
|
email: ara.t.howard@gmail.com
|
37
27
|
executables: []
|
38
|
-
|
39
28
|
extensions: []
|
40
|
-
|
41
29
|
extra_rdoc_files: []
|
42
|
-
|
43
|
-
files:
|
30
|
+
files:
|
44
31
|
- lib/upload_cache.rb
|
45
32
|
- Rakefile
|
46
33
|
- README
|
47
|
-
|
34
|
+
- upload_cache.gemspec
|
48
35
|
homepage: http://github.com/ahoward/upload_cache
|
49
36
|
licenses: []
|
50
|
-
|
51
37
|
post_install_message:
|
52
38
|
rdoc_options: []
|
53
|
-
|
54
|
-
require_paths:
|
39
|
+
require_paths:
|
55
40
|
- lib
|
56
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
42
|
none: false
|
58
|
-
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
|
63
|
-
- 0
|
64
|
-
version: "0"
|
65
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
48
|
none: false
|
67
|
-
requirements:
|
68
|
-
- -
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
|
71
|
-
segments:
|
72
|
-
- 0
|
73
|
-
version: "0"
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
74
53
|
requirements: []
|
75
|
-
|
76
54
|
rubyforge_project: codeforpeople
|
77
|
-
rubygems_version: 1.
|
55
|
+
rubygems_version: 1.8.11
|
78
56
|
signing_key:
|
79
57
|
specification_version: 3
|
80
58
|
summary: upload_cache
|
81
59
|
test_files: []
|
82
|
-
|