redisk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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