io-like 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (11) hide show
  1. data/CONTRIBUTORS +13 -0
  2. data/GPL +676 -0
  3. data/HACKING +123 -0
  4. data/LEGAL +8 -0
  5. data/LICENSE +57 -0
  6. data/MANIFEST +10 -0
  7. data/NEWS +13 -0
  8. data/README +135 -0
  9. data/lib/io/like.rb +1329 -0
  10. data/test/lib/likestringio.rb +167 -0
  11. 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
+