File Coverage

blib/lib/POE/Component/IRC/Plugin/FollowTail.pm
Criterion Covered Total %
statement 51 58 87.9
branch 5 10 50.0
condition 1 3 33.3
subroutine 13 15 86.6
pod 1 3 33.3
total 71 89 79.7


line stmt bran cond sub pod time code
1             package POE::Component::IRC::Plugin::FollowTail;
2             $POE::Component::IRC::Plugin::FollowTail::VERSION = '6.95';
3 2     2   2783 use strict;
  2         5  
  2         90  
4 2     2   12 use warnings FATAL => 'all';
  2         3  
  2         126  
5 2     2   9 use Carp;
  2         3  
  2         153  
6 2     2   10 use File::Glob ':glob';
  2         3  
  2         521  
7 2     2   18 use File::Spec::Functions 'rel2abs';
  2         5  
  2         159  
8 2     2   12 use POE qw(Wheel::FollowTail);
  2         8  
  2         18  
9 2     2   16693 use POE::Component::IRC::Plugin qw( :ALL );
  2         5  
  2         1821  
10              
11             sub new {
12 1     1 1 467 my ($package) = shift;
13 1 50       6 croak "$package requires an even number of arguments" if @_ & 1;
14 1         6 my %args = @_;
15 1         8 $args{lc $_} = delete $args{$_} for keys %args;
16              
17 1 50       6 die "$package requires a 'filename' attribute" if !defined $args{filename};
18 1         76 $args{filename} = bsd_glob($args{filename});
19 1 50       16 die "File '$args{filename}' does not exist" if !-e $args{filename};
20 1         7 $args{filename} = rel2abs($args{filename});
21              
22 1         31 return bless \%args, $package;
23             }
24              
25             sub PCI_register {
26 1     1 0 826 my ($self, $irc) = splice @_, 0, 2;
27 1         6 $self->{irc} = $irc;
28 1         9 POE::Session->create(
29             object_states => [
30             $self => [ qw(_start _shutdown _input _error _reset) ],
31             ],
32             );
33              
34 1         172 return 1;
35             }
36              
37             sub PCI_unregister {
38 1     1 0 2713 my ($self, $irc) = splice @_, 0, 2;
39 1         4 delete $self->{irc};
40 1         18 $poe_kernel->post( $self->{session_id} => '_shutdown' );
41 1         135 $poe_kernel->refcount_decrement( $self->{session_id}, __PACKAGE__ );
42 1         62 return 1;
43             }
44              
45             sub _start {
46 1     1   342 my ($kernel, $self) = @_[KERNEL, OBJECT];
47              
48 1         5 $self->{session_id} = $_[SESSION]->ID();
49 1         9 $kernel->refcount_increment( $self->{session_id}, __PACKAGE__ );
50              
51             $self->{wheel} = POE::Wheel::FollowTail->new(
52             Filename => $self->{filename},
53             InputEvent => '_input',
54             ErrorEvent => '_error',
55             ResetEvent => '_reset',
56             ( defined $self->{filter} && $self->{filter}->isa('POE::Filter')
57             ? ( Filter => $self->{filter} )
58 1 50 33     66 : ()
59             ),
60             );
61              
62 1         803 return;
63             }
64              
65             sub _shutdown {
66 1     1   790 my ($kernel, $self, $term) = @_[KERNEL, OBJECT, ARG0];
67 1         9 delete $self->{wheel};
68 1 50       311 $kernel->refcount_decrement( $self->{session_id}, __PACKAGE__ ) if $term;
69 1         7 return;
70             }
71              
72             sub _input {
73 1     1   1002428 my ($kernel, $self, $input) = @_[KERNEL, OBJECT, ARG0];
74 1         13 $self->{irc}->send_event( 'irc_tail_input', $self->{filename}, $input );
75 1         196 return;
76             }
77              
78             sub _error {
79 0     0     my ($kernel, $self) = @_[KERNEL, OBJECT];
80 0           $self->{irc}->send_event( 'irc_tail_error', $self->{filename}, @_[ARG0..ARG2] );
81 0           $kernel->yield('_shutdown','TERM');
82 0           return;
83             }
84              
85             sub _reset {
86 0     0     my ($kernel, $self) = @_[KERNEL, OBJECT];
87 0           $self->{irc}->send_event( 'irc_tail_reset', $self->{filename} );
88 0           return;
89             }
90              
91             1;
92              
93             =encoding utf8
94              
95             =head1 NAME
96              
97             POE::Component::IRC::Plugin::FollowTail - A PoCo-IRC plugin to follow the tail
98             of an ever-growing file
99              
100             =head1 SYNOPSIS
101              
102             use POE qw(Component::IRC Component::IRC::Plugin::FollowTail);
103              
104             my $nickname = 'Flibble' . $$;
105             my $ircname = 'Flibble the Sailor Bot';
106             my $ircserver = 'irc.blahblahblah.irc';
107             my $filename = '/some/such/file/here';
108             my @channels = ( '#Blah', '#Foo', '#Bar' );
109              
110             my $irc = POE::Component::IRC->spawn(
111             nick => $nickname,
112             server => $ircserver,
113             port => $port,
114             ircname => $ircname,
115             ) or die "Oh noooo! $!";
116              
117             POE::Session->create(
118             package_states => [
119             main => [ qw(_start irc_001 irc_tail_input irc_tail_error irc_tail_reset) ],
120             ],
121             );
122              
123             $poe_kernel->run();
124              
125             sub _start {
126             $irc->plugin_add( 'FollowTail' => POE::Component::IRC::Plugin::FollowTail->new(
127             filename => $filename,
128             ));
129             $irc->yield( register => 'all' );
130             $irc->yield( connect => { } );
131             return;
132             }
133              
134             sub irc_001 {
135             $irc->yield( join => $_ ) for @channels;
136             return;
137             }
138              
139             sub irc_tail_input {
140             my ($kernel, $sender, $filename, $input) = @_[KERNEL, SENDER, ARG0, ARG1];
141             $kernel->post( $sender, 'privmsg', $_, "$filename: $input" ) for @channels;
142             return;
143             }
144              
145             sub irc_tail_error {
146             my ($kernel, $sender, $filename, $errnum, $errstring)
147             = @_[KERNEL, SENDER, ARG0 .. ARG2];
148             $kernel->post( $sender, 'privmsg', $_, "$filename: ERROR: $errnum $errstring" ) for @channels;
149             $irc->plugin_del( 'FollowTail' );
150             return;
151             }
152              
153             sub irc_tail_reset {
154             my ($kernel, $sender, $filename) = @_[KERNEL, SENDER, ARG0];
155             $kernel->post( $sender, 'privmsg', $_, "$filename: RESET EVENT" ) for @channels;
156             return;
157             }
158              
159             =head1 DESCRIPTION
160              
161             POE::Component::IRC::Plugin::FollowTail is a L
162             plugin that uses L to follow
163             the end of an ever-growing file. It generates C prefixed events for
164             each new record that is appended to its file.
165              
166             =head1 METHODS
167              
168             =head2 C
169              
170             Takes two arguments:
171              
172             B<'filename'>, the name of the file to tail, mandatory;
173              
174             B<'filter'>, a POE::Filter object to pass to POE::Wheel::FollowTail, optional;
175              
176             Returns a plugin object suitable for feeding to
177             L's C method.
178              
179             =head1 OUTPUT EVENTS
180              
181             The plugin generates the following additional
182             L events:
183              
184             =head2 C
185              
186             Emitted for every complete record read. C will be the filename,
187             C the record which was read.
188              
189             =head2 C
190              
191             Emitted whenever an error occurs. C will be the filename, C
192             and C hold numeric and string values for $!, respectively.
193              
194             =head2 C
195              
196             Emitted every time a file is reset. C will be the filename.
197              
198             =head1 AUTHOR
199              
200             Chris 'BinGOs' Williams
201              
202             =head1 SEE ALSO
203              
204             L
205              
206             L
207              
208             =cut