# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/ # # Copyright (C) 2000-2018 Peter Thoeny, peter[at]thoeny.org # and TWiki Contributors. All Rights Reserved. TWiki Contributors # are listed in the AUTHORS file in the root of this distribution. # NOTE: Please extend that file, not this notice. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 3 # of the License, or (at your option) any later version. For # more details read LICENSE in the root of this distribution. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # As per the GPL, removal of this notice is prohibited. =pod ---+ package TWiki::LineIterator Iterator over the lines in a file =cut package TWiki::LineIterator; use strict; =pod ---++ new( $file ) Create a new iterator over the given file. if the file cannot be opened, then there will be no elements in the iterator. =cut sub new { my ($class, $file) = @_; my $this = bless({}, $class); $this->{nextLine} = undef; if( open($this->{handle}, '<', $file )) { $this->next(); } else { die $!; }; $this->{process} = undef; $this->{filter} = undef; return $this; } sub _DESTROY { my $this = shift; if( defined( $this->{nextLine} )) { # the iterator is still open close( $this->{handle} ); } } =pod ---++ hasNext() -> $boolean Returns false when the iterator is exhausted. my $it = new TWiki::ListIterator(\@list); while ($it->hasNext()) { ... =cut sub hasNext { my $this = shift; return defined( $this->{nextLine} ); } =pod ---++ next() -> $data Return the next line in the file. The iterator object can be customised to pre- and post-process entries from the list before returning them. This is done by setting two fields in the iterator object: * ={filter}= can be defined to be a sub that filters each entry. The entry will be ignored (next() will not return it) if the filter returns false. * ={process}= can be defined to be a sub to process each entry before it is returned by next. The value returned from next is the value returned by the process function. For example, my $it = new TWiki::LineIterator("/etc/passwd"); $it->{filter} = sub { $_[0] =~ /^.*?:/; return $1; }; $it->{process} = sub { return "User $_[0]"; }; while ($it->hasNext()) { my $x = $it->next(); print "$x\n"; } =cut sub next { my ($this) = @_; my $curLine = $this->{nextLine}; my $h = $this->{handle}; local $/ = "\n"; do { $this->{nextLine} = <$h>; if( ! defined( $this->{nextLine} )) { close( $h ); } else { chomp( $this->{nextLine} ); } } while (!( !defined( $this->{nextLine} ) || !$this->{filter} || !&{$this->{filter}}($this->{nextLine}))); $curLine = &{$this->{process}}($curLine) if $this->{process}; return $curLine; } 1;