tempfile 0.2.0 → 0.3.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
  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