win32-nio 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +2 -0
- data/MANIFEST +9 -0
- data/README +70 -0
- data/Rakefile +23 -0
- data/benchmarks/win32_nio_benchmarks.rb +113 -0
- data/lib/win32/nio.rb +215 -0
- data/test/test_win32_nio_read.rb +88 -0
- data/test/test_win32_nio_readlines.rb +61 -0
- data/win32-nio.gemspec +23 -0
- metadata +75 -0
data/CHANGES
ADDED
data/MANIFEST
ADDED
data/README
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
= Description
|
2
|
+
Native IO for Windows. This class matches and extends the current Ruby
|
3
|
+
IO class API, using native Windows functions underneath the hood.
|
4
|
+
|
5
|
+
= Synopsis
|
6
|
+
require 'win32/nio'
|
7
|
+
include Win32
|
8
|
+
|
9
|
+
p NIO.read('some_file.text')
|
10
|
+
|
11
|
+
p NIO.readlines('some_file.txt')
|
12
|
+
|
13
|
+
= Proof of Concept
|
14
|
+
This code is ALPHA!
|
15
|
+
|
16
|
+
This code is mostly a proof of concept to see how to implement Ruby's
|
17
|
+
IO functions in pure Windows functions. While it does offer a couple of
|
18
|
+
features over and above Ruby's IO interface, such as the ability to supply
|
19
|
+
an event or a block to the NIO.read method, it offers little practical
|
20
|
+
advantage at the moment.
|
21
|
+
|
22
|
+
In addition, it is currently using pure Ruby (via win32-api), which means
|
23
|
+
it isn't optimized for speed.
|
24
|
+
|
25
|
+
= Benchmarks
|
26
|
+
|
27
|
+
Using my HP Windows XP Pro laptop, with a 1.66 core duo Pentium T5500 and
|
28
|
+
2gb of RAM, I saw these results, which were typical in repeated runs:
|
29
|
+
|
30
|
+
user system total real
|
31
|
+
IO.read(small) 0.016000 0.047000 0.063000 ( 0.063000)
|
32
|
+
NIO.read(small) 0.109000 0.000000 0.109000 ( 0.109000)
|
33
|
+
IO.read(medium) 0.422000 0.094000 0.516000 ( 0.532000)
|
34
|
+
NIO.read(medium) 0.937000 0.062000 0.999000 ( 1.047000)
|
35
|
+
IO.read(large) 3.282000 1.063000 4.345000 ( 4.468000)
|
36
|
+
NIO.read(large) 8.187000 1.062000 9.249000 ( 9.454000)
|
37
|
+
IO.readlines(small) 0.156000 0.063000 0.219000 ( 0.234000)
|
38
|
+
NIO.readlines(small) 0.141000 0.000000 0.141000 ( 0.797000)
|
39
|
+
IO.readlines(medium) 2.984000 0.250000 3.234000 ( 3.625000)
|
40
|
+
NIO.readlines(medium) 1.172000 0.062000 1.234000 ( 3.406000)
|
41
|
+
IO.readlines(large) 18.625000 2.281000 20.906000 ( 21.532000)
|
42
|
+
NIO.readlines(large) 12.406000 0.563000 12.969000 (122.643000)
|
43
|
+
|
44
|
+
Note that, in most cases, the user and system time has decreased, but
|
45
|
+
the real time has increased.
|
46
|
+
|
47
|
+
= Known Bugs
|
48
|
+
None that I know of. Please log any other bug reports on the RubyForge
|
49
|
+
project page at http://www.rubyforge.net/projects/win32utils
|
50
|
+
|
51
|
+
= Future Plans
|
52
|
+
The pure Ruby code is really only meant for prototyping. The eventual
|
53
|
+
plan is to convert the Ruby code to equivalent C code in order to improve
|
54
|
+
performance.
|
55
|
+
|
56
|
+
= License
|
57
|
+
Ruby's
|
58
|
+
|
59
|
+
= Copyright
|
60
|
+
(C) 2008 Daniel J. Berger, All Rights Reserved
|
61
|
+
|
62
|
+
= Warranty
|
63
|
+
This package is provided "as is" and without any express or
|
64
|
+
implied warranties, including, without limitation, the implied
|
65
|
+
warranties of merchantability and fitness for a particular purpose.
|
66
|
+
|
67
|
+
= Author(s)
|
68
|
+
Daniel Berger
|
69
|
+
Park Heesob
|
70
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rbconfig'
|
4
|
+
include Config
|
5
|
+
|
6
|
+
desc 'Install the win32-nio library (non-gem)'
|
7
|
+
task :install do
|
8
|
+
sitelibdir = CONFIG['sitelibdir']
|
9
|
+
installdir = File.join(sitelibdir, 'win32')
|
10
|
+
file = 'lib\win32\nio.rb'
|
11
|
+
|
12
|
+
Dir.mkdir(installdir) unless File.exists?(installdir)
|
13
|
+
FileUtils.cp(file, installdir, :verbose => true)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Run the benchmark suite'
|
17
|
+
task :bench do
|
18
|
+
sh "ruby -Ilib benchmarks/win32_nio_benchmarks.rb"
|
19
|
+
|
20
|
+
Rake::TestTask.new do |t|
|
21
|
+
t.verbose = true
|
22
|
+
t.warning = true
|
23
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
########################################################################
|
2
|
+
# win32_nio_benchmarks.rb
|
3
|
+
#
|
4
|
+
# Run this via the 'rake bench' task to compare win32-nio with Ruby's
|
5
|
+
# own IO methods. This benchmark will take a bit of time, since it
|
6
|
+
# generates some test files on the fly.
|
7
|
+
########################################################################
|
8
|
+
require 'benchmark'
|
9
|
+
require 'win32/nio'
|
10
|
+
include Win32
|
11
|
+
|
12
|
+
MAX = (ARGV[0] || '10').chomp.to_i # Default to 10 iterations
|
13
|
+
PHRASE = "The quick brown fox jumped over the lazy dog's back"
|
14
|
+
|
15
|
+
SMALL_FILE = "small_nio_test.txt" # 588k
|
16
|
+
MEDIUM_FILE = "medium_nio_test.txt" # 6mb
|
17
|
+
LARGE_FILE = "large_nio_test.txt" # 60mb
|
18
|
+
HUGE_FILE = "huge_nio_test.txt" # 618mb
|
19
|
+
|
20
|
+
unless File.exists?(SMALL_FILE)
|
21
|
+
File.open(SMALL_FILE, 'w'){ |fh|
|
22
|
+
10000.times{ |n| fh.puts PHRASE + ": #{n}" }
|
23
|
+
}
|
24
|
+
|
25
|
+
puts "Small file created"
|
26
|
+
end
|
27
|
+
|
28
|
+
unless File.exists?(MEDIUM_FILE)
|
29
|
+
File.open(MEDIUM_FILE, 'w'){ |fh|
|
30
|
+
110000.times{ |n| fh.puts PHRASE + ": #{n}" }
|
31
|
+
}
|
32
|
+
|
33
|
+
puts "Medium file created"
|
34
|
+
end
|
35
|
+
|
36
|
+
unless File.exists?(LARGE_FILE)
|
37
|
+
File.open(LARGE_FILE, 'w'){ |fh|
|
38
|
+
1000000.times{ |n| fh.puts PHRASE + ": #{n}" }
|
39
|
+
}
|
40
|
+
|
41
|
+
puts "Large file created"
|
42
|
+
end
|
43
|
+
|
44
|
+
unless File.exists?(HUGE_FILE)
|
45
|
+
#File.open(HUGE_FILE, 'w'){ |fh|
|
46
|
+
# 10000000.times{ |n| fh.puts PHRASE + ": #{n}" }
|
47
|
+
#}
|
48
|
+
|
49
|
+
#puts "Huge file created"
|
50
|
+
end
|
51
|
+
|
52
|
+
Benchmark.bm(20) do |x|
|
53
|
+
x.report('IO.read(small)'){
|
54
|
+
MAX.times{ IO.read(SMALL_FILE) }
|
55
|
+
}
|
56
|
+
|
57
|
+
x.report('NIO.read(small)'){
|
58
|
+
MAX.times{ NIO.read(SMALL_FILE) }
|
59
|
+
}
|
60
|
+
|
61
|
+
x.report('IO.read(medium)'){
|
62
|
+
MAX.times{ IO.read(MEDIUM_FILE) }
|
63
|
+
}
|
64
|
+
|
65
|
+
x.report('NIO.read(medium)'){
|
66
|
+
MAX.times{ NIO.read(MEDIUM_FILE) }
|
67
|
+
}
|
68
|
+
|
69
|
+
x.report('IO.read(large)'){
|
70
|
+
MAX.times{ IO.read(LARGE_FILE) }
|
71
|
+
}
|
72
|
+
|
73
|
+
x.report('NIO.read(large)'){
|
74
|
+
MAX.times{ NIO.read(LARGE_FILE) }
|
75
|
+
}
|
76
|
+
|
77
|
+
#x.report('IO.read(huge)'){
|
78
|
+
# MAX.times{ IO.read(HUGE_FILE) }
|
79
|
+
#}
|
80
|
+
|
81
|
+
#x.report('NIO.read(huge)'){
|
82
|
+
# MAX.times{ NIO.read(HUGE_FILE) }
|
83
|
+
#}
|
84
|
+
|
85
|
+
x.report('IO.readlines(small)'){
|
86
|
+
MAX.times{ IO.readlines(SMALL_FILE) }
|
87
|
+
}
|
88
|
+
|
89
|
+
x.report('NIO.readlines(small)'){
|
90
|
+
MAX.times{ NIO.readlines(SMALL_FILE) }
|
91
|
+
}
|
92
|
+
|
93
|
+
x.report('IO.readlines(medium)'){
|
94
|
+
MAX.times{ IO.readlines(MEDIUM_FILE) }
|
95
|
+
}
|
96
|
+
|
97
|
+
x.report('NIO.readlines(medium)'){
|
98
|
+
MAX.times{ NIO.readlines(MEDIUM_FILE) }
|
99
|
+
}
|
100
|
+
|
101
|
+
x.report('IO.readlines(large)'){
|
102
|
+
MAX.times{ IO.readlines(LARGE_FILE) }
|
103
|
+
}
|
104
|
+
|
105
|
+
x.report('NIO.readlines(large)'){
|
106
|
+
MAX.times{ NIO.readlines(LARGE_FILE) }
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
File.delete(SMALL_FILE) if File.exists?(SMALL_FILE)
|
111
|
+
File.delete(MEDIUM_FILE) if File.exists?(MEDIUM_FILE)
|
112
|
+
File.delete(LARGE_FILE) if File.exists?(LARGE_FILE)
|
113
|
+
File.delete(HUGE_FILE) if File.exists?(HUGE_FILE)
|
data/lib/win32/nio.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'windows/file'
|
2
|
+
require 'windows/handle'
|
3
|
+
require 'windows/error'
|
4
|
+
require 'windows/memory'
|
5
|
+
require 'windows/nio'
|
6
|
+
require 'windows/synchronize'
|
7
|
+
require 'windows/system_info'
|
8
|
+
require 'windows/thread'
|
9
|
+
require 'windows/msvcrt/io'
|
10
|
+
require 'windows/msvcrt/buffer'
|
11
|
+
require 'win32/event'
|
12
|
+
|
13
|
+
module Win32
|
14
|
+
class NIO
|
15
|
+
include Windows::File
|
16
|
+
include Windows::Handle
|
17
|
+
include Windows::Error
|
18
|
+
include Windows::Synchronize
|
19
|
+
include Windows::MSVCRT::IO
|
20
|
+
include Windows::MSVCRT::Buffer
|
21
|
+
include Windows::SystemInfo
|
22
|
+
include Windows::Memory
|
23
|
+
include Windows::NIO
|
24
|
+
include Windows::Thread
|
25
|
+
|
26
|
+
extend Windows::File
|
27
|
+
extend Windows::Handle
|
28
|
+
extend Windows::Error
|
29
|
+
extend Windows::Synchronize
|
30
|
+
extend Windows::MSVCRT::IO
|
31
|
+
extend Windows::MSVCRT::Buffer
|
32
|
+
extend Windows::SystemInfo
|
33
|
+
extend Windows::Memory
|
34
|
+
extend Windows::NIO
|
35
|
+
extend Windows::Thread
|
36
|
+
|
37
|
+
# The version of this library
|
38
|
+
VERSION = '0.0.1'
|
39
|
+
|
40
|
+
# Error typically raised if any of the native functions fail.
|
41
|
+
class Error < StandardError; end
|
42
|
+
|
43
|
+
# This method is similar to Ruby's IO.read method except that, in
|
44
|
+
# addition to using native function calls, accepts an optional +event+
|
45
|
+
# argument for the fourth argument, which must be an instance of
|
46
|
+
# Win32::Event (if provided). The event is automatically set to a
|
47
|
+
# signaled state when the read operation completes.
|
48
|
+
#
|
49
|
+
# If a block is provided, then it is treated as a callback that fires
|
50
|
+
# when the read operation is complete.
|
51
|
+
#
|
52
|
+
def self.read(port_name, length=nil, offset=0, event=nil, &block)
|
53
|
+
if length
|
54
|
+
raise TypeError unless length.is_a?(Fixnum)
|
55
|
+
raise ArgumentError if length < 0
|
56
|
+
end
|
57
|
+
|
58
|
+
if offset
|
59
|
+
raise TypeError unless offset.is_a?(Fixnum)
|
60
|
+
raise ArgumentError if offset < 0
|
61
|
+
end
|
62
|
+
|
63
|
+
if event
|
64
|
+
raise TypeError unless event.is_a?(Win32::Event)
|
65
|
+
end
|
66
|
+
|
67
|
+
flags = FILE_FLAG_SEQUENTIAL_SCAN
|
68
|
+
|
69
|
+
overlapped = 0.chr * 20 # sizeof(OVERLAPPED)
|
70
|
+
overlapped[8,4] = [offset].pack('L') # OVERLAPPED.Offset
|
71
|
+
|
72
|
+
if offset > 0 || event
|
73
|
+
flags |= FILE_FLAG_OVERLAPPED
|
74
|
+
overlapped[16,4] = [event.handle].pack('L') if event
|
75
|
+
end
|
76
|
+
|
77
|
+
handle = CreateFile(
|
78
|
+
port_name,
|
79
|
+
FILE_READ_DATA,
|
80
|
+
FILE_SHARE_READ,
|
81
|
+
0,
|
82
|
+
OPEN_EXISTING,
|
83
|
+
flags,
|
84
|
+
0
|
85
|
+
)
|
86
|
+
|
87
|
+
if handle == INVALID_HANDLE_VALUE
|
88
|
+
raise Error, get_last_error
|
89
|
+
end
|
90
|
+
|
91
|
+
# Ruby's File.size is broken, so we implement it here. Also, if an
|
92
|
+
# offset is provided, we can reduce the size to only what we need.
|
93
|
+
if length.nil?
|
94
|
+
size = [0].pack('Q')
|
95
|
+
GetFileSizeEx(handle, size)
|
96
|
+
length = size.unpack('Q').first
|
97
|
+
length -= offset if offset
|
98
|
+
end
|
99
|
+
|
100
|
+
buf = 0.chr * length
|
101
|
+
|
102
|
+
begin
|
103
|
+
if block_given?
|
104
|
+
callback = Win32::API::Callback.new('LLP', 'V'){ block.call }
|
105
|
+
bool = ReadFileEx(handle, buf, length, overlapped, callback)
|
106
|
+
else
|
107
|
+
bytes = [0].pack('L')
|
108
|
+
bool = ReadFile(handle, buf, length, bytes, overlapped)
|
109
|
+
end
|
110
|
+
|
111
|
+
errno = GetLastError()
|
112
|
+
|
113
|
+
SleepEx(1, true) # Must be in alertable wait state
|
114
|
+
|
115
|
+
unless bool
|
116
|
+
if errno = ERROR_IO_PENDING
|
117
|
+
unless GetOverlappedResult(handle, overlapped, bytes, true)
|
118
|
+
raise Error, get_last_error
|
119
|
+
end
|
120
|
+
else
|
121
|
+
raise Error, errno
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
event.wait if event
|
126
|
+
ensure
|
127
|
+
CloseHandle(handle)
|
128
|
+
end
|
129
|
+
|
130
|
+
buf[0, length]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Reads the entire file specified by portname as individual lines, and
|
134
|
+
# returns those lines in an array. Lines are separated by +sep+.
|
135
|
+
#--
|
136
|
+
# The semantics are the same as the MRI version but the implementation
|
137
|
+
# is drastically different. We use a scattered IO read.
|
138
|
+
#
|
139
|
+
def self.readlines(file, sep = "\r\n")
|
140
|
+
handle = CreateFile(
|
141
|
+
file,
|
142
|
+
GENERIC_READ,
|
143
|
+
FILE_SHARE_READ,
|
144
|
+
nil,
|
145
|
+
OPEN_EXISTING,
|
146
|
+
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
|
147
|
+
nil
|
148
|
+
)
|
149
|
+
|
150
|
+
if handle == INVALID_HANDLE_VALUE
|
151
|
+
raise Error, get_last_error
|
152
|
+
end
|
153
|
+
|
154
|
+
sysbuf = 0.chr * 40
|
155
|
+
GetSystemInfo(sysbuf)
|
156
|
+
|
157
|
+
file_size = [0].pack('Q')
|
158
|
+
GetFileSizeEx(handle, file_size)
|
159
|
+
file_size = file_size.unpack('Q')[0]
|
160
|
+
|
161
|
+
page_size = sysbuf[4,4].unpack('L')[0] # dwPageSize
|
162
|
+
page_num = (file_size.to_f / page_size).ceil
|
163
|
+
|
164
|
+
begin
|
165
|
+
base_address = VirtualAlloc(
|
166
|
+
nil,
|
167
|
+
page_size * page_num,
|
168
|
+
MEM_COMMIT,
|
169
|
+
PAGE_READWRITE
|
170
|
+
)
|
171
|
+
|
172
|
+
buf_list = []
|
173
|
+
|
174
|
+
for i in 0...page_num
|
175
|
+
buf_list.push(base_address + page_size * i)
|
176
|
+
end
|
177
|
+
|
178
|
+
seg_array = buf_list.pack('Q*') + 0.chr * 8
|
179
|
+
overlapped = 0.chr * 20
|
180
|
+
|
181
|
+
bool = ReadFileScatter(
|
182
|
+
handle,
|
183
|
+
seg_array,
|
184
|
+
page_size * page_num,
|
185
|
+
nil,
|
186
|
+
overlapped
|
187
|
+
)
|
188
|
+
|
189
|
+
unless bool
|
190
|
+
error = GetLastError()
|
191
|
+
if error != ERROR_IO_PENDING
|
192
|
+
raise Error, get_last_error(error)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
SleepEx(1, true) unless HasOverlappedIoCompleted(overlapped)
|
197
|
+
|
198
|
+
buffer = 0.chr * file_size
|
199
|
+
memcpy(buffer, buf_list[0], file_size)
|
200
|
+
ensure
|
201
|
+
CloseHandle(handle)
|
202
|
+
VirtualFree(base_address, 0, MEM_RELEASE)
|
203
|
+
end
|
204
|
+
|
205
|
+
if sep == ""
|
206
|
+
buffer = buffer.split(/(\r\n){2,}/)
|
207
|
+
buffer.delete("\r\n")
|
208
|
+
else
|
209
|
+
buffer = buffer.split(sep)
|
210
|
+
end
|
211
|
+
|
212
|
+
buffer
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'test-unit'
|
3
|
+
|
4
|
+
require 'win32/nio'
|
5
|
+
require 'test/unit'
|
6
|
+
include Win32
|
7
|
+
|
8
|
+
class TC_Win32_NIO_Read < Test::Unit::TestCase
|
9
|
+
def self.startup
|
10
|
+
@@file = 'read_test.txt'
|
11
|
+
@@text = "The quick brown fox jumped over the lazy dog's back"
|
12
|
+
|
13
|
+
File.open(@@file, 'w'){ |fh|
|
14
|
+
100.times{ |n|
|
15
|
+
fh.puts @@text + ": #{n}"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup
|
21
|
+
@size = File.size(@@file)
|
22
|
+
@event = Win32::Event.new('test')
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_nio_version
|
26
|
+
assert_equal('0.0.1', Win32::NIO::VERSION)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_nio_read_basic
|
30
|
+
assert_respond_to(NIO, :read)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_nio_read_with_file_name
|
34
|
+
assert_nothing_raised{ NIO.read(@@file) }
|
35
|
+
assert_kind_of(String, NIO.read(@@file))
|
36
|
+
assert_true(NIO.read(@@file).size == @size)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_nio_read_with_file_name_and_length
|
40
|
+
assert_nothing_raised{ NIO.read(@@file, 19) }
|
41
|
+
assert_equal('The quick brown fox', NIO.read(@@file, 19))
|
42
|
+
assert_equal('', NIO.read(@@file, 0))
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_nio_read_with_file_name_and_length_and_offset
|
46
|
+
assert_nothing_raised{ NIO.read(@@file, 19, 4) }
|
47
|
+
assert_equal('quick brown fox', NIO.read(@@file, 15, 4))
|
48
|
+
assert_equal("lazy dog's back: 99\r\n", NIO.read(@@file, nil, @size-21))
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_nio_read_with_event
|
52
|
+
assert_false(@event.signaled?)
|
53
|
+
assert_nothing_raised{ NIO.read(@@file, 9, 0, @event) }
|
54
|
+
assert_true(@event.signaled?)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_nio_read_expected_errors
|
58
|
+
assert_raise(ArgumentError){ NIO.read }
|
59
|
+
assert_raise(ArgumentError){ NIO.read(@@file, -1) }
|
60
|
+
assert_raise(TypeError){ NIO.read(@@file, 'foo') }
|
61
|
+
assert_raise(ArgumentError){ NIO.read(@@file, 1, -1) }
|
62
|
+
assert_raise(TypeError){ NIO.read(@@file, 1, 'foo') }
|
63
|
+
assert_raise(TypeError){ NIO.read(@@file, 1, 1, 'foo') }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_readlines_basic
|
67
|
+
assert_respond_to(NIO, :readlines)
|
68
|
+
assert_nothing_raised{ NIO.readlines(@@file) }
|
69
|
+
assert_kind_of(Array, NIO.readlines(@@file))
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_readlines
|
73
|
+
assert_equal("#{@@text}: 0", NIO.readlines(@@file).first)
|
74
|
+
assert_equal("#{@@text}: 99", NIO.readlines(@@file).last)
|
75
|
+
end
|
76
|
+
|
77
|
+
def teardown
|
78
|
+
@size = nil
|
79
|
+
@event.close if @event
|
80
|
+
@event = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.teardown
|
84
|
+
File.delete(@@file) if File.exists?(@@file)
|
85
|
+
@@file = nil
|
86
|
+
@@text = nil
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#######################################################################
|
2
|
+
# test_win32_nio_readlines.rb
|
3
|
+
#
|
4
|
+
# Test case for the Win32::NIO.readlines method.
|
5
|
+
#######################################################################
|
6
|
+
require 'rubygems'
|
7
|
+
gem 'test-unit'
|
8
|
+
require 'test/unit'
|
9
|
+
require 'win32/nio'
|
10
|
+
include Win32
|
11
|
+
|
12
|
+
class TC_Win32_NIO_Readlines < Test::Unit::TestCase
|
13
|
+
def self.startup
|
14
|
+
@@line = "The quick brown fox jumped over the lazy dog's back"
|
15
|
+
@@file = "readlines_test.txt"
|
16
|
+
@@size = 10
|
17
|
+
File.open(@@file, 'w'){ |fh|
|
18
|
+
1.upto(@@size){ |n|
|
19
|
+
fh.puts @@line + ": #{n}"
|
20
|
+
fh.puts if n % 3 == 0
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup
|
26
|
+
@array = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_nio_readlines_basic
|
30
|
+
assert_respond_to(NIO, :readlines)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_nio_readlines
|
34
|
+
assert_nothing_raised{ NIO.readlines(@@file) }
|
35
|
+
assert_kind_of(Array, NIO.readlines(@@file))
|
36
|
+
assert_equal(@@size + 3, NIO.readlines(@@file).size)
|
37
|
+
assert_equal(@@line + ': 1', NIO.readlines(@@file).first)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_nio_readlines_with_empty_line_ending
|
41
|
+
assert_nothing_raised{ NIO.readlines(@@file, '') }
|
42
|
+
assert_kind_of(Array, NIO.readlines(@@file, ''))
|
43
|
+
assert_equal(4, NIO.readlines(@@file, '').size)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_nio_readlines_expected_errors
|
47
|
+
assert_raise(ArgumentError){ NIO.readlines }
|
48
|
+
assert_raise(ArgumentError){ NIO.readlines(@@file, '', true) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def teardown
|
52
|
+
@array = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.shutdown
|
56
|
+
File.delete(@@file) if File.exists?(@@file)
|
57
|
+
@@file = nil
|
58
|
+
@@size = nil
|
59
|
+
@@line = nil
|
60
|
+
end
|
61
|
+
end
|
data/win32-nio.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |gem|
|
4
|
+
gem.name = "win32-nio"
|
5
|
+
gem.version = "0.0.1"
|
6
|
+
gem.author = "Daniel J. Berger"
|
7
|
+
gem.email = "djberg96@gmail.com"
|
8
|
+
gem.homepage = "http://www.rubyforge.org/projects/win32utils"
|
9
|
+
gem.platform = Gem::Platform::RUBY
|
10
|
+
gem.summary = "Native IO for MS Windows"
|
11
|
+
gem.description = "Native IO for MS Windows"
|
12
|
+
gem.has_rdoc = true
|
13
|
+
gem.files = Dir["lib/win32/*.rb"] + Dir["test/*"] + Dir["[A-Z]*"] + Dir["benchmarks/*.rb"]
|
14
|
+
gem.files.reject! { |fn| fn.include? "CVS" }
|
15
|
+
gem.require_path = "lib"
|
16
|
+
gem.extra_rdoc_files = ["README", "CHANGES", "MANIFEST"]
|
17
|
+
gem.rubyforge_project = "Win32Utils"
|
18
|
+
gem.add_dependency("windows-pr", ">= 0.9.5")
|
19
|
+
end
|
20
|
+
|
21
|
+
if $0 == __FILE__
|
22
|
+
Gem::Builder.new(spec).build
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: win32-nio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel J. Berger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-11-28 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: windows-pr
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.9.5
|
24
|
+
version:
|
25
|
+
description: Native IO for MS Windows
|
26
|
+
email: djberg96@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- CHANGES
|
34
|
+
- MANIFEST
|
35
|
+
files:
|
36
|
+
- lib/win32/nio.rb
|
37
|
+
- test/test_win32_nio_read.rb
|
38
|
+
- test/test_win32_nio_readlines.rb
|
39
|
+
- benchmarks
|
40
|
+
- CHANGES
|
41
|
+
- lib
|
42
|
+
- MANIFEST
|
43
|
+
- Rakefile
|
44
|
+
- README
|
45
|
+
- test
|
46
|
+
- win32-nio.gemspec
|
47
|
+
- benchmarks/win32_nio_benchmarks.rb
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://www.rubyforge.org/projects/win32utils
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project: Win32Utils
|
70
|
+
rubygems_version: 1.3.1
|
71
|
+
signing_key:
|
72
|
+
specification_version: 2
|
73
|
+
summary: Native IO for MS Windows
|
74
|
+
test_files: []
|
75
|
+
|