file-temp 1.2.1 → 1.7.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 +5 -5
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/{CHANGES → CHANGES.rdoc} +33 -0
- data/LICENSE +177 -0
- data/MANIFEST.rdoc +13 -0
- data/README.rdoc +66 -0
- data/Rakefile +8 -47
- data/certs/djberg96_pub.pem +26 -0
- data/file-temp.gemspec +22 -14
- data/lib/file-temp.rb +1 -0
- data/lib/file/{temp_java.rb → java/temp.rb} +14 -16
- data/lib/file/temp.rb +11 -2
- data/lib/file/unix/temp.rb +106 -0
- data/lib/file/windows/temp.rb +217 -0
- data/spec/file_temp_spec.rb +159 -0
- metadata +75 -32
- metadata.gz.sig +0 -0
- data/MANIFEST +0 -9
- data/README +0 -61
- data/lib/file/temp_c.rb +0 -254
- data/test/test_file_temp.rb +0 -135
data/lib/file-temp.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'file/temp'
|
@@ -2,17 +2,14 @@ require 'java'
|
|
2
2
|
import java.lang.System
|
3
3
|
|
4
4
|
class File::Temp < File
|
5
|
-
# The version of the file-temp library.
|
6
|
-
VERSION = '1.2.1'
|
7
|
-
|
8
5
|
# The temporary directory used on MS Windows or Unix.
|
9
6
|
TMPDIR = java.lang.System.getProperties["java.io.tmpdir"]
|
10
7
|
|
11
8
|
# The name of the temporary file.
|
12
9
|
attr_reader :path
|
13
10
|
|
14
|
-
# Creates a new, anonymous, temporary file in your
|
15
|
-
# directory.
|
11
|
+
# Creates a new, anonymous, temporary file in your system's temporary
|
12
|
+
# directory, or whichever directory you specify.
|
16
13
|
#
|
17
14
|
# If the +delete+ option is set to true (the default) then the temporary file
|
18
15
|
# will be deleted automatically as soon as all references to it are closed.
|
@@ -30,11 +27,11 @@ class File::Temp < File
|
|
30
27
|
#
|
31
28
|
# Example:
|
32
29
|
#
|
33
|
-
# fh = File::Temp.new(true, 'rb_file_temp_XXXXXX')
|
30
|
+
# fh = File::Temp.new(delete: true, template: 'rb_file_temp_XXXXXX')
|
34
31
|
# fh.puts 'hello world'
|
35
32
|
# fh.close
|
36
33
|
#
|
37
|
-
def initialize(delete
|
34
|
+
def initialize(delete: true, template: 'rb_file_temp_XXXXXX', directory: TMPDIR, options: {})
|
38
35
|
raise TypeError unless template.is_a?(String)
|
39
36
|
|
40
37
|
# Since Java uses a GUID extension to generate a unique file name
|
@@ -44,26 +41,27 @@ class File::Temp < File
|
|
44
41
|
# For consistency between implementations, convert errors here
|
45
42
|
# to Errno::EINVAL.
|
46
43
|
begin
|
47
|
-
@file = java.io.File.createTempFile(template, nil)
|
44
|
+
@file = java.io.File.createTempFile(template, nil, java.io.File.new(directory))
|
48
45
|
rescue NativeException => err
|
49
46
|
raise SystemCallError.new(22), template # 22 is EINVAL
|
50
47
|
end
|
51
48
|
|
52
49
|
@file.deleteOnExit if delete
|
50
|
+
options[:mode] ||= 'wb+'
|
53
51
|
|
54
|
-
|
52
|
+
path = @file.getName
|
53
|
+
super(path, options)
|
55
54
|
|
56
|
-
|
55
|
+
@path = path unless delete
|
57
56
|
end
|
58
57
|
|
59
|
-
# Generates a unique file name
|
58
|
+
# Generates a unique file name based on your tmpdir, or whichever
|
59
|
+
# directory you specify.
|
60
60
|
#
|
61
|
-
def self.temp_name
|
62
|
-
file = java.io.File.createTempFile('rb_file_temp_', nil)
|
61
|
+
def self.temp_name(directory = TMPDIR)
|
62
|
+
file = java.io.File.createTempFile('rb_file_temp_', nil, java.io.File.new(directory))
|
63
63
|
file.deleteOnExit
|
64
|
-
|
65
|
-
file.finalize
|
66
|
-
name
|
64
|
+
directory + file.getName
|
67
65
|
end
|
68
66
|
|
69
67
|
# Identical to the File#close method except that we also finalize
|
data/lib/file/temp.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
+
class File::Temp < File
|
2
|
+
# The version of the file-temp library
|
3
|
+
VERSION = '1.7.0'.freeze
|
4
|
+
end
|
5
|
+
|
1
6
|
if RUBY_PLATFORM == 'java'
|
2
|
-
|
7
|
+
require_relative 'java/temp'
|
3
8
|
else
|
4
|
-
|
9
|
+
if File::ALT_SEPARATOR
|
10
|
+
require_relative 'windows/temp'
|
11
|
+
else
|
12
|
+
require_relative 'unix/temp'
|
13
|
+
end
|
5
14
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
class File::Temp < File
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib FFI::Library::LIBC
|
7
|
+
|
8
|
+
# :stopdoc:
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attach_function :fclose, [:pointer], :int
|
13
|
+
attach_function :_fileno, :fileno, [:pointer], :int
|
14
|
+
attach_function :strerror, [:int], :string
|
15
|
+
attach_function :tmpfile, [], :pointer
|
16
|
+
attach_function :tmpnam, [:pointer], :string
|
17
|
+
attach_function :mktemp, [:pointer], :string
|
18
|
+
|
19
|
+
private_class_method :mktemp, :strerror, :tmpfile
|
20
|
+
private_class_method :tmpnam, :fclose, :_fileno
|
21
|
+
|
22
|
+
public
|
23
|
+
|
24
|
+
# :startdoc:
|
25
|
+
|
26
|
+
# The temporary directory used on MS Windows or Unix by default.
|
27
|
+
TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['TMPDIR'] || Dir.tmpdir
|
28
|
+
|
29
|
+
# The name of the temporary file. Set to nil if the +delete+ option to the
|
30
|
+
# constructor is true.
|
31
|
+
attr_reader :path
|
32
|
+
|
33
|
+
# Creates a new, anonymous, temporary file in your tmpdir, or whichever
|
34
|
+
# directory you specifiy.
|
35
|
+
#
|
36
|
+
# If the +delete+ option is set to true (the default) then the temporary file
|
37
|
+
# will be deleted automatically as soon as all references to it are closed.
|
38
|
+
# Otherwise, the file will live on in your tmpdir path.
|
39
|
+
#
|
40
|
+
# If the +delete+ option is set to false, then the file is not deleted. In
|
41
|
+
# addition, you can supply a string +template+ that the system replaces with
|
42
|
+
# a unique filename. This template should end with 3 to 6 'X' characters.
|
43
|
+
# The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
|
44
|
+
# file lives in the directory where it was created.
|
45
|
+
#
|
46
|
+
# The +template+ argument is ignored if the +delete+ argument is true.
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
#
|
50
|
+
# fh = File::Temp.new(delete: true, template: 'rb_file_temp_XXXXXX') => file
|
51
|
+
# fh.puts 'hello world'
|
52
|
+
# fh.close
|
53
|
+
#
|
54
|
+
def initialize(delete: true, template: 'rb_file_temp_XXXXXX', directory: TMPDIR, options: {})
|
55
|
+
@fptr = nil
|
56
|
+
|
57
|
+
if delete
|
58
|
+
@fptr = tmpfile()
|
59
|
+
raise SystemCallError.new('tmpfile', FFI.errno) if @fptr.null?
|
60
|
+
fd = _fileno(@fptr)
|
61
|
+
else
|
62
|
+
begin
|
63
|
+
omask = File.umask(077)
|
64
|
+
ptr = FFI::MemoryPointer.from_string(template)
|
65
|
+
str = mktemp(ptr)
|
66
|
+
|
67
|
+
if str.nil? || str.empty?
|
68
|
+
raise SystemCallError.new('mktemp', FFI.errno)
|
69
|
+
end
|
70
|
+
|
71
|
+
@path = File.join(directory, ptr.read_string)
|
72
|
+
ensure
|
73
|
+
File.umask(omask)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
options[:mode] ||= 'wb+'
|
78
|
+
|
79
|
+
if delete
|
80
|
+
super(fd, options)
|
81
|
+
else
|
82
|
+
super(@path, options)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# The close method was overridden to ensure the internal file pointer that we
|
87
|
+
# potentially created in the constructor is closed. It is otherwise identical
|
88
|
+
# to the File#close method.
|
89
|
+
#--
|
90
|
+
# This is probably unnecessary since Ruby will close the fd, and in reality
|
91
|
+
# the fclose function probably fails with an Errno::EBADF. Consequently
|
92
|
+
# I will let it silently fail as a no-op.
|
93
|
+
#
|
94
|
+
def close
|
95
|
+
super
|
96
|
+
fclose(@fptr) if @fptr && !@fptr.null?
|
97
|
+
end
|
98
|
+
|
99
|
+
# Generates a unique file name.
|
100
|
+
#
|
101
|
+
# Note that a file is not actually generated on the filesystem.
|
102
|
+
#
|
103
|
+
def self.temp_name
|
104
|
+
tmpnam(nil) << '.tmp'
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
class File::Temp < File
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib FFI::Library::LIBC
|
7
|
+
|
8
|
+
# :stopdoc:
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attach_function :_close, [:int], :int
|
13
|
+
attach_function :fclose, [:pointer], :int
|
14
|
+
attach_function :_fdopen, [:int, :string], :pointer
|
15
|
+
attach_function :_fileno, [:pointer], :int
|
16
|
+
attach_function :_get_errno, [:pointer], :int
|
17
|
+
attach_function :_open, [:string, :int, :int], :int
|
18
|
+
attach_function :_open_osfhandle, [:long, :int], :int
|
19
|
+
attach_function :tmpnam_s, [:pointer, :size_t], :int
|
20
|
+
attach_function :mktemp_s, :_mktemp_s, [:pointer, :size_t], :int
|
21
|
+
|
22
|
+
private_class_method :_close, :fclose, :_fdopen, :_fileno, :_get_errno
|
23
|
+
private_class_method :_open, :_open_osfhandle, :mktemp_s, :tmpnam_s
|
24
|
+
|
25
|
+
ffi_lib :kernel32
|
26
|
+
|
27
|
+
attach_function :CloseHandle, [:long], :bool
|
28
|
+
attach_function :CreateFileW, [:buffer_in, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :long
|
29
|
+
attach_function :DeleteFileW, [:string], :bool
|
30
|
+
attach_function :GetTempPathW, [:ulong, :buffer_out], :ulong
|
31
|
+
attach_function :GetTempFileNameW, [:buffer_in, :string, :uint, :buffer_out], :uint
|
32
|
+
|
33
|
+
private_class_method :_close, :_fdopen, :_open, :_open_osfhandle
|
34
|
+
private_class_method :CloseHandle, :CreateFileW, :DeleteFileW
|
35
|
+
private_class_method :GetTempPathW, :GetTempFileNameW
|
36
|
+
|
37
|
+
S_IWRITE = 128
|
38
|
+
S_IREAD = 256
|
39
|
+
BINARY = 0x8000
|
40
|
+
SHORT_LIVED = 0x1000
|
41
|
+
GENERIC_READ = 0x80000000
|
42
|
+
GENERIC_WRITE = 0x40000000
|
43
|
+
CREATE_ALWAYS = 2
|
44
|
+
|
45
|
+
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
|
46
|
+
FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
|
47
|
+
|
48
|
+
FILE_ATTRIBUTE_NORMAL = 0x00000080
|
49
|
+
FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
|
50
|
+
INVALID_HANDLE_VALUE = -1
|
51
|
+
|
52
|
+
public
|
53
|
+
|
54
|
+
# :startdoc:
|
55
|
+
|
56
|
+
# The temporary directory used on MS Windows or Unix by default.
|
57
|
+
TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['USERPROFILE'] || Dir.tmpdir
|
58
|
+
|
59
|
+
# The name of the temporary file. Set to nil if the +delete+ option to the
|
60
|
+
# constructor is true.
|
61
|
+
attr_reader :path
|
62
|
+
|
63
|
+
# Creates a new, anonymous, temporary file in your File::Temp::TMPDIR
|
64
|
+
# directory, or whichever directory you specify.
|
65
|
+
#
|
66
|
+
# If the +delete+ option is set to true (the default) then the temporary file
|
67
|
+
# will be deleted automatically as soon as all references to it are closed.
|
68
|
+
# Otherwise, the file will live on in your File::Temp::TMPDIR path.
|
69
|
+
#
|
70
|
+
# If the +delete+ option is set to false, then the file is not deleted. In
|
71
|
+
# addition, you can supply a string +template+ that the system replaces with
|
72
|
+
# a unique filename. This template should end with 3 to 6 'X' characters.
|
73
|
+
# The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
|
74
|
+
# file lives in the directory where it was created.
|
75
|
+
#
|
76
|
+
# The +template+ argument is ignored if the +delete+ argument is true.
|
77
|
+
#
|
78
|
+
# Example:
|
79
|
+
#
|
80
|
+
# fh = File::Temp.new(delete: true, template: 'rb_file_temp_XXXXXX')
|
81
|
+
# fh.puts 'hello world'
|
82
|
+
# fh.close
|
83
|
+
#
|
84
|
+
def initialize(delete: true, template: 'rb_file_temp_XXXXXX', directory: TMPDIR, options: {})
|
85
|
+
@fptr = nil
|
86
|
+
|
87
|
+
if delete
|
88
|
+
@fptr = tmpfile()
|
89
|
+
fd = _fileno(@fptr)
|
90
|
+
else
|
91
|
+
begin
|
92
|
+
omask = File.umask(077)
|
93
|
+
ptr = FFI::MemoryPointer.from_string(template)
|
94
|
+
errno = mktemp_s(ptr, ptr.size)
|
95
|
+
|
96
|
+
raise SystemCallError.new('mktemp_s', errno) if errno != 0
|
97
|
+
|
98
|
+
@path = File.join(directory, ptr.read_string)
|
99
|
+
@path.tr!(File::SEPARATOR, File::ALT_SEPARATOR)
|
100
|
+
ensure
|
101
|
+
File.umask(omask)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
options[:mode] ||= 'wb+'
|
106
|
+
|
107
|
+
if delete
|
108
|
+
super(fd, options)
|
109
|
+
else
|
110
|
+
super(@path, options)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# The close method was overridden to ensure the internal file pointer we
|
115
|
+
# created in the constructor is closed. It is otherwise identical to the
|
116
|
+
# File#close method.
|
117
|
+
#
|
118
|
+
def close
|
119
|
+
super
|
120
|
+
fclose(@fptr) if @fptr
|
121
|
+
end
|
122
|
+
|
123
|
+
# Generates a unique file name based on your default temporary directory,
|
124
|
+
# or whichever directory you specify.
|
125
|
+
#
|
126
|
+
# Note that a file is not actually generated on the filesystem.
|
127
|
+
#--
|
128
|
+
# NOTE: One quirk of the Windows function is that, after the first call, it
|
129
|
+
# adds a file extension of sequential numbers in base 32, e.g. .1-.1vvvvvu.
|
130
|
+
#
|
131
|
+
def self.temp_name(directory: TMPDIR)
|
132
|
+
ptr = FFI::MemoryPointer.new(:char, 1024)
|
133
|
+
errno = tmpnam_s(ptr, ptr.size)
|
134
|
+
|
135
|
+
raise SystemCallError.new('tmpnam_s', errno) if errno != 0
|
136
|
+
|
137
|
+
directory + ptr.read_string + 'tmp'
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# For those times when we want the posix errno rather than a formatted string.
|
143
|
+
# This is necessary because FFI.errno appears to be using GetLastError() which
|
144
|
+
# does not always match what _get_errno() returns.
|
145
|
+
#
|
146
|
+
def get_posix_errno
|
147
|
+
ptr = FFI::MemoryPointer.new(:int)
|
148
|
+
_get_errno(ptr)
|
149
|
+
ptr.read_int
|
150
|
+
end
|
151
|
+
|
152
|
+
# Simple wrapper around the GetTempPath function.
|
153
|
+
#
|
154
|
+
def get_temp_path
|
155
|
+
buf = 0.chr * 1024
|
156
|
+
buf.encode!("UTF-16LE")
|
157
|
+
|
158
|
+
if GetTempPathW(buf.size, buf) == 0
|
159
|
+
raise SystemCallError, FFI.errno, 'GetTempPathW'
|
160
|
+
end
|
161
|
+
|
162
|
+
buf.strip.chop # remove trailing slash
|
163
|
+
end
|
164
|
+
|
165
|
+
# The version of tmpfile() implemented by Microsoft is unacceptable.
|
166
|
+
# It attempts to write to C:\ (root) instead of a temporary directory.
|
167
|
+
# This is not only bad behavior, it won't work on Windows 7 and later
|
168
|
+
# without admin rights due to security restrictions.
|
169
|
+
#
|
170
|
+
# This is a custom implementation based on some code from the Cairo
|
171
|
+
# project.
|
172
|
+
#
|
173
|
+
def tmpfile
|
174
|
+
file_name = get_temp_path()
|
175
|
+
buf = 0.chr * 1024
|
176
|
+
buf.encode!("UTF-16LE")
|
177
|
+
|
178
|
+
if GetTempFileNameW(file_name, 'rb_', 0, buf) == 0
|
179
|
+
raise SystemCallError, FFI.errno, 'GetTempFileNameW'
|
180
|
+
end
|
181
|
+
|
182
|
+
file_name = buf.strip
|
183
|
+
|
184
|
+
handle = CreateFileW(
|
185
|
+
file_name,
|
186
|
+
GENERIC_READ | GENERIC_WRITE,
|
187
|
+
0,
|
188
|
+
nil,
|
189
|
+
CREATE_ALWAYS,
|
190
|
+
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
|
191
|
+
0
|
192
|
+
)
|
193
|
+
|
194
|
+
if handle == INVALID_HANDLE_VALUE
|
195
|
+
error = FFI.errno
|
196
|
+
DeleteFileW(file_name)
|
197
|
+
raise SystemCallError.new('CreateFileW', error)
|
198
|
+
end
|
199
|
+
|
200
|
+
fd = _open_osfhandle(handle, 0)
|
201
|
+
|
202
|
+
if fd < 0
|
203
|
+
CloseHandle(handle)
|
204
|
+
raise SystemCallError, get_posix_errno, '_open_osfhandle'
|
205
|
+
end
|
206
|
+
|
207
|
+
fp = _fdopen(fd, 'w+b')
|
208
|
+
|
209
|
+
if fp.nil?
|
210
|
+
_close(fd)
|
211
|
+
CloseHandle(handle)
|
212
|
+
raise SystemCallError, get_posix_errno, 'fdopen'
|
213
|
+
end
|
214
|
+
|
215
|
+
fp
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
######################################################################
|
2
|
+
# file_temp_spec.rb
|
3
|
+
#
|
4
|
+
# Test suite for the file-temp library. These tests should be run
|
5
|
+
# via the 'rake spec' task.
|
6
|
+
######################################################################
|
7
|
+
require 'rspec'
|
8
|
+
require 'file/temp'
|
9
|
+
|
10
|
+
RSpec.describe File::Temp do
|
11
|
+
let(:windows) { File::ALT_SEPARATOR }
|
12
|
+
let(:osx) { RbConfig::CONFIG['host_os'] =~ /darwin/i }
|
13
|
+
|
14
|
+
before do
|
15
|
+
@dir = File::Temp::TMPDIR
|
16
|
+
@template = 'file-temp-test-XXXXX'
|
17
|
+
@fh = nil
|
18
|
+
|
19
|
+
# Because Dir[] doesn't work right with backslashes
|
20
|
+
@dir = @dir.tr("\\", "/") if windows
|
21
|
+
end
|
22
|
+
|
23
|
+
context "constants" do
|
24
|
+
example "library version is set to expected value" do
|
25
|
+
expect( File::Temp::VERSION).to eq('1.7.0')
|
26
|
+
expect(File::Temp::VERSION).to be_frozen
|
27
|
+
end
|
28
|
+
|
29
|
+
example "TMPDIR constant is defined" do
|
30
|
+
expect(File::Temp::TMPDIR).to be_kind_of(String)
|
31
|
+
expect(File::Temp::TMPDIR.size).to be > 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "threads" do
|
36
|
+
example "library works as expected with multiple threads" do
|
37
|
+
threads = []
|
38
|
+
expect{ 100.times{ threads << Thread.new{ File::Temp.new }}}.not_to raise_error
|
39
|
+
expect{ threads.each{ |t| t.join }.not_to raise_error }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "constructor" do
|
44
|
+
example "constructor works as expected with default auto delete option" do
|
45
|
+
expect{
|
46
|
+
@fh = File::Temp.new
|
47
|
+
@fh.print "hello"
|
48
|
+
@fh.close
|
49
|
+
}.not_to raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
example "constructor works as expected with false auto delete option" do
|
53
|
+
expect{
|
54
|
+
@fh = File::Temp.new(:delete => false)
|
55
|
+
@fh.print "hello"
|
56
|
+
@fh.close
|
57
|
+
}.not_to raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
example "constructor accepts and uses an optional template as expected" do
|
61
|
+
expect{ File::Temp.new(:delete => false, :template => 'temp_foo_XXXXXX').close }.not_to raise_error
|
62
|
+
expect(Dir["#{@dir}/temp_foo*"].length).to be >= 1
|
63
|
+
end
|
64
|
+
|
65
|
+
example "constructor with false auto delete and block works as expected" do
|
66
|
+
expect{
|
67
|
+
File::Temp.open(:delete => false, :template => 'temp_foo_XXXXXX'){ |fh| fh.puts "hello" }
|
68
|
+
}.not_to raise_error
|
69
|
+
expect(Dir["#{@dir}/temp_foo*"].length).to be >= 1
|
70
|
+
end
|
71
|
+
|
72
|
+
example "constructor accepts a maximum of three arguments" do
|
73
|
+
expect{
|
74
|
+
@fh = File::Temp.new(
|
75
|
+
:delete => true,
|
76
|
+
:template => 'temp_bar_XXXXX',
|
77
|
+
:directory => Dir.pwd,
|
78
|
+
:bogus => 1
|
79
|
+
)
|
80
|
+
}.to raise_error(ArgumentError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "template" do
|
85
|
+
example "template argument must be a string" do
|
86
|
+
expect{ @fh = File::Temp.new(:delete => false, :template => 1) }.to raise_error(TypeError)
|
87
|
+
end
|
88
|
+
|
89
|
+
example "an error is raised if a custom template is invalid" do
|
90
|
+
skip "skipped on OSX" if osx
|
91
|
+
expect{ File::Temp.new(:delete => false, :template => 'xx') }.to raise_error(Errno::EINVAL)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "temp_name" do
|
96
|
+
example "temp_name basic functionality" do
|
97
|
+
expect(File::Temp).to respond_to(:temp_name)
|
98
|
+
expect{ File::Temp.temp_name }.not_to raise_error
|
99
|
+
expect(File::Temp.temp_name).to be_kind_of(String)
|
100
|
+
end
|
101
|
+
|
102
|
+
example "temp_name returns expected value" do
|
103
|
+
if windows
|
104
|
+
expect( File.extname(File::Temp.temp_name)).to match(/^.*?\d*?tmp/)
|
105
|
+
else
|
106
|
+
expect( File.extname(File::Temp.temp_name)).to eq('.tmp')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "path" do
|
112
|
+
example "temp path basic functionality" do
|
113
|
+
@fh = File::Temp.new
|
114
|
+
expect(@fh).to respond_to(:path)
|
115
|
+
end
|
116
|
+
|
117
|
+
example "temp path is nil if delete option is true" do
|
118
|
+
@fh = File::Temp.new
|
119
|
+
expect(@fh.path).to be_nil
|
120
|
+
end
|
121
|
+
|
122
|
+
example "temp path is not nil if delete option is false" do
|
123
|
+
@fh = File::Temp.new(delete: false)
|
124
|
+
expect(@fh.path).not_to be_nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "ffi" do
|
129
|
+
example "ffi functions are private" do
|
130
|
+
methods = File::Temp.methods(false).map(&:to_s)
|
131
|
+
expect(methods).not_to include('_fileno')
|
132
|
+
expect(methods).not_to include('mkstemp')
|
133
|
+
expect(methods).not_to include('_umask')
|
134
|
+
expect(methods).not_to include('fclose')
|
135
|
+
expect(methods).not_to include('strerror')
|
136
|
+
expect(methods).not_to include('tmpnam')
|
137
|
+
expect(methods).not_to include('CloseHandle')
|
138
|
+
expect(methods).not_to include('CreateFileA')
|
139
|
+
expect(methods).not_to include('DeleteFileA')
|
140
|
+
expect(methods).not_to include('GetTempPathA')
|
141
|
+
expect(methods).not_to include('GetTempFileNameA')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
after do
|
146
|
+
@dir = nil
|
147
|
+
@template = nil
|
148
|
+
@fh.close if @fh && !@fh.closed?
|
149
|
+
@fh = nil
|
150
|
+
|
151
|
+
Dir["temp_*"].each{ |f| File.delete(f) }
|
152
|
+
Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
|
153
|
+
|
154
|
+
Dir.chdir(File::Temp::TMPDIR) do
|
155
|
+
Dir["temp_*"].each{ |f| File.delete(f) }
|
156
|
+
Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|