win32-nio 0.0.1
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 +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
|
+
|