file-tail 1.2.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 82cf3f0b3b8d131b06101e28680a2dd0d2fb70fc
4
- data.tar.gz: 59c4c79c2499a858925cbd96f87052a875616118
2
+ SHA256:
3
+ metadata.gz: 8fcbea1582da9d2d6ce23fc0826608abf44625e90577916288001461593c2e0a
4
+ data.tar.gz: '0780cfca7c7d53f9a005ac2e1035daa249a758eab32a3b29aefb4142bd624127'
5
5
  SHA512:
6
- metadata.gz: 4b5cd1010abe3d92b58d2a43f08fc1f587b834e2130e836371a11b6989cb6fa605e5770e8a662b649643c8346f44919a96ca7c04b92b91e69358a0aadbdf02b0
7
- data.tar.gz: 23982bf55e95a0369e30d7cce2fd77f4d2736006091a59daa9781eb1e7d4163c7b9db9b46d0c1019ebec9be222f2aa9de0497faa1a0fdbfa28093ae8a6fa3509
6
+ metadata.gz: adeee1b62fe358f4e8f3ae1f13127b6b94e741e9520f94611bff8e4f1083f5ccbb5a0fbb3e8d9a6e68281e12231304b8cb24de644b7c062c3db76e9062ca4589
7
+ data.tar.gz: a9057bdfb9b771c1ee58cda13ea0f7639b2ff1b599b5628f5815060f52063d1ee354cd2dfd2368b96add7da4a0cdad3447c6622ed45bcc95a7f8926c8168fd46
data/.all_images.yml ADDED
@@ -0,0 +1,19 @@
1
+ dockerfile: |-
2
+ RUN apk add --no-cache build-base yaml-dev git openssl-dev
3
+
4
+ fail_fast: true
5
+
6
+ script: &script |-
7
+ echo -e "\e[1m"
8
+ ruby -v
9
+ echo -e "\e[0m"
10
+ bundle update --all
11
+ bundle install --jobs=$(getconf _NPROCESSORS_ONLN)
12
+ rake test
13
+
14
+ images:
15
+ ruby:4.0-alpine: *script
16
+ ruby:3.4-alpine: *script
17
+ ruby:3.3-alpine: *script
18
+ ruby:3.2-alpine: *script
19
+ ruby:3.1-alpine: *script
@@ -0,0 +1,51 @@
1
+ # Simple workflow for deploying static content to GitHub Pages
2
+ name: Deploy static content to Pages
3
+
4
+ on:
5
+ # Runs on pushes targeting the default branch
6
+ push:
7
+ branches: [ "master" ]
8
+
9
+ # Allows you to run this workflow manually from the Actions tab
10
+ workflow_dispatch:
11
+
12
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13
+ permissions:
14
+ contents: read
15
+ pages: write
16
+ id-token: write
17
+
18
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20
+ concurrency:
21
+ group: "pages"
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ # Single deploy job since we're just deploying
26
+ deploy:
27
+ environment:
28
+ name: github-pages
29
+ url: ${{ steps.deployment.outputs.page_url }}
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - name: Checkout
33
+ uses: actions/checkout@v4
34
+ - name: Setup Pages
35
+ uses: actions/configure-pages@v5
36
+ - name: Setup Ruby
37
+ uses: ruby/setup-ruby@v1
38
+ with:
39
+ ruby-version: '3.4'
40
+ - name: Generate Documentation
41
+ run: |
42
+ gem install gem_hadar
43
+ bundle install
44
+ rake doc
45
+ - name: Upload artifact
46
+ uses: actions/upload-pages-artifact@v3
47
+ with:
48
+ path: 'doc'
49
+ - name: Deploy to GitHub Pages
50
+ id: deployment
51
+ uses: actions/deploy-pages@v4
data/.gitignore CHANGED
@@ -3,6 +3,10 @@
3
3
  .AppleDouble
4
4
  .bundle
5
5
  .rbx
6
+ .utilsrc
7
+ .yardoc
6
8
  Gemfile.lock
7
9
  coverage
10
+ errors.lst
8
11
  pkg
12
+ tmp
data/.travis.yml CHANGED
@@ -1,8 +1,10 @@
1
1
  rvm:
2
2
  - 2.1
3
3
  - 2.2
4
- - 2.3.3
5
- - 2.4.1
4
+ - 2.3
5
+ - 2.4
6
+ - 2.5
7
+ - 2.6
6
8
  - ruby-head
7
9
  - jruby-head
8
10
  sudo: false
data/CHANGES.md ADDED
@@ -0,0 +1,190 @@
1
+ # Changes
2
+
3
+ ## 2026-01-02 v1.4.0
4
+
5
+ - Enhanced file reopening logic to handle `Errno::ENOENT` and `Errno::ESTALE`
6
+ errors separately, preventing line skipping during file rotation
7
+ - Fixed buffer size parameter passing and cleaned up the close block
8
+ - Added nil safety check for `@out.path` before removing temporary files
9
+ - Updated gemspec to include the `LICENSE` file and added a GitHub Actions
10
+ workflow
11
+ - Replaced the old documentation in README with a comprehensive architecture
12
+ overview, usage examples, and debugging sections
13
+ - Added automated documentation deployment workflow using GitHub Actions with
14
+ Ruby **3.4** environment
15
+ - Removed unnecessary `t =` assignment for thread in `rtail` binary
16
+ - Removed support for Ruby **3.0** Alpine image in CI configuration
17
+ - Renamed `COPYING` file to `LICENSE` for better standard compliance
18
+ - Added `.yardoc` to gitignore and rake ignore list
19
+ - Updated test file path to use the `tmp` directory for better test
20
+ organization
21
+ - Added `tmp` directory to gitignore, gemspec, and git tracking with
22
+ `tmp/.gitkeep`
23
+ - Updated CI image configuration to support Ruby **4.0** with `yaml-dev` and
24
+ `openssl-dev` dependencies
25
+ - Updated gem metadata and dependencies, including `rubygems_version` to
26
+ **4.0.2** and `gem_hadar` development dependency to **>= 2.16.3**
27
+ - Added changelog generation support to the Rakefile for automated changelog
28
+ management
29
+ - Updated Dockerfile dependencies for Ruby version detection and added Ruby
30
+ **3.4**-alpine image support
31
+ - Fixed typos in the codebase
32
+
33
+ ## 2024-09-13 v1.3.0
34
+
35
+ ### Significant Changes
36
+
37
+ * **Improved waiting for log output by counting lines**
38
+ + Increased timeout from 2 seconds to 10 seconds in multiple places
39
+ * **Added Ruby version check in Dockerfile**
40
+ + Update `gem update --system` and installation to be conditional on Ruby version
41
+ + Replace `bundle` with `bundle install` in script section
42
+ * **Convert CHANGES file to CHANGES\.md**
43
+
44
+ ### Bug Fixes
45
+
46
+ * **Add exit handler to delete temporary file**
47
+ - Added at_exit block to delete test file created in setup method.
48
+ * **Refactor File class for debugging**
49
+ - Remove hardcoded `$DEBUG` variable usage in reopen_file and output_debug_information methods
50
+ - Introduce debug? method to check if `FILE_TAIL_DEBUG` environment variable is set to 1.
51
+
52
+ ### Dependency Updates
53
+
54
+ * **Update Ruby dependencies and add new development dependencies**
55
+ + Added `.all_images.yml` file with Dockerfile configuration
56
+ + Updated Gemfile to use Ruby **3.5.18** instead of **2.7.8**
57
+ + Updated Rakefile to ignore additional files
58
+ + Updated `file-tail.gemspec` to include `.all_images.yml` in the list of files
59
+ + Updated `tests/file_tail_test.rb` to use absolute path for test file
60
+ + Added new development dependencies: `all_images`, `simplecov`, and `debug`
61
+ + Updated dependency versions: `gem_hadar` to **1.17.1**, `test-unit` to
62
+ **3.0**, and `tins` to **1.0**
63
+
64
+ ## 2016-04-19 v1.2.0
65
+
66
+ * Make line separator configurable
67
+
68
+ ## 2016-04-19 v1.1.1
69
+
70
+ * Fix tests on Ruby 2.3.0
71
+
72
+ ## 2014-09-26 v1.1.0
73
+
74
+ * Depend on tins ~ 1.0
75
+
76
+ ## 2012-05-31 v1.0.10
77
+
78
+ * Use rewind to force IO#lineno to be reset.
79
+
80
+ ## 2012-05-31 v1.0.9
81
+
82
+ * Reopen file in :top mode at the beginning.
83
+
84
+ ## 2011-12-24 v1.0.8
85
+
86
+ * Support simplecov.
87
+
88
+ ## 2011-07-15 v1.0.7
89
+
90
+ * Use gem_hadar to shorten Rakefile.
91
+
92
+ ## 2011-06-25 v1.0.6
93
+
94
+ * Create a gem spec file again.
95
+ * Added a File::Tail::Group to tail multiple files more easily.
96
+
97
+ ## 2010-03-25 v1.0.5
98
+
99
+ * Added rtail executable, a nice app to supervise logfiles and logdirs.
100
+ * Disabled creation of gem spec file.
101
+ * Cleaned up documentation a bit.
102
+
103
+ ## 2009-08-21 v1.0.4
104
+
105
+ * Fixed the threaded tests for Ruby 1.9.
106
+ * Create a gem spec file.
107
+ * Some cleanup.
108
+
109
+ ## 2008-04-07 v1.0.3
110
+
111
+ * Danny Colligan <danny.colligan@sendori.com> reported a memory leak in long
112
+ running scripts using file-tail. I changed file-ta il to only use block.call,
113
+ which seems to improve the memory behaviour. I am still not sure, where the
114
+ problem actually stems f rom, though.
115
+
116
+ ## 2007-04-19 v1.0.2
117
+
118
+ * make_doc.rb was missing from the source archive. Thanks to Rick Ohnemus
119
+ <rick.ohnemus@systemware.com> for reporting it.
120
+
121
+ ## 2007-04-19 v1.0.1
122
+
123
+ * Bugfix: File::Tail::Logfile#open with block, now closes the file like
124
+ File#open does. Found by Alex Doan <alex.doan@wachovia. com>,
125
+ ruby-talk:248383.
126
+
127
+ ## 2007-03-30 v1.0.0
128
+
129
+ * Bugfix: David.Barzilay@swisscom.com reported, that file tails may skip some
130
+ log file lines, after rotating it. I think, that I fixed that problem.
131
+ * Added a after_reopen callback as well, that is called after reopening of the
132
+ tailed file has occured.
133
+ * Removed rewind/wind methods even earlier than planned: I placed the
134
+ deprecation warning for rewind method in File instead of File::Tail, which
135
+ caused rewind to stop working completely after loading file/tail. Duh! I
136
+ blame vim's matchit, because it jump ed to the wrong end keyword.
137
+
138
+ ## 2007-02-08 v0.1.4
139
+
140
+ * Renamed rewind method to backward, and wind method to forward, because
141
+ someone already had the good idea to name a method IO# rewind, which was
142
+ overwritten by the mixed in File::Tail methods. The old methods are now
143
+ deprecated and will be removed in a n ew 0.2.x version of the library.
144
+ * Added a bit more of documentation.
145
+
146
+ ## 2005-08-20 v0.1.3
147
+
148
+ * Applied LOAD_PATH patch by Daniel Berger, binary mode changes were already in
149
+ the CVS. Seemed to be like cheating to me, thou gh. ;)
150
+ * Skipping one windows test for the moment, too. Sigh!
151
+
152
+ ## 2004-09-30 v0.1.2
153
+
154
+ * First Rubyforge release
155
+ * Added Rakefile
156
+ * Supports gem build now.
157
+
158
+ ## 2004-09-01 v0.1.1
159
+
160
+ * Josh Endries <josh@endries.org> found a bug that caused File::Tail to
161
+ malfunction on FreeBSD. Hotfix: Use a side effect of se ek to clearerr the
162
+ tailed file handle after EOFError has been raised.
163
+
164
+ ## 2004-04-13 v0.1.0
165
+
166
+ * API documentation with rdoc.
167
+ * return_if_eof attribute added.
168
+ * Added array return mode for finite tail call without block given.
169
+ * install.rb now uses ruby version site_dir.
170
+ * Some code and directory structure cleanup.
171
+
172
+ ## 2002-08-02 v0.0.2
173
+
174
+ * Heavy refactoring, more and smaller methods and expception handling
175
+ * Added check for inode and device equality of files as suggested by James
176
+ F.Hranicky <jfh@cise.ufl.edu> and Curt Sampson <cjs@ cynic.net> to cover
177
+ remove rotation
178
+ * If filesize shrinks suddenly, File::Tail assumes that copy and truncate
179
+ rotation has happend: The file is reopened and every new line is handled.
180
+ * NFS-Fix: Errno::ESTALE is caught.
181
+ * wind added to skip the first n lines, as James F.Hranicky's suggested and
182
+ changed name of last-method to rewind, because I li ked his method names
183
+ better than mine ;)
184
+ * Renamed next to tail either.
185
+ * The API has changed - but I think very few people care at the moment.
186
+ * Lots of tests added.
187
+
188
+ ## 2002-07-30 v0.0.1
189
+
190
+ * Initial Release
data/Gemfile CHANGED
@@ -3,8 +3,3 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
-
7
- group :development do
8
- gem 'simplecov'
9
- gem 'utils'
10
- end
data/README.md CHANGED
@@ -5,69 +5,308 @@
5
5
  This is a small ruby library that allows it to "tail" files in Ruby, including
6
6
  following a file, that still is growing like the unix command 'tail -f' can.
7
7
 
8
- ## Download
8
+ ## Documentation
9
9
 
10
- The latest version of *File::Tail* (file-tail) can be found at
10
+ Complete API documentation is available at: [GitHub.io](https://flori.github.io/file-tail/)
11
+
12
+ ## Architecture Overview
13
+
14
+ File::Tail follows a well-defined architectural pattern with clear
15
+ separation of concerns between several key components:
11
16
 
17
+ ### Core Components
12
18
 
13
- http://flori.github.com/file-tail
19
+ **File::Tail Module**
20
+ - The central hub extending File objects with tailing capabilities 🔄
21
+ - Provides core methods for forward/backward traversal and tailing 📊
22
+ - Handles file system events like rotation, truncation, and deletion 🔁
23
+
24
+ **File::Tail::Logfile**
25
+ - A convenience class that simplifies opening and tailing files with options 🚀
26
+ - Includes File::Tail module for direct file access 🧠
27
+ - Supports various initialization patterns for flexible usage 🔄
28
+
29
+ **File::Tail::Group**
30
+ - Manages multiple files to be tailed together 🔄
31
+ - Uses ThreadGroup to coordinate multiple tailing threads ⏳
32
+ - Provides batch operations for concurrent file monitoring 📊
33
+
34
+ **File::Tail::Tailer**
35
+ - A Thread subclass that supervises a single file's tailing 🧠
36
+ - Uses queues for line buffering and thread-safe communication 📦
37
+ - Implements method_missing for thread-local variable access ⚡
38
+
39
+ ### Component Interactions
40
+
41
+ ```mermaid
42
+ graph LR
43
+ A[File::Tail] --> B[File::Tail::Logfile]
44
+ A --> C[File::Tail::Group]
45
+ C --> D[File::Tail::Tailer]
46
+ D --> E[Thread]
47
+ A --> F[File::Tail::LineExtension]
48
+ F --> G[Lines from tailers]
49
+ ```
50
+
51
+ The File::Tail module acts as the foundation, providing core functionality that
52
+ is extended by Logfile and Group classes. The Group class coordinates multiple
53
+ Tailer threads, each managing a single file's tailing process.
54
+
55
+ ### Loading Mechanism
56
+
57
+ File::Tail supports two primary access patterns:
58
+
59
+ 1. **Direct File Extension** - Extending File objects directly with File::Tail:
60
+ ```ruby
61
+ File.open(filename) do |log|
62
+ log.extend(File::Tail)
63
+ log.backward(10)
64
+ log.tail { |line| puts line }
65
+ end
66
+ ```
67
+
68
+ 2. **Logfile Convenience Class** - Using the Logfile wrapper for simpler usage:
69
+ ```ruby
70
+ File::Tail::Logfile.tail('app.log', :backward => 10) do |line|
71
+ puts line
72
+ end
73
+ ```
14
74
 
15
75
  ## Installation
16
76
 
17
77
  To install file-tail via its gem type:
18
78
 
19
- # gem install file-tail
79
+ ```bash
80
+ gem install file-tail
81
+ ```
82
+
83
+ You can also put this line into your Gemfile:
84
+
85
+ ```ruby
86
+ gem 'file-tail'
87
+ ```
88
+
89
+ and bundle. This will make the File::Tail module available for extending File objects.
20
90
 
21
91
  ## Usage
22
92
 
23
93
  File::Tail is a module in the File class. A lightweight class interface for
24
94
  logfiles can be seen under File::Tail::Logfile.
25
95
 
26
- Direct extension of File objects with File::Tail works like that:
96
+ ### Direct Extension of File Objects
97
+
98
+ ```ruby
99
+ File.open(filename) do |log|
100
+ log.extend(File::Tail)
101
+ log.interval # 10
102
+ log.backward(10)
103
+ log.tail { |line| puts line }
104
+ end
105
+ ```
106
+
107
+ It's also possible to mix File::Tail in your own File classes (see also File::Tail::Logfile):
27
108
 
28
- File.open(filename) do |log|
29
- log.extend(File::Tail)
30
- log.interval # 10
31
- log.backward(10)
32
- log.tail { |line| puts line }
33
- end
109
+ ```ruby
110
+ class MyFile < File
111
+ include File::Tail
112
+ end
113
+ log = MyFile.new("myfile")
114
+ log.interval # 10
115
+ log.backward(10)
116
+ log.tail { |line| print line }
117
+ ```
34
118
 
35
- It's also possible to mix File::Tail in your own File classes
36
- (see also File::Tail::Logfile):
119
+ The forward/backward method returns self, so it's possible to chain methods together like that:
37
120
 
38
- class MyFile < File
39
- include File::Tail
40
- end
41
- log # MyFile.new("myfile")
42
- log.interval # 10
43
- log.backward(10)
44
- log.tail { |line| print line }
121
+ ```ruby
122
+ log.backward(10).tail { |line| puts line }
123
+ ```
45
124
 
46
- The forward/backward method returns self, so it's possible to chain
47
- methods together like that:
125
+ ### Multiple File Tailing with Group
48
126
 
49
- log.backward(10).tail { |line| puts line }
127
+ ```ruby
128
+ group = File::Tail::Group.new
129
+ group.add_filename('app.log')
130
+ group.add_filename('error.log')
131
+ group.tail { |line| puts line }
132
+ ```
50
133
 
51
- A command line utility named rtail, that uses File::Tail is provided as well.
134
+ ### Advanced Usage with Callbacks
135
+
136
+ ```ruby
137
+ log = File::Tail::Logfile.open('app.log')
138
+ log.after_reopen { |file| puts "File reopened: #{file.path}" }
139
+ log.tail { |line| puts line }
140
+ ```
141
+
142
+ ### Backward Traversal
143
+
144
+ ```ruby
145
+ # Tail last 10 lines of file
146
+ File::Tail::Logfile.open('app.log', :backward => 10) do |log|
147
+ log.tail { |line| puts line }
148
+ end
149
+
150
+ # Skip first 5 lines and tail
151
+ File::Tail::Logfile.open('app.log', :forward => 5) do |log|
152
+ log.tail { |line| puts line }
153
+ end
154
+ ```
52
155
 
53
156
  ## Documentation
54
157
 
55
158
  To create the documentation of this module, type
56
159
 
57
- ```
160
+ ```bash
58
161
  $ rake doc
59
162
  ```
60
163
 
61
164
  and the API documentation is generated.
62
165
 
63
- In the examples direcotry is a small example of tail and
166
+ In the examples directory is a small example of tail and
64
167
  pager program that use this module. You also may want look
65
168
  at the end of examples/tail.rb for a little example.
66
169
 
170
+ ## Debugging and Troubleshooting
171
+
172
+ File::Tail provides built-in debugging capabilities through environment variables:
173
+
174
+ ### Enabling Debug Output
175
+
176
+ Set the `FILE_TAIL_DEBUG` environment variable to enable detailed debugging information:
177
+
178
+ ```bash
179
+ export FILE_TAIL_DEBUG=1
180
+ ruby your_tail_script.rb
181
+ ```
182
+
183
+ This will output information about:
184
+ - File paths being tailed
185
+ - Line counts and intervals
186
+ - Reopening events
187
+ - Sleep intervals and timing
188
+
189
+ ### Exception Handling
190
+
191
+ File::Tail defines several specific exceptions for different failure scenarios:
192
+
193
+ ```ruby
194
+ begin
195
+ log.tail { |line| puts line }
196
+ rescue File::Tail::DeletedException
197
+ # Handle file deletion
198
+ rescue File::Tail::ReopenException
199
+ # Handle file rotation/reopening
200
+ rescue File::Tail::BreakException
201
+ # Handle end-of-file with break_if_eof set
202
+ rescue File::Tail::ReturnException
203
+ # Internal exception for controlling tailing behavior
204
+ end
205
+ ```
206
+
207
+ ## Configuration
208
+
209
+ ### Key Attributes
210
+
211
+ File::Tail provides several configurable attributes for fine-tuning behavior:
212
+
213
+ ```ruby
214
+ log = File::Tail::Logfile.open('app.log')
215
+ log.interval = 1.0 # Initial sleep interval (default: 10)
216
+ log.max_interval = 5.0 # Maximum sleep interval (default: 10)
217
+ log.reopen_deleted = true # Reopen deleted files (default: true)
218
+ log.reopen_suspicious = true # Reopen on suspicious events (default: true)
219
+ log.suspicious_interval = 60 # Interval before suspicious event detection (default: 60)
220
+ log.break_if_eof = false # Break on EOF (default: false)
221
+ log.return_if_eof = false # Return on EOF (default: false)
222
+ ```
223
+
224
+ ### Advanced Configuration
225
+
226
+ ```ruby
227
+ # Configure for high-traffic logs
228
+ log.interval = 0.1
229
+ log.max_interval = 1.0
230
+ log.suspicious_interval = 30
231
+
232
+ # Configure for low-traffic logs
233
+ log.interval = 5.0
234
+ log.max_interval = 30.0
235
+ log.suspicious_interval = 120
236
+ ```
237
+
238
+ ## Performance Considerations
239
+
240
+ ### Thread Safety
241
+
242
+ File::Tail uses thread-safe mechanisms for concurrent file monitoring:
243
+ - ThreadGroup for managing tailer threads
244
+ - Mutex and ConditionVariable for synchronization
245
+ - Queue-based line buffering for thread communication
246
+
247
+ ### Memory Management
248
+
249
+ The library implements efficient memory usage:
250
+ - Lines are buffered in queues per tailer
251
+ - Exponential backoff reduces CPU usage when files are quiet
252
+ - Proper thread lifecycle management prevents resource leaks
253
+
254
+ ### File System Event Handling
255
+
256
+ File::Tail gracefully handles various file system events:
257
+ - File rotation (log rotation)
258
+ - File truncation
259
+ - File deletion
260
+ - File reopening after deletion
261
+
262
+ ## Error Handling
263
+
264
+ File::Tail provides comprehensive error handling for common file system scenarios:
265
+
266
+ ### File::Tail Exception Hierarchy
267
+
268
+ ```mermaid
269
+ classDiagram
270
+ class TailException {
271
+ <<abstract>>
272
+ +message
273
+ }
274
+
275
+ class DeletedException
276
+ class ReturnException
277
+ class BreakException
278
+ class ReopenException
279
+
280
+ TailException <|-- DeletedException
281
+ TailException <|-- ReturnException
282
+ TailException <|-- BreakException
283
+ TailException <|-- ReopenException
284
+ ```
285
+
286
+ ### Safe Usage Pattern
287
+
288
+ ```ruby
289
+ def safe_tail(filename)
290
+ File::Tail::Logfile.open(filename) do |log|
291
+ log.tail { |line| puts line }
292
+ rescue File::Tail::DeletedException
293
+ puts "File was deleted, stopping tailing"
294
+ rescue File::Tail::ReopenException
295
+ puts "File reopened, continuing tailing"
296
+ end
297
+ end
298
+ ```
299
+
300
+ ## Download
301
+
302
+ The latest version of *File::Tail* (file-tail) can be found at
303
+
304
+ https://github.com/flori/file-tail
305
+
67
306
  ## Author
68
307
 
69
308
  Florian Frank mailto:flori@ping.de
70
309
 
71
310
  ## License
72
311
 
73
- Apache License, Version 2.0 See the COPYING file in the source archive.
312
+ This software is licensed under the [Apache 2.0 license](LICENSE).
data/Rakefile CHANGED
@@ -11,12 +11,23 @@ GemHadar do
11
11
  summary "#{path_name.camelize} for Ruby"
12
12
  description 'Library to tail files in Ruby'
13
13
  test_dir 'tests'
14
- ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', 'coverage', '*.rbc', '.rbx', '.AppleDouble', '.bundle'
14
+ ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', 'coverage', '*.rbc', '.rbx',
15
+ '.AppleDouble', '.bundle', 'errors.lst', '.utilsrc', 'tmp', '.yardoc'
15
16
  readme 'README.md'
16
17
  licenses << 'Apache-2.0'
17
18
 
19
+ changelog do
20
+ filename 'CHANGES.md'
21
+ end
22
+
23
+ github_workflows(
24
+ 'static.yml' => {}
25
+ )
18
26
 
19
27
  dependency 'tins', '~>1.0'
20
28
 
21
- development_dependency 'test-unit', '~>2.4.0'
29
+ development_dependency 'test-unit', '~>3.0'
30
+ development_dependency 'all_images'
31
+ development_dependency 'simplecov'
32
+ development_dependency 'debug'
22
33
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.4.0
data/bin/rtail CHANGED
@@ -39,7 +39,7 @@ end
39
39
 
40
40
  add_logfiles logfiles
41
41
 
42
- t = Thread.new do
42
+ Thread.new do
43
43
  $logfiles.tail do |line|
44
44
  if $opt['M']
45
45
  puts "#{line.file.path}: #{line}"
data/file-tail.gemspec CHANGED
@@ -1,40 +1,31 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: file-tail 1.2.0 ruby lib
2
+ # stub: file-tail 1.4.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "file-tail".freeze
6
- s.version = "1.2.0"
6
+ s.version = "1.4.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Florian Frank".freeze]
11
- s.date = "2017-04-13"
11
+ s.date = "1980-01-02"
12
12
  s.description = "Library to tail files in Ruby".freeze
13
13
  s.email = "flori@ping.de".freeze
14
14
  s.extra_rdoc_files = ["README.md".freeze, "lib/file-tail.rb".freeze, "lib/file/tail.rb".freeze, "lib/file/tail/group.rb".freeze, "lib/file/tail/line_extension.rb".freeze, "lib/file/tail/logfile.rb".freeze, "lib/file/tail/tailer.rb".freeze, "lib/file/tail/version.rb".freeze]
15
- s.files = [".gitignore".freeze, ".travis.yml".freeze, "CHANGES".freeze, "COPYING".freeze, "Gemfile".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/rtail".freeze, "examples/pager.rb".freeze, "examples/tail.rb".freeze, "file-tail.gemspec".freeze, "lib/file-tail.rb".freeze, "lib/file/tail.rb".freeze, "lib/file/tail/group.rb".freeze, "lib/file/tail/line_extension.rb".freeze, "lib/file/tail/logfile.rb".freeze, "lib/file/tail/tailer.rb".freeze, "lib/file/tail/version.rb".freeze, "tests/file_tail_group_test.rb".freeze, "tests/file_tail_test.rb".freeze, "tests/test_helper.rb".freeze]
15
+ s.files = [".all_images.yml".freeze, ".github/workflows/static.yml".freeze, ".gitignore".freeze, ".travis.yml".freeze, "CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/rtail".freeze, "examples/pager.rb".freeze, "examples/tail.rb".freeze, "file-tail.gemspec".freeze, "lib/file-tail.rb".freeze, "lib/file/tail.rb".freeze, "lib/file/tail/group.rb".freeze, "lib/file/tail/line_extension.rb".freeze, "lib/file/tail/logfile.rb".freeze, "lib/file/tail/tailer.rb".freeze, "lib/file/tail/version.rb".freeze, "tests/file_tail_group_test.rb".freeze, "tests/file_tail_test.rb".freeze, "tests/test_helper.rb".freeze, "tmp/.gitkeep".freeze]
16
16
  s.homepage = "http://github.com/flori/file-tail".freeze
17
17
  s.licenses = ["Apache-2.0".freeze]
18
18
  s.rdoc_options = ["--title".freeze, "File-tail - File::Tail for Ruby".freeze, "--main".freeze, "README.md".freeze]
19
- s.rubygems_version = "2.6.11".freeze
19
+ s.rubygems_version = "4.0.2".freeze
20
20
  s.summary = "File::Tail for Ruby".freeze
21
21
  s.test_files = ["tests/file_tail_group_test.rb".freeze, "tests/file_tail_test.rb".freeze, "tests/test_helper.rb".freeze]
22
22
 
23
- if s.respond_to? :specification_version then
24
- s.specification_version = 4
23
+ s.specification_version = 4
25
24
 
26
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.9.1"])
28
- s.add_development_dependency(%q<test-unit>.freeze, ["~> 2.4.0"])
29
- s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.0"])
30
- else
31
- s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.9.1"])
32
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.4.0"])
33
- s.add_dependency(%q<tins>.freeze, ["~> 1.0"])
34
- end
35
- else
36
- s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.9.1"])
37
- s.add_dependency(%q<test-unit>.freeze, ["~> 2.4.0"])
38
- s.add_dependency(%q<tins>.freeze, ["~> 1.0"])
39
- end
25
+ s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.16.3".freeze])
26
+ s.add_development_dependency(%q<test-unit>.freeze, ["~> 3.0".freeze])
27
+ s.add_development_dependency(%q<all_images>.freeze, [">= 0".freeze])
28
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
29
+ s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
30
+ s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.0".freeze])
40
31
  end
@@ -51,7 +51,7 @@ class File
51
51
  end
52
52
  if backward = opts[:backward] || opts[:rewind]
53
53
  (args = []) << backward
54
- args << opt[:bufsiz] if opts[:bufsiz]
54
+ args << opts[:bufsiz] if opts[:bufsiz]
55
55
  file.backward(*args)
56
56
  elsif forward = opts[:forward] || opts[:wind]
57
57
  file.forward(forward)
@@ -64,7 +64,6 @@ class File
64
64
  block.call file
65
65
  ensure
66
66
  file.close
67
- nil
68
67
  end
69
68
  else
70
69
  file
@@ -1,6 +1,6 @@
1
1
  module File::Tail
2
2
  # File::Tail version
3
- VERSION = '1.2.0'
3
+ VERSION = '1.4.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
data/lib/file/tail.rb CHANGED
@@ -17,7 +17,7 @@ class File
17
17
  class DeletedException < TailException; end
18
18
 
19
19
  # The ReturnException is raised and caught
20
- # internally to implement "tail -10" behaviour.
20
+ # internally to implement "tail -10" behavior.
21
21
  class ReturnException < TailException; end
22
22
 
23
23
  # The BreakException is raised if the <code>break_if_eof</code>
@@ -26,7 +26,7 @@ class File
26
26
  class BreakException < TailException; end
27
27
 
28
28
  # The ReopenException is raised internally if File::Tail
29
- # gets suspicious something unusual has happend to
29
+ # gets suspicious something unusual has happened to
30
30
  # the tailed file, e. g., it was rotated away. The exception
31
31
  # is caught and an attempt to reopen it is made.
32
32
  class ReopenException < TailException
@@ -66,14 +66,14 @@ class File
66
66
  attr_accessor :reopen_suspicious
67
67
 
68
68
  # The callback is called with _self_ as an argument after a reopen has
69
- # occured. This allows a tailing script to find out, if a logfile has been
70
- # rotated.
69
+ # occurred. This allows a tailing script to find out, if a logfile has
70
+ # been rotated.
71
71
  def after_reopen(&block)
72
72
  @after_reopen = block
73
73
  end
74
74
 
75
- # This attribute is the invterval in seconds before File::Tail
76
- # gets suspicious that something has happend to it's tailed file
75
+ # This attribute is the interval in seconds before File::Tail
76
+ # gets suspicious that something has happened to it's tailed file
77
77
  # and an attempt to reopen it is made.
78
78
  #
79
79
  # If the attribute <code>reopen_suspicious</code> is
@@ -241,16 +241,18 @@ class File
241
241
  if @stat
242
242
  if stat.ino != @stat.ino or stat.dev != @stat.dev
243
243
  @stat = nil
244
- raise ReopenException.new(:top)
244
+ raise ReopenException.new(:top) # File ino/dev has changed, start from top
245
245
  end
246
246
  if stat.size < @stat.size
247
247
  @stat = nil
248
- raise ReopenException.new(:top)
248
+ raise ReopenException.new(:top) # File shrunk, start from top
249
249
  end
250
250
  end
251
251
  @stat = stat
252
- rescue Errno::ENOENT, Errno::ESTALE
253
- raise ReopenException
252
+ rescue Errno::ENOENT
253
+ raise ReopenException.new(:top) # File was missing, maybe it has been rotated, start from top
254
+ rescue Errno::ESTALE
255
+ raise ReopenException # File is stale let's try opening again with same mo
254
256
  end
255
257
 
256
258
  def sleep_interval
@@ -272,7 +274,7 @@ class File
272
274
  end
273
275
 
274
276
  def reopen_file(mode)
275
- $DEBUG and $stdout.print "Reopening '#{path}', mode = #{mode}.\n"
277
+ debug? and $stdout.print "Reopening '#{path}', mode = #{mode}.\n"
276
278
  @no_read = 0
277
279
  reopen(path)
278
280
  if mode == :bottom
@@ -290,7 +292,7 @@ class File
290
292
  end
291
293
 
292
294
  def output_debug_information
293
- $DEBUG or return
295
+ debug? or return
294
296
  STDERR.puts({
295
297
  :path => path,
296
298
  :lines => @lines,
@@ -300,6 +302,10 @@ class File
300
302
  }.inspect)
301
303
  self
302
304
  end
305
+
306
+ def debug?
307
+ ENV['FILE_TAIL_DEBUG'].to_i == 1
308
+ end
303
309
  end
304
310
  end
305
311
 
@@ -4,13 +4,16 @@ require 'test_helper'
4
4
  require 'file/tail'
5
5
  require 'timeout'
6
6
  require 'thread'
7
+ require 'fileutils'
7
8
  Thread.abort_on_exception = true
8
9
 
9
10
  class FileTailTest < Test::Unit::TestCase
10
11
  include File::Tail
12
+ include FileUtils
11
13
 
12
14
  def setup
13
- @out = File.new("test.#$$", "wb")
15
+ @out = File.new(File.join('tmp', "test.#$$"), "wb")
16
+ at_exit { path = @out&.path and rm_f File.expand_path(path) }
14
17
  append(@out, 100)
15
18
  @in = File.new(@out.path, "rb")
16
19
  @in.extend(File::Tail)
@@ -194,7 +197,7 @@ class FileTailTest < Test::Unit::TestCase
194
197
  lines = []
195
198
  logger = Thread.new do
196
199
  begin
197
- Timeout::timeout(2) do
200
+ Timeout::timeout(10) do
198
201
  @in.tail do |l|
199
202
  lines << l
200
203
  end
@@ -225,7 +228,7 @@ class FileTailTest < Test::Unit::TestCase
225
228
  lines = []
226
229
  logger = Thread.new do
227
230
  begin
228
- Timeout::timeout(2) do
231
+ Timeout::timeout(10) do
229
232
  @in.tail do |l|
230
233
  lines << l
231
234
  end
@@ -261,7 +264,7 @@ class FileTailTest < Test::Unit::TestCase
261
264
  lines = []
262
265
  logger = Thread.new do
263
266
  begin
264
- Timeout::timeout(2) do
267
+ Timeout::timeout(10) do
265
268
  @in.tail(15) do |l|
266
269
  lines << l
267
270
  end
@@ -298,7 +301,7 @@ class FileTailTest < Test::Unit::TestCase
298
301
  lines = []
299
302
  logger = Thread.new do
300
303
  begin
301
- Timeout::timeout(2) do
304
+ Timeout::timeout(10) do
302
305
  @in.tail(110) do |l|
303
306
  lines << l
304
307
  end
@@ -307,8 +310,10 @@ class FileTailTest < Test::Unit::TestCase
307
310
  end
308
311
  end
309
312
  appender = Thread.new do
310
- until logger.stop?
311
- sleep 0.1
313
+ Timeout::timeout(10) do
314
+ until lines.size == 100
315
+ sleep 0.1
316
+ end
312
317
  end
313
318
  @out.close
314
319
  File.unlink(@out.path)
@@ -331,7 +336,7 @@ class FileTailTest < Test::Unit::TestCase
331
336
  lines = []
332
337
  logger = Thread.new do
333
338
  begin
334
- Timeout::timeout(2) do
339
+ Timeout::timeout(10) do
335
340
  @in.tail(110) do |l|
336
341
  lines << l
337
342
  end
@@ -340,8 +345,10 @@ class FileTailTest < Test::Unit::TestCase
340
345
  end
341
346
  end
342
347
  appender = Thread.new do
343
- until logger.stop?
344
- sleep 0.1
348
+ Timeout::timeout(10) do
349
+ until lines.size == 100
350
+ sleep 0.1
351
+ end
345
352
  end
346
353
  @out.truncate 0
347
354
  @out.close
data/tmp/.gitkeep ADDED
File without changes
metadata CHANGED
@@ -1,43 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: file-tail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2017-04-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: gem_hadar
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - "~>"
16
+ - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 1.9.1
18
+ version: 2.16.3
20
19
  type: :development
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
- - - "~>"
23
+ - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: 1.9.1
25
+ version: 2.16.3
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: test-unit
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: 2.4.0
32
+ version: '3.0'
34
33
  type: :development
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: 2.4.0
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: all_images
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: simplecov
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: debug
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
41
82
  - !ruby/object:Gem::Dependency
42
83
  name: tins
43
84
  requirement: !ruby/object:Gem::Requirement
@@ -66,11 +107,13 @@ extra_rdoc_files:
66
107
  - lib/file/tail/tailer.rb
67
108
  - lib/file/tail/version.rb
68
109
  files:
110
+ - ".all_images.yml"
111
+ - ".github/workflows/static.yml"
69
112
  - ".gitignore"
70
113
  - ".travis.yml"
71
- - CHANGES
72
- - COPYING
114
+ - CHANGES.md
73
115
  - Gemfile
116
+ - LICENSE
74
117
  - README.md
75
118
  - Rakefile
76
119
  - VERSION
@@ -88,11 +131,11 @@ files:
88
131
  - tests/file_tail_group_test.rb
89
132
  - tests/file_tail_test.rb
90
133
  - tests/test_helper.rb
134
+ - tmp/.gitkeep
91
135
  homepage: http://github.com/flori/file-tail
92
136
  licenses:
93
137
  - Apache-2.0
94
138
  metadata: {}
95
- post_install_message:
96
139
  rdoc_options:
97
140
  - "--title"
98
141
  - File-tail - File::Tail for Ruby
@@ -111,9 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
154
  - !ruby/object:Gem::Version
112
155
  version: '0'
113
156
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.6.11
116
- signing_key:
157
+ rubygems_version: 4.0.2
117
158
  specification_version: 4
118
159
  summary: File::Tail for Ruby
119
160
  test_files:
data/CHANGES DELETED
@@ -1,82 +0,0 @@
1
- 2016-04-19 * 1.2.0 * Make line separator configurable
2
- 2016-04-19 * 1.1.1 * Fix tests on Ruby 2.3.0
3
- 2014-09-26 * 1.1.0 * Depend on tins ~ 1.0
4
- 2012-05-31 * 1.0.10 * Use rewind to force IO#lineno to be reset.
5
- 2012-05-31 * 1.0.9 * Reopen file in :top mode at the beginning.
6
- 2011-12-24 * 1.0.8 * Support simplecov.
7
- 2011-07-15 * 1.0.7 * Use gem_hadar to shorten Rakefile.
8
- 2011-06-25 * 1.0.6 * Create a gem spec file again.
9
- * Added a File::Tail::Group to tail multiple files more easily.
10
- 2010-03-25 * 1.0.5 * Added rtail executable, a nice app to supervise logfiles
11
- and logdirs.
12
- * Disabled creation of gem spec file.
13
- * Cleaned up documentation a bit.
14
- 2009-08-21 * 1.0.4 * Fixed the threaded tests for Ruby 1.9.
15
- * Create a gem spec file.
16
- * Some cleanup.
17
- 2008-04-07 * 1.0.3 * Danny Colligan <danny.colligan@sendori.com> reported a
18
- memory leak in long running scripts using file-tail. I
19
- think this might be a ruby related problem, which is
20
- caused/aggravated by using yield after having &block
21
- parameter in a method. I changed file-tail to only use
22
- block.call, which seems to improve the memory behaviour. I
23
- am still not sure, where the problem actually stems
24
- from, though.
25
- 2007-04-19 * 1.0.2 * make_doc.rb was missing from the source archive. Thanks to
26
- Rick Ohnemus <rick.ohnemus@systemware.com> for reporting it.
27
- 2007-04-19 * 1.0.1 * Bugfix: File::Tail::Logfile#open with block, now closes
28
- the file like File#open does. Found by Alex Doan
29
- <alex.doan@wachovia.com>, ruby-talk:248383.
30
- 2007-03-30 * 1.0.0 * Bugfix: David.Barzilay@swisscom.com reported, that file
31
- tails may skip some log file lines, after rotating it. I
32
- think, that I fixed that problem.
33
- I added a after_reopen callback as well, that is called
34
- after reopening of the tailed file has occured.
35
- * Removed rewind/wind methods even earlier than planned: I
36
- placed the deprecation warning for rewind method in File
37
- instead of File::Tail, which caused rewind to stop working
38
- completely after loading file/tail. Duh! I blame vim's
39
- matchit, because it jumped to the wrong end keyword.
40
- 2007-02-08 * 0.1.4 * Renamed rewind method to backward, and wind method to
41
- forward, because someone already had the good idea to name
42
- a method IO#rewind, which was overwritten by the mixed in
43
- File::Tail methods. The old methods are now deprecated and
44
- will be removed in a new 0.2.x version of the library.
45
- * Added a bit more of documentation.
46
- 2005-08-20 * 0.1.3 * Applied LOAD_PATH patch by Daniel Berger, binary mode
47
- changes were already in the CVS. Seemed to be like cheating
48
- to me, though. ;)
49
- * Skipping one windows test for the moment, too. Sigh!
50
- 2004-09-30 * 0.1.2 * First Rubyforge release
51
- * Added Rakefile
52
- * Supports gem build now.
53
- 2004-09-01 * 0.1.1 * Josh Endries <josh@endries.org> found a bug
54
- that caused File::Tail to malfunction on FreeBSD.
55
- Hotfix: Use a side effect of seek to clearerr the tailed
56
- file handle after EOFError has been raised.
57
- 2004-04-13 * 0.1.0 * API documentation with rdoc.
58
- * return_if_eof attribute added.
59
- * Added array return mode for finite tail call without block
60
- given.
61
- * install.rb now uses ruby version site_dir.
62
- * Some code and directory structure cleanup.
63
- 2002-08-02 * 0.0.2 * Heavy refactoring, more and smaller methods
64
- and expception handling
65
- * Added check for inode and device equality of files
66
- as suggested by
67
- James F.Hranicky <jfh@cise.ufl.edu> and
68
- Curt Sampson <cjs@cynic.net> to cover remove
69
- rotation
70
- * If filesize shrinks suddenly, File::Tail assumes that
71
- copy and truncate rotation has happend: The file
72
- is reopened and every new line is handled.
73
- * NFS-Fix: Errno::ESTALE is caught.
74
- * wind added to skip the first n lines, as
75
- James F.Hranicky's suggested and changed
76
- name of last-method to rewind, because I liked
77
- his method names better than mine ;)
78
- * Renamed next to tail either.
79
- * The API has changed - but I think very few people
80
- care at the moment.
81
- * Lots of tests added.
82
- 2002-07-30 * 0.0.1 * Initial Release
File without changes