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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 441e2cb96bc4f1d0c808dbde645e2985849607d7edd297b2e26fa427094eaa59
4
- data.tar.gz: fcaf9af92f27ac9c91877ae3542dcada76e95e4c31196fbf01fa7a6213d47fea
3
+ metadata.gz: ef81a8dfbe90ff3468ef6d7f52763a4a0882fe3c96822b0d3fbb1fe3fb01b944
4
+ data.tar.gz: 0b920d194d7a08a1dd0ad13244c7746b19787d4068127648b5d2c561b8cd0079
5
5
  SHA512:
6
- metadata.gz: 664dd5cdf708cf51e87f1ed8b375bf754c48dfecac717c119cfff8298018132762a4debc1b65d420128071ef6db28f893e589a5f0dc6a5e13738afc167c7436b
7
- data.tar.gz: 4237b4700b4a8d365931e286e1e199a79c362f70ce9349d1c19bc43fb2a78f461b384e4ba1e49c7ca8967d0ae474865018c45481c8813d979bf63a47561cd2bf
6
+ metadata.gz: 8788788b42ea43fd0e3d82304cb1edf2fd8a601c6c69e6c30870fa5c2783adfed0f6fbe7e77f39c5b4f561d42c628e25513ccd79b5da3f6199eecf680325e6d1
7
+ data.tar.gz: 31319dfadc78caabea0e53c0073c157ae4707b6855172a95041f875f8ea39f2181d058c9b3665ff8244e15c7a8f42a4f39d72d00525cac3b5764faf5dfb05ab0
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ LICENSE.txt
2
+ README.md
3
+ lib/
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. 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.
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
- # == Good practices
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
- # Please refer to #unlink for more information and a code example.
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
- VERSION = "0.2.0"
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
- @tmpfile = File.open(tmpname, @mode, **opts)
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(@tmpfile)
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
- @tmpfile = File.open(@tmpfile.path, mode, **@opts)
170
- __setobj__(@tmpfile)
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
- @tmpfile.close
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(@tmpfile.path)
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
- ObjectSpace.undefine_finalizer(self)
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 : @tmpfile.path
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 !@tmpfile.closed?
252
- @tmpfile.size # File#size calls rb_io_flush_raw()
348
+ if !__getobj__.closed?
349
+ __getobj__.size # File#size calls rb_io_flush_raw()
253
350
  else
254
- File.size(@tmpfile.path)
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 @tmpfile.closed?
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
- class Remover # :nodoc:
269
- def initialize(tmpfile)
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
- @tmpfile = tmpfile
377
+ @unlinked = false
272
378
  end
273
379
 
274
- def call(*args)
275
- return if @pid != Process.pid
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
- $stderr.puts "removing #{@tmpfile.path}..." if $DEBUG
386
+ def call(object_id)
387
+ @open_files.delete(object_id).close
278
388
 
279
- @tmpfile.close
280
- begin
281
- File.unlink(@tmpfile.path)
282
- rescue Errno::ENOENT
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
- # With no block, the file is not removed automatically,
357
- # and so should be explicitly removed.
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
- # Argument +basename+, if given, may be one of:
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 with +mode+ must be an integer,
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
- # With a block given, creates the file as above, passes it to the block,
393
- # and returns the block's value;
394
- # before the return, the file object is closed and the underlying file is removed:
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.2.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: 2023-11-07 00:00:00.000000000 Z
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
- - ".github/dependabot.yml"
21
- - ".github/workflows/test.yml"
22
- - ".gitignore"
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.0.dev
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: []
@@ -1,6 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: 'github-actions'
4
- directory: '/'
5
- schedule:
6
- interval: 'weekly'
@@ -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
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/Gemfile DELETED
@@ -1,7 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gemspec
4
-
5
- gem "rake"
6
- gem "test-unit"
7
- gem "test-unit-ruby-core"
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
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
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