archive-zip 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/CONTRIBUTORS +13 -0
- data/GPL +676 -0
- data/HACKING +122 -0
- data/LEGAL +8 -0
- data/LICENSE +57 -0
- data/MANIFEST +26 -0
- data/NEWS +22 -0
- data/README +130 -0
- data/lib/archive/support/io-like.rb +12 -0
- data/lib/archive/support/io.rb +14 -0
- data/lib/archive/support/iowindow.rb +123 -0
- data/lib/archive/support/stringio.rb +22 -0
- data/lib/archive/support/time.rb +85 -0
- data/lib/archive/support/zlib.rb +211 -0
- data/lib/archive/zip.rb +643 -0
- data/lib/archive/zip/codec.rb +30 -0
- data/lib/archive/zip/codec/deflate.rb +206 -0
- data/lib/archive/zip/codec/store.rb +241 -0
- data/lib/archive/zip/datadescriptor.rb +54 -0
- data/lib/archive/zip/entry.rb +991 -0
- data/lib/archive/zip/error.rb +22 -0
- data/lib/archive/zip/extrafield.rb +23 -0
- data/lib/archive/zip/extrafield/extendedtimestamp.rb +101 -0
- data/lib/archive/zip/extrafield/raw.rb +32 -0
- data/lib/archive/zip/extrafield/unix.rb +101 -0
- data/test/test_archive.rb +8 -0
- metadata +98 -0
data/HACKING
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
= Guide to Hacking Archive::Zip
|
2
|
+
|
3
|
+
== Licensing
|
4
|
+
|
5
|
+
Contributed code must be licensed under the same license as this project. See
|
6
|
+
the included LICENSE file for details. Special consideration MAY be made in
|
7
|
+
some cases, but such cases will be rare.
|
8
|
+
|
9
|
+
|
10
|
+
== Dependencies
|
11
|
+
|
12
|
+
=== Runtime
|
13
|
+
|
14
|
+
* Ruby 1.8.6 or greater
|
15
|
+
|
16
|
+
|
17
|
+
=== Build
|
18
|
+
|
19
|
+
* rubygems 0.9.0 or greater
|
20
|
+
* rake 0.8.1 or greater
|
21
|
+
* allison 2.0.3 (optional - used for documentation only, if available)
|
22
|
+
* rsync (optional - used for publishing documentation)
|
23
|
+
|
24
|
+
|
25
|
+
=== Install
|
26
|
+
|
27
|
+
* rubygems 0.9.0 or greater
|
28
|
+
|
29
|
+
|
30
|
+
== Versioning Policy
|
31
|
+
|
32
|
+
Version numbers will be in <em>x.y.z</em> format, where <em>x</em>, <em>y</em>,
|
33
|
+
and <em>z</em> are integers starting from 0. The version increment rules are
|
34
|
+
as follows:
|
35
|
+
|
36
|
+
<b>x</b>:: Planned releases which implement significant changes and/or break API
|
37
|
+
compatibility. An exception is to be made for the transition from
|
38
|
+
the <em>0.y.z</em> series to the <em>1.y.z</em> series since the
|
39
|
+
<em>0.y.z</em> series is expected to be unstable throughout
|
40
|
+
development. When incremented, <em>y</em> and <em>z</em> are reset
|
41
|
+
to 0.
|
42
|
+
<b>y</b>:: Planned releases which incorporate numerous bug fixes and/or new
|
43
|
+
features which do not break backward compatibility. When
|
44
|
+
incremented, <em>z</em> is reset to 0.
|
45
|
+
<b>z</b>:: Generally, unplanned releases which incorporate a single fix for a
|
46
|
+
critical defect.
|
47
|
+
|
48
|
+
This is the {Rational Versioning Policy}[http://www.rubygems.org/read/chapter/7]
|
49
|
+
as outlined in the {RubyGems User Guide}[http://www.rubygems.org/read/book/1].
|
50
|
+
|
51
|
+
|
52
|
+
== Support Policy
|
53
|
+
|
54
|
+
Due to limitations in resources (time/money/manpower), this project will focus
|
55
|
+
primarily upon the development line of the current release at any given time.
|
56
|
+
Fixes and new features should be applied first to that development line and then
|
57
|
+
backported to earlier releases if necessary and feasible. Long term maintenance
|
58
|
+
of previous releases is not planned. Users are generally expected to upgrade to
|
59
|
+
the latest release in order to receive updates unless an explicit declaration of
|
60
|
+
support for a previous release is made.
|
61
|
+
|
62
|
+
|
63
|
+
== Coding Style
|
64
|
+
|
65
|
+
The following points are not necessarily set in stone but should rather be used
|
66
|
+
as a good guideline. Consistency is the goal of coding style, and changes will
|
67
|
+
be more easily accepted if they are consistent with the rest of the code.
|
68
|
+
|
69
|
+
<b>File Encoding</b>:: UTF-8
|
70
|
+
<b>Indentation</b>:: Two spaces; no tabs
|
71
|
+
<b>Comments</b>:: Document classes, attributes, methods, and code
|
72
|
+
<b>Boolean Operators</b>:: Use <tt>&&</tt> and <tt>||</tt> for boolean tests;
|
73
|
+
avoid <tt>and</tt> and <tt>or</tt>
|
74
|
+
<b>Method Calls</b>:: Use <tt>a_method(arg, arg, etc)</tt>; <b>not</b>
|
75
|
+
<tt>a_method( arg, arg, etc )</tt>,
|
76
|
+
<tt>a_method arg, arg, etc</tt>, or any other
|
77
|
+
variation
|
78
|
+
<b>Blocks</b>:: <tt>do end</tt> for multi-line blocks and
|
79
|
+
<tt>{ }</tt> for single-line blocks
|
80
|
+
<b>Line length</b>:: Limit lines to a maximum of 80 characters
|
81
|
+
<b>General</b>:: Try to follow the flow and style of the rest of the
|
82
|
+
code
|
83
|
+
|
84
|
+
|
85
|
+
== Generating Patches
|
86
|
+
|
87
|
+
Patches should usually be generated against the <em>HEAD</em> revision of the
|
88
|
+
<em>master</em> branch. When generating patches, please try to implement only
|
89
|
+
a single feature or bug fix per patch. Documentation describing a patch should
|
90
|
+
be included along with the patch so that the maintainer can more easily
|
91
|
+
determine whether or not a patch is acceptable. Patches lacking the necessary
|
92
|
+
documentation will be ignored.
|
93
|
+
|
94
|
+
Patches will be much more readily accepted if test cases are provided which
|
95
|
+
verify correct operation. Such test cases should be provided within the patch
|
96
|
+
rather than as a separate patch. Proper documentation, especially for
|
97
|
+
user-visible APIs, is highly prized; providing accurate and detailed
|
98
|
+
documentation, often in the form of rubydocs, throughout new code contributions
|
99
|
+
will also increase the desirability of a patch.
|
100
|
+
|
101
|
+
If a series of patches is generated which cannot be applied individually, make
|
102
|
+
sure to mention the dependency relationships in whatever medium is being used
|
103
|
+
to distribute the patches. For instance, if a bug is discovered while
|
104
|
+
implementing a new feature, create a patch which fixes the bug followed by a
|
105
|
+
separate patch adding the feature. If the feature patch requires the bug fix
|
106
|
+
patch in order to work, note that dependency in the comments for the feature
|
107
|
+
patch by somehow referencing the bug fix patch.
|
108
|
+
|
109
|
+
The patch generation process in general:
|
110
|
+
$ git clone git://rubyforge.org/archive-zip.git # Clone the repo and check out
|
111
|
+
# the master branch.
|
112
|
+
$ cd archive-zip # Enter the workspace.
|
113
|
+
(make and test changes)
|
114
|
+
$ git add file1 file2 .. # Add new/modified files.
|
115
|
+
$ git commit # Commit changes.
|
116
|
+
$ git format-patch -C HEAD^ # Create a patch for the last
|
117
|
+
# commit.
|
118
|
+
|
119
|
+
Repeat as necessary until all patches are generated. Then either attach them to
|
120
|
+
1 or more email messages addressed to the maintainer or attach them to tickets
|
121
|
+
in the issue tracker for the project. Remember to include a brief description
|
122
|
+
of the patch and its dependencies, if any.
|
data/LEGAL
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
LICENSE text follows:
|
2
|
+
|
3
|
+
Archive::Zip is copyrighted free software by Jeremy Bopp
|
4
|
+
<jeremy at bopp dot net>. You can redistribute it and/or modify it under
|
5
|
+
either the terms of the GPL (see the included GPL file), or the conditions
|
6
|
+
below:
|
7
|
+
|
8
|
+
1. You may make and give away verbatim copies of the source form of the
|
9
|
+
software without restriction, provided that you duplicate all of the
|
10
|
+
original copyright notices and associated disclaimers.
|
11
|
+
|
12
|
+
2. You may modify your copy of the software in any way, provided that
|
13
|
+
you do at least ONE of the following:
|
14
|
+
|
15
|
+
a) place your modifications in the Public Domain or otherwise
|
16
|
+
make them Freely Available, such as by posting said
|
17
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
18
|
+
the author to include your modifications in the software.
|
19
|
+
|
20
|
+
b) use the modified software only within your corporation or
|
21
|
+
organization.
|
22
|
+
|
23
|
+
c) rename any non-standard executables so the names do not conflict
|
24
|
+
with standard executables, which must also be provided.
|
25
|
+
|
26
|
+
d) make other distribution arrangements with the author.
|
27
|
+
|
28
|
+
3. You may distribute the software in object code or executable
|
29
|
+
form, provided that you do at least ONE of the following:
|
30
|
+
|
31
|
+
a) distribute the executables and library files of the software,
|
32
|
+
together with instructions (in the manual page or equivalent)
|
33
|
+
on where to get the original distribution.
|
34
|
+
|
35
|
+
b) accompany the distribution with the machine-readable source of
|
36
|
+
the software.
|
37
|
+
|
38
|
+
c) give non-standard executables non-standard names, with
|
39
|
+
instructions on where to get the original software distribution.
|
40
|
+
|
41
|
+
d) make other distribution arrangements with the author.
|
42
|
+
|
43
|
+
4. You may modify and include the covered part of the software into any
|
44
|
+
other software (possibly commercial). But some files in the
|
45
|
+
distribution may not be written by the author, such that they are not
|
46
|
+
under these terms. (See the file LEGAL for a listing and conditions)
|
47
|
+
|
48
|
+
5. The scripts and library files supplied as input to or produced as
|
49
|
+
output from the software do not automatically fall under the
|
50
|
+
copyright of the software, but belong to whomever generated them,
|
51
|
+
and may be sold commercially, and may be aggregated with this
|
52
|
+
software.
|
53
|
+
|
54
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
55
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
56
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
57
|
+
PURPOSE.
|
data/MANIFEST
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
CONTRIBUTORS
|
2
|
+
GPL
|
3
|
+
HACKING
|
4
|
+
LEGAL
|
5
|
+
LICENSE
|
6
|
+
MANIFEST
|
7
|
+
NEWS
|
8
|
+
README
|
9
|
+
lib/archive/support/io-like.rb
|
10
|
+
lib/archive/support/io.rb
|
11
|
+
lib/archive/support/iowindow.rb
|
12
|
+
lib/archive/support/stringio.rb
|
13
|
+
lib/archive/support/time.rb
|
14
|
+
lib/archive/support/zlib.rb
|
15
|
+
lib/archive/zip.rb
|
16
|
+
lib/archive/zip/codec.rb
|
17
|
+
lib/archive/zip/codec/deflate.rb
|
18
|
+
lib/archive/zip/codec/store.rb
|
19
|
+
lib/archive/zip/entry.rb
|
20
|
+
lib/archive/zip/datadescriptor.rb
|
21
|
+
lib/archive/zip/extrafield.rb
|
22
|
+
lib/archive/zip/extrafield/extendedtimestamp.rb
|
23
|
+
lib/archive/zip/extrafield/raw.rb
|
24
|
+
lib/archive/zip/extrafield/unix.rb
|
25
|
+
lib/archive/zip/error.rb
|
26
|
+
test/test_archive.rb
|
data/NEWS
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
= News and Notifications by Version
|
2
|
+
|
3
|
+
This file lists noteworthy changes which may affect users of this project. More
|
4
|
+
detailed information is available in the rest of the documentation.
|
5
|
+
|
6
|
+
<b>NOTE:</b> Date stamps in the following entries are in YYYY/MM/DD format.
|
7
|
+
|
8
|
+
|
9
|
+
== v0.1.0 (2008/07/10)
|
10
|
+
|
11
|
+
* Initial release
|
12
|
+
* Archive creation and extraction is supported with only a few lines of code
|
13
|
+
(See README)
|
14
|
+
* Archives can be updated "in place" or dumped out to other files or pipes
|
15
|
+
* Files, symlinks, and directories are supported within archives
|
16
|
+
* Unix permission/mode bits are supported
|
17
|
+
* Unix user and group ownerships are supported.
|
18
|
+
* Unix last accessed and last modified times are supported.
|
19
|
+
* Entry extension (AKA extra field) implementations can be added on the fly.
|
20
|
+
* Unknown entry extension types are preserved during archive processing.
|
21
|
+
* Deflate and Store compression codecs supported out of the box
|
22
|
+
* More compression codecs can be added on the fly
|
data/README
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
= Archive::Zip - ZIP Archival Made Easy
|
2
|
+
|
3
|
+
The Archive::Zip library intends to provide a simple, yet complete and
|
4
|
+
Ruby-esque, interface to working with ZIP archives.
|
5
|
+
|
6
|
+
Basic archive creation and extraction can be handled using only a few methods.
|
7
|
+
More complex operations involving the manipulation of existing archives in place
|
8
|
+
(adding, removing, and modifying entries) are also possible with a little more
|
9
|
+
work. Even adding advanced features such as new compression codecs are
|
10
|
+
supported with a moderate amount of effort.
|
11
|
+
|
12
|
+
|
13
|
+
== License
|
14
|
+
|
15
|
+
Copyright © 2008 Jeremy Bopp <jeremy at bopp dot net>
|
16
|
+
|
17
|
+
Licensed under the same terms as Ruby -- See the included LICENSE file for
|
18
|
+
details
|
19
|
+
|
20
|
+
|
21
|
+
== Installation/Removal
|
22
|
+
|
23
|
+
Download the GEM file and install it with:
|
24
|
+
% sudo gem install archive-zip-VERSION.gem
|
25
|
+
|
26
|
+
or directly with:
|
27
|
+
% sudo gem install archive-zip
|
28
|
+
|
29
|
+
Removal is the same in either case:
|
30
|
+
% sudo gem uninstall archive-zip
|
31
|
+
|
32
|
+
|
33
|
+
== Example
|
34
|
+
More examples can be found in the +examples+ directory of the source
|
35
|
+
distribution.
|
36
|
+
|
37
|
+
Create a few archives:
|
38
|
+
gem 'archive-zip' # Use require_gem for rubygems versions older than 0.9.0.
|
39
|
+
require 'archive/zip'
|
40
|
+
|
41
|
+
# Add a_directory and its contents to example1.zip.
|
42
|
+
Archive::Zip.archive('example1.zip', 'a_directory')
|
43
|
+
|
44
|
+
# Add the contents of a_directory to example2.zip.
|
45
|
+
Archive::Zip.archive('example2.zip', 'a_directory/.')
|
46
|
+
|
47
|
+
# Add a_file and a_directory and its contents to example3.zip.
|
48
|
+
Archive::Zip.archive('example3.zip', ['a_directory', 'a_file'])
|
49
|
+
|
50
|
+
# Add only the files and symlinks contained in a_directory under the path
|
51
|
+
# a/b/c/a_directory in example4.zip.
|
52
|
+
Archive::Zip.archive(
|
53
|
+
'example4.zip',
|
54
|
+
'a_directory',
|
55
|
+
:directories => false,
|
56
|
+
:path_prefix => 'a/b/c'
|
57
|
+
)
|
58
|
+
|
59
|
+
# Create a new archive which will be written to a pipe.
|
60
|
+
# Assume $stdout is the write end a pipe.
|
61
|
+
# (ruby example.rb | cat >example.zip)
|
62
|
+
Archive::Zip.open(nil, $stdout) do |z|
|
63
|
+
z.archive('a_directory')
|
64
|
+
end
|
65
|
+
|
66
|
+
Now extract those archives:
|
67
|
+
gem 'archive-zip' # Use require_gem for rubygems versions older than 0.9.0.
|
68
|
+
require 'archive/zip'
|
69
|
+
|
70
|
+
# Extract example1.zip to a_destination.
|
71
|
+
Archive::Zip.extract('example1.zip', 'a_destination')
|
72
|
+
|
73
|
+
# Extract example2.zip to a_destination, skipping directory entries.
|
74
|
+
Archive::Zip.extract(
|
75
|
+
'example2.zip',
|
76
|
+
'a_destination',
|
77
|
+
:directories => false
|
78
|
+
)
|
79
|
+
|
80
|
+
# Extract example3.zip to a_destination, skipping symlinks.
|
81
|
+
Archive::Zip.extract(
|
82
|
+
'example3.zip',
|
83
|
+
'a_destination',
|
84
|
+
:symlinks => false
|
85
|
+
)
|
86
|
+
|
87
|
+
# Extract example4.zip to a_destination, skipping entries for which files
|
88
|
+
# already exist but are newer or for which files do not exist at all.
|
89
|
+
Archive::Zip.extract(
|
90
|
+
'example4.zip',
|
91
|
+
'a_destination',
|
92
|
+
:create => false,
|
93
|
+
:overwrite => :older
|
94
|
+
)
|
95
|
+
|
96
|
+
|
97
|
+
== Features
|
98
|
+
|
99
|
+
1. 100% native Ruby. (Well, almost... depends on zlib.)
|
100
|
+
2. Archive creation and extraction is supported with only a few lines of code.
|
101
|
+
3. Archives can be updated "in place" or dumped out to other files or pipes.
|
102
|
+
4. Files, symlinks, and directories are supported within archives.
|
103
|
+
5. Unix permission/mode bits are supported.
|
104
|
+
6. Unix user and group ownerships are supported.
|
105
|
+
7. Unix last accessed and last modified times are supported.
|
106
|
+
8. Entry extension (AKA extra field) implementations can be added on the fly.
|
107
|
+
9. Unknown entry extension types are preserved during archive processing.
|
108
|
+
10. The Deflate and Store compression codecs are supported out of the box.
|
109
|
+
11. More compression codecs can be added on the fly.
|
110
|
+
|
111
|
+
|
112
|
+
== Known Bugs/Limitations
|
113
|
+
|
114
|
+
1. More testcases are needed.
|
115
|
+
2. All file entries are archived and extracted in binary mode. No attempt is
|
116
|
+
made to normalize text files to the line ending convention of any target
|
117
|
+
system.
|
118
|
+
3. Hard links and device files are not currently supported within archives.
|
119
|
+
4. Reading archives from non-seekable IO, such as pipes and sockets, is not
|
120
|
+
supported.
|
121
|
+
5. MSDOS permission attributes are not supported.
|
122
|
+
6. Encryption is not supported.
|
123
|
+
7. Zip64 is not supported.
|
124
|
+
8. Digital signatures are not supported.
|
125
|
+
|
126
|
+
|
127
|
+
== Contributing
|
128
|
+
|
129
|
+
Contributions for bug fixes, documentation, extensions, tests, etc. are
|
130
|
+
encouraged. Please read the file HACKING for details.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Try to first load io-like from rubygems and then fall back to assuming a
|
2
|
+
# standard installation.
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'io-like', '>= 0.1.0'
|
6
|
+
rescue LoadError
|
7
|
+
# Failed to load via rubygems.
|
8
|
+
end
|
9
|
+
|
10
|
+
# This will work for the gem and standard install assuming io-like is available
|
11
|
+
# at all.
|
12
|
+
require 'io/like'
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'archive/support/io-like'
|
2
|
+
|
3
|
+
# IOWindow represents an IO object which wraps another one allowing read access
|
4
|
+
# to a subset of the data within the stream.
|
5
|
+
#
|
6
|
+
# <b>NOTE:</b> This object is NOT thread safe.
|
7
|
+
class IOWindow
|
8
|
+
include IO::Like
|
9
|
+
|
10
|
+
# Creates a new instance of this class using _io_ as the data source
|
11
|
+
# and where _window_position_ and _window_size_ define the location and size
|
12
|
+
# of data window respectively.
|
13
|
+
#
|
14
|
+
# _io_ must be opened for reading and must be seekable. _window_position_
|
15
|
+
# must be an integer greater than or equal to 0. _window_size_ must be an
|
16
|
+
# integer greater than or equal to 0.
|
17
|
+
def initialize(io, window_position, window_size)
|
18
|
+
raise ArgumentError, 'non-seekable IO object given' unless io.seekable?
|
19
|
+
|
20
|
+
@io = io
|
21
|
+
@unbuffered_pos = 0
|
22
|
+
self.window_position = window_position
|
23
|
+
self.window_size = window_size
|
24
|
+
end
|
25
|
+
|
26
|
+
# The file position at which this window begins.
|
27
|
+
attr_reader :window_position
|
28
|
+
|
29
|
+
# Set the file position at which this window begins.
|
30
|
+
# _window_position_ must be an integer greater than or equal to 0.
|
31
|
+
def window_position=(window_position)
|
32
|
+
unless window_position.kind_of?(Fixnum) then
|
33
|
+
raise ArgumentError, 'non-integer window position given'
|
34
|
+
end
|
35
|
+
if window_position < 0 then
|
36
|
+
raise ArgumentError, 'non-positive window position given'
|
37
|
+
end
|
38
|
+
|
39
|
+
@window_position = window_position
|
40
|
+
end
|
41
|
+
|
42
|
+
# The size of the window.
|
43
|
+
attr_reader :window_size
|
44
|
+
|
45
|
+
# Set the size of the window.
|
46
|
+
# _window_size_ must be an integer greater than or equal to 0.
|
47
|
+
def window_size=(window_size)
|
48
|
+
unless window_size.kind_of?(Fixnum) then
|
49
|
+
raise ArgumentError, 'non-integer window size given'
|
50
|
+
end
|
51
|
+
raise ArgumentError, 'non-positive window size given' if window_size < 0
|
52
|
+
|
53
|
+
@window_size = window_size
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def unbuffered_read(length)
|
59
|
+
restore_self
|
60
|
+
|
61
|
+
# Error out if the end of the window is reached.
|
62
|
+
raise EOFError, 'end of file reached' if @unbuffered_pos >= @window_size
|
63
|
+
|
64
|
+
# Limit the read operation to the window.
|
65
|
+
length = @window_size - @unbuffered_pos if @unbuffered_pos + length > @window_size
|
66
|
+
|
67
|
+
# Fill a buffer with the data from the delegate.
|
68
|
+
buffer = @io.read(length)
|
69
|
+
# Error out if the end of the delegate is reached.
|
70
|
+
raise EOFError, 'end of file reached' if buffer.nil?
|
71
|
+
|
72
|
+
# Update the position.
|
73
|
+
@unbuffered_pos += buffer.length
|
74
|
+
|
75
|
+
buffer
|
76
|
+
ensure
|
77
|
+
restore_delegate
|
78
|
+
end
|
79
|
+
|
80
|
+
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
81
|
+
# Convert the offset and whence into an absolute position.
|
82
|
+
case whence
|
83
|
+
when IO::SEEK_SET
|
84
|
+
new_pos = offset
|
85
|
+
when IO::SEEK_CUR
|
86
|
+
new_pos = @unbuffered_pos + offset
|
87
|
+
when IO::SEEK_END
|
88
|
+
new_pos = @window_size + offset
|
89
|
+
end
|
90
|
+
|
91
|
+
# Error out if the position is outside the window.
|
92
|
+
raise Errno::EINVAL, 'Invalid argument' if new_pos < 0 or new_pos > @window_size
|
93
|
+
|
94
|
+
# Set the new position.
|
95
|
+
@unbuffered_pos = new_pos
|
96
|
+
end
|
97
|
+
|
98
|
+
def unbuffered_write(string)
|
99
|
+
restore_self
|
100
|
+
|
101
|
+
# Ensure that the outputted string will not extend past the window.
|
102
|
+
string = string.slice(0, @window_size - @unbuffered_pos)
|
103
|
+
@io.write(string)
|
104
|
+
ensure
|
105
|
+
restore_delegate
|
106
|
+
end
|
107
|
+
|
108
|
+
# Restores the state of the delegate IO object to that saved by a prior call
|
109
|
+
# to #restore_self.
|
110
|
+
def restore_delegate
|
111
|
+
@io.pos = @delegate_pos
|
112
|
+
@io.lineno = @delegate_lineno
|
113
|
+
end
|
114
|
+
|
115
|
+
# Saves the state of the delegate IO object so that it can be restored later
|
116
|
+
# using #restore_delegate and then configures the delegate so as to restore
|
117
|
+
# the state of this object.
|
118
|
+
def restore_self
|
119
|
+
@delegate_pos = @io.pos
|
120
|
+
@delegate_lineno = @io.lineno
|
121
|
+
@io.pos = @window_position + @unbuffered_pos
|
122
|
+
end
|
123
|
+
end
|