io-like 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +13 -0
- data/GPL +676 -0
- data/HACKING +123 -0
- data/LEGAL +8 -0
- data/LICENSE +57 -0
- data/MANIFEST +10 -0
- data/NEWS +13 -0
- data/README +135 -0
- data/lib/io/like.rb +1329 -0
- data/test/lib/likestringio.rb +167 -0
- metadata +73 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'io/like'
|
2
|
+
|
3
|
+
class LikeStringIO
|
4
|
+
include IO::Like
|
5
|
+
|
6
|
+
def self.open(string = '', mode = 'rw')
|
7
|
+
lsio = new(string, mode)
|
8
|
+
return lsio unless block_given?
|
9
|
+
|
10
|
+
begin
|
11
|
+
yield(lsio)
|
12
|
+
ensure
|
13
|
+
lsio.close unless lsio.closed?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(string = '', mode = 'rw')
|
18
|
+
@unbuffered_pos = 0
|
19
|
+
@string = string
|
20
|
+
self.fill_size = 0
|
21
|
+
self.flush_size = 0
|
22
|
+
self.sync = true
|
23
|
+
# TODO: These need to be set based on mode.
|
24
|
+
@closed_read = false
|
25
|
+
@closed_write = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
raise IOError, 'closed stream' if closed_read? && closed_write?
|
30
|
+
close_read unless closed_read?
|
31
|
+
close_write unless closed_write?
|
32
|
+
end
|
33
|
+
|
34
|
+
def close_read
|
35
|
+
raise IOError, 'closing non-duplex IO for reading' if @closed_read
|
36
|
+
@closed_read = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def close_write
|
40
|
+
raise IOError, 'closing non-duplex IO for writing' if @closed_write
|
41
|
+
flush
|
42
|
+
@closed_write = true
|
43
|
+
end
|
44
|
+
|
45
|
+
def closed?
|
46
|
+
closed_read? && closed_write?
|
47
|
+
end
|
48
|
+
|
49
|
+
def closed_read?
|
50
|
+
@closed_read
|
51
|
+
end
|
52
|
+
|
53
|
+
def closed_write?
|
54
|
+
@closed_write
|
55
|
+
end
|
56
|
+
|
57
|
+
def eof
|
58
|
+
@unbuffered_pos >= @string.length
|
59
|
+
end
|
60
|
+
alias :eof? :eof
|
61
|
+
|
62
|
+
def readable?
|
63
|
+
! closed_read? && true
|
64
|
+
end
|
65
|
+
|
66
|
+
def size
|
67
|
+
string.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def string
|
71
|
+
flush
|
72
|
+
@string
|
73
|
+
end
|
74
|
+
|
75
|
+
def string=(string)
|
76
|
+
@string = string
|
77
|
+
@unbuffered_pos = 0
|
78
|
+
internal_read_buffer.slice!(0..-1)
|
79
|
+
internal_write_buffer.slice!(0..-1)
|
80
|
+
end
|
81
|
+
|
82
|
+
def truncate(length)
|
83
|
+
raise IOError, 'not opened for writing' unless writable?
|
84
|
+
raise Errno::EINVAL, 'Invalid argument - negative length' unless length > 0
|
85
|
+
|
86
|
+
if length > @string.length then
|
87
|
+
@string += "\000" * (length - @string.length)
|
88
|
+
else
|
89
|
+
@string.slice!(0, length)
|
90
|
+
end
|
91
|
+
|
92
|
+
length
|
93
|
+
end
|
94
|
+
|
95
|
+
def unread(string)
|
96
|
+
raise IOError, 'closed stream' if closed_read?
|
97
|
+
raise IOError, 'not opened for reading' unless readable?
|
98
|
+
|
99
|
+
# Pad any space between the end of the wrapped string and the current
|
100
|
+
# position with null characters.
|
101
|
+
if @unbuffered_pos > @string.length then
|
102
|
+
@string << ("\000" * (@unbuffered_pos - @string.length))
|
103
|
+
end
|
104
|
+
|
105
|
+
length = [string.length, @unbuffered_pos].min
|
106
|
+
old_pos = @unbuffered_pos
|
107
|
+
@unbuffered_pos -= length
|
108
|
+
@string = @string.slice(0, @unbuffered_pos) +
|
109
|
+
string.slice(-length, length) +
|
110
|
+
@string.slice(old_pos..-1)
|
111
|
+
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def writable?
|
116
|
+
! closed_write? && true
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def unbuffered_read(length)
|
122
|
+
# Error out of the end of the wrapped string is reached.
|
123
|
+
raise EOFError, 'end of file reached' if eof?
|
124
|
+
|
125
|
+
# Fill a buffer with the data from the wrapped string.
|
126
|
+
buffer = @string.slice(@unbuffered_pos, length)
|
127
|
+
# Update the position.
|
128
|
+
@unbuffered_pos += buffer.length
|
129
|
+
|
130
|
+
buffer
|
131
|
+
end
|
132
|
+
|
133
|
+
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
134
|
+
# Convert the offset and whence into an absolute position.
|
135
|
+
case whence
|
136
|
+
when IO::SEEK_SET
|
137
|
+
new_pos = offset
|
138
|
+
when IO::SEEK_CUR
|
139
|
+
new_pos = @unbuffered_pos + offset
|
140
|
+
when IO::SEEK_END
|
141
|
+
new_pos = @string.length + offset
|
142
|
+
end
|
143
|
+
|
144
|
+
# Error out if the position is before the beginning of the wrapped string.
|
145
|
+
raise Errno::EINVAL, 'Invalid argument' if new_pos < 0
|
146
|
+
|
147
|
+
# Set the new position.
|
148
|
+
@unbuffered_pos = new_pos
|
149
|
+
end
|
150
|
+
|
151
|
+
def unbuffered_write(string)
|
152
|
+
# Pad any space between the end of the wrapped string and the current
|
153
|
+
# position with null characters.
|
154
|
+
if @unbuffered_pos > @string.length then
|
155
|
+
@string << ("\000" * (@unbuffered_pos - @string.length))
|
156
|
+
end
|
157
|
+
|
158
|
+
# Insert the new string into the wrapped string, replacing sections as
|
159
|
+
# necessary.
|
160
|
+
@string = @string.slice(0, @unbuffered_pos) +
|
161
|
+
string +
|
162
|
+
(@string.slice((@unbuffered_pos + string.length)..-1) || '')
|
163
|
+
|
164
|
+
# Update the position.
|
165
|
+
@unbuffered_pos += string.length
|
166
|
+
end
|
167
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: io-like
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeremy Bopp
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-03 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: "The IO::Like module provides the methods of an IO object based upon on a few simple methods provided by the including class: unbuffered_read, unbuffered_write, and unbuffered_seek. These methods provide the underlying read, write, and seek support respectively, and only the method or methods necessary to the correct operation of the IO aspects of the including class need to be provided. Missing functionality will cause the resulting object to appear read-only, write-only, and/or unseekable depending on which underlying methods are absent. Additionally, read and write operations which are buffered in IO are buffered with independently configurable buffer sizes. Duplexed objects (those with separate read and write streams) are also supported."
|
17
|
+
email: jeremy at bopp dot net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- CONTRIBUTORS
|
24
|
+
- HACKING
|
25
|
+
- LICENSE
|
26
|
+
- GPL
|
27
|
+
- LEGAL
|
28
|
+
- NEWS
|
29
|
+
- README
|
30
|
+
files:
|
31
|
+
- lib/io/like.rb
|
32
|
+
- test/lib/likestringio.rb
|
33
|
+
- CONTRIBUTORS
|
34
|
+
- HACKING
|
35
|
+
- LICENSE
|
36
|
+
- GPL
|
37
|
+
- LEGAL
|
38
|
+
- NEWS
|
39
|
+
- README
|
40
|
+
- MANIFEST
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://io-like.rubyforge.org
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --title
|
46
|
+
- IO::Like Documentation
|
47
|
+
- --charset
|
48
|
+
- utf-8
|
49
|
+
- --line-numbers
|
50
|
+
- --inline-source
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.8.1
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: io-like
|
68
|
+
rubygems_version: 1.2.0
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: A module which provides the functionality of an IO object to any class which provides a couple of simple methods.
|
72
|
+
test_files: []
|
73
|
+
|