io-extra 1.1.1 → 1.2.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.
- data/CHANGES +10 -0
- data/MANIFEST +1 -1
- data/README +15 -6
- data/Rakefile +61 -0
- data/examples/example_io_extra.rb +42 -0
- data/ext/extconf.rb +19 -1
- data/ext/io/extra.c +170 -24
- data/io-extra.gemspec +42 -0
- data/test/test_io_extra.rb +59 -26
- metadata +27 -11
data/CHANGES
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 1.2.0 - 28-Jul-2009
|
2
|
+
* Several Linux compatibility fixes, all provided by Eric Wong.
|
3
|
+
* Now compatible with 1.9.x thanks to Eric Wong.
|
4
|
+
* Bug fix for IO.pread - memory leak and null byte behavior spotted and
|
5
|
+
fixed by Eric Wong.
|
6
|
+
* Changed license to Artistic 2.0.
|
7
|
+
* Added test-unit 2.x as a development dependency.
|
8
|
+
* Several tests were updated to use features from test-unit 2.x.
|
9
|
+
* Fixed the 'example' rake task.
|
10
|
+
|
1
11
|
== 1.1.1 - 8-Sep-2008
|
2
12
|
* Added the IO.pread_ptr method. This returns the buffer address
|
3
13
|
rather than the buffer itself.
|
data/MANIFEST
CHANGED
data/README
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
The io-extra library provides a few extra IO methods that you may find
|
3
3
|
handy. They are IO.closefrom, IO.fdwalk, IO#directio? and IO#directio=.
|
4
4
|
|
5
|
-
Not supported on MS Windows
|
5
|
+
Not supported on MS Windows.
|
6
|
+
|
7
|
+
Limited support for OS X.
|
6
8
|
|
7
9
|
= Installation
|
8
10
|
== Standard Installation
|
@@ -10,6 +12,9 @@ Not supported on MS Windows or OS X.
|
|
10
12
|
rake install
|
11
13
|
|
12
14
|
== Gem Installation
|
15
|
+
=== Remote
|
16
|
+
gem install io-extra
|
17
|
+
=== Local
|
13
18
|
rake test (optional)
|
14
19
|
rake install_gem
|
15
20
|
|
@@ -51,17 +56,21 @@ For further documentation, see the io_extra.txt file or the inline
|
|
51
56
|
documentation that was generated by RDoc (if you did a gem install).
|
52
57
|
|
53
58
|
= Known Issues
|
54
|
-
None that I'm aware of. Please file any bug
|
55
|
-
at http://www.rubyforge.org/projects/shards.
|
59
|
+
None that I'm aware of (beyond those documented above). Please file any bug
|
60
|
+
reports on the project page at http://www.rubyforge.org/projects/shards.
|
56
61
|
|
57
62
|
= Future Plans
|
58
|
-
I may add the File::O_DIRECT open constant on platforms that support it.
|
63
|
+
* I may add the File::O_DIRECT open constant on platforms that support it.
|
64
|
+
* Switch from C extension to FFI.
|
65
|
+
|
66
|
+
= Acknowledgements
|
67
|
+
Eric Wong for some great work on Linux compatibility and other fixes.
|
59
68
|
|
60
69
|
= License
|
61
|
-
|
70
|
+
Artistic 2.0
|
62
71
|
|
63
72
|
= Copyright
|
64
|
-
(C) 2003-
|
73
|
+
(C) 2003-2009 Daniel J. Berger
|
65
74
|
All Rights Reserved
|
66
75
|
|
67
76
|
= Warranty
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rbconfig'
|
5
|
+
include Config
|
6
|
+
|
7
|
+
case RUBY_PLATFORM
|
8
|
+
when /mswin/i
|
9
|
+
STDERR.puts 'Not supported on this platform. Exiting.'
|
10
|
+
exit(-1)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Clean the build files for the io-extra source"
|
14
|
+
task :clean do
|
15
|
+
FileUtils.rm_rf('io') if File.exists?('io')
|
16
|
+
Dir.chdir('ext') do
|
17
|
+
sh 'make distclean' if File.exists?('extra.o')
|
18
|
+
|
19
|
+
FileUtils.rm_rf('extra/extra.c') if File.exists?('extra.c')
|
20
|
+
|
21
|
+
build_file = File.join(Dir.pwd, 'io', 'extra.' + Config::CONFIG['DLEXT'])
|
22
|
+
File.delete(build_file) if File.exists?(build_file)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Build the io-extra library (but don't install it)"
|
27
|
+
task :build => [:clean] do
|
28
|
+
Dir.chdir('ext') do
|
29
|
+
ruby 'extconf.rb'
|
30
|
+
sh 'make'
|
31
|
+
build_file = File.join(Dir.pwd, 'extra.' + Config::CONFIG['DLEXT'])
|
32
|
+
Dir.mkdir('io') unless File.exists?('io')
|
33
|
+
FileUtils.cp(build_file, 'io')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Install the io-extra package (non-gem)"
|
38
|
+
task :install => [:build] do
|
39
|
+
Dir.chdir('ext') do
|
40
|
+
sh 'make install'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Install the io-extra package as a gem"
|
45
|
+
task :install_gem do
|
46
|
+
ruby 'io-extra.gemspec'
|
47
|
+
file = Dir["io-extra*.gem"].last
|
48
|
+
sh "gem install #{file}"
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Run the example io-extra program"
|
52
|
+
task :example => [:build] do
|
53
|
+
ruby '-Iext examples/example_io_extra.rb'
|
54
|
+
end
|
55
|
+
|
56
|
+
Rake::TestTask.new do |t|
|
57
|
+
task :test => :build
|
58
|
+
t.libs << 'ext'
|
59
|
+
t.verbose = true
|
60
|
+
t.warning = true
|
61
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
##############################################################################
|
2
|
+
# test.rb
|
3
|
+
#
|
4
|
+
# This is a small test program for the io-extra library. Modify as you see
|
5
|
+
# fit. You can run this via the 'rake example' task.
|
6
|
+
##############################################################################
|
7
|
+
require "io/extra"
|
8
|
+
p IO::EXTRA_VERSION
|
9
|
+
|
10
|
+
fh = File.open("foo.txt","w+")
|
11
|
+
|
12
|
+
=begin
|
13
|
+
p fh.directio?
|
14
|
+
|
15
|
+
fh.directio = IO::DIRECTIO_ON
|
16
|
+
p fh.directio?
|
17
|
+
|
18
|
+
fh.close
|
19
|
+
=end
|
20
|
+
|
21
|
+
IO.fdwalk(0){ |handle|
|
22
|
+
p handle
|
23
|
+
p handle.fileno
|
24
|
+
puts
|
25
|
+
}
|
26
|
+
|
27
|
+
=begin
|
28
|
+
STDIN.close
|
29
|
+
|
30
|
+
# Should print "Hello" 2 times
|
31
|
+
IO.fdwalk(0){ |fd|
|
32
|
+
puts "Hello #{fd}"
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
IO.closefrom(0)
|
37
|
+
|
38
|
+
puts "Done" # Shouldn't see this
|
39
|
+
=end
|
40
|
+
|
41
|
+
fh.close
|
42
|
+
File.delete("foo.txt") if File.exists?("foo.txt")
|
data/ext/extconf.rb
CHANGED
@@ -4,14 +4,32 @@ require 'rbconfig'
|
|
4
4
|
|
5
5
|
dir_config('io')
|
6
6
|
|
7
|
+
have_header('stdint.h')
|
8
|
+
have_header('sys/resource.h')
|
7
9
|
have_func('closefrom')
|
8
10
|
have_func('fdwalk')
|
9
11
|
have_func('directio')
|
10
12
|
have_func('pread')
|
11
13
|
have_func('pwrite')
|
14
|
+
have_func('rb_str_set_len', 'ruby.h')
|
12
15
|
|
13
|
-
|
16
|
+
case Config::CONFIG['host_os']
|
17
|
+
when /darwin/i
|
14
18
|
$CPPFLAGS += " -D_MACOS"
|
19
|
+
when /linux/i
|
20
|
+
# this may be needed for other platforms as well
|
21
|
+
$CPPFLAGS += " -D_XOPEN_SOURCE=500"
|
22
|
+
|
23
|
+
# for O_DIRECT
|
24
|
+
$CPPFLAGS += " -D_GNU_SOURCE=1"
|
25
|
+
|
26
|
+
# we know Linux is always capable of this, but /proc/ may not be mounted
|
27
|
+
# at build time
|
28
|
+
$CPPFLAGS += %{ '-DPROC_SELF_FD_DIR="/proc/self/fd"'}
|
29
|
+
end
|
30
|
+
|
31
|
+
if have_macro("O_DIRECT", %w(sys/types.h fcntl.h))
|
32
|
+
$CPPFLAGS += " -DHAVE_O_DIRECT_MACRO"
|
15
33
|
end
|
16
34
|
|
17
35
|
create_makefile('io/extra', 'io')
|
data/ext/io/extra.c
CHANGED
@@ -1,16 +1,77 @@
|
|
1
1
|
/* Extra methods for the IO class */
|
2
2
|
#include "ruby.h"
|
3
|
+
#ifdef HAVE_RUBY_IO_H
|
4
|
+
#include "ruby/io.h"
|
5
|
+
#else
|
3
6
|
#include "rubyio.h"
|
7
|
+
#endif
|
8
|
+
|
4
9
|
#include <unistd.h>
|
5
10
|
#include <stdlib.h>
|
11
|
+
#include <errno.h>
|
12
|
+
|
13
|
+
#ifdef HAVE_STDINT_H
|
14
|
+
#include <stdint.h>
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#ifndef RSTRING_PTR
|
18
|
+
#define RSTRING_PTR(v) (RSTRING(v)->ptr)
|
19
|
+
#define RSTRING_LEN(v) (RSTRING(v)->len)
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#ifndef HAVE_RB_STR_SET_LEN
|
23
|
+
/* this is taken from Ruby 1.8.7, 1.8.6 may not have it */
|
24
|
+
static void rb_18_str_set_len(VALUE str, long len)
|
25
|
+
{
|
26
|
+
RSTRING(str)->len = len;
|
27
|
+
RSTRING(str)->ptr[len] = '\0';
|
28
|
+
}
|
29
|
+
#define rb_str_set_len(str,len) rb_18_str_set_len(str,len)
|
30
|
+
#endif
|
31
|
+
|
6
32
|
|
7
|
-
#
|
33
|
+
#ifdef PROC_SELF_FD_DIR
|
34
|
+
#include <dirent.h>
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#if !defined(HAVE_CLOSEFROM) || !defined(HAVE_FDWALK)
|
38
|
+
#ifdef HAVE_SYS_RESOURCE_H
|
8
39
|
#include <sys/resource.h>
|
9
40
|
#endif
|
41
|
+
static int open_max(void){
|
42
|
+
#ifdef HAVE_SYS_RESOURCE_H
|
43
|
+
struct rlimit limits;
|
44
|
+
|
45
|
+
if(!getrlimit(RLIMIT_NOFILE, &limits) &&
|
46
|
+
limits.rlim_max != RLIM_INFINITY &&
|
47
|
+
limits.rlim_max > 0 &&
|
48
|
+
limits.rlim_max <= INT_MAX)
|
49
|
+
return (int)limits.rlim_max;
|
50
|
+
#endif
|
51
|
+
#ifdef _SC_OPEN_MAX
|
52
|
+
{
|
53
|
+
long tmp;
|
54
|
+
|
55
|
+
if ((tmp = sysconf(_SC_OPEN_MAX)) && tmp > 0 && tmp <= INT_MAX)
|
56
|
+
return (int)tmp;
|
57
|
+
}
|
58
|
+
#endif
|
59
|
+
#ifdef OPEN_MAX
|
60
|
+
return OPEN_MAX;
|
61
|
+
#else
|
62
|
+
return 1024; /* a common limit */
|
63
|
+
#endif
|
64
|
+
}
|
65
|
+
#endif
|
10
66
|
|
11
|
-
#
|
67
|
+
#if defined(HAVE_DIRECTIO) || defined(HAVE_O_DIRECT_MACRO)
|
12
68
|
#include <sys/types.h>
|
69
|
+
#endif
|
13
70
|
#include <fcntl.h>
|
71
|
+
|
72
|
+
#ifndef DIRECTIO_OFF
|
73
|
+
#define DIRECTIO_OFF 0
|
74
|
+
#define DIRECTIO_ON 1
|
14
75
|
#endif
|
15
76
|
|
16
77
|
/*
|
@@ -22,30 +83,76 @@
|
|
22
83
|
*
|
23
84
|
* This method uses your system's builtin closefrom() function, if supported.
|
24
85
|
* Otherwise, it uses a manual, and (probably) less efficient approach.
|
25
|
-
*
|
86
|
+
*
|
26
87
|
*--
|
27
88
|
* The manual approach was copied from the closefrom() man page on Solaris 9.
|
28
|
-
* Not implemented on OS X because the getrlimit function is busted.
|
29
89
|
*/
|
30
90
|
static VALUE io_closefrom(VALUE klass, VALUE v_low_fd){
|
31
|
-
#ifdef _MACOS
|
32
|
-
rb_raise(rb_eNotImpError, "IO.closefrom is not implemented on this platform");
|
33
|
-
#endif
|
34
|
-
|
35
91
|
#ifdef HAVE_CLOSEFROM
|
36
92
|
closefrom(NUM2INT(v_low_fd));
|
37
93
|
#else
|
38
94
|
int i, lowfd;
|
39
|
-
|
40
|
-
getrlimit(RLIMIT_NOFILE, &limits);
|
95
|
+
int maxfd = open_max();
|
41
96
|
lowfd = NUM2INT(v_low_fd);
|
42
97
|
|
43
|
-
for(i = lowfd; i <
|
98
|
+
for(i = lowfd; i < maxfd; i++)
|
44
99
|
close(i);
|
45
100
|
#endif
|
46
101
|
return klass;
|
47
102
|
}
|
48
103
|
|
104
|
+
#ifndef HAVE_FDWALK
|
105
|
+
static int fdwalk(int (*func)(void *data, int fd), void *data){
|
106
|
+
int rv = 0;
|
107
|
+
int fd;
|
108
|
+
|
109
|
+
#ifdef PROC_SELF_FD_DIR
|
110
|
+
DIR *dir = opendir(PROC_SELF_FD_DIR);
|
111
|
+
|
112
|
+
if(dir){ /* procfs may not be mounted... */
|
113
|
+
struct dirent *ent;
|
114
|
+
int saved_errno;
|
115
|
+
int dir_fd = dirfd(dir);
|
116
|
+
|
117
|
+
while((ent = readdir(dir))){
|
118
|
+
char *err = NULL;
|
119
|
+
|
120
|
+
if(ent->d_name[0] == '.')
|
121
|
+
continue;
|
122
|
+
|
123
|
+
errno = 0;
|
124
|
+
fd = (int)strtol(ent->d_name, &err, 10);
|
125
|
+
|
126
|
+
if (errno || ! err || *err || fd == dir_fd)
|
127
|
+
continue;
|
128
|
+
|
129
|
+
if ((rv = func(data, fd)))
|
130
|
+
break;
|
131
|
+
}
|
132
|
+
saved_errno = errno;
|
133
|
+
closedir(dir);
|
134
|
+
errno = saved_errno;
|
135
|
+
} else
|
136
|
+
#endif /* PROC_SELF_FD_DIR */
|
137
|
+
{
|
138
|
+
int maxfd = open_max();
|
139
|
+
|
140
|
+
for(fd = 0; fd < maxfd; fd++){
|
141
|
+
/* use fcntl to detect whether fd is a valid file descriptor */
|
142
|
+
errno = 0;
|
143
|
+
if(fcntl(fd, F_GETFD) < 0)
|
144
|
+
continue;
|
145
|
+
|
146
|
+
errno = 0;
|
147
|
+
if ((rv = func(data, fd)))
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
return rv;
|
152
|
+
}
|
153
|
+
#define HAVE_FDWALK
|
154
|
+
#endif
|
155
|
+
|
49
156
|
#ifdef HAVE_FDWALK
|
50
157
|
/*
|
51
158
|
* Used by io_fdwalk. Yields a File object back to the block.
|
@@ -53,7 +160,7 @@ static VALUE io_closefrom(VALUE klass, VALUE v_low_fd){
|
|
53
160
|
*/
|
54
161
|
static int close_func(void* lowfd, int fd){
|
55
162
|
VALUE v_args[1];
|
56
|
-
|
163
|
+
|
57
164
|
v_args[0] = UINT2NUM(fd);
|
58
165
|
rb_yield(rb_class_new_instance(1, v_args, rb_cFile));
|
59
166
|
return 0;
|
@@ -75,12 +182,12 @@ static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
|
75
182
|
lowfd = NUM2INT(v_low_fd);
|
76
183
|
|
77
184
|
fdwalk(close_func, &lowfd);
|
78
|
-
|
185
|
+
|
79
186
|
return klass;
|
80
187
|
}
|
81
188
|
#endif
|
82
189
|
|
83
|
-
#
|
190
|
+
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT)
|
84
191
|
/*
|
85
192
|
* call-seq:
|
86
193
|
* IO#directio?
|
@@ -89,6 +196,7 @@ static VALUE io_fdwalk(int argc, VALUE* argv, VALUE klass){
|
|
89
196
|
* current handle. The default is false.
|
90
197
|
*/
|
91
198
|
static VALUE io_get_directio(VALUE self){
|
199
|
+
#if defined(HAVE_DIRECTIO)
|
92
200
|
VALUE v_advice = Qnil;
|
93
201
|
|
94
202
|
if(rb_ivar_defined(rb_cIO, rb_intern("@directio")))
|
@@ -98,6 +206,15 @@ static VALUE io_get_directio(VALUE self){
|
|
98
206
|
v_advice = Qfalse;
|
99
207
|
|
100
208
|
return v_advice;
|
209
|
+
#elif defined(O_DIRECT)
|
210
|
+
int fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
|
211
|
+
int flags = fcntl(fd, F_GETFL);
|
212
|
+
|
213
|
+
if(flags < 0)
|
214
|
+
rb_sys_fail("fcntl");
|
215
|
+
|
216
|
+
return (flags & O_DIRECT) ? Qtrue : Qfalse;
|
217
|
+
#endif /* O_DIRECT */
|
101
218
|
}
|
102
219
|
|
103
220
|
/*
|
@@ -122,11 +239,32 @@ static VALUE io_set_directio(VALUE self, VALUE v_advice){
|
|
122
239
|
/* Retrieve the current file descriptor in order to pass it to directio() */
|
123
240
|
fd = NUM2INT(rb_funcall(self, rb_intern("fileno"), 0, 0));
|
124
241
|
|
242
|
+
#if defined(HAVE_DIRECTIO)
|
125
243
|
if(directio(fd, advice) < 0)
|
126
244
|
rb_raise(rb_eStandardError, "The directio() call failed");
|
127
245
|
|
128
246
|
if(advice == DIRECTIO_ON)
|
129
247
|
rb_iv_set(self, "directio", Qtrue);
|
248
|
+
#else
|
249
|
+
{
|
250
|
+
int flags = fcntl(fd, F_GETFL);
|
251
|
+
|
252
|
+
if(flags < 0)
|
253
|
+
rb_sys_fail("fcntl");
|
254
|
+
|
255
|
+
if(advice == DIRECTIO_OFF){
|
256
|
+
if(flags & O_DIRECT){
|
257
|
+
if(fcntl(fd, F_SETFL, flags & ~O_DIRECT) < 0)
|
258
|
+
rb_sys_fail("fcntl");
|
259
|
+
}
|
260
|
+
} else { /* DIRECTIO_ON */
|
261
|
+
if(!(flags & O_DIRECT)){
|
262
|
+
if(fcntl(fd, F_SETFL, flags | O_DIRECT) < 0)
|
263
|
+
rb_sys_fail("fcntl");
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
#endif
|
130
268
|
|
131
269
|
return self;
|
132
270
|
}
|
@@ -144,12 +282,15 @@ static VALUE s_io_pread(VALUE klass, VALUE v_fd, VALUE v_nbyte, VALUE v_offset){
|
|
144
282
|
int fd = NUM2INT(v_fd);
|
145
283
|
size_t nbyte = NUM2ULONG(v_nbyte);
|
146
284
|
off_t offset = NUM2ULONG(v_offset);
|
147
|
-
|
285
|
+
VALUE str = rb_str_new(NULL, nbyte);
|
286
|
+
ssize_t nread = pread(fd, RSTRING_PTR(str), nbyte, offset);
|
148
287
|
|
149
|
-
if(
|
288
|
+
if (nread < 0)
|
150
289
|
rb_sys_fail("pread");
|
290
|
+
if (nread != nbyte)
|
291
|
+
rb_str_set_len(str, nread);
|
151
292
|
|
152
|
-
return
|
293
|
+
return str;
|
153
294
|
}
|
154
295
|
|
155
296
|
/*
|
@@ -192,8 +333,8 @@ static VALUE s_io_pwrite(VALUE klass, VALUE v_fd, VALUE v_buf, VALUE v_offset){
|
|
192
333
|
|
193
334
|
result = pwrite(
|
194
335
|
NUM2INT(v_fd),
|
195
|
-
|
196
|
-
|
336
|
+
RSTRING_PTR(v_buf),
|
337
|
+
RSTRING_LEN(v_buf),
|
197
338
|
NUM2INT(v_offset)
|
198
339
|
);
|
199
340
|
|
@@ -214,17 +355,22 @@ void Init_extra(){
|
|
214
355
|
rb_define_singleton_method(rb_cIO, "fdwalk", io_fdwalk, -1);
|
215
356
|
#endif
|
216
357
|
|
217
|
-
#
|
358
|
+
#if defined(HAVE_DIRECTIO) || defined(O_DIRECT)
|
218
359
|
rb_define_method(rb_cIO, "directio?", io_get_directio, 0);
|
219
360
|
rb_define_method(rb_cIO, "directio=", io_set_directio, 1);
|
220
|
-
|
361
|
+
|
221
362
|
/* 0: Applications get the default system behavior when accessing file data. */
|
222
363
|
rb_define_const(rb_cIO, "DIRECTIO_OFF", UINT2NUM(DIRECTIO_OFF));
|
223
|
-
|
364
|
+
|
224
365
|
/* 1: File data is not cached in the system's memory pages. */
|
225
366
|
rb_define_const(rb_cIO, "DIRECTIO_ON", UINT2NUM(DIRECTIO_ON));
|
226
367
|
#endif
|
227
368
|
|
369
|
+
#ifdef O_DIRECT
|
370
|
+
/* 040000: direct disk access (in Linux) */
|
371
|
+
rb_define_const(rb_cIO, "DIRECT", UINT2NUM(O_DIRECT));
|
372
|
+
#endif
|
373
|
+
|
228
374
|
#ifdef HAVE_PREAD
|
229
375
|
rb_define_singleton_method(rb_cIO, "pread", s_io_pread, 3);
|
230
376
|
rb_define_singleton_method(rb_cIO, "pread_ptr", s_io_pread_ptr, 3);
|
@@ -234,6 +380,6 @@ void Init_extra(){
|
|
234
380
|
rb_define_singleton_method(rb_cIO, "pwrite", s_io_pwrite, 3);
|
235
381
|
#endif
|
236
382
|
|
237
|
-
/* 1.
|
238
|
-
rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_new2("1.
|
383
|
+
/* 1.2.0: The version of this library. This a string. */
|
384
|
+
rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_new2("1.2.0"));
|
239
385
|
}
|
data/io-extra.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
spec = Gem::Specification.new do |gem|
|
5
|
+
if Config::CONFIG['host_os'] =~ /mswin|dos|win32/i
|
6
|
+
STDERR.puts 'Not supported on this platform. Exiting.'
|
7
|
+
exit(-1)
|
8
|
+
end
|
9
|
+
|
10
|
+
gem.name = 'io-extra'
|
11
|
+
gem.version = '1.2.0'
|
12
|
+
gem.author = 'Daniel J. Berger'
|
13
|
+
gem.license = 'Artistic 2.0'
|
14
|
+
gem.email = 'djberg96@gmail.com'
|
15
|
+
gem.homepage = 'http://www.rubyforge.org/projects/shards'
|
16
|
+
gem.platform = Gem::Platform::RUBY
|
17
|
+
gem.summary = 'Adds extra methods to the IO class.'
|
18
|
+
gem.test_file = 'test/test_io_extra.rb'
|
19
|
+
gem.extensions = ['ext/extconf.rb']
|
20
|
+
gem.files = Dir['**/*'].reject{ |f| f.include?('CVS') }
|
21
|
+
|
22
|
+
gem.extra_rdoc_files = [
|
23
|
+
'CHANGES',
|
24
|
+
'README',
|
25
|
+
'MANIFEST',
|
26
|
+
'ext/io/extra.c'
|
27
|
+
]
|
28
|
+
|
29
|
+
gem.rubyforge_project = 'shards'
|
30
|
+
gem.required_ruby_version = '>= 1.8.0'
|
31
|
+
|
32
|
+
gem.add_development_dependency('test-unit', '>= 2.0.3')
|
33
|
+
|
34
|
+
gem.description = <<-EOF
|
35
|
+
Adds the IO.closefrom, IO.fdwalk, IO.pread, IO.pread_ptr, and IO.pwrite
|
36
|
+
class methods as well as the IO#directio and IO#directio? instance
|
37
|
+
methods (for those platforms that support them).
|
38
|
+
EOF
|
39
|
+
end
|
40
|
+
|
41
|
+
Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
|
42
|
+
Gem::Builder.new(spec).build
|
data/test/test_io_extra.rb
CHANGED
@@ -4,7 +4,11 @@
|
|
4
4
|
# Test suite for the io-extra library. This test should be run via the
|
5
5
|
# 'rake test' task.
|
6
6
|
###########################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
7
10
|
require 'test/unit'
|
11
|
+
require 'rbconfig'
|
8
12
|
require 'io/extra'
|
9
13
|
|
10
14
|
class TC_IO_Extra < Test::Unit::TestCase
|
@@ -15,40 +19,51 @@ class TC_IO_Extra < Test::Unit::TestCase
|
|
15
19
|
end
|
16
20
|
|
17
21
|
def test_version
|
18
|
-
assert_equal('1.
|
22
|
+
assert_equal('1.2.0', IO::EXTRA_VERSION)
|
19
23
|
end
|
20
|
-
|
21
|
-
unless Config::CONFIG['host_os'] =~ /darwin/i
|
22
|
-
def test_directio
|
23
|
-
assert_respond_to(@fh, :directio?)
|
24
|
-
assert_nothing_raised{ @fh.directio? }
|
25
|
-
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
def test_direct_constant
|
26
|
+
omit_unless(Config::CONFIG['host_os'] =~ /linux/i, 'Linux-only')
|
27
|
+
assert_equal(040000, IO::DIRECT)
|
28
|
+
assert_equal(040000, File::DIRECT)
|
29
|
+
end
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
def test_open_direct
|
32
|
+
omit_unless(Config::CONFIG['host_os'] =~ /linux/i, 'Linux-only')
|
33
|
+
assert_nothing_raised do
|
34
|
+
fh = File.open(@fh.path, IO::RDWR|IO::DIRECT)
|
35
|
+
fh.close
|
36
36
|
end
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
def test_directio
|
40
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
41
|
+
assert_respond_to(@fh, :directio?)
|
42
|
+
assert_nothing_raised{ @fh.directio? }
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_directio_set
|
46
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
47
|
+
assert_respond_to(@fh, :directio=)
|
48
|
+
assert_raises(StandardError){ @fh.directio = 99 }
|
49
|
+
assert_nothing_raised{ @fh.directio = IO::DIRECTIO_ON }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_constants
|
53
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
54
|
+
assert_not_nil(IO::DIRECTIO_ON)
|
55
|
+
assert_not_nil(IO::DIRECTIO_OFF)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_fdwalk
|
59
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
60
|
+
assert_respond_to(IO, :fdwalk)
|
61
|
+
assert_nothing_raised{ IO.fdwalk(0){ } }
|
42
62
|
end
|
43
63
|
|
44
64
|
def test_closefrom
|
45
65
|
assert_respond_to(IO, :closefrom)
|
46
|
-
|
47
|
-
if Config::CONFIG['host_os'] =~ /darwin/i
|
48
|
-
assert_raise(NotImplementedError){ IO.closefrom(3) }
|
49
|
-
else
|
50
|
-
assert_nothing_raised{ IO.closefrom(3) }
|
51
|
-
end
|
66
|
+
assert_nothing_raised{ IO.closefrom(3) }
|
52
67
|
end
|
53
68
|
|
54
69
|
def test_pread
|
@@ -58,11 +73,29 @@ class TC_IO_Extra < Test::Unit::TestCase
|
|
58
73
|
assert_equal("quick", IO.pread(@fh.fileno, 5, 4))
|
59
74
|
end
|
60
75
|
|
76
|
+
def test_pread_binary
|
77
|
+
@fh.close rescue nil
|
78
|
+
@fh = File.open(@file, "ab")
|
79
|
+
@fh.binmode
|
80
|
+
size = @fh.stat.size
|
81
|
+
assert_nothing_raised { @fh.syswrite("FOO\0HELLO") }
|
82
|
+
@fh.close rescue nil
|
83
|
+
@fh = File.open(@file)
|
84
|
+
assert_equal("O\0H", IO.pread(@fh.fileno, 3, size + 2))
|
85
|
+
end
|
86
|
+
|
61
87
|
def test_pread_ptr
|
62
88
|
@fh.close rescue nil
|
63
89
|
@fh = File.open(@file)
|
64
90
|
assert_respond_to(IO, :pread_ptr)
|
65
|
-
assert_kind_of(
|
91
|
+
assert_kind_of(Integer, IO.pread_ptr(@fh.fileno, 5, 4))
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_pread_last
|
95
|
+
@fh.close rescue nil
|
96
|
+
@fh = File.open(@file)
|
97
|
+
size = @fh.stat.size
|
98
|
+
assert_equal("ck\n", IO.pread(@fh.fileno, 5, size - 3))
|
66
99
|
end
|
67
100
|
|
68
101
|
def test_pwrite
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-extra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -9,11 +9,20 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-07-28 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: test-unit
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.3
|
24
|
+
version:
|
25
|
+
description: " Adds the IO.closefrom, IO.fdwalk, IO.pread, IO.pread_ptr, and IO.pwrite\n class methods as well as the IO#directio and IO#directio? instance\n methods (for those platforms that support them).\n"
|
17
26
|
email: djberg96@gmail.com
|
18
27
|
executables: []
|
19
28
|
|
@@ -23,15 +32,22 @@ extra_rdoc_files:
|
|
23
32
|
- CHANGES
|
24
33
|
- README
|
25
34
|
- MANIFEST
|
35
|
+
- ext/io/extra.c
|
26
36
|
files:
|
37
|
+
- CHANGES
|
27
38
|
- doc/io_extra.txt
|
28
|
-
-
|
39
|
+
- examples/example_io_extra.rb
|
40
|
+
- ext/extconf.rb
|
29
41
|
- ext/io/extra.c
|
30
|
-
-
|
31
|
-
- README
|
42
|
+
- io-extra.gemspec
|
32
43
|
- MANIFEST
|
44
|
+
- Rakefile
|
45
|
+
- README
|
46
|
+
- test/test_io_extra.rb
|
33
47
|
has_rdoc: true
|
34
48
|
homepage: http://www.rubyforge.org/projects/shards
|
49
|
+
licenses:
|
50
|
+
- Artistic 2.0
|
35
51
|
post_install_message:
|
36
52
|
rdoc_options: []
|
37
53
|
|
@@ -52,9 +68,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
68
|
requirements: []
|
53
69
|
|
54
70
|
rubyforge_project: shards
|
55
|
-
rubygems_version: 1.
|
71
|
+
rubygems_version: 1.3.5
|
56
72
|
signing_key:
|
57
|
-
specification_version:
|
58
|
-
summary: Adds
|
73
|
+
specification_version: 3
|
74
|
+
summary: Adds extra methods to the IO class.
|
59
75
|
test_files:
|
60
76
|
- test/test_io_extra.rb
|