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