tempfile 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6ccc754d48cea474a69828abfd078e10caca47c832b2f9ff8d21f9a64f1e0f22
4
+ data.tar.gz: 2ee1ed2819d49208a4501c1a5e4ecc25707e2d53e331696b9f7d0fb460d30538
5
+ SHA512:
6
+ metadata.gz: e7b403c598ec72689933ffab89f635e28a61029cc421852b842a064aa92d2ef863cc67b83535bec4b70ef483add54b02460d5b540a1ab8427e6d86196669e4df
7
+ data.tar.gz: 12536bd046614d957e368353c27cc4961f86ca6b404963aa1ebd094377055404c1c31dc09fff99124bc7ae151888118dfecdd9eb205e11fe57696cf11cde8598
@@ -0,0 +1,24 @@
1
+ name: ubuntu
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "test-unit"
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,51 @@
1
+ # Tempfile
2
+
3
+ A utility class for managing temporary files. When you create a Tempfile
4
+ object, it will create a temporary file with a unique filename. A Tempfile
5
+ objects behaves just like a File object, and you can perform all the usual
6
+ file operations on it: reading data, writing data, changing its permissions,
7
+ etc. So although this class does not explicitly document all instance methods
8
+ supported by File, you can in fact call any File instance method on a
9
+ Tempfile object.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'tempfile'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle install
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install tempfile
26
+
27
+ ## Usage
28
+
29
+ ```ruby
30
+ require 'tempfile'
31
+
32
+ file = Tempfile.new('foo')
33
+ file.path # => A unique filename in the OS's temp directory,
34
+ # e.g.: "/tmp/foo.24722.0"
35
+ # This filename contains 'foo' in its basename.
36
+ file.write("hello world")
37
+ file.rewind
38
+ file.read # => "hello world"
39
+ file.close
40
+ file.unlink # deletes the temp file
41
+ ```
42
+
43
+ ## Development
44
+
45
+ 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.
46
+
47
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/tempfile.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
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__)
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,350 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # tempfile - manipulates temporary files
4
+ #
5
+ # $Id$
6
+ #
7
+
8
+ require 'delegate'
9
+ require 'tmpdir'
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.
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 existence 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.
81
+ class Tempfile < DelegateClass(File)
82
+ # Creates a temporary file with permissions 0600 (= only readable and
83
+ # writable by the owner) and opens it with mode "w+".
84
+ #
85
+ # The +basename+ parameter is used to determine the name of the
86
+ # temporary file. You can either pass a String or an Array with
87
+ # 2 String elements. In the former form, the temporary file's base
88
+ # name will begin with the given string. In the latter form,
89
+ # the temporary file's base name will begin with the array's first
90
+ # element, and end with the second element. For example:
91
+ #
92
+ # file = Tempfile.new('hello')
93
+ # file.path # => something like: "/tmp/hello2843-8392-92849382--0"
94
+ #
95
+ # # Use the Array form to enforce an extension in the filename:
96
+ # file = Tempfile.new(['hello', '.jpg'])
97
+ # file.path # => something like: "/tmp/hello2843-8392-92849382--0.jpg"
98
+ #
99
+ # The temporary file will be placed in the directory as specified
100
+ # by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
101
+ #
102
+ # file = Tempfile.new('hello', '/home/aisaka')
103
+ # file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
104
+ #
105
+ # You can also pass an options hash. Under the hood, Tempfile creates
106
+ # the temporary file using +File.open+. These options will be passed to
107
+ # +File.open+. This is mostly useful for specifying encoding
108
+ # options, e.g.:
109
+ #
110
+ # Tempfile.new('hello', '/home/aisaka', encoding: 'ascii-8bit')
111
+ #
112
+ # # You can also omit the 'tmpdir' parameter:
113
+ # Tempfile.new('hello', encoding: 'ascii-8bit')
114
+ #
115
+ # Note: +mode+ keyword argument, as accepted by Tempfile, can only be
116
+ # numeric, combination of the modes defined in File::Constants.
117
+ #
118
+ # === Exceptions
119
+ #
120
+ # If Tempfile.new cannot find a unique filename within a limited
121
+ # number of tries, then it will raise an exception.
122
+ def initialize(basename="", tmpdir=nil, mode: 0, **options)
123
+ warn "Tempfile.new doesn't call the given block.", uplevel: 1 if block_given?
124
+
125
+ @unlinked = false
126
+ @mode = mode|File::RDWR|File::CREAT|File::EXCL
127
+ ::Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
128
+ opts[:perm] = 0600
129
+ @tmpfile = File.open(tmpname, @mode, **opts)
130
+ @opts = opts.freeze
131
+ end
132
+ ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))
133
+
134
+ super(@tmpfile)
135
+ end
136
+
137
+ # Opens or reopens the file with mode "r+".
138
+ def open
139
+ _close
140
+ mode = @mode & ~(File::CREAT|File::EXCL)
141
+ @tmpfile = File.open(@tmpfile.path, mode, **@opts)
142
+ __setobj__(@tmpfile)
143
+ end
144
+
145
+ def _close # :nodoc:
146
+ @tmpfile.close
147
+ end
148
+ protected :_close
149
+
150
+ # Closes the file. If +unlink_now+ is true, then the file will be unlinked
151
+ # (deleted) after closing. Of course, you can choose to later call #unlink
152
+ # if you do not unlink it now.
153
+ #
154
+ # If you don't explicitly unlink the temporary file, the removal
155
+ # will be delayed until the object is finalized.
156
+ def close(unlink_now=false)
157
+ _close
158
+ unlink if unlink_now
159
+ end
160
+
161
+ # Closes and unlinks (deletes) the file. Has the same effect as called
162
+ # <tt>close(true)</tt>.
163
+ def close!
164
+ close(true)
165
+ end
166
+
167
+ # Unlinks (deletes) the file from the filesystem. One should always unlink
168
+ # the file after using it, as is explained in the "Explicit close" good
169
+ # practice section in the Tempfile overview:
170
+ #
171
+ # file = Tempfile.new('foo')
172
+ # begin
173
+ # # ...do something with file...
174
+ # ensure
175
+ # file.close
176
+ # file.unlink # deletes the temp file
177
+ # end
178
+ #
179
+ # === Unlink-before-close
180
+ #
181
+ # On POSIX systems it's possible to unlink a file before closing it. This
182
+ # practice is explained in detail in the Tempfile overview (section
183
+ # "Unlink after creation"); please refer there for more information.
184
+ #
185
+ # However, unlink-before-close may not be supported on non-POSIX operating
186
+ # systems. Microsoft Windows is the most notable case: unlinking a non-closed
187
+ # file will result in an error, which this method will silently ignore. If
188
+ # you want to practice unlink-before-close whenever possible, then you should
189
+ # write code like this:
190
+ #
191
+ # file = Tempfile.new('foo')
192
+ # file.unlink # On Windows this silently fails.
193
+ # begin
194
+ # # ... do something with file ...
195
+ # ensure
196
+ # file.close! # Closes the file handle. If the file wasn't unlinked
197
+ # # because #unlink failed, then this method will attempt
198
+ # # to do so again.
199
+ # end
200
+ def unlink
201
+ return if @unlinked
202
+ begin
203
+ File.unlink(@tmpfile.path)
204
+ rescue Errno::ENOENT
205
+ rescue Errno::EACCES
206
+ # may not be able to unlink on Windows; just ignore
207
+ return
208
+ end
209
+ ObjectSpace.undefine_finalizer(self)
210
+ @unlinked = true
211
+ end
212
+ alias delete unlink
213
+
214
+ # Returns the full path name of the temporary file.
215
+ # This will be nil if #unlink has been called.
216
+ def path
217
+ @unlinked ? nil : @tmpfile.path
218
+ end
219
+
220
+ # Returns the size of the temporary file. As a side effect, the IO
221
+ # buffer is flushed before determining the size.
222
+ def size
223
+ if !@tmpfile.closed?
224
+ @tmpfile.size # File#size calls rb_io_flush_raw()
225
+ else
226
+ File.size(@tmpfile.path)
227
+ end
228
+ end
229
+ alias length size
230
+
231
+ # :stopdoc:
232
+ def inspect
233
+ if @tmpfile.closed?
234
+ "#<#{self.class}:#{path} (closed)>"
235
+ else
236
+ "#<#{self.class}:#{path}>"
237
+ end
238
+ end
239
+
240
+ class Remover # :nodoc:
241
+ def initialize(tmpfile)
242
+ @pid = Process.pid
243
+ @tmpfile = tmpfile
244
+ end
245
+
246
+ def call(*args)
247
+ return if @pid != Process.pid
248
+
249
+ $stderr.puts "removing #{@tmpfile.path}..." if $DEBUG
250
+
251
+ @tmpfile.close
252
+ begin
253
+ File.unlink(@tmpfile.path)
254
+ rescue Errno::ENOENT
255
+ end
256
+
257
+ $stderr.puts "done" if $DEBUG
258
+ end
259
+ end
260
+
261
+ class << self
262
+ # :startdoc:
263
+
264
+ # Creates a new Tempfile.
265
+ #
266
+ # If no block is given, this is a synonym for Tempfile.new.
267
+ #
268
+ # If a block is given, then a Tempfile object will be constructed,
269
+ # and the block is run with said object as argument. The Tempfile
270
+ # object will be automatically closed after the block terminates.
271
+ # The call returns the value of the block.
272
+ #
273
+ # In any case, all arguments (<code>*args</code>) will be passed to Tempfile.new.
274
+ #
275
+ # Tempfile.open('foo', '/home/temp') do |f|
276
+ # # ... do something with f ...
277
+ # end
278
+ #
279
+ # # Equivalent:
280
+ # f = Tempfile.open('foo', '/home/temp')
281
+ # begin
282
+ # # ... do something with f ...
283
+ # ensure
284
+ # f.close
285
+ # end
286
+ def open(*args, **kw)
287
+ tempfile = new(*args, **kw)
288
+
289
+ if block_given?
290
+ begin
291
+ yield(tempfile)
292
+ ensure
293
+ tempfile.close
294
+ end
295
+ else
296
+ tempfile
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ # Creates a temporary file as usual File object (not Tempfile).
303
+ # It doesn't use finalizer and delegation.
304
+ #
305
+ # If no block is given, this is similar to Tempfile.new except
306
+ # creating File instead of Tempfile.
307
+ # The created file is not removed automatically.
308
+ # You should use File.unlink to remove it.
309
+ #
310
+ # If a block is given, then a File object will be constructed,
311
+ # and the block is invoked with the object as the argument.
312
+ # The File object will be automatically closed and
313
+ # the temporary file is removed after the block terminates.
314
+ # The call returns the value of the block.
315
+ #
316
+ # In any case, all arguments (+basename+, +tmpdir+, +mode+, and
317
+ # <code>**options</code>) will be treated as Tempfile.new.
318
+ #
319
+ # Tempfile.create('foo', '/home/temp') do |f|
320
+ # # ... do something with f ...
321
+ # end
322
+ #
323
+ def Tempfile.create(basename="", tmpdir=nil, mode: 0, **options)
324
+ tmpfile = nil
325
+ Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
326
+ mode |= File::RDWR|File::CREAT|File::EXCL
327
+ opts[:perm] = 0600
328
+ tmpfile = File.open(tmpname, mode, **opts)
329
+ end
330
+ if block_given?
331
+ begin
332
+ yield tmpfile
333
+ ensure
334
+ unless tmpfile.closed?
335
+ if File.identical?(tmpfile, tmpfile.path)
336
+ unlinked = File.unlink tmpfile.path rescue nil
337
+ end
338
+ tmpfile.close
339
+ end
340
+ unless unlinked
341
+ begin
342
+ File.unlink tmpfile.path
343
+ rescue Errno::ENOENT
344
+ end
345
+ end
346
+ end
347
+ else
348
+ tmpfile
349
+ end
350
+ end
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "tempfile"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Yukihiro Matsumoto"]
5
+ spec.email = ["matz@ruby-lang.org"]
6
+
7
+ spec.summary = %q{A utility class for managing temporary files.}
8
+ spec.description = %q{A utility class for managing temporary files.}
9
+ spec.homepage = "https://github.com/ruby/tempfile"
10
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
11
+
12
+ spec.metadata["homepage_uri"] = spec.homepage
13
+ spec.metadata["source_code_uri"] = spec.homepage
14
+
15
+ # Specify which files should be added to the gem when it is released.
16
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
17
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tempfile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yukihiro Matsumoto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-04-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A utility class for managing temporary files.
14
+ email:
15
+ - matz@ruby-lang.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".github/workflows/test.yml"
21
+ - ".gitignore"
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
28
+ - lib/tempfile.rb
29
+ - tempfile.gemspec
30
+ homepage: https://github.com/ruby/tempfile
31
+ licenses: []
32
+ metadata:
33
+ homepage_uri: https://github.com/ruby/tempfile
34
+ source_code_uri: https://github.com/ruby/tempfile
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.5.0
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.2.0.pre1
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: A utility class for managing temporary files.
54
+ test_files: []