tempfile 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.document +3 -0
- data/BSDL +22 -0
- data/COPYING +56 -0
- data/README.md +4 -0
- data/lib/tempfile.rb +260 -45
- metadata +9 -14
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/test.yml +0 -28
- data/.gitignore +0 -8
- data/Gemfile +0 -7
- data/Gemfile.lock +0 -23
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/tempfile.gemspec +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef81a8dfbe90ff3468ef6d7f52763a4a0882fe3c96822b0d3fbb1fe3fb01b944
|
4
|
+
data.tar.gz: 0b920d194d7a08a1dd0ad13244c7746b19787d4068127648b5d2c561b8cd0079
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8788788b42ea43fd0e3d82304cb1edf2fd8a601c6c69e6c30870fa5c2783adfed0f6fbe7e77f39c5b4f561d42c628e25513ccd79b5da3f6199eecf680325e6d1
|
7
|
+
data.tar.gz: 31319dfadc78caabea0e53c0073c157ae4707b6855172a95041f875f8ea39f2181d058c9b3665ff8244e15c7a8f42a4f39d72d00525cac3b5764faf5dfb05ab0
|
data/.document
ADDED
data/BSDL
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
1. Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
15
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
16
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
17
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
18
|
+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
19
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
20
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
21
|
+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
22
|
+
SUCH DAMAGE.
|
data/COPYING
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
2
|
+
You can redistribute it and/or modify it under either the terms of the
|
3
|
+
2-clause BSDL (see the file BSDL), or the conditions below:
|
4
|
+
|
5
|
+
1. You may make and give away verbatim copies of the source form of the
|
6
|
+
software without restriction, provided that you duplicate all of the
|
7
|
+
original copyright notices and associated disclaimers.
|
8
|
+
|
9
|
+
2. You may modify your copy of the software in any way, provided that
|
10
|
+
you do at least ONE of the following:
|
11
|
+
|
12
|
+
a. place your modifications in the Public Domain or otherwise
|
13
|
+
make them Freely Available, such as by posting said
|
14
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
15
|
+
the author to include your modifications in the software.
|
16
|
+
|
17
|
+
b. use the modified software only within your corporation or
|
18
|
+
organization.
|
19
|
+
|
20
|
+
c. give non-standard binaries non-standard names, with
|
21
|
+
instructions on where to get the original software distribution.
|
22
|
+
|
23
|
+
d. make other distribution arrangements with the author.
|
24
|
+
|
25
|
+
3. You may distribute the software in object code or binary form,
|
26
|
+
provided that you do at least ONE of the following:
|
27
|
+
|
28
|
+
a. distribute the binaries and library files of the software,
|
29
|
+
together with instructions (in the manual page or equivalent)
|
30
|
+
on where to get the original distribution.
|
31
|
+
|
32
|
+
b. accompany the distribution with the machine-readable source of
|
33
|
+
the software.
|
34
|
+
|
35
|
+
c. give non-standard binaries non-standard names, with
|
36
|
+
instructions on where to get the original software distribution.
|
37
|
+
|
38
|
+
d. make other distribution arrangements with the author.
|
39
|
+
|
40
|
+
4. You may modify and include the part of the software into any other
|
41
|
+
software (possibly commercial). But some files in the distribution
|
42
|
+
are not written by the author, so that they are not under these terms.
|
43
|
+
|
44
|
+
For the list of those files and their copying conditions, see the
|
45
|
+
file LEGAL.
|
46
|
+
|
47
|
+
5. The scripts and library files supplied as input to or produced as
|
48
|
+
output from the software do not automatically fall under the
|
49
|
+
copyright of the software, but belong to whomever generated them,
|
50
|
+
and may be sold commercially, and may be aggregated with this
|
51
|
+
software.
|
52
|
+
|
53
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
54
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
55
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
56
|
+
PURPOSE.
|
data/README.md
CHANGED
@@ -40,6 +40,10 @@ file.close
|
|
40
40
|
file.unlink # deletes the temp file
|
41
41
|
```
|
42
42
|
|
43
|
+
## Documentation
|
44
|
+
|
45
|
+
[RDoc](https://docs.ruby-lang.org/en/master/Tempfile.html)
|
46
|
+
|
43
47
|
## Development
|
44
48
|
|
45
49
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/tempfile.rb
CHANGED
@@ -8,18 +8,61 @@
|
|
8
8
|
require 'delegate'
|
9
9
|
require 'tmpdir'
|
10
10
|
|
11
|
-
# A utility class for managing temporary files.
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
11
|
+
# A utility class for managing temporary files.
|
12
|
+
#
|
13
|
+
# There are two kind of methods of creating a temporary file:
|
14
|
+
#
|
15
|
+
# - Tempfile.create (recommended)
|
16
|
+
# - Tempfile.new and Tempfile.open (mostly for backward compatibility, not recommended)
|
17
|
+
#
|
18
|
+
# Tempfile.create creates a usual \File object.
|
19
|
+
# The timing of file deletion is predictable.
|
20
|
+
# Also, it supports open-and-unlink technique which
|
21
|
+
# removes the temporary file immediately after creation.
|
22
|
+
#
|
23
|
+
# Tempfile.new and Tempfile.open creates a \Tempfile object.
|
24
|
+
# The created file is removed by the GC (finalizer).
|
25
|
+
# The timing of file deletion is not predictable.
|
18
26
|
#
|
19
27
|
# == Synopsis
|
20
28
|
#
|
21
29
|
# require 'tempfile'
|
22
30
|
#
|
31
|
+
# # Tempfile.create with a block
|
32
|
+
# # The filename are choosen automatically.
|
33
|
+
# # (You can specify the prefix and suffix of the filename by an optional argument.)
|
34
|
+
# Tempfile.create {|f|
|
35
|
+
# f.puts "foo"
|
36
|
+
# f.rewind
|
37
|
+
# f.read # => "foo\n"
|
38
|
+
# } # The file is removed at block exit.
|
39
|
+
#
|
40
|
+
# # Tempfile.create without a block
|
41
|
+
# # You need to unlink the file in non-block form.
|
42
|
+
# f = Tempfile.create
|
43
|
+
# f.puts "foo"
|
44
|
+
# f.close
|
45
|
+
# File.unlink(f.path) # You need to unlink the file.
|
46
|
+
#
|
47
|
+
# # Tempfile.create(anonymous: true) without a block
|
48
|
+
# f = Tempfile.create(anonymous: true)
|
49
|
+
# # The file is already removed because anonymous.
|
50
|
+
# f.path # => "/tmp/" (no filename since no file)
|
51
|
+
# f.puts "foo"
|
52
|
+
# f.rewind
|
53
|
+
# f.read # => "foo\n"
|
54
|
+
# f.close
|
55
|
+
#
|
56
|
+
# # Tempfile.create(anonymous: true) with a block
|
57
|
+
# Tempfile.create(anonymous: true) {|f|
|
58
|
+
# # The file is already removed because anonymous.
|
59
|
+
# f.path # => "/tmp/" (no filename since no file)
|
60
|
+
# f.puts "foo"
|
61
|
+
# f.rewind
|
62
|
+
# f.read # => "foo\n"
|
63
|
+
# }
|
64
|
+
#
|
65
|
+
# # Not recommended: Tempfile.new without a block
|
23
66
|
# file = Tempfile.new('foo')
|
24
67
|
# file.path # => A unique filename in the OS's temp directory,
|
25
68
|
# # e.g.: "/tmp/foo.24722.0"
|
@@ -30,7 +73,27 @@ require 'tmpdir'
|
|
30
73
|
# file.close
|
31
74
|
# file.unlink # deletes the temp file
|
32
75
|
#
|
33
|
-
# ==
|
76
|
+
# == About Tempfile.new and Tempfile.open
|
77
|
+
#
|
78
|
+
# This section does not apply to Tempfile.create because
|
79
|
+
# it returns a File object (not a Tempfile object).
|
80
|
+
#
|
81
|
+
# When you create a Tempfile object,
|
82
|
+
# it will create a temporary file with a unique filename. A Tempfile
|
83
|
+
# objects behaves just like a File object, and you can perform all the usual
|
84
|
+
# file operations on it: reading data, writing data, changing its permissions,
|
85
|
+
# etc. So although this class does not explicitly document all instance methods
|
86
|
+
# supported by File, you can in fact call any File instance method on a
|
87
|
+
# Tempfile object.
|
88
|
+
#
|
89
|
+
# A Tempfile object has a finalizer to remove the temporary file.
|
90
|
+
# This means that the temporary file is removed via GC.
|
91
|
+
# This can cause several problems:
|
92
|
+
#
|
93
|
+
# - Long GC intervals and conservative GC can accumulate temporary files that are not removed.
|
94
|
+
# - Temporary files are not removed if Ruby exits abnormally (such as SIGKILL, SEGV).
|
95
|
+
#
|
96
|
+
# There are legacy good practices for Tempfile.new and Tempfile.open as follows.
|
34
97
|
#
|
35
98
|
# === Explicit close
|
36
99
|
#
|
@@ -71,12 +134,17 @@ require 'tmpdir'
|
|
71
134
|
# be able to read from or write to the Tempfile, and you do not need to
|
72
135
|
# know the Tempfile's filename either.
|
73
136
|
#
|
137
|
+
# Also, this guarantees the temporary file is removed even if Ruby exits abnormally.
|
138
|
+
# The OS reclaims the storage for the temporary file when the file is closed or
|
139
|
+
# the Ruby process exits (normally or abnormally).
|
140
|
+
#
|
74
141
|
# For example, a practical use case for unlink-after-creation would be this:
|
75
142
|
# you need a large byte buffer that's too large to comfortably fit in RAM,
|
76
143
|
# e.g. when you're writing a web server and you want to buffer the client's
|
77
144
|
# file upload data.
|
78
145
|
#
|
79
|
-
#
|
146
|
+
# `Tempfile.create(anonymous: true)` supports this behavior.
|
147
|
+
# It also works on Windows.
|
80
148
|
#
|
81
149
|
# == Minor notes
|
82
150
|
#
|
@@ -88,7 +156,8 @@ require 'tmpdir'
|
|
88
156
|
# mutex.
|
89
157
|
class Tempfile < DelegateClass(File)
|
90
158
|
|
91
|
-
|
159
|
+
# The version
|
160
|
+
VERSION = "0.3.0"
|
92
161
|
|
93
162
|
# Creates a file in the underlying file system;
|
94
163
|
# returns a new \Tempfile object based on that file.
|
@@ -152,26 +221,52 @@ class Tempfile < DelegateClass(File)
|
|
152
221
|
|
153
222
|
@unlinked = false
|
154
223
|
@mode = mode|File::RDWR|File::CREAT|File::EXCL
|
224
|
+
tmpfile = nil
|
155
225
|
::Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
|
156
226
|
opts[:perm] = 0600
|
157
|
-
|
227
|
+
tmpfile = File.open(tmpname, @mode, **opts)
|
158
228
|
@opts = opts.freeze
|
159
229
|
end
|
160
|
-
ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))
|
161
230
|
|
162
|
-
super(
|
231
|
+
super(tmpfile)
|
232
|
+
|
233
|
+
@finalizer_manager = FinalizerManager.new(__getobj__.path)
|
234
|
+
@finalizer_manager.register(self, __getobj__)
|
235
|
+
end
|
236
|
+
|
237
|
+
def initialize_dup(other) # :nodoc:
|
238
|
+
initialize_copy_iv(other)
|
239
|
+
super(other)
|
240
|
+
@finalizer_manager.register(self, __getobj__)
|
241
|
+
end
|
242
|
+
|
243
|
+
def initialize_clone(other) # :nodoc:
|
244
|
+
initialize_copy_iv(other)
|
245
|
+
super(other)
|
246
|
+
@finalizer_manager.register(self, __getobj__)
|
247
|
+
end
|
248
|
+
|
249
|
+
private def initialize_copy_iv(other) # :nodoc:
|
250
|
+
@unlinked = other.unlinked
|
251
|
+
@mode = other.mode
|
252
|
+
@opts = other.opts
|
253
|
+
@finalizer_manager = other.finalizer_manager
|
163
254
|
end
|
164
255
|
|
165
256
|
# Opens or reopens the file with mode "r+".
|
166
257
|
def open
|
167
258
|
_close
|
259
|
+
|
168
260
|
mode = @mode & ~(File::CREAT|File::EXCL)
|
169
|
-
|
170
|
-
|
261
|
+
__setobj__(File.open(__getobj__.path, mode, **@opts))
|
262
|
+
|
263
|
+
@finalizer_manager.register(self, __getobj__)
|
264
|
+
|
265
|
+
__getobj__
|
171
266
|
end
|
172
267
|
|
173
268
|
def _close # :nodoc:
|
174
|
-
|
269
|
+
__getobj__.close
|
175
270
|
end
|
176
271
|
protected :_close
|
177
272
|
|
@@ -228,13 +323,15 @@ class Tempfile < DelegateClass(File)
|
|
228
323
|
def unlink
|
229
324
|
return if @unlinked
|
230
325
|
begin
|
231
|
-
File.unlink(
|
326
|
+
File.unlink(__getobj__.path)
|
232
327
|
rescue Errno::ENOENT
|
233
328
|
rescue Errno::EACCES
|
234
329
|
# may not be able to unlink on Windows; just ignore
|
235
330
|
return
|
236
331
|
end
|
237
|
-
|
332
|
+
|
333
|
+
@finalizer_manager.unlinked = true
|
334
|
+
|
238
335
|
@unlinked = true
|
239
336
|
end
|
240
337
|
alias delete unlink
|
@@ -242,47 +339,61 @@ class Tempfile < DelegateClass(File)
|
|
242
339
|
# Returns the full path name of the temporary file.
|
243
340
|
# This will be nil if #unlink has been called.
|
244
341
|
def path
|
245
|
-
@unlinked ? nil :
|
342
|
+
@unlinked ? nil : __getobj__.path
|
246
343
|
end
|
247
344
|
|
248
345
|
# Returns the size of the temporary file. As a side effect, the IO
|
249
346
|
# buffer is flushed before determining the size.
|
250
347
|
def size
|
251
|
-
if
|
252
|
-
|
348
|
+
if !__getobj__.closed?
|
349
|
+
__getobj__.size # File#size calls rb_io_flush_raw()
|
253
350
|
else
|
254
|
-
File.size(
|
351
|
+
File.size(__getobj__.path)
|
255
352
|
end
|
256
353
|
end
|
257
354
|
alias length size
|
258
355
|
|
259
356
|
# :stopdoc:
|
260
357
|
def inspect
|
261
|
-
if
|
358
|
+
if __getobj__.closed?
|
262
359
|
"#<#{self.class}:#{path} (closed)>"
|
263
360
|
else
|
264
361
|
"#<#{self.class}:#{path}>"
|
265
362
|
end
|
266
363
|
end
|
364
|
+
alias to_s inspect
|
267
365
|
|
268
|
-
|
269
|
-
|
366
|
+
protected
|
367
|
+
|
368
|
+
attr_reader :unlinked, :mode, :opts, :finalizer_manager
|
369
|
+
|
370
|
+
class FinalizerManager # :nodoc:
|
371
|
+
attr_accessor :unlinked
|
372
|
+
|
373
|
+
def initialize(path)
|
374
|
+
@open_files = {}
|
375
|
+
@path = path
|
270
376
|
@pid = Process.pid
|
271
|
-
@
|
377
|
+
@unlinked = false
|
272
378
|
end
|
273
379
|
|
274
|
-
def
|
275
|
-
|
380
|
+
def register(obj, file)
|
381
|
+
ObjectSpace.undefine_finalizer(obj)
|
382
|
+
ObjectSpace.define_finalizer(obj, self)
|
383
|
+
@open_files[obj.object_id] = file
|
384
|
+
end
|
276
385
|
|
277
|
-
|
386
|
+
def call(object_id)
|
387
|
+
@open_files.delete(object_id).close
|
278
388
|
|
279
|
-
@
|
280
|
-
|
281
|
-
|
282
|
-
|
389
|
+
if @open_files.empty? && !@unlinked && Process.pid == @pid
|
390
|
+
$stderr.puts "removing #{@path}..." if $DEBUG
|
391
|
+
begin
|
392
|
+
File.unlink(@path)
|
393
|
+
rescue Errno::ENOENT
|
394
|
+
end
|
395
|
+
$stderr.puts "done" if $DEBUG
|
283
396
|
end
|
284
|
-
|
285
|
-
$stderr.puts "done" if $DEBUG
|
286
397
|
end
|
287
398
|
end
|
288
399
|
|
@@ -353,8 +464,9 @@ end
|
|
353
464
|
# see {File Permissions}[https://docs.ruby-lang.org/en/master/File.html#label-File+Permissions].
|
354
465
|
# - Mode is <tt>'w+'</tt> (read/write mode, positioned at the end).
|
355
466
|
#
|
356
|
-
#
|
357
|
-
#
|
467
|
+
# The temporary file removal depends on the keyword argument +anonymous+ and
|
468
|
+
# whether a block is given or not.
|
469
|
+
# See the description about the +anonymous+ keyword argument later.
|
358
470
|
#
|
359
471
|
# Example:
|
360
472
|
#
|
@@ -362,11 +474,36 @@ end
|
|
362
474
|
# f.class # => File
|
363
475
|
# f.path # => "/tmp/20220505-9795-17ky6f6"
|
364
476
|
# f.stat.mode.to_s(8) # => "100600"
|
477
|
+
# f.close
|
365
478
|
# File.exist?(f.path) # => true
|
366
479
|
# File.unlink(f.path)
|
367
480
|
# File.exist?(f.path) # => false
|
368
481
|
#
|
369
|
-
#
|
482
|
+
# Tempfile.create {|f|
|
483
|
+
# f.puts "foo"
|
484
|
+
# f.rewind
|
485
|
+
# f.read # => "foo\n"
|
486
|
+
# f.path # => "/tmp/20240524-380207-oma0ny"
|
487
|
+
# File.exist?(f.path) # => true
|
488
|
+
# } # The file is removed at block exit.
|
489
|
+
#
|
490
|
+
# f = Tempfile.create(anonymous: true)
|
491
|
+
# # The file is already removed because anonymous
|
492
|
+
# f.path # => "/tmp/" (no filename since no file)
|
493
|
+
# f.puts "foo"
|
494
|
+
# f.rewind
|
495
|
+
# f.read # => "foo\n"
|
496
|
+
# f.close
|
497
|
+
#
|
498
|
+
# Tempfile.create(anonymous: true) {|f|
|
499
|
+
# # The file is already removed because anonymous
|
500
|
+
# f.path # => "/tmp/" (no filename since no file)
|
501
|
+
# f.puts "foo"
|
502
|
+
# f.rewind
|
503
|
+
# f.read # => "foo\n"
|
504
|
+
# }
|
505
|
+
#
|
506
|
+
# The argument +basename+, if given, may be one of the following:
|
370
507
|
#
|
371
508
|
# - A string: the generated filename begins with +basename+:
|
372
509
|
#
|
@@ -377,27 +514,57 @@ end
|
|
377
514
|
#
|
378
515
|
# Tempfile.create(%w/foo .jpg/) # => #<File:/tmp/foo20220505-17839-tnjchh.jpg>
|
379
516
|
#
|
380
|
-
# With arguments +basename+ and +tmpdir+, the file is created in directory +tmpdir+:
|
517
|
+
# With arguments +basename+ and +tmpdir+, the file is created in the directory +tmpdir+:
|
381
518
|
#
|
382
519
|
# Tempfile.create('foo', '.') # => #<File:./foo20220505-9795-1emu6g8>
|
383
520
|
#
|
384
|
-
# Keyword arguments +mode+ and +options+ are passed directly to method
|
521
|
+
# Keyword arguments +mode+ and +options+ are passed directly to the method
|
385
522
|
# {File.open}[https://docs.ruby-lang.org/en/master/File.html#method-c-open]:
|
386
523
|
#
|
387
|
-
# - The value given
|
524
|
+
# - The value given for +mode+ must be an integer
|
388
525
|
# and may be expressed as the logical OR of constants defined in
|
389
526
|
# {File::Constants}[https://docs.ruby-lang.org/en/master/File/Constants.html].
|
390
527
|
# - For +options+, see {Open Options}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Open+Options].
|
391
528
|
#
|
392
|
-
#
|
393
|
-
#
|
394
|
-
#
|
529
|
+
# The keyword argument +anonymous+ specifies when the file is removed.
|
530
|
+
#
|
531
|
+
# - <tt>anonymous=false</tt> (default) without a block: the file is not removed.
|
532
|
+
# - <tt>anonymous=false</tt> (default) with a block: the file is removed after the block exits.
|
533
|
+
# - <tt>anonymous=true</tt> without a block: the file is removed before returning.
|
534
|
+
# - <tt>anonymous=true</tt> with a block: the file is removed before the block is called.
|
535
|
+
#
|
536
|
+
# In the first case (<tt>anonymous=false</tt> without a block),
|
537
|
+
# the file is not removed automatically.
|
538
|
+
# It should be explicitly closed.
|
539
|
+
# It can be used to rename to the desired filename.
|
540
|
+
# If the file is not needed, it should be explicitly removed.
|
541
|
+
#
|
542
|
+
# The File#path method of the created file object returns the temporary directory with a trailing slash
|
543
|
+
# when +anonymous+ is true.
|
544
|
+
#
|
545
|
+
# When a block is given, it creates the file as described above, passes it to the block,
|
546
|
+
# and returns the block's value.
|
547
|
+
# Before the returning, the file object is closed and the underlying file is removed:
|
395
548
|
#
|
396
549
|
# Tempfile.create {|file| file.path } # => "/tmp/20220505-9795-rkists"
|
397
550
|
#
|
551
|
+
# Implementation note:
|
552
|
+
#
|
553
|
+
# The keyword argument +anonymous=true+ is implemented using FILE_SHARE_DELETE on Windows.
|
554
|
+
# O_TMPFILE is used on Linux.
|
555
|
+
#
|
398
556
|
# Related: Tempfile.new.
|
399
557
|
#
|
400
|
-
def Tempfile.create(basename="", tmpdir=nil, mode: 0, **options)
|
558
|
+
def Tempfile.create(basename="", tmpdir=nil, mode: 0, anonymous: false, **options, &block)
|
559
|
+
if anonymous
|
560
|
+
create_anonymous(basename, tmpdir, mode: mode, **options, &block)
|
561
|
+
else
|
562
|
+
create_with_filename(basename, tmpdir, mode: mode, **options, &block)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
class << Tempfile
|
567
|
+
private def create_with_filename(basename="", tmpdir=nil, mode: 0, **options)
|
401
568
|
tmpfile = nil
|
402
569
|
Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
|
403
570
|
mode |= File::RDWR|File::CREAT|File::EXCL
|
@@ -425,3 +592,51 @@ def Tempfile.create(basename="", tmpdir=nil, mode: 0, **options)
|
|
425
592
|
tmpfile
|
426
593
|
end
|
427
594
|
end
|
595
|
+
|
596
|
+
File.open(IO::NULL) do |f|
|
597
|
+
File.new(f.fileno, autoclose: false, path: "").path
|
598
|
+
rescue IOError
|
599
|
+
module PathAttr # :nodoc:
|
600
|
+
attr_reader :path
|
601
|
+
|
602
|
+
def self.set_path(file, path)
|
603
|
+
file.extend(self).instance_variable_set(:@path, path)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
private def create_anonymous(basename="", tmpdir=nil, mode: 0, **options, &block)
|
609
|
+
tmpfile = nil
|
610
|
+
tmpdir = Dir.tmpdir() if tmpdir.nil?
|
611
|
+
if defined?(File::TMPFILE) # O_TMPFILE since Linux 3.11
|
612
|
+
begin
|
613
|
+
tmpfile = File.open(tmpdir, File::RDWR | File::TMPFILE, 0600)
|
614
|
+
rescue Errno::EISDIR, Errno::ENOENT, Errno::EOPNOTSUPP
|
615
|
+
# kernel or the filesystem does not support O_TMPFILE
|
616
|
+
# fallback to create-and-unlink
|
617
|
+
end
|
618
|
+
end
|
619
|
+
if tmpfile.nil?
|
620
|
+
mode |= File::SHARE_DELETE | File::BINARY # Windows needs them to unlink the opened file.
|
621
|
+
tmpfile = create_with_filename(basename, tmpdir, mode: mode, **options)
|
622
|
+
File.unlink(tmpfile.path)
|
623
|
+
tmppath = tmpfile.path
|
624
|
+
end
|
625
|
+
path = File.join(tmpdir, '')
|
626
|
+
unless tmppath == path
|
627
|
+
# clear path.
|
628
|
+
tmpfile.autoclose = false
|
629
|
+
tmpfile = File.new(tmpfile.fileno, mode: File::RDWR, path: path)
|
630
|
+
PathAttr.set_path(tmpfile, path) if defined?(PathAttr)
|
631
|
+
end
|
632
|
+
if block
|
633
|
+
begin
|
634
|
+
yield tmpfile
|
635
|
+
ensure
|
636
|
+
tmpfile.close
|
637
|
+
end
|
638
|
+
else
|
639
|
+
tmpfile
|
640
|
+
end
|
641
|
+
end
|
642
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tempfile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yukihiro Matsumoto
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A utility class for managing temporary files.
|
14
14
|
email:
|
@@ -17,17 +17,12 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- ".
|
21
|
-
-
|
22
|
-
-
|
23
|
-
- Gemfile
|
24
|
-
- Gemfile.lock
|
20
|
+
- ".document"
|
21
|
+
- BSDL
|
22
|
+
- COPYING
|
25
23
|
- README.md
|
26
24
|
- Rakefile
|
27
|
-
- bin/console
|
28
|
-
- bin/setup
|
29
25
|
- lib/tempfile.rb
|
30
|
-
- tempfile.gemspec
|
31
26
|
homepage: https://github.com/ruby/tempfile
|
32
27
|
licenses:
|
33
28
|
- Ruby
|
@@ -35,7 +30,7 @@ licenses:
|
|
35
30
|
metadata:
|
36
31
|
homepage_uri: https://github.com/ruby/tempfile
|
37
32
|
source_code_uri: https://github.com/ruby/tempfile
|
38
|
-
post_install_message:
|
33
|
+
post_install_message:
|
39
34
|
rdoc_options: []
|
40
35
|
require_paths:
|
41
36
|
- lib
|
@@ -50,8 +45,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
45
|
- !ruby/object:Gem::Version
|
51
46
|
version: '0'
|
52
47
|
requirements: []
|
53
|
-
rubygems_version: 3.5.
|
54
|
-
signing_key:
|
48
|
+
rubygems_version: 3.5.11
|
49
|
+
signing_key:
|
55
50
|
specification_version: 4
|
56
51
|
summary: A utility class for managing temporary files.
|
57
52
|
test_files: []
|
data/.github/dependabot.yml
DELETED
data/.github/workflows/test.yml
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
name: ubuntu
|
2
|
-
|
3
|
-
on: [push, pull_request]
|
4
|
-
|
5
|
-
jobs:
|
6
|
-
ruby-versions:
|
7
|
-
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
8
|
-
with:
|
9
|
-
engine: cruby
|
10
|
-
min_version: 2.5
|
11
|
-
test:
|
12
|
-
needs: ruby-versions
|
13
|
-
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
14
|
-
strategy:
|
15
|
-
matrix:
|
16
|
-
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
17
|
-
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
18
|
-
runs-on: ${{ matrix.os }}
|
19
|
-
steps:
|
20
|
-
- uses: actions/checkout@v4
|
21
|
-
- name: Set up Ruby
|
22
|
-
uses: ruby/setup-ruby@v1
|
23
|
-
with:
|
24
|
-
ruby-version: ${{ matrix.ruby }}
|
25
|
-
- name: Install dependencies
|
26
|
-
run: bundle install
|
27
|
-
- name: Run test
|
28
|
-
run: rake test
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
tempfile (0.1.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
power_assert (1.1.5)
|
10
|
-
rake (13.0.1)
|
11
|
-
test-unit (3.3.5)
|
12
|
-
power_assert
|
13
|
-
|
14
|
-
PLATFORMS
|
15
|
-
ruby
|
16
|
-
|
17
|
-
DEPENDENCIES
|
18
|
-
rake
|
19
|
-
tempfile!
|
20
|
-
test-unit
|
21
|
-
|
22
|
-
BUNDLED WITH
|
23
|
-
2.1.4
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "tempfile"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/tempfile.gemspec
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
name = File.basename(__FILE__, ".gemspec")
|
2
|
-
version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
|
3
|
-
break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
|
4
|
-
/^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
|
5
|
-
end rescue nil
|
6
|
-
end
|
7
|
-
|
8
|
-
Gem::Specification.new do |spec|
|
9
|
-
spec.name = name
|
10
|
-
spec.version = version
|
11
|
-
spec.authors = ["Yukihiro Matsumoto"]
|
12
|
-
spec.email = ["matz@ruby-lang.org"]
|
13
|
-
|
14
|
-
spec.summary = %q{A utility class for managing temporary files.}
|
15
|
-
spec.description = %q{A utility class for managing temporary files.}
|
16
|
-
spec.homepage = "https://github.com/ruby/tempfile"
|
17
|
-
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
18
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
19
|
-
|
20
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
21
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
22
|
-
|
23
|
-
# Specify which files should be added to the gem when it is released.
|
24
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
26
|
-
`git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
-
end
|
28
|
-
spec.require_paths = ["lib"]
|
29
|
-
end
|