file-temp 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,4 +1,10 @@
1
- = 1.0.0
1
+ = 1.1.0 - 21-Oct-2009
2
+ * Now pure Ruby, using FFI.
3
+ * Fixed RF Bug #26757 - FILE pointer leak. Thanks go to Eric Wong for the spot.
4
+ * Renamed and refactored the test file slightly.
5
+ * Updated the gemspec.
6
+
7
+ = 1.0.0 - 12-Apr-2008
2
8
  * Added security via umask().
3
9
  * Version bump to 1.0.0.
4
10
 
data/MANIFEST CHANGED
@@ -3,6 +3,5 @@
3
3
  * README
4
4
  * Rakefile
5
5
  * file-temp.gemspec
6
- * ext/extconf.rb
7
- * ext/temp.c
8
- * test/tc_file_temp.rb
6
+ * lib/file/temp.rb
7
+ * test/test_file_temp.rb
data/README CHANGED
@@ -1,27 +1,29 @@
1
- = Description
1
+ == Description
2
2
  The file-temp library is an alternate way to handle tempfile generation.
3
3
 
4
- = Synopsis
4
+ == Requirements
5
+ ffi 0.5.0 or later
6
+
7
+ == Synopsis
5
8
  require 'file/temp'
6
9
 
7
- fh = FileTemp.new
10
+ fh = File::Temp.new
8
11
  fh.puts "hello"
9
12
  fh.close # => Tempfile automatically deleted
10
13
 
11
- fh = FileTemp.new(false)
14
+ fh = File::Temp.new(false)
12
15
  fh.puts "world"
13
16
  fh.close # => Tempfile still on your filesystem
14
17
 
15
- = Installation
16
- == Standard Installation
18
+ == Installation
19
+ === Rubygems
20
+ gem install file-temp
21
+
22
+ === Standard Installation
17
23
  rake test (optional)
18
24
  rake install
19
25
 
20
- == Gem Installation
21
- rake test (optional)
22
- rake gem_install
23
-
24
- = Motivation
26
+ == Motivation
25
27
  Ruby's tempfile.rb is overwrought and susceptible to race conditions. This
26
28
  This library uses your system's native tmpfile() or mkstemp() functions
27
29
  instead of trying to handle race conditions manually via pure Ruby.
@@ -29,31 +31,34 @@
29
31
  This library is also more secure because it restricts file permission via
30
32
  umask() for files created with mkstemp().
31
33
 
32
- = Other libraries
34
+ == Other libraries
33
35
  I am aware of Cian Synnott's ruby-stemp project. However, I don't like the
34
36
  interface, it's GNU-centric (which causes portability issues), and Cian
35
37
  has disabled all the trackers and mailing lists on the RubyForge project
36
38
  site, as well as online SCM access. So, if he doesn't want feedback, I'm
37
39
  not going to waste time with it.
38
40
 
39
- = Future Plans
40
- I plan on adding a pure Ruby version for MS Windows eventually.
41
+ == JRuby
42
+ As of JRuby 1.3.1 this library will not work with JRuby because it does
43
+ not support low level systems programming.
44
+
45
+ == MS Windows
46
+ You may need to use the mingw build in order to use this library.
41
47
 
42
- = License
43
- Ruby's
48
+ == License
49
+ Artistic 2.0
44
50
 
45
- = Copyright
46
- (C) 2007-2008 Daniel J. Berger
51
+ == Copyright
52
+ (C) 2007-2009 Daniel J. Berger
47
53
  All Rights Reserved
48
54
 
49
- = Warranty
50
- This package is provided "as is" and without any express or
55
+ == Warranty
56
+ This library is provided "as is" and without any express or
51
57
  implied warranties, including, without limitation, the implied
52
58
  warranties of merchantability and fitness for a particular purpose.
53
59
 
54
- = Author
60
+ == Author
55
61
  Daniel J. Berger
56
- djberg96 at gmail dot com
57
62
 
58
- = See also
63
+ == See also
59
64
  tmpfile(), mkstemp(), tmpnam()
data/Rakefile CHANGED
@@ -1,51 +1,27 @@
1
1
  require 'rake'
2
- require 'rake/clean'
3
2
  require 'rake/testtask'
3
+ require 'rbconfig'
4
4
 
5
- desc "Clean the build files for the file-temp source for UNIX filetems"
6
- task :clean do
7
- make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
8
- Dir.chdir('ext') do
9
- FileUtils.rm_rf('file') if File.exists?('file')
10
- build_file = 'temp.' + Config::CONFIG['DLEXT']
11
- obj_file = 'temp.obj'
12
- if File.exists?(build_file) || File.exists?(obj_file)
13
- sh "#{make} distclean"
14
- end
15
- File.delete("temp.so.manifest") if File.exists?("temp.so.manifest")
16
- end
5
+ desc 'Install the file-temp library (non-gem)'
6
+ task :install do
7
+ dir = File.join(CONFIG['sitelibdir'], 'file')
8
+ Dir.mkdir(dir) unless File.exists?(dir)
9
+ file = 'lib/file/temp.rb'
10
+ FileUtils.cp_r(file, dir, :verbose => true)
17
11
  end
18
12
 
19
- desc "Build the file-temp package on UNIX filetems (but don't install it)"
20
- task :build => [:clean] do
21
- make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
22
- Dir.chdir('ext') do
23
- ruby 'extconf.rb'
24
- sh "#{make}"
25
- build_file = 'temp.' + Config::CONFIG['DLEXT']
26
- Dir.mkdir('file') unless File.exists?('file')
27
- FileUtils.cp(build_file, 'file')
28
- end
29
- end
30
-
31
- desc "Install the file-temp package"
32
- task :install => [:build] do
33
- Dir.chdir('ext') do
34
- make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
35
- sh "#{make} install"
36
- end
37
- end
13
+ desc 'Build the gem'
14
+ task :gem do
15
+ spec = eval(IO.read('file-temp.gemspec'))
16
+ Gem::Builder.new(spec).build
38
17
 
39
- desc "Install the file-temp package as a gem"
40
- task :install_gem do
41
- ruby 'file-temp.gemspec'
18
+ desc 'Install the file-temp library as a gem'
19
+ task :install_gem => [:gem] do
42
20
  file = Dir["*.gem"].first
43
21
  sh "gem install #{file}"
44
22
  end
45
23
 
46
- desc "Run the test suite"
47
- Rake::TestTask.new("test") do |t|
48
- task :test => :build
49
- t.libs << 'ext'
50
- t.test_files = FileList['test/tc_file_temp.rb']
24
+ Rake::TestTask.new do |t|
25
+ t.verbose = true
26
+ t.warning = true
51
27
  end
data/file-temp.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'file-temp'
5
+ gem.version = '1.1.0'
6
+ gem.author = 'Daniel J. Berger'
7
+ gem.email = 'djberg96@gmail.com'
8
+ gem.homepage = 'http://www.rubyforge.org/projects/shards'
9
+ gem.summary = 'An alternative way to generate temp files'
10
+ gem.test_file = 'test/test_file_temp.rb'
11
+ gem.has_rdoc = true
12
+ gem.files = Dir['**/*'].delete_if{ |item| item.include?('CVS') }
13
+
14
+ gem.extra_rdoc_files = ['CHANGES', 'README', 'MANIFEST']
15
+ gem.rubyforge_project = 'shards'
16
+ gem.required_ruby_version = '>= 1.8.6'
17
+
18
+ gem.add_dependency('use', '>= 1.3.1')
19
+ gem.add_dependency('ffi', '>= 0.5.0')
20
+ gem.add_development_dependency('test-unit', '>= 2.0.3')
21
+
22
+ gem.description = <<-EOF
23
+ The file-temp library provides an alternative approach to generating
24
+ temporary files. Features included improved security, a superior
25
+ interface, and better support for MS Windows.
26
+ EOF
27
+ end
data/lib/file/temp.rb ADDED
@@ -0,0 +1,211 @@
1
+ require 'rbconfig'
2
+ require 'ffi'
3
+
4
+ class File::Temp < File
5
+ extend FFI::Library
6
+
7
+ # :stopdoc:
8
+
9
+ private
10
+
11
+ # True if operating system is MS Windows
12
+ WINDOWS = Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
13
+
14
+ if WINDOWS
15
+ ffi_lib 'msvcrt'
16
+
17
+ attach_function '_close', [:int], :int
18
+ attach_function 'fclose', [:pointer], :int
19
+ attach_function '_fdopen', [:int, :string], :pointer
20
+ attach_function '_fileno', [:pointer], :int
21
+ attach_function '_mktemp', [:string], :string
22
+ attach_function '_open', [:string, :int, :int], :int
23
+ attach_function '_open_osfhandle', [:long, :int], :int
24
+ attach_function 'tmpnam', [:string], :string
25
+ attach_function '_umask', [:int], :int
26
+
27
+ ffi_lib 'kernel32'
28
+
29
+ attach_function 'CloseHandle', [:long], :bool
30
+ attach_function 'CreateFileA', [:string, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :long
31
+ attach_function 'DeleteFileA', [:string], :bool
32
+ attach_function 'GetTempPathA', [:long, :string], :long
33
+ attach_function 'GetTempFileNameA', [:string, :string, :uint, :pointer], :uint
34
+
35
+ S_IWRITE = 128
36
+ S_IREAD = 256
37
+ BINARY = 0x8000
38
+ SHORT_LIVED = 0x1000
39
+ GENERIC_READ = 0x80000000
40
+ GENERIC_WRITE = 0x40000000
41
+ CREATE_ALWAYS = 2
42
+
43
+ FILE_ATTRIBUTE_NORMAL = 0x00000080
44
+ FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
45
+ INVALID_HANDLE_VALUE = -1
46
+ else
47
+ attach_function 'fileno', [:pointer], :int
48
+ attach_function 'mkstemp', [:string], :int
49
+ attach_function 'umask', [:int], :int
50
+ attach_function 'tmpfile', [], :pointer
51
+ attach_function 'fclose', [:pointer], :int
52
+ attach_function 'tmpnam', [:string], :string
53
+ end
54
+
55
+ public
56
+
57
+ # :startdoc:
58
+
59
+ # The version of the file-temp library.
60
+ VERSION = '1.1.0'
61
+
62
+ if WINDOWS
63
+ # The temporary directory used on MS Windows.
64
+ TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['USERPROFILE'] || "C:\\Windows\\Temp"
65
+ else
66
+ # The temporary directory used on Unix.
67
+ TMPDIR = ENV['TEMP'] || ENV['TMP'] || ENV['TMPDIR'] || '/tmp'
68
+ end
69
+
70
+ public
71
+
72
+ # Creates a new, anonymous, temporary file in your File::Temp::TMPDIR
73
+ # directory
74
+ #
75
+ # If the +delete+ option is set to true (the default) then the temporary file
76
+ # will be deleted automatically as soon as all references to it are closed.
77
+ # Otherwise, the file will live on in your File::Temp::TMPDIR path.
78
+ #
79
+ # If the +delete+ option is set to false, then the file is not deleted. In
80
+ # addition, you can supply a string +template+ that the system replaces with
81
+ # a unique filename. This template should end with 3 to 6 'X' characters.
82
+ # The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
83
+ # file lives in the directory where it was created.
84
+ #
85
+ # The +template+ argument is ignored if the +delete+ argument is true.
86
+ #
87
+ # Example:
88
+ #
89
+ # fh = File::Temp.new(true, 'rb_file_temp_XXXXXX') => file
90
+ # fh.puts 'hello world'
91
+ # fh.close
92
+ #
93
+ def initialize(delete = true, template = 'rb_file_temp_XXXXXX')
94
+ @fptr = nil
95
+
96
+ if delete
97
+ @fptr = tmpfile()
98
+ fd = WINDOWS ? _fileno(@fptr) : fileno(@fptr)
99
+ else
100
+ begin
101
+ if WINDOWS
102
+ template = _mktemp(template)
103
+ omask = _umask(077)
104
+ else
105
+ omask = umask(077)
106
+ end
107
+ fd = mkstemp(File.join(TMPDIR, template))
108
+ raise SystemCallError, 'mkstemp()' if fd < 0
109
+ ensure
110
+ WINDOWS ? _umask(omask) : umask(omask)
111
+ end
112
+ end
113
+
114
+ super(fd, 'wb+')
115
+ end
116
+
117
+ # The close method was overridden to ensure the internal file pointer we
118
+ # created in the constructor is closed. It is otherwise identical to the
119
+ # File#close method.
120
+ #
121
+ def close
122
+ super
123
+ fclose(@fptr) if @fptr
124
+ end
125
+
126
+ # Generates a unique file name, prefixed with the value of the
127
+ # File::Temp::TMPDIR constant.
128
+ #
129
+ # Note that a file is not actually generated on the filesystem.
130
+ #
131
+ def self.temp_name
132
+ TMPDIR + tmpnam(nil) << '.tmp'
133
+ end
134
+
135
+ private
136
+
137
+ if WINDOWS
138
+ # The version of tmpfile() implemented by Microsoft is unacceptable.
139
+ # It attempts to write to C:\ (root) instead of a temporary directory.
140
+ # This is not only bad behavior, it won't work on Windows 7 and later
141
+ # without admin rights due to security restrictions.
142
+ #
143
+ # This is a custom implementation based on some code from the Cairo
144
+ # project.
145
+ #
146
+ def tmpfile
147
+ buf = 1.chr * 1024
148
+
149
+ if GetTempPathA(buf.length, buf) == 0
150
+ raise SystemCallError, 'GetTempPath()'
151
+ end
152
+
153
+ file_name = buf[ /^[^\0]*/ ].chop # remove trailing slash
154
+ buf = 1.chr * 1024
155
+
156
+ if GetTempFileNameA(file_name, 'rb_', 0, buf) == 0
157
+ raise SystemCallError, 'GetTempFileName()'
158
+ end
159
+
160
+ file_name = buf[ /^[^\0]*/ ]
161
+
162
+ handle = CreateFileA(
163
+ file_name,
164
+ GENERIC_READ | GENERIC_WRITE,
165
+ 0,
166
+ nil,
167
+ CREATE_ALWAYS,
168
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
169
+ 0
170
+ )
171
+
172
+ if handle == INVALID_HANDLE_VALUE
173
+ DeleteFileA(file_name)
174
+ raise SystemCallError, 'CreateFile()'
175
+ end
176
+
177
+ fd = _open_osfhandle(handle, 0)
178
+
179
+ if fd < 0
180
+ CloseHandle(handle)
181
+ raise SystemCallError, 'open_osfhandle()'
182
+ end
183
+
184
+ fp = _fdopen(fd, 'w+b')
185
+
186
+ if fp.nil?
187
+ _close(fd)
188
+ raise SystemCallError, 'fdopen()'
189
+ end
190
+
191
+ fp
192
+ end
193
+
194
+ # The MS C runtime does not define a mkstemp() function, so we've
195
+ # created one here.
196
+ #
197
+ def mkstemp(template)
198
+ flags = RDWR | BINARY | CREAT | EXCL | SHORT_LIVED
199
+ pmode = S_IREAD | S_IWRITE
200
+
201
+ fd = _open(template, flags, pmode)
202
+
203
+ raise SystemCallError, 'mkstemp()' if fd < 0
204
+
205
+ fd
206
+ end
207
+ end
208
+ end
209
+
210
+ # For backwards compatability
211
+ FileTemp = File::Temp
@@ -0,0 +1,91 @@
1
+ ######################################################################
2
+ # test_file_temp.rb
3
+ #
4
+ # Test suite for the file-temp library. These tests should be run
5
+ # via the 'rake test' task.
6
+ ######################################################################
7
+ require 'rubygems'
8
+ gem 'test-unit'
9
+
10
+ require 'test/unit'
11
+ require 'file/temp'
12
+ require 'rbconfig'
13
+
14
+ class TC_File_Temp < Test::Unit::TestCase
15
+ def setup
16
+ @dir = File::Temp::TMPDIR
17
+ @template = 'file-temp-test-XXXXX'
18
+ @fh = nil
19
+
20
+ # Because Dir[] doesn't work right with backslashes
21
+ @dir = @dir.tr("\\", "/") if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
22
+ end
23
+
24
+ def test_file_temp_version
25
+ assert_equal('1.1.0', File::Temp::VERSION)
26
+ end
27
+
28
+ def test_file_temp_threaded
29
+ threads = []
30
+ assert_nothing_raised{ 100.times{ threads << Thread.new{ File::Temp.new }}}
31
+ assert_nothing_raised{ threads.join }
32
+ end
33
+
34
+ def test_file_temp_tmpdir
35
+ assert_not_nil(File::Temp::TMPDIR)
36
+ assert_kind_of(String, File::Temp::TMPDIR)
37
+ end
38
+
39
+ def test_file_temp_auto_delete
40
+ assert_nothing_raised{ @fh = File::Temp.new }
41
+ assert_nothing_raised{ @fh.print "hello" }
42
+ assert_nothing_raised{ @fh.close }
43
+ end
44
+
45
+ def test_file_temp_no_delete
46
+ assert_nothing_raised{ @fh = File::Temp.new(false) }
47
+ assert_nothing_raised{ @fh.print "hello" }
48
+ assert_nothing_raised{ @fh.close }
49
+ assert_true(Dir["#{@dir}/rb_file_temp*"].length == 1)
50
+ end
51
+
52
+ def test_file_temp_no_delete_with_template
53
+ assert_nothing_raised{ File::Temp.new(false, 'temp_foo_XXXXXX').close }
54
+ assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
55
+ end
56
+
57
+ def test_file_temp_no_delete_with_block
58
+ assert_nothing_raised{ File::Temp.open(false, 'temp_foo_XXXXXX'){ |fh| fh.puts "hello" } }
59
+ assert_true(Dir["#{@dir}/temp_foo*"].length >= 1)
60
+ end
61
+
62
+ def test_file_temp_expected_errors
63
+ assert_raise(TypeError, ArgumentError){ @fh = File::Temp.new(false, 1) }
64
+ assert_raise(ArgumentError){ @fh = File::Temp.new(true, 'temp_bar_XXXXX', 1) }
65
+ end
66
+
67
+ def test_file_temp_name_basic_functionality
68
+ assert_respond_to(File::Temp, :temp_name)
69
+ assert_nothing_raised{ File::Temp.temp_name }
70
+ assert_kind_of(String, File::Temp.temp_name)
71
+ end
72
+
73
+ def test_file_temp_name
74
+ assert_equal('.tmp', File.extname(File::Temp.temp_name))
75
+ end
76
+
77
+ def teardown
78
+ @dir = nil
79
+ @template = nil
80
+ @fh.close if @fh && !@fh.closed?
81
+ @fh = nil
82
+
83
+ Dir["temp_*"].each{ |f| File.delete(f) }
84
+ Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
85
+
86
+ Dir.chdir(File::Temp::TMPDIR) do
87
+ Dir["temp_*"].each{ |f| File.delete(f) }
88
+ Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
89
+ end
90
+ end
91
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file-temp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -9,30 +9,61 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-12 00:00:00 -06:00
12
+ date: 2009-10-21 00:00:00 -06:00
13
13
  default_executable:
14
- dependencies: []
15
-
16
- description: An alternative way to generate tempfiles
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: use
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: ffi
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: test-unit
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.3
44
+ version:
45
+ description: " The file-temp library provides an alternative approach to generating\n temporary files. Features included improved security, a superior\n interface, and better support for MS Windows.\n"
17
46
  email: djberg96@gmail.com
18
47
  executables: []
19
48
 
20
- extensions:
21
- - ext/extconf.rb
49
+ extensions: []
50
+
22
51
  extra_rdoc_files:
23
52
  - CHANGES
24
53
  - README
25
54
  - MANIFEST
26
- - ext/temp.c
27
55
  files:
28
- - test/tc_file_temp.rb
29
56
  - CHANGES
57
+ - file-temp.gemspec
58
+ - lib/file/temp.rb
30
59
  - MANIFEST
31
60
  - Rakefile
32
61
  - README
33
- - ext/temp.c
62
+ - test/test_file_temp.rb
34
63
  has_rdoc: true
35
64
  homepage: http://www.rubyforge.org/projects/shards
65
+ licenses: []
66
+
36
67
  post_install_message:
37
68
  rdoc_options: []
38
69
 
@@ -42,7 +73,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
73
  requirements:
43
74
  - - ">="
44
75
  - !ruby/object:Gem::Version
45
- version: 1.8.0
76
+ version: 1.8.6
46
77
  version:
47
78
  required_rubygems_version: !ruby/object:Gem::Requirement
48
79
  requirements:
@@ -53,9 +84,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
84
  requirements: []
54
85
 
55
86
  rubyforge_project: shards
56
- rubygems_version: 1.0.1
87
+ rubygems_version: 1.3.5
57
88
  signing_key:
58
- specification_version: 2
59
- summary: An alternative way to generate tempfiles
89
+ specification_version: 3
90
+ summary: An alternative way to generate temp files
60
91
  test_files:
61
- - test/tc_file_temp.rb
92
+ - test/test_file_temp.rb
data/ext/extconf.rb DELETED
@@ -1,13 +0,0 @@
1
- require 'mkmf'
2
- dir_config('tmpfile')
3
-
4
- have_func('tmpfile_s')
5
- have_func('_sopen_s')
6
-
7
- unless have_func('tmpfile')
8
- raise 'This library is not supported on your platform. Aborting'
9
- end
10
-
11
- have_func('mkstemp')
12
-
13
- create_makefile('file/temp')
data/ext/temp.c DELETED
@@ -1,120 +0,0 @@
1
- #include <ruby.h>
2
- #include <stdio.h>
3
- #include <sys/stat.h>
4
-
5
- #ifdef HAVE__SOPEN_S
6
- #include <share.h>
7
- #endif
8
-
9
- #ifndef HAVE_MKSTEMP
10
- #include <fcntl.h>
11
- #include <temp.h>
12
- #endif
13
-
14
- #ifndef P_tmpdir
15
- #define P_tmpdir "/tmp"
16
- #endif
17
-
18
- #define VERSION "1.0.0"
19
-
20
- VALUE cFileTemp;
21
-
22
- /* call-seq:
23
- * FileTemp.new(delete = true, template = 'rb_file_temp_XXXXXX') => file
24
- *
25
- * Creates a new, anonymous temporary file in your FileTemp::TMPDIR directory,
26
- * or /tmp if that cannot be accessed. If your $TMPDIR environment variable is
27
- * set, it will be used instead. If $TMPDIR is not writable by the process, it
28
- * will resort back to FileTemp::TMPDIR or /tmp.
29
- *
30
- * If the +delete+ option is set to true (the default) then the temporary file
31
- * will be deleted automatically as soon as all references to it are closed.
32
- * Otherwise, the file will live on in your $TMPDIR.
33
- *
34
- * If the +delete+ option is set to false, then the file is *not* deleted. In
35
- * addition, you can supply a string +template+ that the system replaces with
36
- * a unique filename. This template should end with 3 to 6 'X' characters.
37
- * The default template is 'rb_file_temp_XXXXXX'. In this case the temporary
38
- * file lives in the directory where it was created.
39
- *
40
- * The +template+ argument is ignored if the +delete+ argument is true.
41
- */
42
- static VALUE tempfile_init(int argc, VALUE* argv, VALUE self){
43
- VALUE v_args[2];
44
- VALUE v_delete;
45
- VALUE v_template;
46
-
47
- rb_scan_args(argc, argv, "02", &v_delete, &v_template);
48
-
49
- if(NIL_P(v_delete))
50
- v_delete = Qtrue;
51
-
52
- if(RTEST(v_delete)){
53
- #ifdef HAVE_TMPFILE_S
54
- FILE* fptr;
55
-
56
- if(tmpfile_s(&fptr))
57
- rb_sys_fail("tmpfile_s()");
58
- #else
59
- FILE* fptr = tmpfile();
60
- if(!fptr)
61
- rb_sys_fail("tmpfile()");
62
- #endif
63
- v_args[0] = INT2FIX(fileno(fptr));
64
- }
65
- else{
66
- int fd, omask;
67
-
68
- if(NIL_P(v_template))
69
- v_template = rb_str_new2("rb_file_temp_XXXXXX");
70
-
71
- /* Set the umask to improve security */
72
- omask = umask(077);
73
- fd = mkstemp(StringValuePtr(v_template));
74
- umask(omask);
75
-
76
- if(fd < 0)
77
- rb_sys_fail("mkstemp()");
78
-
79
- v_args[0] = INT2FIX(fd);
80
- }
81
-
82
- /* This bit of explicitness is necessary for MS Windows */
83
- v_args[1] = rb_str_new2("wb+");
84
-
85
- return rb_call_super(2, v_args);
86
- }
87
-
88
- /*
89
- * Generates a unique file name, prefixed with the value of FileTemp::TMPDIR.
90
- * Note that a file is not actually generated on the filesystem.
91
- */
92
- static VALUE tempfile_tmpnam(VALUE klass){
93
- char buf[L_tmpnam];
94
- return rb_str_new2(tmpnam(buf));
95
- }
96
-
97
- void Init_temp(){
98
-
99
- /* The FileTemp class creates managed temporary files. Unlike Ruby's
100
- * Tempfile class from this standard library, this is a subclass of File.
101
- * In addition, the temporary file is automatically deleted when all
102
- * references to it are closed (instead of waiting until the Ruby process
103
- * is complete).
104
- */
105
- cFileTemp = rb_define_class("FileTemp", rb_cFile);
106
-
107
- /* Instance Methods */
108
- rb_define_method(cFileTemp, "initialize", tempfile_init, -1);
109
-
110
- /* Singleton Methods */
111
- rb_define_singleton_method(cFileTemp, "temp_name", tempfile_tmpnam, 0);
112
-
113
- /* Constants */
114
-
115
- /* ENV['P_tmpdir']: Your system's tmpdir */
116
- rb_define_const(cFileTemp, "TMPDIR", rb_str_new2(P_tmpdir));
117
-
118
- /* 0.1.3: The version of this library */
119
- rb_define_const(cFileTemp, "VERSION", rb_str_new2(VERSION));
120
- }
data/test/tc_file_temp.rb DELETED
@@ -1,64 +0,0 @@
1
- ######################################################################
2
- # tc_file_temp.rb
3
- #
4
- # Test suite for the file-temp library. These tests should be run
5
- # via the 'rake test' task.
6
- ######################################################################
7
- require 'test/unit'
8
- require 'file/temp'
9
-
10
- class TC_File_Temp < Test::Unit::TestCase
11
- def setup
12
- @template = 'file-temp-test-XXXXX'
13
- @fh = nil
14
- end
15
-
16
- def test_file_temp_version
17
- assert_equal('1.0.0', FileTemp::VERSION)
18
- end
19
-
20
- def test_file_temp_threaded
21
- threads = []
22
- assert_nothing_raised{ 100.times{ threads << Thread.new{ FileTemp.new }}}
23
- assert_nothing_raised{ threads.join }
24
- end
25
-
26
- def test_file_temp_tmpdir
27
- assert_not_nil(FileTemp::TMPDIR)
28
- assert_kind_of(String, FileTemp::TMPDIR)
29
- unless RUBY_PLATFORM.match('mswin')
30
- assert_equal(true, ['/tmp', '/var/tmp/'].include?(FileTemp::TMPDIR))
31
- end
32
- end
33
-
34
- def test_file_temp_auto_delete
35
- assert_nothing_raised{ @fh = FileTemp.new }
36
- assert_nothing_raised{ @fh.print "hello" }
37
- assert_nothing_raised{ @fh.close }
38
- end
39
-
40
- def test_file_temp_no_delete
41
- assert_nothing_raised{ @fh = FileTemp.new(false) }
42
- assert_equal(true, Dir["rb_file_temp*"].length == 1)
43
- assert_nothing_raised{ @fh.print "hello" }
44
- assert_nothing_raised{ @fh.close }
45
- end
46
-
47
- def test_file_temp_no_delete_with_template
48
- assert_nothing_raised{ @fh = FileTemp.new(false, 'temp_foo_XXXXX') }
49
- assert_equal(true, Dir["temp_foo*"].length == 1)
50
- end
51
-
52
- def test_file_temp_expected_errors
53
- assert_raise(TypeError){ @fh = FileTemp.new(false, 1) }
54
- assert_raise(ArgumentError){ @fh = FileTemp.new(true, 'temp_bar_XXXXX', 1) }
55
- end
56
-
57
- def teardown
58
- @template = nil
59
- @fh.close if @fh && !@fh.closed?
60
- @fh = nil
61
- Dir["temp_*"].each{ |f| File.delete(f) }
62
- Dir["rb_file_temp_*"].each{ |f| File.delete(f) }
63
- end
64
- end