io-extra 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -4,7 +4,7 @@
4
4
  * Rakefile
5
5
  * io-extra.gemspec
6
6
  * doc/io_extra.txt
7
- * examples/test.rb
7
+ * examples/example_io_extra.rb
8
8
  * ext/extconf.rb
9
9
  * ext/io/extra.c
10
10
  * test/test_io_extra.rb
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 or OS X.
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 reports on the project page
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
- Ruby's
70
+ Artistic 2.0
62
71
 
63
72
  = Copyright
64
- (C) 2003-2008 Daniel J. Berger
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
- if Config::CONFIG['host_os'] =~ /darwin/i
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
- #ifndef HAVE_CLOSEFROM
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
- #ifdef HAVE_DIRECTIO
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
- struct rlimit limits;
40
- getrlimit(RLIMIT_NOFILE, &limits);
95
+ int maxfd = open_max();
41
96
  lowfd = NUM2INT(v_low_fd);
42
97
 
43
- for(i = lowfd; i < limits.rlim_max; 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
- #ifdef HAVE_DIRECTIO
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
- char* buf = malloc(nbyte + 1);
285
+ VALUE str = rb_str_new(NULL, nbyte);
286
+ ssize_t nread = pread(fd, RSTRING_PTR(str), nbyte, offset);
148
287
 
149
- if(pread(fd, buf, nbyte, offset) == -1)
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 rb_str_new2(buf);
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
- RSTRING(v_buf)->ptr,
196
- RSTRING(v_buf)->len,
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
- #ifdef HAVE_DIRECTIO
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.1.1: The version of this package. This a string. */
238
- rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_new2("1.1.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
@@ -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.1.1', IO::EXTRA_VERSION)
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
- def test_directio_set
28
- assert_respond_to(@fh, :directio=)
29
- assert_raises(StandardError){ @fh.directio = 99 }
30
- assert_nothing_raised{ @fh.directio = IO::DIRECTIO_ON }
31
- end
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
- def test_constants
34
- assert_not_nil(IO::DIRECTIO_ON)
35
- assert_not_nil(IO::DIRECTIO_OFF)
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
- def test_fdwalk
39
- assert_respond_to(IO, :fdwalk)
40
- assert_nothing_raised{ IO.fdwalk(0){ } }
41
- end
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(Fixnum, IO.pread_ptr(@fh.fileno, 5, 4))
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.1.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: 2008-09-08 00:00:00 -06:00
12
+ date: 2009-07-28 00:00:00 -06:00
13
13
  default_executable:
14
- dependencies: []
15
-
16
- description: Adds the IO.closefrom, IO.fdwalk, IO.pread, IO.pread_ptr, and IO.pwrite class methods as well as the IO#directio and IO#directio? instance methods (for those platforms that support them).
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
- - test/test_io_extra.rb
39
+ - examples/example_io_extra.rb
40
+ - ext/extconf.rb
29
41
  - ext/io/extra.c
30
- - CHANGES
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.2.0
71
+ rubygems_version: 1.3.5
56
72
  signing_key:
57
- specification_version: 2
58
- summary: Adds the IO.closefrom, IO.fdwalk, IO.pread, IO.pread_ptr, and IO.pwrite class methods as well as the IO#directio and IO#directio? instance methods (for those platforms that support them).
73
+ specification_version: 3
74
+ summary: Adds extra methods to the IO class.
59
75
  test_files:
60
76
  - test/test_io_extra.rb