rubysl-tempfile 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ef0738dac62e35b9f6360922f94efc28d20fd39
4
- data.tar.gz: fce5f3e54ef1085c072f867ae45bf51884d13061
3
+ metadata.gz: 0f82c47d38159bb53a71a207db4db87b6d0ace1d
4
+ data.tar.gz: 026e066a5774dbfb057f861cc78a9ae7717be308
5
5
  SHA512:
6
- metadata.gz: e1ad962fc20d677dcb0b0179803065ef8f7ec8042808549b80e6b8dc12fea148327f19ee919974a3addcbd305474ee9917d58164715190fce6ec39ad033c51c1
7
- data.tar.gz: 7b28bfb3515238570324440c5752d69d6b9def6feaa70847889e678b58bc88f0934853fa78a29f9ea665d70aa328f648a4a2dd5c458ca897b20a7ee40756db48
6
+ metadata.gz: daa1c9f4243df03b5f6266f0c451b6cba2fd1c499eab3e814575953a6c0124b3dbbe4d792c4c3e0ef11b852b41e88d24e8835ee7cb4c284027f573ee4f419b02
7
+ data.tar.gz: c6485ac719d85e2fd2ace909a61a52cccc0883752de27ab15e1ba53022745ced1d5d3388465a99366669ff4d255435577493226a7b49e7d050fb20a55e33b52e
@@ -3,5 +3,5 @@ env:
3
3
  - RUBYLIB=lib
4
4
  script: bundle exec mspec
5
5
  rvm:
6
- - 1.8.7
7
- - rbx-nightly-18mode
6
+ - 1.9.3
7
+ - rbx-nightly-19mode
@@ -1,94 +1,166 @@
1
1
  #
2
2
  # tempfile - manipulates temporary files
3
3
  #
4
- # $Id: tempfile.rb 16127 2008-04-21 09:43:44Z knu $
4
+ # $Id: tempfile.rb 31768 2011-05-28 23:31:24Z yugui $
5
5
  #
6
6
 
7
7
  require 'delegate'
8
8
  require 'tmpdir'
9
+ require 'thread'
9
10
 
10
- # A class for managing temporary files. This library is written to be
11
- # thread safe.
11
+ # A utility class for managing temporary files. When you create a Tempfile
12
+ # object, it will create a temporary file with a unique filename. A Tempfile
13
+ # objects behaves just like a File object, and you can perform all the usual
14
+ # file operations on it: reading data, writing data, changing its permissions,
15
+ # etc. So although this class does not explicitly document all instance methods
16
+ # supported by File, you can in fact call any File instance method on a
17
+ # Tempfile object.
18
+ #
19
+ # == Synopsis
20
+ #
21
+ # require 'tempfile'
22
+ #
23
+ # file = Tempfile.new('foo')
24
+ # file.path # => A unique filename in the OS's temp directory,
25
+ # # e.g.: "/tmp/foo.24722.0"
26
+ # # This filename contains 'foo' in its basename.
27
+ # file.write("hello world")
28
+ # file.rewind
29
+ # file.read # => "hello world"
30
+ # file.close
31
+ # file.unlink # deletes the temp file
32
+ #
33
+ # == Good practices
34
+ #
35
+ # === Explicit close
36
+ #
37
+ # When a Tempfile object is garbage collected, or when the Ruby interpreter
38
+ # exits, its associated temporary file is automatically deleted. This means
39
+ # that's it's unnecessary to explicitly delete a Tempfile after use, though
40
+ # it's good practice to do so: not explicitly deleting unused Tempfiles can
41
+ # potentially leave behind large amounts of tempfiles on the filesystem
42
+ # until they're garbage collected. The existance of these temp files can make
43
+ # it harder to determine a new Tempfile filename.
44
+ #
45
+ # Therefore, one should always call #unlink or close in an ensure block, like
46
+ # this:
47
+ #
48
+ # file = Tempfile.new('foo')
49
+ # begin
50
+ # ...do something with file...
51
+ # ensure
52
+ # file.close
53
+ # file.unlink # deletes the temp file
54
+ # end
55
+ #
56
+ # === Unlink after creation
57
+ #
58
+ # On POSIX systems, it's possible to unlink a file right after creating it,
59
+ # and before closing it. This removes the filesystem entry without closing
60
+ # the file handle, so it ensures that only the processes that already had
61
+ # the file handle open can access the file's contents. It's strongly
62
+ # recommended that you do this if you do not want any other processes to
63
+ # be able to read from or write to the Tempfile, and you do not need to
64
+ # know the Tempfile's filename either.
65
+ #
66
+ # For example, a practical use case for unlink-after-creation would be this:
67
+ # you need a large byte buffer that's too large to comfortably fit in RAM,
68
+ # e.g. when you're writing a web server and you want to buffer the client's
69
+ # file upload data.
70
+ #
71
+ # Please refer to #unlink for more information and a code example.
72
+ #
73
+ # == Minor notes
74
+ #
75
+ # Tempfile's filename picking method is both thread-safe and inter-process-safe:
76
+ # it guarantees that no other threads or processes will pick the same filename.
77
+ #
78
+ # Tempfile itself however may not be entirely thread-safe. If you access the
79
+ # same Tempfile object from multiple threads then you should protect it with a
80
+ # mutex.
12
81
  class Tempfile < DelegateClass(File)
13
- MAX_TRY = 10
14
- @@cleanlist = []
15
-
16
- # Creates a temporary file of mode 0600 in the temporary directory,
17
- # opens it with mode "w+", and returns a Tempfile object which
18
- # represents the created temporary file. A Tempfile object can be
19
- # treated just like a normal File object.
20
- #
21
- # The basename parameter is used to determine the name of a
22
- # temporary file. If an Array is given, the first element is used
23
- # as prefix string and the second as suffix string, respectively.
24
- # Otherwise it is treated as prefix string.
25
- #
26
- # If tmpdir is omitted, the temporary directory is determined by
27
- # Dir::tmpdir provided by 'tmpdir.rb'.
28
- # When $SAFE > 0 and the given tmpdir is tainted, it uses
29
- # /tmp. (Note that ENV values are tainted by default)
30
- def initialize(basename, tmpdir=Dir::tmpdir)
31
- if $SAFE > 0 and tmpdir.tainted?
32
- tmpdir = '/tmp'
33
- end
34
-
35
- lock = nil
36
- n = failure = 0
82
+ MAX_TRY = 10 # :nodoc:
83
+ include Dir::Tmpname
37
84
 
38
- begin
39
- Thread.critical = true
85
+ # call-seq:
86
+ # new(basename, [tmpdir = Dir.tmpdir], [options])
87
+ #
88
+ # Creates a temporary file with permissions 0600 (= only readable and
89
+ # writable by the owner) and opens it with mode "w+".
90
+ #
91
+ # The +basename+ parameter is used to determine the name of the
92
+ # temporary file. You can either pass a String or an Array with
93
+ # 2 String elements. In the former form, the temporary file's base
94
+ # name will begin with the given string. In the latter form,
95
+ # the temporary file's base name will begin with the array's first
96
+ # element, and end with the second element. For example:
97
+ #
98
+ # file = Tempfile.new('hello')
99
+ # file.path # => something like: "/tmp/hello2843-8392-92849382--0"
100
+ #
101
+ # # Use the Array form to enforce an extension in the filename:
102
+ # file = Tempfile.new(['hello', '.jpg'])
103
+ # file.path # => something like: "/tmp/hello2843-8392-92849382--0.jpg"
104
+ #
105
+ # The temporary file will be placed in the directory as specified
106
+ # by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
107
+ # When $SAFE > 0 and the given +tmpdir+ is tainted, it uses
108
+ # '/tmp' as the temporary directory. Please note that ENV values
109
+ # are tainted by default, and +Dir.tmpdir+'s return value might
110
+ # come from environment variables (e.g. <tt>$TMPDIR</tt>).
111
+ #
112
+ # file = Tempfile.new('hello', '/home/aisaka')
113
+ # file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
114
+ #
115
+ # You can also pass an options hash. Under the hood, Tempfile creates
116
+ # the temporary file using +File.open+. These options will be passed to
117
+ # +File.open+. This is mostly useful for specifying encoding
118
+ # options, e.g.:
119
+ #
120
+ # Tempfile.new('hello', '/home/aisaka', :encoding => 'ascii-8bit')
121
+ #
122
+ # # You can also omit the 'tmpdir' parameter:
123
+ # Tempfile.new('hello', :encoding => 'ascii-8bit')
124
+ #
125
+ # === Exceptions
126
+ #
127
+ # If Tempfile.new cannot find a unique filename within a limited
128
+ # number of tries, then it will raise an exception.
129
+ def initialize(basename, *rest)
130
+ @data = []
131
+ @clean_proc = Remover.new(@data)
132
+ ObjectSpace.define_finalizer(self, @clean_proc)
40
133
 
134
+ create(basename, *rest) do |tmpname, n, opts|
135
+ lock = tmpname + '.lock'
136
+ mode = File::RDWR|File::CREAT|File::EXCL
137
+ perm = 0600
138
+ if opts
139
+ mode |= opts.delete(:mode) || 0
140
+ opts[:perm] = perm
141
+ perm = nil
142
+ else
143
+ opts = perm
144
+ end
145
+ self.class.mkdir(lock)
41
146
  begin
42
- tmpname = File.join(tmpdir, make_tmpname(basename, n))
43
- lock = tmpname + '.lock'
44
- n += 1
45
- end while @@cleanlist.include?(tmpname) or
46
- File.exist?(lock) or File.exist?(tmpname)
47
-
48
- Dir.mkdir(lock)
49
- rescue
50
- failure += 1
51
- retry if failure < MAX_TRY
52
- raise "cannot generate tempfile `%s'" % tmpname
53
- ensure
54
- Thread.critical = false
147
+ @data[1] = @tmpfile = File.open(tmpname, mode, opts)
148
+ @data[0] = @tmpname = tmpname
149
+ ensure
150
+ self.class.rmdir(lock)
151
+ end
152
+ @mode = mode & ~(File::CREAT|File::EXCL)
153
+ perm or opts.freeze
154
+ @opts = opts
55
155
  end
56
156
 
57
- @data = [tmpname]
58
- @clean_proc = Tempfile.callback(@data)
59
- ObjectSpace.define_finalizer(self, @clean_proc)
60
-
61
- @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
62
- @tmpname = tmpname
63
- @@cleanlist << @tmpname
64
- @data[1] = @tmpfile
65
- @data[2] = @@cleanlist
66
-
67
157
  super(@tmpfile)
68
-
69
- # Now we have all the File/IO methods defined, you must not
70
- # carelessly put bare puts(), etc. after this.
71
-
72
- Dir.rmdir(lock)
73
158
  end
74
159
 
75
- def make_tmpname(basename, n)
76
- case basename
77
- when Array
78
- prefix, suffix = *basename
79
- else
80
- prefix, suffix = basename, ''
81
- end
82
-
83
- t = Time.now.strftime("%Y%m%d")
84
- path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
85
- end
86
- private :make_tmpname
87
-
88
160
  # Opens or reopens the file with mode "r+".
89
161
  def open
90
162
  @tmpfile.close if @tmpfile
91
- @tmpfile = File.open(@tmpname, 'r+')
163
+ @tmpfile = File.open(@tmpname, @mode, @opts)
92
164
  @data[1] = @tmpfile
93
165
  __setobj__(@tmpfile)
94
166
  end
@@ -100,8 +172,9 @@ class Tempfile < DelegateClass(File)
100
172
  end
101
173
  protected :_close
102
174
 
103
- # Closes the file. If the optional flag is true, unlinks the file
104
- # after closing.
175
+ # Closes the file. If +unlink_now+ is true, then the file will be unlinked
176
+ # (deleted) after closing. Of course, you can choose to later call #unlink
177
+ # if you do not unlink it now.
105
178
  #
106
179
  # If you don't explicitly unlink the temporary file, the removal
107
180
  # will be delayed until the object is finalized.
@@ -113,25 +186,57 @@ class Tempfile < DelegateClass(File)
113
186
  end
114
187
  end
115
188
 
116
- # Closes and unlinks the file.
189
+ # Closes and unlinks (deletes) the file. Has the same effect as called
190
+ # <tt>close(true)</tt>.
117
191
  def close!
118
192
  _close
119
- @clean_proc.call
193
+ unlink
120
194
  ObjectSpace.undefine_finalizer(self)
121
- @data = @tmpname = nil
122
195
  end
123
196
 
124
- # Unlinks the file. On UNIX-like systems, it is often a good idea
125
- # to unlink a temporary file immediately after creating and opening
126
- # it, because it leaves other programs zero chance to access the
127
- # file.
197
+ # Unlinks (deletes) the file from the filesystem. One should always unlink
198
+ # the file after using it, as is explained in the "Explicit close" good
199
+ # practice section in the Tempfile overview:
200
+ #
201
+ # file = Tempfile.new('foo')
202
+ # begin
203
+ # ...do something with file...
204
+ # ensure
205
+ # file.close
206
+ # file.unlink # deletes the temp file
207
+ # end
208
+ #
209
+ # === Unlink-before-close
210
+ #
211
+ # On POSIX systems it's possible to unlink a file before closing it. This
212
+ # practice is explained in detail in the Tempfile overview (section
213
+ # "Unlink after creation"); please refer there for more information.
214
+ #
215
+ # However, unlink-before-close may not be supported on non-POSIX operating
216
+ # systems. Microsoft Windows is the most notable case: unlinking a non-closed
217
+ # file will result in an error, which this method will silently ignore. If
218
+ # you want to practice unlink-before-close whenever possible, then you should
219
+ # write code like this:
220
+ #
221
+ # file = Tempfile.new('foo')
222
+ # file.unlink # On Windows this silently fails.
223
+ # begin
224
+ # ... do something with file ...
225
+ # ensure
226
+ # file.close! # Closes the file handle. If the file wasn't unlinked
227
+ # # because #unlink failed, then this method will attempt
228
+ # # to do so again.
229
+ # end
128
230
  def unlink
129
231
  # keep this order for thread safeness
232
+ return unless @tmpname
130
233
  begin
131
- File.unlink(@tmpname) if File.exist?(@tmpname)
132
- @@cleanlist.delete(@tmpname)
133
- @data = @tmpname = nil
134
- ObjectSpace.undefine_finalizer(self)
234
+ if File.exist?(@tmpname)
235
+ File.unlink(@tmpname)
236
+ end
237
+ # remove tmpname from remover
238
+ @data[0] = @data[2] = nil
239
+ @tmpname = nil
135
240
  rescue Errno::EACCES
136
241
  # may not be able to unlink on Windows; just ignore
137
242
  end
@@ -139,6 +244,7 @@ class Tempfile < DelegateClass(File)
139
244
  alias delete unlink
140
245
 
141
246
  # Returns the full path name of the temporary file.
247
+ # This will be nil if #unlink has been called.
142
248
  def path
143
249
  @tmpname
144
250
  end
@@ -149,52 +255,83 @@ class Tempfile < DelegateClass(File)
149
255
  if @tmpfile
150
256
  @tmpfile.flush
151
257
  @tmpfile.stat.size
258
+ elsif @tmpname
259
+ File.size(@tmpname)
152
260
  else
153
261
  0
154
262
  end
155
263
  end
156
264
  alias length size
157
265
 
158
- class << self
159
- def callback(data) # :nodoc:
160
- pid = $$
161
- lambda {
162
- if pid == $$
163
- path, tmpfile, cleanlist = *data
266
+ # :stopdoc:
267
+ class Remover
268
+ def initialize(data)
269
+ @pid = $$
270
+ @data = data
271
+ end
164
272
 
165
- print "removing ", path, "..." if $DEBUG
273
+ def call(*args)
274
+ if @pid == $$
275
+ path, tmpfile = *@data
166
276
 
167
- tmpfile.close if tmpfile
277
+ STDERR.print "removing ", path, "..." if $DEBUG
168
278
 
169
- # keep this order for thread safeness
170
- File.unlink(path) if File.exist?(path)
171
- cleanlist.delete(path) if cleanlist
279
+ tmpfile.close if tmpfile
172
280
 
173
- print "done\n" if $DEBUG
281
+ # keep this order for thread safeness
282
+ if path
283
+ File.unlink(path) if File.exist?(path)
174
284
  end
175
- }
285
+
286
+ STDERR.print "done\n" if $DEBUG
287
+ end
176
288
  end
289
+ end
290
+ # :startdoc:
177
291
 
178
- # If no block is given, this is a synonym for new().
292
+ class << self
293
+ # Creates a new Tempfile.
294
+ #
295
+ # If no block is given, this is a synonym for Tempfile.new.
179
296
  #
180
- # If a block is given, it will be passed tempfile as an argument,
181
- # and the tempfile will automatically be closed when the block
182
- # terminates. In this case, open() returns nil.
297
+ # If a block is given, then a Tempfile object will be constructed,
298
+ # and the block is run with said object as argument. The Tempfile
299
+ # oject will be automatically closed after the block terminates.
300
+ # The call returns the value of the block.
301
+ #
302
+ # In any case, all arguments (+*args+) will be passed to Tempfile.new.
303
+ #
304
+ # Tempfile.open('foo', '/home/temp') do |f|
305
+ # ... do something with f ...
306
+ # end
307
+ #
308
+ # # Equivalent:
309
+ # f = Tempfile.open('foo', '/home/temp')
310
+ # begin
311
+ # ... do something with f ...
312
+ # ensure
313
+ # f.close
314
+ # end
183
315
  def open(*args)
184
316
  tempfile = new(*args)
185
317
 
186
318
  if block_given?
187
- begin
188
- yield(tempfile)
189
- ensure
190
- tempfile.close
191
- end
192
-
193
- nil
319
+ begin
320
+ yield(tempfile)
321
+ ensure
322
+ tempfile.close
323
+ end
194
324
  else
195
- tempfile
325
+ tempfile
196
326
  end
197
327
  end
328
+
329
+ def mkdir(*args)
330
+ Dir.mkdir(*args)
331
+ end
332
+ def rmdir(*args)
333
+ Dir.rmdir(*args)
334
+ end
198
335
  end
199
336
  end
200
337
 
@@ -1,5 +1,5 @@
1
1
  module RubySL
2
2
  module Tempfile
3
- VERSION = "1.0.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.required_ruby_version = "~> 1.8.7"
19
+ spec.required_ruby_version = "~> 2.0"
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysl-tempfile
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-27 00:00:00.000000000 Z
11
+ date: 2013-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -95,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
95
  requirements:
96
96
  - - ~>
97
97
  - !ruby/object:Gem::Version
98
- version: 1.8.7
98
+ version: '2.0'
99
99
  required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - '>='