redisk 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +23 -0
- data/LICENSE +20 -0
- data/README.rdoc +56 -0
- data/Rakefile +49 -0
- data/lib/redisk/helper.rb +13 -0
- data/lib/redisk/io.rb +867 -0
- data/lib/redisk/logger.rb +36 -0
- data/lib/redisk/stat.rb +382 -0
- data/lib/redisk.rb +37 -0
- data/redisk.gemspec +70 -0
- data/spec/fixtures/rails.log +100 -0
- data/spec/redis-test.conf +132 -0
- data/spec/redisk_io_spec.rb +348 -0
- data/spec/redisk_logger_spec.rb +53 -0
- data/spec/redisk_stat_spec.rb +87 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +47 -0
- metadata +105 -0
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
|