win32-nio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+