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 ADDED
@@ -0,0 +1,2 @@
1
+ == 0.0.1 - 28-Nov-2008
2
+ * Initial release
data/MANIFEST ADDED
@@ -0,0 +1,9 @@
1
+ * CHANGES
2
+ * MANIFEST
3
+ * Rakefile
4
+ * README
5
+ * win32-nio.gemspec
6
+ * benchmarks/win32_nio_benchmarks.rb
7
+ * lib/win32/nio.rb
8
+ * test/test_win32_nio_read.rb
9
+ * test/test_win32_nio_readlines.rb
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
+