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/.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
|