redisk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/redisk/io.rb ADDED
@@ -0,0 +1,867 @@
1
+ module Redisk
2
+ class IO
3
+ include Enumerable
4
+ extend Helper
5
+ include Helper
6
+
7
+ class NotImplementedError < RuntimeError; end
8
+ class EOFError < ::EOFError; end
9
+
10
+ attr_reader :name, :mode, :_
11
+
12
+ def initialize(name, mode = 'rw')
13
+ @name = name
14
+ @mode = mode # we're going to just ignore this for now
15
+ @buffer = nil
16
+ @sync = false
17
+ @size = 0
18
+ @lineno = 0
19
+ end
20
+ alias :for_fd :initialize
21
+
22
+ def self.list_key(name)
23
+ "#{name}:_list"
24
+ end
25
+
26
+ def list_key
27
+ self.class.list_key(name)
28
+ end
29
+
30
+ # Executes the block for every line in the named I/O port, where lines are
31
+ # separated by sep_string.
32
+ #
33
+ # IO.foreach("testfile") {|x| print "GOT ", x }
34
+ # produces:
35
+ #
36
+ # GOT This is line one
37
+ # GOT This is line two
38
+ # GOT This is line three
39
+ # GOT And so on...
40
+ def self.foreach(name, &block)
41
+ readlines(name).each(&block)
42
+ nil
43
+ end
44
+
45
+ # With no associated block, open is a synonym for IO::new. If the optional
46
+ # code block is given, it will be passed io as an argument, and the IO
47
+ # object will automatically be closed when the block terminates. In this
48
+ # instance, IO::open returns the value of the block.
49
+ def self.open(name, mode = 'r')
50
+ io = new(name, mode)
51
+ block_given? ? yield(io) : io
52
+ end
53
+
54
+ # IO.pipe → array
55
+ # Creates a pair of pipe endpoints (connected to each other) and returns
56
+ # them as a two-element array of IO objects: [ read_file, write_file ].
57
+ # Not available on all platforms.
58
+ #
59
+ # In the example below, the two processes close the ends of the pipe that
60
+ # they are not using. This is not just a cosmetic nicety. The read end of
61
+ # a pipe will not generate an end of file condition if there are any
62
+ # writers with the pipe still open. In the case of the parent process, the
63
+ # rd.read will never return if it does not first issue a wr.close.
64
+ #
65
+ # rd, wr = IO.pipe
66
+ #
67
+ # if fork
68
+ # wr.close
69
+ # puts "Parent got: <#{rd.read}>"
70
+ # rd.close
71
+ # Process.wait
72
+ # else
73
+ # rd.close
74
+ # puts "Sending message to parent"
75
+ # wr.write "Hi Dad"
76
+ # wr.close
77
+ # end
78
+ # produces:
79
+ #
80
+ # Sending message to parent
81
+ # Parent got: <Hi Dad>
82
+ def self.pipe
83
+ raise NotImplementedError, ".pipe is not implemented"
84
+ end
85
+
86
+ # Opens the file, optionally seeks to the given offset, then returns
87
+ # length bytes (defaulting to the rest of the file). read ensures the file
88
+ # is closed before returning.
89
+ #
90
+ # IO.read("testfile") #=> "This is line one\nThis is line
91
+ # two\nThis is line three\nAnd so on...\n"
92
+ # IO.read("testfile", 20) #=> "This is line one\nThi"
93
+ # IO.read("testfile", 20, 10) #=> "ne one\nThis is line "
94
+ def self.read(name, length = nil, offset = nil)
95
+ start_i = offset || 0
96
+ end_i = length ? start_i + (length - 1) : -1
97
+ values = redis.lrange(list_key(name), start_i, end_i)
98
+ values.join("\n")
99
+ end
100
+
101
+ # Reads the entire file specified by name as individual lines, and returns
102
+ # those lines in an array. Lines are separated by sep_string.
103
+ #
104
+ # a = IO.readlines("testfile")
105
+ # a[0] #=> "This is line one\n"
106
+ def self.readlines(name)
107
+ redis.lrange list_key(name), 0, -1
108
+ end
109
+
110
+ # IO.select(read_array
111
+ # [, write_array
112
+ # [, error_array
113
+ # [, timeout]]] ) => array or nil
114
+ # See Kernel#select.
115
+ def self.select(name)
116
+ raise NotImplementedError, ".select is not implemented"
117
+ end
118
+
119
+ # IO.sysopen(path, [mode, [perm]]) => fixnum
120
+ # Opens the given path, returning the underlying file descriptor as a
121
+ # Fixnum.
122
+ #
123
+ # IO.sysopen("testfile") #=> 3
124
+ def self.sysopen(name)
125
+ raise NotImplementedError, ".sysopen is not implemented"
126
+ end
127
+
128
+ # String Output—Writes obj to ios. obj will be converted to a string using
129
+ # to_s.
130
+ #
131
+ # $stdout << "Hello " << "world!\n"
132
+ # produces:
133
+ #
134
+ # Hello world!
135
+ def <<(text)
136
+ @buffer ||= ''
137
+ @buffer << text
138
+ flush if sync
139
+ @buffer
140
+ end
141
+
142
+ # ios.binmode => ios
143
+ # Puts ios into binary mode. This is useful only in MS-DOS/Windows
144
+ # environments. Once a stream is in binary mode, it cannot be reset to
145
+ # nonbinary mode.
146
+ #
147
+ def binmode; end
148
+
149
+ # ios.close => nil
150
+ # Closes ios and flushes any pending writes to the operating system. The
151
+ # stream is unavailable for any further data operations; an IOError is
152
+ # raised if such an attempt is made. I/O streams are automatically closed
153
+ # when they are claimed by the garbage collector.
154
+ #
155
+ # If ios is opened by IO.popen, close sets $?.
156
+ def close
157
+
158
+ end
159
+
160
+ # ios.close_read => nil
161
+ # Closes the read end of a duplex I/O stream (i.e., one that contains both
162
+ # a read and a write stream, such as a pipe). Will raise an IOError if the
163
+ # stream is not duplexed.
164
+ #
165
+ # f = IO.popen("/bin/sh","r+")
166
+ # f.close_read
167
+ # f.readlines
168
+ # produces:
169
+ #
170
+ # prog.rb:3:in `readlines': not opened for reading (IOError)
171
+ # from prog.rb:3
172
+ def close_read
173
+
174
+ end
175
+
176
+ # ios.close_write => nil
177
+ # Closes the write end of a duplex I/O stream (i.e., one that contains
178
+ # both a read and a write stream, such as a pipe). Will raise an IOError
179
+ # if the stream is not duplexed.
180
+ #
181
+ # f = IO.popen("/bin/sh","r+")
182
+ # f.close_write
183
+ # f.print "nowhere"
184
+ # produces:
185
+ #
186
+ # prog.rb:3:in `write': not opened for writing (IOError)
187
+ # from prog.rb:3:in `print'
188
+ # from prog.rb:3
189
+ def close_write
190
+
191
+ end
192
+
193
+ # ios.closed? => true or false
194
+ # Returns true if ios is completely closed (for duplex streams, both
195
+ # reader and writer), false otherwise.
196
+ #
197
+ # f = File.new("testfile")
198
+ # f.close #=> nil
199
+ # f.closed? #=> true
200
+ # f = IO.popen("/bin/sh","r+")
201
+ # f.close_write #=> nil
202
+ # f.closed? #=> false
203
+ # f.close_read #=> nil
204
+ # f.closed? #=> true
205
+ def closed
206
+
207
+ end
208
+
209
+ # ios.each(sep_string=$/) {|line| block } => ios
210
+ # ios.each_line(sep_string=$/) {|line| block } => ios
211
+ # Executes the block for every line in ios, where lines are separated by
212
+ # sep_string. ios must be opened for reading or an IOError will be raised.
213
+ #
214
+ # f = File.new("testfile")
215
+ # f.each {|line| puts "#{f.lineno}: #{line}" }
216
+ # produces:
217
+ #
218
+ # 1: This is line one
219
+ # 2: This is line two
220
+ # 3: This is line three
221
+ # 4: And so on...
222
+ def each(&block)
223
+ rewind
224
+ length.times do
225
+ yield gets
226
+ end
227
+ self
228
+ end
229
+ alias :each_line :each
230
+
231
+ # ios.each_byte {|byte| block } => nil
232
+ # Calls the given block once for each byte (0..255) in ios, passing the
233
+ # byte as an argument. The stream must be opened for reading or an IOError
234
+ # will be raised.
235
+ #
236
+ # f = File.new("testfile")
237
+ # checksum = 0
238
+ # f.each_byte {|x| checksum ^= x } #=> #<File:testfile>
239
+ # checksum #=> 12
240
+ def each_byte
241
+
242
+ end
243
+
244
+ # ios.eof => true or false
245
+ # ios.eof? => true or false
246
+ # Returns true if ios is at end of file that means there are no more data
247
+ # to read. The stream must be opened for reading or an IOError will be
248
+ # raised.
249
+ #
250
+ # f = File.new("testfile")
251
+ # dummy = f.readlines
252
+ # f.eof #=> true
253
+ # If ios is a stream such as pipe or socket, IO#eof? blocks until the
254
+ # other end sends some data or closes it.
255
+ #
256
+ # r, w = IO.pipe
257
+ # Thread.new { sleep 1; w.close }
258
+ # r.eof? #=> true after 1 second blocking
259
+ #
260
+ # r, w = IO.pipe
261
+ # Thread.new { sleep 1; w.puts "a" }
262
+ # r.eof? #=> false after 1 second blocking
263
+ #
264
+ # r, w = IO.pipe
265
+ # r.eof? # blocks forever
266
+ # Note that IO#eof? reads data to a input buffer. So IO#sysread doesn‘t
267
+ # work with IO#eof?.
268
+ def eof
269
+ lineno >= length
270
+ end
271
+ alias :eof? :eof
272
+
273
+ # ios.fcntl(integer_cmd, arg) => integer
274
+ # Provides a mechanism for issuing low-level commands to control or query
275
+ # file-oriented I/O streams. Arguments and results are platform dependent.
276
+ # If arg is a number, its value is passed directly. If it is a string, it
277
+ # is interpreted as a binary sequence of bytes (Array#pack might be a
278
+ # useful way to build this string). On Unix platforms, see fcntl(2) for
279
+ # details. Not implemented on all platforms.
280
+ def fcntl(integer_cmd, arg)
281
+
282
+ end
283
+
284
+ # ios.fileno => fixnum
285
+ # ios.to_i => fixnum
286
+ # Returns an integer representing the numeric file descriptor for ios.
287
+ #
288
+ # $stdin.fileno #=> 0
289
+ # $stdout.fileno #=> 1
290
+ def fileno
291
+ end
292
+ alias :to_i :fileno
293
+
294
+ # ios.flush => ios
295
+ # Flushes any buffered data within ios to the underlying operating system
296
+ # (note that this is Ruby internal buffering only; the OS may buffer the
297
+ # data as well).
298
+ #
299
+ # $stdout.print "no newline"
300
+ # $stdout.flush
301
+ # produces:
302
+ #
303
+ # no newline
304
+ def flush
305
+ if @buffer
306
+ redis.rpush list_key, @buffer
307
+ @size += @buffer.length
308
+ stat.write_attribute(:size, @size)
309
+ stat.write_attribute(:mtime, Time.now)
310
+ end
311
+ @buffer = nil
312
+ end
313
+
314
+ # ios.fsync => 0 or nil
315
+ # Immediately writes all buffered data in ios to disk. Returns nil if the
316
+ # underlying operating system does not support fsync(2). Note that fsync
317
+ # differs from using IO#sync=. The latter ensures that data is flushed
318
+ # from Ruby‘s buffers, but doesn‘t not guarantee that the underlying
319
+ # operating system actually writes it to disk.
320
+ def fsync
321
+ end
322
+
323
+ # ios.getc => fixnum or nil
324
+ # Gets the next 8-bit byte (0..255) from ios. Returns nil if called at end
325
+ # of file.
326
+ #
327
+ # f = File.new("testfile")
328
+ # f.getc #=> 84
329
+ # f.getc #=> 104
330
+ def getc
331
+ end
332
+
333
+ # ios.gets(sep_string=$/) => string or nil
334
+ # Reads the next ``line’’ from the I/O stream; lines are separated by
335
+ # sep_string. A separator of nil reads the entire contents, and a
336
+ # zero-length separator reads the input a paragraph at a time (two
337
+ # successive newlines in the input separate paragraphs). The stream must
338
+ # be opened for reading or an IOError will be raised. The line read in
339
+ # will be returned and also assigned to $_. Returns nil if called at end
340
+ # of file.
341
+ #
342
+ # File.new("testfile").gets #=> "This is line one\n"
343
+ # $_ #=> "This is line one\n"
344
+ def gets
345
+ flush
346
+ val = redis.lrange(list_key, lineno, lineno + 1)
347
+ if val = val.first
348
+ self.lineno += 1
349
+ $_ = @_ = val
350
+ val
351
+ end
352
+ end
353
+
354
+ # Return a string describing this IO object.
355
+ def inspect
356
+ "#<Redisk::IO (#{name})>"
357
+ end
358
+ alias :to_s :inspect
359
+
360
+ #
361
+ # ios.ioctl(integer_cmd, arg) => integer
362
+ # Provides a mechanism for issuing low-level commands to control or query
363
+ # I/O devices. Arguments and results are platform dependent. If arg is a
364
+ # number, its value is passed directly. If it is a string, it is
365
+ # interpreted as a binary sequence of bytes. On Unix platforms, see
366
+ # ioctl(2) for details. Not implemented on all platforms.
367
+ #
368
+ def ioctl(integer_cmd, arg)
369
+ end
370
+
371
+ # ios.isatty => true or false
372
+ # ios.tty? => true or false
373
+ # Returns true if ios is associated with a terminal device (tty), false
374
+ # otherwise.
375
+ def isatty
376
+ false
377
+ end
378
+
379
+ # the number of lines in the current list/file
380
+ def length
381
+ redis.llen list_key
382
+ end
383
+ alias :lines :length
384
+
385
+ # the estimated size in bytes of the current file
386
+ def size
387
+ @size
388
+ end
389
+
390
+ # ios.lineno => integer
391
+ # Returns the current line number in ios. The stream must be opened for
392
+ # reading. lineno counts the number of times gets is called, rather than
393
+ # the number of newlines encountered. The two values will differ if gets
394
+ # is called with a separator other than newline. See also the $. variable.
395
+ #
396
+ # f = File.new("testfile")
397
+ # f.lineno #=> 0
398
+ # f.gets #=> "This is line one\n"
399
+ # f.lineno #=> 1
400
+ # f.gets #=> "This is line two\n"
401
+ # f.lineno #=> 2
402
+ def lineno
403
+ @lineno
404
+ end
405
+
406
+ # ios.lineno = integer => integer
407
+ # Manually sets the current line number to the given value. $. is updated
408
+ # only on the next read.
409
+ #
410
+ # f = File.new("testfile")
411
+ # f.gets #=> "This is line one\n"
412
+ # $. #=> 1
413
+ # f.lineno = 1000
414
+ # f.lineno #=> 1000
415
+ # $. # lineno of last read #=> 1
416
+ # f.gets #=> "This is line two\n"
417
+ # $. # lineno of last read #=> 1001
418
+ def lineno=(num)
419
+ @lineno = num
420
+ end
421
+
422
+ # ios.pid => fixnum
423
+ # Returns the process ID of a child process associated with ios. This will
424
+ # be set by IO::popen.
425
+ #
426
+ # pipe = IO.popen("-")
427
+ # if pipe
428
+ # $stderr.puts "In parent, child pid is #{pipe.pid}"
429
+ # else
430
+ # $stderr.puts "In child, pid is #{$$}"
431
+ # end
432
+ # produces:
433
+ #
434
+ # In child, pid is 26209
435
+ # In parent, child pid is 26209
436
+ def pid
437
+
438
+ end
439
+
440
+ # ios.pos => integer
441
+ # ios.tell => integer
442
+ # Returns the current offset (in bytes) of ios.
443
+ #
444
+ # f = File.new("testfile")
445
+ # f.pos #=> 0
446
+ # f.gets #=> "This is line one\n"
447
+ # f.pos #=> 17
448
+ def pos
449
+
450
+ end
451
+ alias :tell :pos
452
+
453
+ # ios.pos = integer => integer
454
+ # Seeks to the given position (in bytes) in ios.
455
+ #
456
+ # f = File.new("testfile")
457
+ # f.pos = 17
458
+ # f.gets #=> "This is line two\n"
459
+ def pos=(num)
460
+
461
+ end
462
+
463
+ # ios.print() => nil
464
+ # ios.print(obj, ...) => nil
465
+ # Writes the given object(s) to ios. The stream must be opened for
466
+ # writing. If the output record separator ($\) is not nil, it will be
467
+ # appended to the output. If no arguments are given, prints $_. Objects
468
+ # that aren‘t strings will be converted by calling their to_s method. With
469
+ # no argument, prints the contents of the variable $_. Returns nil.
470
+ #
471
+ # $stdout.print("This is ", 100, " percent.\n")
472
+ # produces:
473
+ #
474
+ # This is 100 percent.
475
+ def print(*args)
476
+ args.empty? ?
477
+ write(@_) :
478
+ write(args.collect {|a| a.to_s }.join)
479
+ nil
480
+ end
481
+
482
+ # ios.printf(format_string [, obj, ...] ) => nil
483
+ # Formats and writes to ios, converting parameters under control of the
484
+ # format string. See Kernel#sprintf for details.
485
+ def printf(format_string, *args)
486
+ write sprintf(format_string, *args)
487
+ nil
488
+ end
489
+
490
+ # ios.putc(obj) => obj
491
+ # If obj is Numeric, write the character whose code is obj, otherwise
492
+ # write the first character of the string representation of obj to ios.
493
+ #
494
+ # $stdout.putc "A"
495
+ # $stdout.putc 65
496
+ # produces:
497
+ #
498
+ # AA
499
+ def putc(obj)
500
+
501
+ end
502
+
503
+ # ios.puts(obj, ...) => nil
504
+ # Writes the given objects to ios as with IO#print. Writes a record
505
+ # separator (typically a newline) after any that do not already end with a
506
+ # newline sequence. If called with an array argument, writes each element
507
+ # on a new line. If called without arguments, outputs a single record
508
+ # separator.
509
+ #
510
+ # $stdout.puts("this", "is", "a", "test")
511
+ # produces:
512
+ #
513
+ # this
514
+ # is
515
+ # a
516
+ # test
517
+ def puts(*args)
518
+ args.empty? ?
519
+ write('') :
520
+ args.each {|a| write(a) }
521
+ nil
522
+ end
523
+
524
+ # ios.read([length [, buffer]]) => string, buffer, or nil
525
+ # Reads at most length bytes from the I/O stream, or to the end of file if
526
+ # length is omitted or is nil. length must be a non-negative integer or
527
+ # nil. If the optional buffer argument is present, it must reference a
528
+ # String, which will receive the data.
529
+ #
530
+ # At end of file, it returns nil or "" depend on length. ios.read() and
531
+ # ios.read(nil) returns "". ios.read(positive-integer) returns nil.
532
+ #
533
+ # f = File.new("testfile")
534
+ # f.read(16) #=> "This is line one"
535
+ def read
536
+
537
+ end
538
+
539
+ # ios.read_nonblock(maxlen) => string
540
+ # ios.read_nonblock(maxlen, outbuf) => outbuf
541
+ # Reads at most maxlen bytes from ios using read(2) system call after
542
+ # O_NONBLOCK is set for the underlying file descriptor.
543
+ #
544
+ # If the optional outbuf argument is present, it must reference a String,
545
+ # which will receive the data.
546
+ #
547
+ # read_nonblock just calls read(2). It causes all errors read(2) causes:
548
+ # EAGAIN, EINTR, etc. The caller should care such errors.
549
+ #
550
+ # read_nonblock causes EOFError on EOF.
551
+ #
552
+ # If the read buffer is not empty, read_nonblock reads from the buffer
553
+ # like readpartial. In this case, read(2) is not called.
554
+ #
555
+ def read_nonblock
556
+
557
+ end
558
+
559
+
560
+ # readbytes(n)
561
+ # Reads exactly n bytes.
562
+ #
563
+ # If the data read is nil an EOFError is raised.
564
+ #
565
+ # If the data read is too short a TruncatedDataError is raised and the
566
+ # read data is obtainable via its data method.
567
+ #
568
+ def readbytes(n)
569
+
570
+ end
571
+
572
+ # ios.readchar => fixnum
573
+ # Reads a character as with IO#getc, but raises an EOFError on end of
574
+ # file.
575
+ def readchar
576
+
577
+ end
578
+
579
+ # ios.readline(sep_string=$/) => string
580
+ # Reads a line as with IO#gets, but raises an EOFError on end of file.
581
+ def readline
582
+ if eof?
583
+ raise EOFError, "At the end of the IO #{inspect}"
584
+ else
585
+ gets
586
+ end
587
+ end
588
+
589
+ # ios.readlines(sep_string=$/) => array
590
+ # Reads all of the lines in ios, and returns them in anArray. Lines are
591
+ # separated by the optional sep_string. If sep_string is nil, the rest of
592
+ # the stream is returned as a single record. The stream must be opened for
593
+ # reading or an IOError will be raised.
594
+ #
595
+ # f = File.new("testfile")
596
+ # f.readlines[0] #=> "This is line one\n"
597
+ def readlines
598
+ self.class.readlines(name)
599
+ end
600
+
601
+ # ios.readpartial(maxlen) => string
602
+ # ios.readpartial(maxlen, outbuf) => outbuf
603
+ # Reads at most maxlen bytes from the I/O stream. It blocks only if ios
604
+ # has no data immediately available. It doesn‘t block if some data
605
+ # available. If the optional outbuf argument is present, it must reference
606
+ # a String, which will receive the data. It raises EOFError on end of
607
+ # file.
608
+ #
609
+ # readpartial is designed for streams such as pipe, socket, tty, etc. It
610
+ # blocks only when no data immediately available. This means that it
611
+ # blocks only when following all conditions hold.
612
+ #
613
+ # the buffer in the IO object is empty.
614
+ # the content of the stream is empty.
615
+ # the stream is not reached to EOF.
616
+ # When readpartial blocks, it waits data or EOF on the stream. If some
617
+ # data is reached, readpartial returns with the data. If EOF is reached,
618
+ # readpartial raises EOFError.
619
+ #
620
+ # When readpartial doesn‘t blocks, it returns or raises immediately. If
621
+ # the buffer is not empty, it returns the data in the buffer. Otherwise if
622
+ # the stream has some content, it returns the data in the stream.
623
+ # Otherwise if the stream is reached to EOF, it raises EOFError.
624
+ #
625
+ # r, w = IO.pipe # buffer pipe content
626
+ # w << "abc" # "" "abc".
627
+ # r.readpartial(4096) #=> "abc" "" ""
628
+ # r.readpartial(4096) # blocks because buffer and pipe is empty.
629
+ #
630
+ # r, w = IO.pipe # buffer pipe content
631
+ # w << "abc" # "" "abc"
632
+ # w.close # "" "abc" EOF
633
+ # r.readpartial(4096) #=> "abc" "" EOF
634
+ # r.readpartial(4096) # raises EOFError
635
+ #
636
+ # r, w = IO.pipe # buffer pipe content
637
+ # w << "abc\ndef\n" # "" "abc\ndef\n"
638
+ # r.gets #=> "abc\n" "def\n" ""
639
+ # w << "ghi\n" # "def\n" "ghi\n"
640
+ # r.readpartial(4096) #=> "def\n" "" "ghi\n"
641
+ # r.readpartial(4096) #=> "ghi\n" "" ""
642
+ # Note that readpartial behaves similar to sysread. The differences are:
643
+ #
644
+ # If the buffer is not empty, read from the buffer instead of "sysread for
645
+ # buffered IO (IOError)".
646
+ # It doesn‘t cause Errno::EAGAIN and Errno::EINTR. When readpartial meets
647
+ # EAGAIN and EINTR by read system call, readpartial retry the system call.
648
+ # The later means that readpartial is nonblocking-flag insensitive. It
649
+ # blocks on the situation IO#sysread causes Errno::EAGAIN as if the fd is
650
+ # blocking mode.
651
+ #
652
+ def readpartial
653
+
654
+ end
655
+
656
+ # ios.reopen(other_IO) => ios
657
+ # ios.reopen(path, mode_str) => ios
658
+ # Reassociates ios with the I/O stream given in other_IO or to a new
659
+ # stream opened on path. This may dynamically change the actual class of
660
+ # this stream.
661
+ #
662
+ # f1 = File.new("testfile")
663
+ # f2 = File.new("testfile")
664
+ # f2.readlines[0] #=> "This is line one\n"
665
+ # f2.reopen(f1) #=> #<File:testfile>
666
+ # f2.readlines[0] #=> "This is line one\n"
667
+ def reopen()
668
+
669
+ end
670
+
671
+ # ios.rewind => 0
672
+ # Positions ios to the beginning of input, resetting lineno to zero.
673
+ #
674
+ # f = File.new("testfile")
675
+ # f.readline #=> "This is line one\n"
676
+ # f.rewind #=> 0
677
+ # f.lineno #=> 0
678
+ # f.readline #=> "This is line one\n"
679
+ def rewind
680
+ self.lineno = 0
681
+ end
682
+
683
+ # scanf(str,&b)
684
+ # The trick here is doing a match where you grab one line of input at a
685
+ # time. The linebreak may or may not occur at the boundary where the
686
+ # string matches a format specifier. And if it does, some rule about
687
+ # whitespace may or may not be in effect…
688
+ #
689
+ # That‘s why this is much more elaborate than the string version.
690
+ #
691
+ # For each line: Match succeeds (non-emptily) and the last attempted
692
+ # spec/string sub-match succeeded:
693
+ #
694
+ # could the last spec keep matching?
695
+ # yes: save interim results and continue (next line)
696
+ # The last attempted spec/string did not match:
697
+ #
698
+ # are we on the next-to-last spec in the string?
699
+ #
700
+ # yes:
701
+ # is fmt_string.string_left all spaces?
702
+ # yes: does current spec care about input space?
703
+ # yes: fatal failure
704
+ # no: save interim results and continue
705
+ # no: continue [this state could be analyzed further]
706
+ def scanf
707
+
708
+ end
709
+
710
+ SEEK_SET = 0
711
+ SEEK_CUR = 1
712
+ SEEK_END = 2
713
+
714
+ # ios.seek(amount, whence=SEEK_SET) → 0
715
+ # Seeks to a given offset anInteger in the stream according to the value
716
+ # of whence:
717
+ #
718
+ # IO::SEEK_CUR | Seeks to _amount_ plus current position
719
+ # --------------+----------------------------------------------------
720
+ # IO::SEEK_END | Seeks to _amount_ plus end of stream (you probably
721
+ # | want a negative value for _amount_)
722
+ # --------------+----------------------------------------------------
723
+ # IO::SEEK_SET | Seeks to the absolute location given by _amount_
724
+ # Example:
725
+ #
726
+ # f = File.new("testfile")
727
+ # f.seek(-13, IO::SEEK_END) #=> 0
728
+ # f.readline #=> "And so on...\n"
729
+ def seek(offset, whence = SEEK_SET)
730
+ case whence
731
+ when SEEK_SET
732
+ self.lineno = offset
733
+ when SEEK_END
734
+ self.lineno = length + offset
735
+ when SEEK_CUR
736
+ self.lineno += offset
737
+ end
738
+ 0
739
+ end
740
+
741
+ # ios.stat => stat
742
+ # Returns status information for ios as an object of type File::Stat.
743
+ #
744
+ # f = File.new("testfile")
745
+ # s = f.stat
746
+ # "%o" % s.mode #=> "100644"
747
+ # s.blksize #=> 4096
748
+ # s.atime #=> Wed Apr 09 08:53:54 CDT 2003
749
+ def stat
750
+ @stat ||= Redisk::Stat.new(name)
751
+ end
752
+
753
+ # ios.sync => true or false
754
+ # Returns the current ``sync mode’’ of ios. When sync mode is true, all
755
+ # output is immediately flushed to the underlying operating system and is
756
+ # not buffered by Ruby internally. See also IO#fsync.
757
+ #
758
+ # f = File.new("testfile")
759
+ # f.sync #=> false
760
+ def sync
761
+ @sync
762
+ end
763
+
764
+ # ios.sync = boolean => boolean
765
+ # Sets the ``sync mode’’ to true or false. When sync mode is true, all
766
+ # output is immediately flushed to the underlying operating system and is
767
+ # not buffered internally. Returns the new state. See also IO#fsync.
768
+ #
769
+ # f = File.new("testfile")
770
+ # f.sync = true
771
+ # (produces no output)
772
+ def sync=(setting)
773
+ @sync = !!setting
774
+ end
775
+
776
+ # ios.sysread(integer ) => string
777
+ # Reads integer bytes from ios using a low-level read and returns them as
778
+ # a string. Do not mix with other methods that read from ios or you may
779
+ # get unpredictable results. Raises SystemCallError on error and EOFError
780
+ # at end of file.
781
+ #
782
+ # f = File.new("testfile")
783
+ # f.sysread(16) #=> "This is line one"
784
+ def sysread(num)
785
+
786
+ end
787
+
788
+ # ios.sysseek(offset, whence=SEEK_SET) => integer
789
+ # Seeks to a given offset in the stream according to the value of whence
790
+ # (see IO#seek for values of whence). Returns the new offset into the
791
+ # file.
792
+ #
793
+ # f = File.new("testfile")
794
+ # f.sysseek(-13, IO::SEEK_END) #=> 53
795
+ # f.sysread(10) #=> "And so on."
796
+ def sysseek(offset, whence = SEEK_SET)
797
+ end
798
+
799
+ # ios.syswrite(string) => integer
800
+ # Writes the given string to ios using a low-level write. Returns the
801
+ # number of bytes written. Do not mix with other methods that write to ios
802
+ # or you may get unpredictable results. Raises SystemCallError on error.
803
+ #
804
+ # f = File.new("out", "w")
805
+ # f.syswrite("ABCDEF") #=> 6
806
+ def syswrite(string)
807
+
808
+ end
809
+
810
+ # truncate the IO to size, taking only the last [size] lines
811
+ def truncate(size = 0)
812
+ size = size.to_i
813
+ if size == 0
814
+ redis.del list_key
815
+ else
816
+ redis.ltrim list_key, -size, -1
817
+ end
818
+ length
819
+ end
820
+
821
+ # ios.ungetc(integer) => nil
822
+ # Pushes back one character (passed as a parameter) onto ios, such that a
823
+ # subsequent buffered read will return it. Only one character may be
824
+ # pushed back before a subsequent read operation (that is, you will be
825
+ # able to read only the last of several characters that have been pushed
826
+ # back). Has no effect with unbuffered reads (such as IO#sysread).
827
+ #
828
+ # f = File.new("testfile") #=> #<File:testfile>
829
+ # c = f.getc #=> 84
830
+ # f.ungetc(c) #=> nil
831
+ # f.getc #=> 84
832
+ def ungetc(int)
833
+
834
+ end
835
+
836
+ # ios.write(string) => integer
837
+ # Writes the given string to ios. The stream must be opened for writing.
838
+ # If the argument is not a string, it will be converted to a string using
839
+ # to_s. Returns the number of bytes written.
840
+ #
841
+ # count = $stdout.write( "This is a test\n" )
842
+ # puts "That was #{count} bytes of data"
843
+ # produces:
844
+ #
845
+ # This is a test
846
+ # That was 15 bytes of data
847
+ def write(string)
848
+ string = string.to_s
849
+ @buffer = string
850
+ flush
851
+ string.length
852
+ end
853
+
854
+ # ios.write_nonblock(string) => integer
855
+ # Writes the given string to ios using write(2) system call after
856
+ # O_NONBLOCK is set for the underlying file descriptor.
857
+ #
858
+ # write_nonblock just calls write(2). It causes all errors write(2)
859
+ # causes: EAGAIN, EINTR, etc. The result may also be smaller than
860
+ # string.length (partial write). The caller should care such errors and
861
+ # partial write.
862
+ #
863
+ def write_nonblock(string)
864
+ end
865
+
866
+ end
867
+ end