win32-nio 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.1.0 - 12-Jul-2012
2
+ * Changed from win32-api to FFI.
3
+ * Now requires Ruby 1.9 or later.
4
+
1
5
  == 0.0.3 - 24-Apr-2010
2
6
  * Removed inline gem building from the gemspec. That's now handled by a
3
7
  Rakefile task.
data/MANIFEST CHANGED
@@ -5,5 +5,9 @@
5
5
  * win32-nio.gemspec
6
6
  * benchmarks/win32_nio_benchmarks.rb
7
7
  * lib/win32/nio.rb
8
+ * lib/windows/constants.rb
9
+ * lib/windows/functions.rb
10
+ * lib/windows/macros.rb
11
+ * lib/windows/structs.rb
8
12
  * test/test_win32_nio_read.rb
9
- * test/test_win32_nio_readlines.rb
13
+ * test/test_win32_nio_readlines.rb
data/README CHANGED
@@ -1,6 +1,6 @@
1
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.
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
4
 
5
5
  = Installation
6
6
  gem install win32-nio
@@ -22,7 +22,7 @@
22
22
  an event or a block to the NIO.read method, it offers little practical
23
23
  advantage at the moment.
24
24
 
25
- In addition, it is currently using pure Ruby (via win32-api), which means
25
+ In addition, it is currently using pure Ruby (via FFI), which means
26
26
  it isn't optimized for speed.
27
27
 
28
28
  = Benchmarks
@@ -60,7 +60,7 @@
60
60
  Artistic 2.0
61
61
 
62
62
  = Copyright
63
- (C) 2008-2010 Daniel J. Berger, All Rights Reserved
63
+ (C) 2008-2012 Daniel J. Berger, All Rights Reserved
64
64
 
65
65
  = Warranty
66
66
  This package is provided "as is" and without any express or
@@ -70,4 +70,3 @@
70
70
  = Author(s)
71
71
  Daniel Berger
72
72
  Park Heesob
73
-
data/Rakefile CHANGED
@@ -1,14 +1,10 @@
1
1
  require 'rake'
2
+ require 'rake/clean'
2
3
  require 'rake/testtask'
3
- require 'rbconfig'
4
- include Config
5
4
 
6
- namespace 'gem' do
7
- desc 'Remove any .gem files from the project.'
8
- task :clean do
9
- Dir['*.gem'].each{ |f| File.delete(f) }
10
- end
5
+ CLEAN.include("**/*.gem", "**/*.txt")
11
6
 
7
+ namespace 'gem' do
12
8
  desc 'Create the win32-nio gem'
13
9
  task :create => [:clean] do
14
10
  spec = eval(IO.read('win32-nio.gemspec'))
@@ -27,7 +23,24 @@ task :bench do
27
23
  sh "ruby -Ilib benchmarks/win32_nio_benchmarks.rb"
28
24
  end
29
25
 
30
- Rake::TestTask.new do |t|
31
- t.verbose = true
32
- t.warning = true
26
+ namespace :test do
27
+ Rake::TestTask.new(:read) do |t|
28
+ t.verbose = true
29
+ t.warning = true
30
+ t.test_files = FileList['test/test_win32_nio_read.rb']
31
+ end
32
+
33
+ Rake::TestTask.new(:readlines) do |t|
34
+ t.verbose = true
35
+ t.warning = true
36
+ t.test_files = FileList['test/test_win32_nio_readlines.rb']
37
+ end
38
+
39
+ Rake::TestTask.new(:all) do |t|
40
+ t.verbose = true
41
+ t.warning = true
42
+ t.test_files = FileList['test/test*.rb']
43
+ end
33
44
  end
45
+
46
+ task :default => 'test:all'
data/lib/win32/nio.rb CHANGED
@@ -1,56 +1,26 @@
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'
1
+ require 'ffi'
11
2
  require 'win32/event'
12
3
 
4
+ require File.join(File.dirname(__FILE__), 'windows/functions')
5
+ require File.join(File.dirname(__FILE__), 'windows/constants')
6
+ require File.join(File.dirname(__FILE__), 'windows/structs')
7
+ require File.join(File.dirname(__FILE__), 'windows/macros')
8
+
13
9
  # The Win32 module serves as a namespace only.
14
10
  module Win32
15
-
11
+
16
12
  # The NIO class encapsulates the native IO methods for MS Windows.
17
13
  class NIO
18
- include Windows::File
19
- include Windows::Handle
20
- include Windows::Error
21
- include Windows::Synchronize
22
- include Windows::MSVCRT::IO
23
- include Windows::MSVCRT::Buffer
24
- include Windows::SystemInfo
25
- include Windows::Memory
26
- include Windows::NIO
27
- include Windows::Thread
28
-
29
- extend Windows::File
30
- extend Windows::Handle
31
- extend Windows::Error
32
- extend Windows::Synchronize
33
- extend Windows::MSVCRT::IO
34
- extend Windows::MSVCRT::Buffer
35
- extend Windows::SystemInfo
36
- extend Windows::Memory
37
- extend Windows::NIO
38
- extend Windows::Thread
39
-
14
+ include Windows::Constants
15
+ include Windows::Structs
16
+ extend Windows::Functions
17
+ extend Windows::Macros
18
+
40
19
  # The version of the win32-nio library
41
- VERSION = '0.0.2'
42
-
43
- # Error typically raised if any of the native functions fail.
44
- class Error < StandardError; end
45
-
46
- # This method is similar to Ruby's IO.read method except that, in
47
- # addition to using native function calls, it accepts an optional +event+
48
- # argument for the fourth argument, which must be an instance of
49
- # Win32::Event (if provided). The event is automatically set to a
50
- # signaled state when the read operation completes.
51
- #
52
- # If a block is provided, then it is treated as a callback that fires
53
- # when the read operation is complete.
20
+ VERSION = '0.1.0'
21
+
22
+ # This method is similar to Ruby's IO.read method except that it uses
23
+ # native function calls.
54
24
  #
55
25
  # Examples:
56
26
  #
@@ -63,94 +33,89 @@ module Win32
63
33
  # # Read 50 bytes starting at offset 10
64
34
  # Win32::NIO.read(file, 50, 10)
65
35
  #
66
- # # Read 25 bytes, starting at offset 5, and print "Done!" when finished.
67
- # Win32::NIO.read(file, 25, 5){ puts "Done!" }
36
+ # Note that the +options+ that may be passed to this method are limited
37
+ # to :encoding, :mode and :event because we're no longer using the open
38
+ # function internally. In the case of :mode the only thing that is checked
39
+ # for is the presence of the 'b' (binary) mode.
68
40
  #
69
- # # Attach an event that fires when finished.
70
- # require 'win32/event'
71
- # event = Win32::Event.new{ puts "Finished!" }
72
- # Win32::NIO.read(file, nil, nil, event)
41
+ # The :event option, if present, must be a Win32::Event object.
42
+ #--
43
+ # In practice the fact that I ignore open_args: is irrelevant since you
44
+ # would never want to open in anything other than GENERIC_READ. I suppose
45
+ # I could change this to as a way to pass flags to CreateFile.
73
46
  #
74
- def self.read(port_name, length=nil, offset=0, event=nil, &block)
75
- if length
76
- raise TypeError unless length.is_a?(Fixnum)
77
- raise ArgumentError if length < 0
78
- end
47
+ def self.read(name, length=nil, offset=0, options={})
48
+ begin
49
+ fname = name + "\0"
50
+ fname.encode!('UTF-16LE')
79
51
 
80
- if offset
81
- raise TypeError unless offset.is_a?(Fixnum)
82
- raise ArgumentError if offset < 0
83
- end
52
+ flags = FILE_FLAG_SEQUENTIAL_SCAN
53
+ olap = Overlapped.new
54
+ event = options[:event]
84
55
 
85
- if event
86
- raise TypeError unless event.is_a?(Win32::Event)
87
- end
56
+ if event
57
+ raise TypeError unless event.is_a?(Win32::Event)
58
+ end
88
59
 
89
- flags = FILE_FLAG_SEQUENTIAL_SCAN
60
+ olap[:Offset] = offset
90
61
 
91
- overlapped = 0.chr * 20 # sizeof(OVERLAPPED)
92
- overlapped[8,4] = [offset].pack('L') # OVERLAPPED.Offset
62
+ if offset > 0 || event
63
+ flags |= FILE_FLAG_OVERLAPPED
64
+ olap[:hEvent] = event.handle if event
65
+ end
93
66
 
94
- if offset > 0 || event
95
- flags |= FILE_FLAG_OVERLAPPED
96
- overlapped[16,4] = [event.handle].pack('L') if event
97
- end
67
+ handle = CreateFileW(
68
+ fname,
69
+ GENERIC_READ,
70
+ FILE_SHARE_READ,
71
+ nil,
72
+ OPEN_EXISTING,
73
+ flags,
74
+ 0
75
+ )
98
76
 
99
- handle = CreateFile(
100
- port_name,
101
- FILE_READ_DATA,
102
- FILE_SHARE_READ,
103
- 0,
104
- OPEN_EXISTING,
105
- flags,
106
- 0
107
- )
108
-
109
- if handle == INVALID_HANDLE_VALUE
110
- raise Error, get_last_error
111
- end
112
-
113
- # Ruby's File.size is broken, so we implement it here. Also, if an
114
- # offset is provided, we can reduce the size to only what we need.
115
- if length.nil?
116
- size = [0].pack('Q')
117
- GetFileSizeEx(handle, size)
118
- length = size.unpack('Q').first
119
- length -= offset if offset
120
- end
77
+ if handle == INVALID_HANDLE_VALUE
78
+ raise SystemCallError.new("CreateFile", FFI.errno)
79
+ end
121
80
 
122
- buf = 0.chr * length
81
+ length ||= File.size(name)
82
+ buf = 0.chr * length
123
83
 
124
- begin
125
84
  if block_given?
126
- callback = Win32::API::Callback.new('LLP', 'V'){ block.call }
127
- bool = ReadFileEx(handle, buf, length, overlapped, callback)
85
+ callback = Proc.new{ |e,b,o| block.call }
86
+ bool = ReadFileEx(handle, buf, buf.size, olap, callback)
128
87
  else
129
- bytes = [0].pack('L')
130
- bool = ReadFile(handle, buf, length, bytes, overlapped)
88
+ bool = ReadFile(handle, buf, buf.size, nil, olap)
131
89
  end
132
-
133
- errno = GetLastError()
90
+
91
+ errno = FFI.errno
134
92
 
135
93
  SleepEx(1, true) # Must be in alertable wait state
136
-
94
+
137
95
  unless bool
138
- if errno = ERROR_IO_PENDING
139
- unless GetOverlappedResult(handle, overlapped, bytes, true)
140
- raise Error, get_last_error
96
+ if errno == ERROR_IO_PENDING
97
+ bytes = FFI::MemoryPointer.new(:ulong)
98
+ unless GetOverlappedResult(handle, olap, bytes, true)
99
+ raise SystemCallError.new("GetOverlappedResult", FFI.errno)
141
100
  end
142
101
  else
143
- raise Error, errno
102
+ raise SystemCallError.new("ReadFile", errno)
144
103
  end
145
104
  end
146
-
147
- event.wait if event
105
+
106
+ result = buf.delete(0.chr)
107
+
108
+ result.encode!(options[:encoding]) if options[:encoding]
109
+
110
+ if options[:mode] && options[:mode].include?('t') && ($/ != "\r\n")
111
+ result.gsub!(/\r\n/, $/)
112
+ end
113
+
114
+ result
148
115
  ensure
149
- CloseHandle(handle)
116
+ CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
150
117
  end
151
-
152
- buf[0, length]
153
- end
118
+ end # NIO.read
154
119
 
155
120
  # Reads the entire file specified by portname as individual lines, and
156
121
  # returns those lines in an array. Lines are separated by +sep+.
@@ -159,79 +124,77 @@ module Win32
159
124
  # is drastically different. We use a scattered IO read.
160
125
  #
161
126
  def self.readlines(file, sep = "\r\n")
162
- handle = CreateFile(
163
- file,
164
- GENERIC_READ,
165
- FILE_SHARE_READ,
166
- nil,
167
- OPEN_EXISTING,
168
- FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
169
- nil
170
- )
171
-
172
- if handle == INVALID_HANDLE_VALUE
173
- raise Error, get_last_error
174
- end
175
-
176
- sysbuf = 0.chr * 40
177
- GetSystemInfo(sysbuf)
178
-
179
- file_size = [0].pack('Q')
180
- GetFileSizeEx(handle, file_size)
181
- file_size = file_size.unpack('Q')[0]
127
+ fname = file + "\0"
128
+ fname.encode!('UTF-16LE')
182
129
 
183
- page_size = sysbuf[4,4].unpack('L')[0] # dwPageSize
184
- page_num = (file_size.to_f / page_size).ceil
185
-
186
130
  begin
187
- base_address = VirtualAlloc(
131
+ handle = CreateFileW(
132
+ fname,
133
+ GENERIC_READ,
134
+ FILE_SHARE_READ,
188
135
  nil,
189
- page_size * page_num,
190
- MEM_COMMIT,
191
- PAGE_READWRITE
136
+ OPEN_EXISTING,
137
+ FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
138
+ 0
192
139
  )
193
-
194
- buf_list = []
195
-
196
- for i in 0...page_num
197
- buf_list.push(base_address + page_size * i)
140
+
141
+ if handle == INVALID_HANDLE_VALUE
142
+ raise SystemCallError.new("CreateFileW", FFI.errno)
198
143
  end
199
-
200
- seg_array = buf_list.pack('Q*') + 0.chr * 8
201
- overlapped = 0.chr * 20
202
-
203
- bool = ReadFileScatter(
204
- handle,
205
- seg_array,
206
- page_size * page_num,
207
- nil,
208
- overlapped
209
- )
210
144
 
211
- unless bool
212
- error = GetLastError()
213
- if error != ERROR_IO_PENDING
214
- raise Error, get_last_error(error)
145
+ sysinfo = SystemInfo.new
146
+ GetSystemInfo(sysinfo)
147
+
148
+ file_size = File.size(file)
149
+ page_size = sysinfo[:dwPageSize]
150
+ page_num = (file_size.to_f / page_size).ceil
151
+
152
+ begin
153
+ size = page_size * page_num
154
+ base_address = VirtualAlloc(nil, size, MEM_COMMIT, PAGE_READWRITE)
155
+
156
+ if base_address == 0
157
+ raise SystemCallError.new("VirtualAlloc", FFI.errno)
215
158
  end
216
- end
217
159
 
218
- SleepEx(1, true) unless HasOverlappedIoCompleted(overlapped)
160
+ # Add 1 for null as per the docs
161
+ array = FFI::MemoryPointer.new(FileSegmentElement, page_num + 1)
219
162
 
220
- buffer = 0.chr * file_size
221
- memcpy(buffer, buf_list[0], file_size)
222
- ensure
223
- CloseHandle(handle)
224
- VirtualFree(base_address, 0, MEM_RELEASE)
225
- end
163
+ for i in 0...page_num
164
+ fse = FileSegmentElement.new(array[i])
165
+ fse[:Alignment] = base_address + page_size * i
166
+ end
167
+
168
+ overlapped = Overlapped.new
169
+
170
+ bool = ReadFileScatter(handle, array, size, nil, overlapped)
171
+
172
+ unless bool
173
+ error = FFI.errno
174
+ if error == ERROR_IO_PENDING
175
+ SleepEx(1, true) while !HasOverlappedIoCompleted(overlapped)
176
+ else
177
+ raise SystemCallError.new("ReadFileScatter", error)
178
+ end
179
+ end
226
180
 
227
- if sep == ""
228
- buffer = buffer.split(/(\r\n){2,}/)
229
- buffer.delete("\r\n")
230
- else
231
- buffer = buffer.split(sep)
181
+ string = array[0].read_pointer.read_string
182
+
183
+ if sep == ""
184
+ array = string.split(/(\r\n){2,}/)
185
+ array.delete("\r\n")
186
+ else
187
+ array = string.split(sep)
188
+ end
189
+
190
+ array
191
+ ensure
192
+ VirtualFree(base_address, 0, MEM_RELEASE)
193
+ end
194
+ ensure
195
+ CloseHandle(handle) if handle && handle != INVALID_HANDLE_VALUE
232
196
  end
197
+ end # NIO.readlines
233
198
 
234
- buffer
235
- end
236
- end
237
- end
199
+ end # NIO
200
+ end # Win32
@@ -0,0 +1,72 @@
1
+ module Windows
2
+ module Constants
3
+ INVALID_HANDLE_VALUE = 0xFFFFFFFF
4
+
5
+ CREATE_NEW = 1
6
+ CREATE_ALWAYS = 2
7
+ OPEN_EXISTING = 3
8
+ OPEN_ALWAYS = 4
9
+ TRUNCATE_EXISTING = 5
10
+
11
+ GENERIC_READ = 0x80000000
12
+ GENERIC_WRITE = 0x40000000
13
+ GENERIC_EXECUTE = 0x20000000
14
+ GENERIC_ALL = 0x10000000
15
+
16
+ FILE_SHARE_READ = 0x00000001
17
+
18
+ FILE_FLAG_WRITE_THROUGH = 0x80000000
19
+ FILE_FLAG_OVERLAPPED = 0x40000000
20
+ FILE_FLAG_NO_BUFFERING = 0x20000000
21
+ FILE_FLAG_RANDOM_ACCESS = 0x10000000
22
+ FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000
23
+ FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
24
+ FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
25
+ FILE_FLAG_POSIX_SEMANTICS = 0x01000000
26
+ FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
27
+ FILE_FLAG_OPEN_NO_RECALL = 0x00100000
28
+ FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
29
+
30
+ MEM_COMMIT = 0x1000
31
+ MEM_RESERVE = 0x2000
32
+ MEM_DECOMMIT = 0x4000
33
+ MEM_RELEASE = 0x8000
34
+ MEM_FREE = 0x10000
35
+ MEM_PRIVATE = 0x20000
36
+ MEM_MAPPED = 0x40000
37
+ MEM_RESET = 0x80000
38
+ MEM_TOP_DOWN = 0x100000
39
+ MEM_WRITE_WATCH = 0x200000
40
+ MEM_PHYSICAL = 0x400000
41
+ MEM_LARGE_PAGES = 0x20000000
42
+ MEM_4MB_PAGES = 0x80000000
43
+
44
+ PAGE_NOACCESS = 0x01
45
+ PAGE_READONLY = 0x02
46
+ PAGE_READWRITE = 0x04
47
+ PAGE_WRITECOPY = 0x08
48
+ PAGE_EXECUTE = 0x10
49
+ PAGE_EXECUTE_READ = 0x20
50
+ PAGE_EXECUTE_READWRITE = 0x40
51
+ PAGE_EXECUTE_WRITECOPY = 0x80
52
+ PAGE_GUARD = 0x100
53
+ PAGE_NOCACHE = 0x200
54
+ PAGE_WRITECOMBINE = 0x400
55
+
56
+ INFINITE = 0xFFFFFFFF
57
+ WAIT_OBJECT_0 = 0
58
+ WAIT_TIMEOUT = 0x102
59
+ WAIT_ABANDONED = 128
60
+ WAIT_ABANDONED_0 = WAIT_ABANDONED
61
+ WAIT_FAILED = 0xFFFFFFFF
62
+
63
+ STATUS_WAIT_0 = 0
64
+ STATUS_ABANDONED_WAIT_0 = 128
65
+ STATUS_USER_APC = 192
66
+ STATUS_TIMEOUT = 258
67
+ STATUS_PENDING = 259
68
+
69
+ ERROR_IO_INCOMPLETE = 996
70
+ ERROR_IO_PENDING = 997
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module Functions
5
+ extend FFI::Library
6
+ ffi_lib :kernel32
7
+ ffi_convention :stdcall
8
+
9
+ attach_function :CloseHandle, [:long], :bool
10
+ attach_function :CreateFileA, [:string, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :ulong
11
+ attach_function :CreateFileW, [:buffer_in, :ulong, :ulong, :pointer, :ulong, :ulong, :ulong], :ulong
12
+ attach_function :GetOverlappedResult, [:ulong, :pointer, :pointer, :bool], :bool
13
+ attach_function :GetSystemInfo, [:pointer], :void
14
+ attach_function :ReadFile, [:ulong, :buffer_out, :ulong, :pointer, :pointer], :bool
15
+ attach_function :ReadFileScatter, [:ulong, :pointer, :ulong, :pointer, :pointer], :bool
16
+ attach_function :SleepEx, [:ulong, :bool], :ulong
17
+ attach_function :VirtualAlloc, [:pointer, :size_t, :ulong, :ulong], :ulong
18
+ attach_function :VirtualFree, [:ulong, :size_t, :ulong], :bool
19
+
20
+ callback :completion_function, [:ulong, :ulong, :pointer], :void
21
+ attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong, :pointer, :completion_function], :bool
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module Windows
2
+ module Macros
3
+ def HasOverlappedIoCompleted(overlapped)
4
+ overlapped[:Internal] != 259 # STATUS_PENDING
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module Structs
5
+ extend FFI::Library
6
+
7
+ # I'm assuming the anonymous struct for the internal union here.
8
+ class Overlapped < FFI::Struct
9
+ layout(
10
+ :Internal, :ulong,
11
+ :InternalHigh, :ulong,
12
+ :Offset, :ulong,
13
+ :OffsetHigh, :ulong,
14
+ :hEvent, :ulong
15
+ )
16
+ end
17
+
18
+ # dwOemId is deprecated. Just assume the nested struct.
19
+ class SystemInfo < FFI::Struct
20
+ layout(
21
+ :wProcessorArchitecture, :ushort,
22
+ :wReserved, :ushort,
23
+ :dwPageSize, :ulong,
24
+ :lpMinimumApplicationAddress, :pointer,
25
+ :lpMaximumApplicationAddress, :pointer,
26
+ :dwActiveProcessorMask, :pointer,
27
+ :dwNumberOfProcessors, :ulong,
28
+ :dwProcessorType, :ulong,
29
+ :dwAllocationGranularity, :ulong,
30
+ :wProcessorLevel, :ushort,
31
+ :wProcessorRevision, :ushort
32
+ )
33
+ end
34
+
35
+ class FileSegmentElement < FFI::Union
36
+ layout(:Buffer, :pointer, :Alignment, :uint64)
37
+ end
38
+ end
39
+ end
@@ -1,90 +1,82 @@
1
- require 'rubygems'
2
- gem 'test-unit'
3
-
1
+ ########################################################################
2
+ # test_win32_nio_read.rb
3
+ #
4
+ # Tests for the NIO.read method.
5
+ ########################################################################
6
+ require 'test-unit'
4
7
  require 'win32/nio'
5
8
  require 'test/unit'
6
9
  include Win32
7
10
 
8
11
  class TC_Win32_NIO_Read < Test::Unit::TestCase
9
- def self.startup
10
- Dir.chdir(File.expand_path(File.dirname(__FILE__)))
12
+ def self.startup
13
+ Dir.chdir(File.expand_path(File.dirname(__FILE__)))
14
+
15
+ @@file = 'read_test.txt'
16
+ @@text = "The quick brown fox jumped over the lazy dog's back"
17
+
18
+ File.open(@@file, 'w'){ |fh|
19
+ 100.times{ |n| fh.puts @@text + ": #{n}" }
20
+ }
21
+ end
22
+
23
+ def setup
24
+ @size = File.size(@@file)
25
+ end
26
+
27
+ test "version number is set to expected value" do
28
+ assert_equal('0.1.0', Win32::NIO::VERSION)
29
+ end
30
+
31
+ test "read method basic functionality" do
32
+ assert_respond_to(NIO, :read)
33
+ assert_nothing_raised{ NIO.read(@@file) }
34
+ end
11
35
 
12
- @@file = 'read_test.txt'
13
- @@text = "The quick brown fox jumped over the lazy dog's back"
14
-
15
- File.open(@@file, 'w'){ |fh|
16
- 100.times{ |n|
17
- fh.puts @@text + ": #{n}"
18
- }
19
- }
20
- end
36
+ test "read method accepts a file name and returns a string of the expected size" do
37
+ assert_kind_of(String, NIO.read(@@file))
38
+ p @size
39
+ p NIO.read(@@file).size
40
+ assert_true(NIO.read(@@file).size == @size)
41
+ end
21
42
 
22
- def setup
23
- @size = File.size(@@file)
24
- @event = Win32::Event.new('test')
25
- end
26
-
27
- def test_nio_version
28
- assert_equal('0.0.2', Win32::NIO::VERSION)
29
- end
43
+ test "read method accepts a length argument and returns a string of that length" do
44
+ assert_nothing_raised{ NIO.read(@@file, 19) }
45
+ assert_equal('The quick brown fox', NIO.read(@@file, 19))
46
+ assert_equal('', NIO.read(@@file, 0))
47
+ end
30
48
 
31
- def test_nio_read_basic
32
- assert_respond_to(NIO, :read)
33
- end
49
+ test "read method accepts an offset and returns a string between offset and length" do
50
+ assert_nothing_raised{ NIO.read(@@file, 19, 4) }
51
+ assert_equal('quick brown fox', NIO.read(@@file, 15, 4))
52
+ assert_equal("lazy dog's back: 99\r\n", NIO.read(@@file, nil, @size-21))
53
+ end
34
54
 
35
- def test_nio_read_with_file_name
36
- assert_nothing_raised{ NIO.read(@@file) }
37
- assert_kind_of(String, NIO.read(@@file))
38
- assert_true(NIO.read(@@file).size == @size)
39
- end
55
+ test "read method requires at least one argument" do
56
+ assert_raise(ArgumentError){ NIO.read }
57
+ end
40
58
 
41
- def test_nio_read_with_file_name_and_length
42
- assert_nothing_raised{ NIO.read(@@file, 19) }
43
- assert_equal('The quick brown fox', NIO.read(@@file, 19))
44
- assert_equal('', NIO.read(@@file, 0))
45
- end
59
+ test "length parameter must be a positive number" do
60
+ assert_raise(ArgumentError){ NIO.read(@@file, -1) }
61
+ assert_raise(TypeError){ NIO.read(@@file, 'foo') }
62
+ end
46
63
 
47
- def test_nio_read_with_file_name_and_length_and_offset
48
- assert_nothing_raised{ NIO.read(@@file, 19, 4) }
49
- assert_equal('quick brown fox', NIO.read(@@file, 15, 4))
50
- assert_equal("lazy dog's back: 99\r\n", NIO.read(@@file, nil, @size-21))
51
- end
52
-
53
- def test_nio_read_with_event
54
- assert_false(@event.signaled?)
55
- assert_nothing_raised{ NIO.read(@@file, 9, 0, @event) }
56
- assert_true(@event.signaled?)
57
- end
64
+ test "offset parameter must be a positive number" do
65
+ assert_raise(Errno::EINVAL, Errno::ENAMETOOLONG){ NIO.read(@@file, 1, -1) }
66
+ assert_raise(TypeError){ NIO.read(@@file, 1, 'foo') }
67
+ end
58
68
 
59
- def test_nio_read_expected_errors
60
- assert_raise(ArgumentError){ NIO.read }
61
- assert_raise(ArgumentError){ NIO.read(@@file, -1) }
62
- assert_raise(TypeError){ NIO.read(@@file, 'foo') }
63
- assert_raise(ArgumentError){ NIO.read(@@file, 1, -1) }
64
- assert_raise(TypeError){ NIO.read(@@file, 1, 'foo') }
65
- assert_raise(TypeError){ NIO.read(@@file, 1, 1, 'foo') }
66
- end
67
-
68
- def test_readlines_basic
69
- assert_respond_to(NIO, :readlines)
70
- assert_nothing_raised{ NIO.readlines(@@file) }
71
- assert_kind_of(Array, NIO.readlines(@@file))
72
- end
73
-
74
- def test_readlines
75
- assert_equal("#{@@text}: 0", NIO.readlines(@@file).first)
76
- assert_equal("#{@@text}: 99", NIO.readlines(@@file).last)
77
- end
69
+ test "options parameter must be a hash" do
70
+ assert_raise(TypeError){ NIO.read(@@file, 1, 1, 'foo') }
71
+ end
78
72
 
79
- def teardown
80
- @size = nil
81
- @event.close if @event
82
- @event = nil
83
- end
73
+ def teardown
74
+ @size = nil
75
+ end
84
76
 
85
- def self.shutdown
86
- File.delete(@@file) if File.exists?(@@file)
87
- @@file = nil
88
- @@text = nil
89
- end
77
+ def self.shutdown
78
+ File.delete(@@file) if File.exists?(@@file)
79
+ @@file = nil
80
+ @@text = nil
81
+ end
90
82
  end
@@ -3,59 +3,64 @@
3
3
  #
4
4
  # Test case for the Win32::NIO.readlines method.
5
5
  #######################################################################
6
- require 'rubygems'
7
- gem 'test-unit'
8
- require 'test/unit'
6
+ require 'test-unit'
9
7
  require 'win32/nio'
10
8
  include Win32
11
9
 
12
10
  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
- }
11
+ def self.startup
12
+ @@line = "The quick brown fox jumped over the lazy dog's back"
13
+ @@file = "readlines_test.txt"
14
+ @@size = 10
15
+
16
+ File.open(@@file, 'w'){ |fh|
17
+ 1.upto(@@size){ |n|
18
+ fh.puts @@line + ": #{n}"
19
+ fh.puts if n % 3 == 0
22
20
  }
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
21
+ }
22
+ end
23
+
24
+ def setup
25
+ @array = nil
26
+ end
27
+
28
+ test "readlines method basic functionality" do
29
+ assert_respond_to(NIO, :readlines)
30
+ assert_nothing_raised{ NIO.readlines(@@file) }
31
+ end
32
+
33
+ test "readlines returns an array" do
34
+ assert_kind_of(Array, NIO.readlines(@@file))
35
+ end
36
+
37
+ test "readlines returns an array of the expected size" do
38
+ assert_equal(@@size + 3, NIO.readlines(@@file).size)
39
+ assert_equal(@@line + ': 1', NIO.readlines(@@file).first)
40
+ end
41
+
42
+ test "readlines treats an empty second argument as a paragraph separator" do
43
+ assert_nothing_raised{ NIO.readlines(@@file, '') }
44
+ assert_kind_of(Array, NIO.readlines(@@file, ''))
45
+ assert_equal(4, NIO.readlines(@@file, '').size)
46
+ end
47
+
48
+ test "readlines expects at least one argument" do
49
+ assert_raise(ArgumentError){ NIO.readlines }
50
+ end
51
+
52
+ test "readlines accepts a maximum of two arguments" do
53
+ assert_raise(ArgumentError){ NIO.readlines(@@file, '', true) }
54
+ end
55
+
56
+ def teardown
57
+ @array = nil
58
+ end
59
+
60
+ def self.shutdown
61
+ File.delete(@@file) if File.exists?(@@file)
62
+ @@file = nil
63
+ @@size = nil
64
+ @@line = nil
65
+ end
61
66
  end
data/win32-nio.gemspec CHANGED
@@ -2,18 +2,22 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'win32-nio'
5
- spec.version = '0.0.3'
5
+ spec.version = '0.1.0'
6
6
  spec.author = 'Daniel J. Berger'
7
7
  spec.license = 'Artistic 2.0'
8
8
  spec.email = 'djberg96@gmail.com'
9
9
  spec.homepage = 'http://www.rubyforge.org/projects/win32utils'
10
- spec.platform = Gem::Platform::RUBY
11
10
  spec.summary = 'Native IO for MS Windows'
12
- spec.has_rdoc = true
13
11
  spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
14
12
 
15
13
  spec.rubyforge_project = 'Win32Utils'
16
14
  spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
15
+ spec.required_ruby_version = '> 1.9.0'
16
+
17
+ spec.add_dependency('ffi')
18
+ spec.add_dependency('win32-event', '>= 0.6.0')
19
+
20
+ spec.add_development_dependency('test-unit')
17
21
 
18
22
  spec.description = <<-EOF
19
23
  The win32-nio library implements certain IO methods using native
@@ -21,8 +25,4 @@ Gem::Specification.new do |spec|
21
25
  layer that MRI typically uses. In addition, some methods provide
22
26
  additional event handling capability.
23
27
  EOF
24
-
25
- spec.add_dependency('windows-pr', '>= 0.9.5')
26
- spec.add_dependency('win32-event', '>= 0.5.0')
27
- spec.add_development_dependency('test-unit', '>= 2.0.3')
28
28
  end
metadata CHANGED
@@ -1,113 +1,112 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: win32-nio
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 3
9
- version: 0.0.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Daniel J. Berger
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2010-04-24 00:00:00 -06:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: windows-pr
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- - 9
30
- - 5
31
- version: 0.9.5
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: win32-event
36
23
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
- - 5
44
- - 0
45
- version: 0.5.0
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: win32-event
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.6.0
46
38
  type: :runtime
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: test-unit
50
39
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- segments:
56
- - 2
57
- - 0
58
- - 3
59
- version: 2.0.3
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.6.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: test-unit
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
60
54
  type: :development
61
- version_requirements: *id003
62
- description: " The win32-nio library implements certain IO methods using native\n Windows function calls rather than using the POSIX compatibility\n layer that MRI typically uses. In addition, some methods provide\n additional event handling capability.\n"
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: ! " The win32-nio library implements certain IO methods using native\n
63
+ \ Windows function calls rather than using the POSIX compatibility\n layer
64
+ that MRI typically uses. In addition, some methods provide\n additional event
65
+ handling capability.\n"
63
66
  email: djberg96@gmail.com
64
67
  executables: []
65
-
66
68
  extensions: []
67
-
68
- extra_rdoc_files:
69
+ extra_rdoc_files:
69
70
  - README
70
71
  - CHANGES
71
72
  - MANIFEST
72
- files:
73
+ files:
73
74
  - benchmarks/win32_nio_benchmarks.rb
74
75
  - CHANGES
75
76
  - lib/win32/nio.rb
77
+ - lib/win32/windows/constants.rb
78
+ - lib/win32/windows/functions.rb
79
+ - lib/win32/windows/macros.rb
80
+ - lib/win32/windows/structs.rb
76
81
  - MANIFEST
77
82
  - Rakefile
78
83
  - README
79
84
  - test/test_win32_nio_read.rb
80
85
  - test/test_win32_nio_readlines.rb
81
86
  - win32-nio.gemspec
82
- has_rdoc: true
83
87
  homepage: http://www.rubyforge.org/projects/win32utils
84
- licenses:
88
+ licenses:
85
89
  - Artistic 2.0
86
90
  post_install_message:
87
91
  rdoc_options: []
88
-
89
- require_paths:
92
+ require_paths:
90
93
  - lib
91
- required_ruby_version: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- segments:
96
- - 0
97
- version: "0"
98
- required_rubygems_version: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- segments:
103
- - 0
104
- version: "0"
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>'
98
+ - !ruby/object:Gem::Version
99
+ version: 1.9.0
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
105
106
  requirements: []
106
-
107
107
  rubyforge_project: Win32Utils
108
- rubygems_version: 1.3.6
108
+ rubygems_version: 1.8.24
109
109
  signing_key:
110
110
  specification_version: 3
111
111
  summary: Native IO for MS Windows
112
112
  test_files: []
113
-