io-like 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.yardopts +1 -0
  2. data/LICENSE +22 -57
  3. data/{LICENSE.rubyspec → LICENSE-rubyspec} +0 -0
  4. data/{NEWS → NEWS.md} +10 -5
  5. data/README.md +269 -0
  6. data/Rakefile +228 -0
  7. data/ruby.1.8.mspec +7 -0
  8. data/spec/binmode_spec.rb +29 -0
  9. data/spec/close_read_spec.rb +64 -0
  10. data/spec/close_spec.rb +36 -0
  11. data/spec/close_write_spec.rb +61 -0
  12. data/spec/closed_spec.rb +16 -0
  13. data/spec/each_byte_spec.rb +38 -0
  14. data/spec/each_line_spec.rb +11 -0
  15. data/spec/each_spec.rb +11 -0
  16. data/spec/eof_spec.rb +11 -0
  17. data/spec/fixtures/classes.rb +96 -0
  18. data/spec/fixtures/gets.txt +9 -0
  19. data/spec/fixtures/numbered_lines.txt +5 -0
  20. data/spec/fixtures/one_byte.txt +1 -0
  21. data/spec/fixtures/paragraphs.txt +7 -0
  22. data/spec/fixtures/readlines.txt +6 -0
  23. data/spec/flush_spec.rb +8 -0
  24. data/spec/getc_spec.rb +44 -0
  25. data/spec/gets_spec.rb +212 -0
  26. data/spec/isatty_spec.rb +6 -0
  27. data/spec/lineno_spec.rb +84 -0
  28. data/spec/output_spec.rb +47 -0
  29. data/spec/pos_spec.rb +53 -0
  30. data/spec/print_spec.rb +97 -0
  31. data/spec/printf_spec.rb +24 -0
  32. data/spec/putc_spec.rb +57 -0
  33. data/spec/puts_spec.rb +99 -0
  34. data/spec/read_spec.rb +162 -0
  35. data/spec/readchar_spec.rb +49 -0
  36. data/spec/readline_spec.rb +60 -0
  37. data/spec/readlines_spec.rb +140 -0
  38. data/spec/readpartial_spec.rb +92 -0
  39. data/spec/rewind_spec.rb +56 -0
  40. data/spec/seek_spec.rb +72 -0
  41. data/spec/shared/each.rb +204 -0
  42. data/spec/shared/eof.rb +116 -0
  43. data/spec/shared/pos.rb +39 -0
  44. data/spec/shared/tty.rb +12 -0
  45. data/spec/shared/write.rb +53 -0
  46. data/spec/sync_spec.rb +56 -0
  47. data/spec/sysread_spec.rb +87 -0
  48. data/spec/sysseek_spec.rb +68 -0
  49. data/spec/syswrite_spec.rb +60 -0
  50. data/spec/tell_spec.rb +7 -0
  51. data/spec/to_io_spec.rb +19 -0
  52. data/spec/tty_spec.rb +6 -0
  53. data/spec/ungetc_spec.rb +118 -0
  54. data/spec/write_spec.rb +61 -0
  55. data/spec_helper.rb +49 -0
  56. metadata +223 -32
  57. data/CONTRIBUTORS +0 -15
  58. data/GPL +0 -676
  59. data/HACKING +0 -123
  60. data/LEGAL +0 -56
  61. data/MANIFEST +0 -10
  62. data/README +0 -150
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ describe "IO::Like#printf" do
5
+ before :each do
6
+ @io = IO.new(STDOUT.fileno, 'w')
7
+ @iowrapper = WritableIOWrapper.open(@io)
8
+ @iowrapper.sync = true
9
+ end
10
+
11
+ after :each do
12
+ @iowrapper.close unless @iowrapper.closed?
13
+ end
14
+
15
+ it "writes the #sprintf formatted string to the file descriptor" do
16
+ lambda do
17
+ @io.printf("%s\n", "look ma, no hands")
18
+ end.should output_to_fd("look ma, no hands\n", @io)
19
+ end
20
+
21
+ it "raises IOError on closed stream" do
22
+ lambda { IOSpecs.closed_file.printf("stuff") }.should raise_error(IOError)
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ describe "IO::Like#putc" do
5
+ before :each do
6
+ @filename = tmp('IO_Like__putc_test')
7
+ @file = File.open(@filename, 'w')
8
+ @file.sync = true
9
+ @iowrapper = WritableIOWrapper.open(@file)
10
+ @iowrapper.sync = true
11
+ end
12
+
13
+ after :each do
14
+ @iowrapper.close unless @iowrapper.closed?
15
+ @file.close unless @file.closed?
16
+ File.unlink @filename
17
+ end
18
+
19
+ it "returns a reference to the object" do
20
+ @iowrapper.putc('a').should == 'a'
21
+ @iowrapper.putc(128).should == 128
22
+ end
23
+
24
+ it "writes the first byte of a String" do
25
+ @iowrapper.putc("foo")
26
+ File.read(@filename).should == 'f'
27
+ end
28
+
29
+ it "writes the first byte of an object's string representation" do
30
+ (obj = mock('test')).should_receive(:to_int).and_return(261)
31
+ @iowrapper.putc(obj)
32
+ File.read(@filename).should == "\005"
33
+ end
34
+
35
+ it "writes Numerics that fit in a C char" do
36
+ @iowrapper.putc(-128)
37
+ @iowrapper.putc(0)
38
+ @iowrapper.putc(255)
39
+
40
+ File.read(@filename).should == "\200\000\377"
41
+ end
42
+
43
+ it "write the first byte of Numerics that don't fit in a C char" do
44
+ @iowrapper.putc(-129)
45
+ @iowrapper.putc(256)
46
+
47
+ File.read(@filename).should == "\177\000"
48
+ end
49
+
50
+ it "checks if the stream is writable" do
51
+ lambda { IOSpecs.readable_iowrapper.putc('a') }.should raise_error(IOError)
52
+ end
53
+
54
+ it "raises IOError on closed stream" do
55
+ lambda { IOSpecs.closed_file.putc('a') }.should raise_error(IOError)
56
+ end
57
+ end
@@ -0,0 +1,99 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ # TODO: need to find a better way to test this. Too fragile to set expectations
5
+ # to each write call. Only care that all the characters are sent not the number
6
+ # or write calls. Also, these tests do not make sure the ordering of the write calls
7
+ # are correct.
8
+ describe "IO::Like#puts" do
9
+ before :each do
10
+ @old_record_separator = $\
11
+ @old_field_separator = $,
12
+ @filename = tmp('IO_Like__print_test')
13
+ @file = File.open(@filename, 'w')
14
+ @file.sync = true
15
+ @iowrapper = WritableIOWrapper.open(@file)
16
+ @iowrapper.sync = true
17
+ end
18
+
19
+ after :each do
20
+ $\ = @old_record_separator
21
+ $, = @old_field_separator
22
+ @iowrapper.close unless @iowrapper.closed?
23
+ @file.close unless @file.closed?
24
+ end
25
+
26
+ it "returns nil" do
27
+ @iowrapper.puts('hello').should == nil
28
+ end
29
+
30
+ it "writes just a newline when given no args" do
31
+ @iowrapper.puts()
32
+ File.read(@filename).should == "\n"
33
+ end
34
+
35
+ it "writes just a newline when given just a newline" do
36
+ @iowrapper.puts("\n")
37
+ File.read(@filename).should == "\n"
38
+ end
39
+
40
+ it "writes nil with a newline when given nil as an arg" do
41
+ @iowrapper.puts(nil)
42
+ File.read(@filename).should == "nil\n"
43
+ end
44
+
45
+ it "coerces arguments to strings using to_s" do
46
+ data = 'abcdefgh9876'
47
+ (obj = mock('test')).should_receive(:to_s).and_return(data)
48
+ @iowrapper.puts(obj)
49
+ File.read(@filename).should == "#{data}\n"
50
+ end
51
+
52
+ it "writes each arg if given several" do
53
+ data1 = 'abcdefgh9876'
54
+ data2 = '12345678zyxw'
55
+ @iowrapper.puts(data1, data2)
56
+ File.read(@filename).should == "#{data1}\n#{data2}\n"
57
+ end
58
+
59
+ it "flattens a nested array before writing it" do
60
+ data = ['abcdefgh9876', '12345678zyxw']
61
+ @iowrapper.puts(data)
62
+ File.read(@filename).should == "#{data[0]}\n#{data[1]}\n"
63
+ end
64
+
65
+ it "writes [...] for a recursive array arg" do
66
+ data = []
67
+ data << 1 << data << 2
68
+ @iowrapper.puts(data)
69
+ File.read(@filename).should == "#{data[0]}\n[...]\n#{data[2]}\n"
70
+ end
71
+
72
+ it "writes a newline after objects that do not end in newlines" do
73
+ data = 'abcdefgh9876'
74
+ @iowrapper.puts(data)
75
+ File.read(@filename).should == "#{data}\n"
76
+ end
77
+
78
+ it "does not write a newline after objects that end in newlines" do
79
+ data = "abcdefgh9876\n"
80
+ @iowrapper.puts(data)
81
+ File.read(@filename).should == data
82
+ end
83
+
84
+ it "ignores the $\ separator global" do
85
+ $\ = ":"
86
+ data1 = 'abcdefgh9876'
87
+ data2 = '12345678zyxw'
88
+ @iowrapper.puts(data1, data2)
89
+ File.read(@filename).should == "#{data1}\n#{data2}\n"
90
+ end
91
+
92
+ it "raises IOError on read-only stream" do
93
+ lambda { IOSpecs.readable_iowrapper.puts }.should raise_error(IOError)
94
+ end
95
+
96
+ it "raises IOError on closed stream" do
97
+ lambda { IOSpecs.closed_file.puts }.should raise_error(IOError)
98
+ end
99
+ end
@@ -0,0 +1,162 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ describe "IO::Like#read" do
5
+ before :each do
6
+ @filename = tmp('IO_Like__read_test')
7
+ @contents = "1234567890"
8
+ File.open(@filename, "w") { |io| io.write(@contents) }
9
+
10
+ @file = File.open(@filename, "r+")
11
+ @iowrapper = IOWrapper.open(@file)
12
+ end
13
+
14
+ after :each do
15
+ @iowrapper.close unless @iowrapper.closed?
16
+ @file.close unless @file.closed?
17
+ File.delete(@filename) if File.exists?(@filename)
18
+ end
19
+
20
+ it "can be read from consecutively" do
21
+ @iowrapper.read(1).should == '1'
22
+ @iowrapper.read(2).should == '23'
23
+ @iowrapper.read(3).should == '456'
24
+ @iowrapper.read(4).should == '7890'
25
+ end
26
+
27
+ it "can read lots of data" do
28
+ data = "\xaa" * (8096 * 2 + 1024) # HACK IO::BufferSize
29
+ File.open(@filename, 'w') { |io| io.write(data) }
30
+ actual = nil
31
+ File.open(@filename, 'r') { |io| actual = io.read }
32
+
33
+ actual.length.should == data.length
34
+ actual.split('').all? { |c| c == "\xaa" }.should == true
35
+ end
36
+
37
+ it "can read lots of data with length" do
38
+ read_length = 8096 * 2 + 1024 # HACK IO::BufferSize
39
+ data = "\xaa" * (read_length + 8096) # HACK same
40
+ File.open(@filename, 'w') { |io| io.write(data) }
41
+ actual = nil
42
+ File.open(@filename, 'r') { |io| actual = io.read(read_length) }
43
+
44
+ actual.length.should == read_length
45
+ actual.split('').all? { |c| c == "\xaa" }.should == true
46
+ end
47
+
48
+ it "consumes zero bytes when reading zero bytes" do
49
+ pre_pos = @iowrapper.pos
50
+
51
+ @iowrapper.read(0).should == ''
52
+ @iowrapper.getc.chr.should == '1'
53
+ end
54
+
55
+ it "is at end-of-file when everything has been read" do
56
+ @iowrapper.read
57
+ @iowrapper.eof?.should == true
58
+ end
59
+
60
+ it "reads the contents of a file" do
61
+ @iowrapper.read.should == @contents
62
+ end
63
+
64
+ it "places the specified number of bytes in the buffer" do
65
+ buf = ""
66
+ @iowrapper.read(5, buf)
67
+
68
+ buf.should == "12345"
69
+ end
70
+
71
+ it "expands the buffer when too small" do
72
+ buf = "ABCDE"
73
+ @iowrapper.read(nil, buf)
74
+
75
+ buf.should == @contents
76
+ end
77
+
78
+ it "overwrites the buffer" do
79
+ buf = "ABCDEFGHIJ"
80
+ @iowrapper.read(nil, buf)
81
+
82
+ buf.should == @contents
83
+ end
84
+
85
+ it "truncates the buffer when too big" do
86
+ buf = "ABCDEFGHIJKLMNO"
87
+ @iowrapper.read(nil, buf)
88
+ buf.should == @contents
89
+
90
+ @iowrapper.rewind
91
+ buf = "ABCDEFGHIJKLMNO"
92
+ @iowrapper.read(5, buf)
93
+ buf.should == @contents[0..4]
94
+ end
95
+
96
+ it "returns the given buffer" do
97
+ buf = ""
98
+
99
+ @iowrapper.read(nil, buf).object_id.should == buf.object_id
100
+ end
101
+
102
+ it "coerces the second argument to string and uses it as a buffer" do
103
+ buf = "ABCDE"
104
+ obj = mock("buff")
105
+ obj.should_receive(:to_str).any_number_of_times.and_return(buf)
106
+
107
+ @iowrapper.read(15, obj).object_id.should_not == obj.object_id
108
+ buf.should == @contents
109
+ end
110
+
111
+ it "returns an empty string at end-of-file" do
112
+ @iowrapper.read
113
+ @iowrapper.read.should == ''
114
+ end
115
+
116
+ it "reads the contents of a file when more bytes are specified" do
117
+ @iowrapper.read(@contents.length + 1).should == @contents
118
+ end
119
+
120
+ it "reads all data available before a SystemCallError is raised" do
121
+ # Overrride @file.sysread to raise SystemCallError every other time it's
122
+ # called.
123
+ class << @file
124
+ alias :sysread_orig :sysread
125
+ def sysread(length)
126
+ if @error_raised then
127
+ @error_raised = false
128
+ sysread_orig(length)
129
+ else
130
+ @error_raised = true
131
+ raise SystemCallError, 'Test Error'
132
+ end
133
+ end
134
+ end
135
+
136
+ lambda { @iowrapper.read }.should raise_error(SystemCallError)
137
+ @iowrapper.read.should == @contents
138
+ end
139
+
140
+ it "returns an empty string when the current pos is bigger than the content size" do
141
+ @iowrapper.pos = 1000
142
+ @iowrapper.read.should == ''
143
+ end
144
+
145
+ it "returns nil at end-of-file with a length" do
146
+ @iowrapper.read
147
+ @iowrapper.read(1).should == nil
148
+ end
149
+
150
+ it "with length argument returns nil when the current pos is bigger than the content size" do
151
+ @iowrapper.pos = 1000
152
+ @iowrapper.read(1).should == nil
153
+ end
154
+
155
+ it "raises IOError on write-only stream" do
156
+ lambda { IOSpecs.writable_iowrapper.read }.should raise_error(IOError)
157
+ end
158
+
159
+ it "raises IOError on closed stream" do
160
+ lambda { IOSpecs.closed_file.read }.should raise_error(IOError)
161
+ end
162
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ describe "IO::Like#readchar" do
5
+ before :each do
6
+ @file_name = File.dirname(__FILE__) + '/fixtures/readlines.txt'
7
+ @io = File.open(@file_name, 'r')
8
+ @iowrapper = IOWrapper.open(@io)
9
+ end
10
+
11
+ after :each do
12
+ @iowrapper.close unless @iowrapper.closed?
13
+ @io.close unless @io.closed?
14
+ end
15
+
16
+ it "returns the next byte from the stream" do
17
+ @io.readchar.should == 86
18
+ @io.readchar.should == 111
19
+ @io.readchar.should == 105
20
+ # read the rest of line
21
+ @io.readline.should == "ci la ligne une.\n"
22
+ @io.readchar.should == 81
23
+ end
24
+
25
+ it "raises EOFError when invoked at the end of the stream" do
26
+ # read entire content
27
+ @io.read
28
+ lambda { @io.readchar }.should raise_error(EOFError)
29
+ end
30
+
31
+ it "raises EOFError when reaches the end of the stream" do
32
+ lambda { loop { @io.readchar } }.should raise_error(EOFError)
33
+ end
34
+
35
+ it "raises EOFError on empty stream" do
36
+ path = tmp('empty.txt')
37
+ File.open(path, "w+") do |empty|
38
+ IOWrapper.open(empty) do |iowrapper|
39
+ lambda { iowrapper.readchar }.should raise_error(EOFError)
40
+ end
41
+ end
42
+
43
+ File.unlink(path)
44
+ end
45
+
46
+ it "raises IOError on closed stream" do
47
+ lambda { IOSpecs.closed_file.readchar }.should raise_error(IOError)
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/fixtures/classes'
3
+
4
+ describe "IO::Like#readline" do
5
+ before :each do
6
+ testfile = File.dirname(__FILE__) + '/fixtures/gets.txt'
7
+ @contents = File.read(testfile)
8
+ @io = File.open(testfile, 'r')
9
+ @iowrapper = IOWrapper.open(@io)
10
+ end
11
+
12
+ after :each do
13
+ @iowrapper.close unless @iowrapper.closed?
14
+ @io.close unless @io.closed?
15
+ end
16
+
17
+ it "returns the next line on the stream" do
18
+ @iowrapper.readline.should == "Voici la ligne une.\n"
19
+ @iowrapper.readline.should == "Qui è la linea due.\n"
20
+ end
21
+
22
+ it "goes back to first position after a rewind" do
23
+ @iowrapper.readline.should == "Voici la ligne une.\n"
24
+ @iowrapper.rewind
25
+ @iowrapper.readline.should == "Voici la ligne une.\n"
26
+ end
27
+
28
+ it "is modified by the cursor position" do
29
+ @iowrapper.seek(1)
30
+ @iowrapper.readline.should == "oici la ligne une.\n"
31
+ end
32
+
33
+ it "reads and returns all data available before a SystemCallError is raised when the separator is nil" do
34
+ # Overrride @io.sysread to raise SystemCallError every other time it's
35
+ # called.
36
+ class << @io
37
+ alias :sysread_orig :sysread
38
+ def sysread(length)
39
+ if @error_raised then
40
+ @error_raised = false
41
+ sysread_orig(length)
42
+ else
43
+ @error_raised = true
44
+ raise SystemCallError, 'Test Error'
45
+ end
46
+ end
47
+ end
48
+
49
+ lambda { @iowrapper.readline(nil) }.should raise_error(SystemCallError)
50
+ @iowrapper.readline(nil).should == @contents
51
+ end
52
+
53
+ it "raises EOFError on end of stream" do
54
+ lambda { loop { @iowrapper.readline } }.should raise_error(EOFError)
55
+ end
56
+
57
+ it "raises IOError on closed stream" do
58
+ lambda { IOSpecs.closed_file.readline }.should raise_error(IOError)
59
+ end
60
+ end