io-extra 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +6 -0
- data/README +6 -3
- data/Rakefile +4 -3
- data/ext/extconf.rb +3 -0
- data/ext/io/extra.c +167 -3
- data/io-extra.gemspec +1 -1
- data/test/test_io_extra.rb +139 -95
- metadata +28 -15
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 1.2.2 - 1-May-2010
|
2
|
+
* Added the IO.writev method which allows you to write arrays without
|
3
|
+
requiring an Array#join call, i.e. "gather write". Thanks go to Eric
|
4
|
+
Wong for supplying the code to support this.
|
5
|
+
* Some Rakefile updates.
|
6
|
+
|
1
7
|
== 1.2.1 - 16-Jan-2010
|
2
8
|
* Some README updates
|
3
9
|
* Updates to the gemspec.
|
data/README
CHANGED
@@ -60,15 +60,18 @@
|
|
60
60
|
documentation that was generated by RDoc (if you did a gem install).
|
61
61
|
|
62
62
|
= Known Issues
|
63
|
-
|
64
|
-
|
63
|
+
The IO.writev tests fail on Solaris. We are not sure why yet.
|
64
|
+
|
65
|
+
Please file any bug reports on the project page at
|
66
|
+
http://www.rubyforge.org/projects/shards.
|
65
67
|
|
66
68
|
= Future Plans
|
67
69
|
* I may add the File::O_DIRECT open constant on platforms that support it.
|
68
70
|
* Switch from C extension to FFI.
|
69
71
|
|
70
72
|
= Acknowledgements
|
71
|
-
Eric Wong for some great work on Linux compatibility and other fixes
|
73
|
+
Eric Wong for some great work on Linux compatibility and other fixes, as
|
74
|
+
well as the code for the IO.writev method.
|
72
75
|
|
73
76
|
= License
|
74
77
|
Artistic 2.0
|
data/Rakefile
CHANGED
@@ -19,6 +19,7 @@ task :clean do
|
|
19
19
|
build_file = File.join(Dir.pwd, 'io', 'extra.' + Config::CONFIG['DLEXT'])
|
20
20
|
File.delete(build_file) if File.exists?(build_file)
|
21
21
|
end
|
22
|
+
Dir['*.gem'].each{ |f| File.delete(f) }
|
22
23
|
end
|
23
24
|
|
24
25
|
desc "Build the io-extra library (but don't install it)"
|
@@ -40,14 +41,14 @@ task :install => [:build] do
|
|
40
41
|
end
|
41
42
|
|
42
43
|
namespace :gem do
|
43
|
-
desc '
|
44
|
-
task :
|
44
|
+
desc 'Create the io-extra gem'
|
45
|
+
task :create do
|
45
46
|
spec = eval(IO.read('io-extra.gemspec'))
|
46
47
|
Gem::Builder.new(spec).build
|
47
48
|
end
|
48
49
|
|
49
50
|
desc "Install the io-extra library as a gem"
|
50
|
-
task :install => [:
|
51
|
+
task :install => [:create] do
|
51
52
|
file = Dir["io-extra*.gem"].last
|
52
53
|
sh "gem install #{file}"
|
53
54
|
end
|
data/ext/extconf.rb
CHANGED
@@ -6,12 +6,15 @@ dir_config('io')
|
|
6
6
|
|
7
7
|
have_header('stdint.h')
|
8
8
|
have_header('sys/resource.h')
|
9
|
+
have_header('sys/uio.h')
|
9
10
|
have_func('closefrom')
|
10
11
|
have_func('fdwalk')
|
11
12
|
have_func('directio')
|
12
13
|
have_func('pread')
|
13
14
|
have_func('pwrite')
|
15
|
+
have_func('writev')
|
14
16
|
have_func('rb_str_set_len', 'ruby.h')
|
17
|
+
have_func('rb_thread_blocking_region')
|
15
18
|
|
16
19
|
case Config::CONFIG['host_os']
|
17
20
|
when /darwin/i
|
data/ext/io/extra.c
CHANGED
@@ -14,6 +14,49 @@
|
|
14
14
|
#include <stdint.h>
|
15
15
|
#endif
|
16
16
|
|
17
|
+
#ifdef HAVE_SYS_UIO_H
|
18
|
+
#include <sys/uio.h>
|
19
|
+
#endif
|
20
|
+
|
21
|
+
#ifdef HAVE_LIMITS_H
|
22
|
+
#include <limits.h>
|
23
|
+
#endif
|
24
|
+
|
25
|
+
#if !defined(IOV_MAX)
|
26
|
+
#if defined(_SC_IOV_MAX)
|
27
|
+
#define IOV_MAX (sysconf(_SC_IOV_MAX))
|
28
|
+
#else
|
29
|
+
/* assume infinity, or let the syscall return with error ... */
|
30
|
+
#define IOV_MAX INT_MAX
|
31
|
+
#endif
|
32
|
+
#endif
|
33
|
+
|
34
|
+
#ifndef HAVE_RB_THREAD_BLOCKING_REGION
|
35
|
+
/*
|
36
|
+
* partial emulation of the 1.9 rb_thread_blocking_region under 1.8,
|
37
|
+
* this is enough to ensure signals are processed safely when doing I/O
|
38
|
+
* to a slow device, but doesn't actually ensure threads can be
|
39
|
+
* scheduled fairly in 1.8
|
40
|
+
*/
|
41
|
+
#include <rubysig.h>
|
42
|
+
#define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
43
|
+
typedef void rb_unblock_function_t(void *);
|
44
|
+
typedef VALUE rb_blocking_function_t(void *);
|
45
|
+
static VALUE
|
46
|
+
rb_thread_blocking_region(
|
47
|
+
rb_blocking_function_t *fn, void *data1,
|
48
|
+
rb_unblock_function_t *ubf, void *data2)
|
49
|
+
{
|
50
|
+
VALUE rv;
|
51
|
+
|
52
|
+
TRAP_BEG;
|
53
|
+
rv = fn(data1);
|
54
|
+
TRAP_END;
|
55
|
+
|
56
|
+
return rv;
|
57
|
+
}
|
58
|
+
#endif
|
59
|
+
|
17
60
|
#ifndef RSTRING_PTR
|
18
61
|
#define RSTRING_PTR(v) (RSTRING(v)->ptr)
|
19
62
|
#define RSTRING_LEN(v) (RSTRING(v)->len)
|
@@ -287,7 +330,7 @@ static VALUE s_io_pread(VALUE klass, VALUE v_fd, VALUE v_nbyte, VALUE v_offset){
|
|
287
330
|
|
288
331
|
if (nread < 0)
|
289
332
|
rb_sys_fail("pread");
|
290
|
-
if (nread != nbyte)
|
333
|
+
if ((size_t)nread != nbyte)
|
291
334
|
rb_str_set_len(str, nread);
|
292
335
|
|
293
336
|
return str;
|
@@ -345,6 +388,121 @@ static VALUE s_io_pwrite(VALUE klass, VALUE v_fd, VALUE v_buf, VALUE v_offset){
|
|
345
388
|
}
|
346
389
|
#endif
|
347
390
|
|
391
|
+
/* this can't be a function since we use alloca() */
|
392
|
+
#define ARY2IOVEC(iov,iovcnt,expect,ary) \
|
393
|
+
do { \
|
394
|
+
VALUE *cur; \
|
395
|
+
struct iovec *tmp; \
|
396
|
+
long n; \
|
397
|
+
if (TYPE(ary) != T_ARRAY) \
|
398
|
+
rb_raise(rb_eArgError, "must be an array of strings"); \
|
399
|
+
cur = RARRAY_PTR(ary); \
|
400
|
+
n = RARRAY_LEN(ary); \
|
401
|
+
if (n > IOV_MAX) \
|
402
|
+
rb_raise(rb_eArgError, "array is larger than IOV_MAX"); \
|
403
|
+
iov = tmp = alloca(sizeof(struct iovec) * n); \
|
404
|
+
expect = 0; \
|
405
|
+
iovcnt = (int)n; \
|
406
|
+
for (; --n >= 0; tmp++, cur++) { \
|
407
|
+
if (TYPE(*cur) != T_STRING) \
|
408
|
+
rb_raise(rb_eArgError, "must be an array of strings"); \
|
409
|
+
tmp->iov_base = RSTRING_PTR(*cur); \
|
410
|
+
tmp->iov_len = RSTRING_LEN(*cur); \
|
411
|
+
expect += tmp->iov_len; \
|
412
|
+
} \
|
413
|
+
} while (0)
|
414
|
+
|
415
|
+
#if defined(HAVE_WRITEV)
|
416
|
+
struct writev_args {
|
417
|
+
int fd;
|
418
|
+
struct iovec *iov;
|
419
|
+
int iovcnt;
|
420
|
+
};
|
421
|
+
|
422
|
+
static VALUE nogvl_writev(void *ptr)
|
423
|
+
{
|
424
|
+
struct writev_args *args = ptr;
|
425
|
+
|
426
|
+
return (VALUE)writev(args->fd, args->iov, args->iovcnt);
|
427
|
+
}
|
428
|
+
|
429
|
+
/*
|
430
|
+
* IO.writev(fd, %w(hello world))
|
431
|
+
*
|
432
|
+
* This method writes the contents of an array of strings to the given +fd+.
|
433
|
+
* It can be useful to avoid generating a temporary string via Array#join
|
434
|
+
* when writing out large arrays of strings.
|
435
|
+
*
|
436
|
+
* The given array should have fewer elements than the IO::IOV_MAX constant.
|
437
|
+
*
|
438
|
+
* Returns the number of bytes written.
|
439
|
+
*/
|
440
|
+
static VALUE s_io_writev(VALUE klass, VALUE fd, VALUE ary) {
|
441
|
+
ssize_t result = 0;
|
442
|
+
ssize_t left;
|
443
|
+
struct writev_args args;
|
444
|
+
|
445
|
+
args.fd = NUM2INT(fd);
|
446
|
+
ARY2IOVEC(args.iov, args.iovcnt, left, ary);
|
447
|
+
|
448
|
+
for(;;) {
|
449
|
+
ssize_t w = (ssize_t)rb_thread_blocking_region(nogvl_writev, &args,
|
450
|
+
RUBY_UBF_IO, 0);
|
451
|
+
|
452
|
+
if(w == -1) {
|
453
|
+
if (rb_io_wait_writable(args.fd)) {
|
454
|
+
continue;
|
455
|
+
} else {
|
456
|
+
if (result > 0) {
|
457
|
+
/*
|
458
|
+
* unlikely to hit this case, return the already written bytes,
|
459
|
+
* we'll let the next write (or close) fail instead
|
460
|
+
*/
|
461
|
+
break;
|
462
|
+
}
|
463
|
+
rb_sys_fail("writev");
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
467
|
+
result += w;
|
468
|
+
if(w == left) {
|
469
|
+
break;
|
470
|
+
} else { /* partial write, this can get tricky */
|
471
|
+
int i;
|
472
|
+
struct iovec *new_iov = args.iov;
|
473
|
+
|
474
|
+
left -= w;
|
475
|
+
|
476
|
+
/* skip over iovecs we've already written completely */
|
477
|
+
for (i = 0; i < args.iovcnt; i++, new_iov++) {
|
478
|
+
if (w == 0)
|
479
|
+
break;
|
480
|
+
|
481
|
+
/*
|
482
|
+
* partially written iov,
|
483
|
+
* modify and retry with current iovec in front
|
484
|
+
*/
|
485
|
+
if (new_iov->iov_len > (size_t)w) {
|
486
|
+
VALUE base = (VALUE)new_iov->iov_base;
|
487
|
+
|
488
|
+
new_iov->iov_len -= w;
|
489
|
+
new_iov->iov_base = (void *)(base + w);
|
490
|
+
break;
|
491
|
+
}
|
492
|
+
|
493
|
+
w -= new_iov->iov_len;
|
494
|
+
}
|
495
|
+
|
496
|
+
/* retry without the already-written iovecs */
|
497
|
+
args.iovcnt -= i;
|
498
|
+
args.iov = new_iov;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
return LONG2NUM(result);
|
503
|
+
}
|
504
|
+
#endif
|
505
|
+
|
348
506
|
/* Adds the IO.closefrom, IO.fdwalk class methods, as well as the IO#directio
|
349
507
|
* and IO#directio? instance methods (if supported on your platform).
|
350
508
|
*/
|
@@ -371,6 +529,8 @@ void Init_extra(){
|
|
371
529
|
rb_define_const(rb_cIO, "DIRECT", UINT2NUM(O_DIRECT));
|
372
530
|
#endif
|
373
531
|
|
532
|
+
rb_define_const(rb_cIO, "IOV_MAX", LONG2NUM(IOV_MAX));
|
533
|
+
|
374
534
|
#ifdef HAVE_PREAD
|
375
535
|
rb_define_singleton_method(rb_cIO, "pread", s_io_pread, 3);
|
376
536
|
rb_define_singleton_method(rb_cIO, "pread_ptr", s_io_pread_ptr, 3);
|
@@ -380,6 +540,10 @@ void Init_extra(){
|
|
380
540
|
rb_define_singleton_method(rb_cIO, "pwrite", s_io_pwrite, 3);
|
381
541
|
#endif
|
382
542
|
|
383
|
-
|
384
|
-
|
543
|
+
#ifdef HAVE_WRITEV
|
544
|
+
rb_define_singleton_method(rb_cIO, "writev", s_io_writev, 2);
|
545
|
+
#endif
|
546
|
+
|
547
|
+
/* 1.2.2: The version of this library. This a string. */
|
548
|
+
rb_define_const(rb_cIO, "EXTRA_VERSION", rb_str_new2("1.2.2"));
|
385
549
|
}
|
data/io-extra.gemspec
CHANGED
data/test/test_io_extra.rb
CHANGED
@@ -9,103 +9,147 @@ gem 'test-unit'
|
|
9
9
|
|
10
10
|
require 'test/unit'
|
11
11
|
require 'rbconfig'
|
12
|
+
require 'io/nonblock'
|
12
13
|
require 'io/extra'
|
13
14
|
|
14
15
|
class TC_IO_Extra < Test::Unit::TestCase
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def setup
|
17
|
+
@file = 'delete_this.txt'
|
18
|
+
@fh = File.open(@file, 'w+')
|
19
|
+
@fh.puts "The quick brown fox jumped over the lazy dog's back"
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
22
|
+
def test_version
|
23
|
+
assert_equal('1.2.2', IO::EXTRA_VERSION)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_direct_constant
|
27
|
+
omit_unless(Config::CONFIG['host_os'] =~ /linux/i, 'Linux-only')
|
28
|
+
assert_equal(040000, IO::DIRECT)
|
29
|
+
assert_equal(040000, File::DIRECT)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_open_direct
|
33
|
+
omit_unless(Config::CONFIG['host_os'] =~ /linux/i, 'Linux-only')
|
34
|
+
assert_nothing_raised do
|
35
|
+
fh = File.open(@fh.path, IO::RDWR|IO::DIRECT)
|
36
|
+
fh.close
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_directio
|
41
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
42
|
+
assert_respond_to(@fh, :directio?)
|
43
|
+
assert_nothing_raised{ @fh.directio? }
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_directio_set
|
47
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
48
|
+
assert_respond_to(@fh, :directio=)
|
49
|
+
assert_raises(StandardError){ @fh.directio = 99 }
|
50
|
+
assert_nothing_raised{ @fh.directio = IO::DIRECTIO_ON }
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_constants
|
54
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
55
|
+
assert_not_nil(IO::DIRECTIO_ON)
|
56
|
+
assert_not_nil(IO::DIRECTIO_OFF)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_IOV_MAX_constant
|
60
|
+
assert_kind_of(Integer, IO::IOV_MAX)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_fdwalk
|
64
|
+
omit_if(Config::CONFIG['host_os'] =~ /darwin/i, 'unsupported')
|
65
|
+
assert_respond_to(IO, :fdwalk)
|
66
|
+
assert_nothing_raised{ IO.fdwalk(0){ } }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_closefrom
|
70
|
+
assert_respond_to(IO, :closefrom)
|
71
|
+
assert_nothing_raised{ IO.closefrom(3) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_pread
|
75
|
+
@fh.close rescue nil
|
76
|
+
@fh = File.open(@file)
|
77
|
+
assert_respond_to(IO, :pread)
|
78
|
+
assert_equal("quick", IO.pread(@fh.fileno, 5, 4))
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_pread_binary
|
82
|
+
@fh.close rescue nil
|
83
|
+
@fh = File.open(@file, "ab")
|
84
|
+
@fh.binmode
|
85
|
+
size = @fh.stat.size
|
86
|
+
assert_nothing_raised { @fh.syswrite("FOO\0HELLO") }
|
87
|
+
@fh.close rescue nil
|
88
|
+
@fh = File.open(@file)
|
89
|
+
assert_equal("O\0H", IO.pread(@fh.fileno, 3, size + 2))
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_pread_ptr
|
93
|
+
@fh.close rescue nil
|
94
|
+
@fh = File.open(@file)
|
95
|
+
assert_respond_to(IO, :pread_ptr)
|
96
|
+
assert_kind_of(Integer, IO.pread_ptr(@fh.fileno, 5, 4))
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_pread_last
|
100
|
+
@fh.close rescue nil
|
101
|
+
@fh = File.open(@file)
|
102
|
+
size = @fh.stat.size
|
103
|
+
assert_equal("ck\n", IO.pread(@fh.fileno, 5, size - 3))
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_pwrite
|
107
|
+
assert_respond_to(IO, :pwrite)
|
108
|
+
assert_nothing_raised{ IO.pwrite(@fh.fileno, "HAL", 0) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_writev
|
112
|
+
assert_respond_to(IO, :writev)
|
113
|
+
assert_equal(10, IO.writev(@fh.fileno, %w(hello world)))
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_writev_retry
|
117
|
+
empty = ""
|
118
|
+
if empty.respond_to?(:force_encoding)
|
119
|
+
empty.force_encoding(Encoding::BINARY)
|
120
|
+
end
|
121
|
+
|
122
|
+
# bs * count should be > PIPE_BUF
|
123
|
+
[ true, false ].each do |nonblock|
|
124
|
+
[ [ 512, 512 ], [ 131073, 3 ], [ 4098, 64 ] ].each do |(bs,count)|
|
125
|
+
rd, wr = IO.pipe
|
126
|
+
wr.nonblock = nonblock
|
127
|
+
buf = File.open("/dev/urandom", "rb") { |fp| fp.sysread(bs) }
|
128
|
+
vec = (1..count).map { buf }
|
129
|
+
pid = fork do
|
130
|
+
wr.close
|
131
|
+
tmp = []
|
132
|
+
sleep 0.1
|
133
|
+
begin
|
134
|
+
tmp << rd.readpartial(8192, buf)
|
135
|
+
rescue EOFError
|
136
|
+
break
|
137
|
+
end while true
|
138
|
+
ok = (vec.join(empty) == tmp.join(empty))
|
139
|
+
exit! ok
|
140
|
+
end
|
141
|
+
assert_nothing_raised { rd.close }
|
142
|
+
assert_equal(bs * count, IO.writev(wr.fileno, vec))
|
143
|
+
assert_nothing_raised { wr.close }
|
144
|
+
_, status = Process.waitpid2(pid)
|
145
|
+
assert status.success?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def teardown
|
151
|
+
@fh.close rescue nil
|
152
|
+
@fh = nil
|
153
|
+
File.delete(@file) if File.exists?(@file)
|
154
|
+
end
|
111
155
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-extra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 2
|
8
|
+
- 2
|
9
|
+
version: 1.2.2
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Daniel J. Berger
|
@@ -9,19 +14,23 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-01
|
17
|
+
date: 2010-05-01 00:00:00 -06:00
|
13
18
|
default_executable:
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: test-unit
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 3
|
23
31
|
version: 2.0.3
|
24
|
-
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
25
34
|
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"
|
26
35
|
email: djberg96@gmail.com
|
27
36
|
executables: []
|
@@ -34,16 +43,16 @@ extra_rdoc_files:
|
|
34
43
|
- MANIFEST
|
35
44
|
- ext/io/extra.c
|
36
45
|
files:
|
37
|
-
- MANIFEST
|
38
|
-
- examples/example_io_extra.rb
|
39
|
-
- README
|
40
46
|
- CHANGES
|
47
|
+
- doc/io_extra.txt
|
48
|
+
- examples/example_io_extra.rb
|
49
|
+
- ext/extconf.rb
|
50
|
+
- ext/io/extra.c
|
41
51
|
- io-extra.gemspec
|
52
|
+
- MANIFEST
|
42
53
|
- Rakefile
|
54
|
+
- README
|
43
55
|
- test/test_io_extra.rb
|
44
|
-
- doc/io_extra.txt
|
45
|
-
- ext/io/extra.c
|
46
|
-
- ext/extconf.rb
|
47
56
|
has_rdoc: true
|
48
57
|
homepage: http://www.rubyforge.org/projects/shards
|
49
58
|
licenses:
|
@@ -57,18 +66,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
66
|
requirements:
|
58
67
|
- - ">="
|
59
68
|
- !ruby/object:Gem::Version
|
69
|
+
segments:
|
70
|
+
- 1
|
71
|
+
- 8
|
72
|
+
- 6
|
60
73
|
version: 1.8.6
|
61
|
-
version:
|
62
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
75
|
requirements:
|
64
76
|
- - ">="
|
65
77
|
- !ruby/object:Gem::Version
|
78
|
+
segments:
|
79
|
+
- 0
|
66
80
|
version: "0"
|
67
|
-
version:
|
68
81
|
requirements: []
|
69
82
|
|
70
83
|
rubyforge_project: shards
|
71
|
-
rubygems_version: 1.3.
|
84
|
+
rubygems_version: 1.3.6
|
72
85
|
signing_key:
|
73
86
|
specification_version: 3
|
74
87
|
summary: Adds extra methods to the IO class.
|