File Coverage

blib/lib/Bot/Backbone/Bot.pm
Criterion Covered Total %
statement 26 27 96.3
branch 2 2 100.0
condition n/a
subroutine 7 8 87.5
pod 4 4 100.0
total 39 41 95.1


line stmt bran cond sub pod time code
1             package Bot::Backbone::Bot;
2             $Bot::Backbone::Bot::VERSION = '0.160630';
3 4     4   5575 use v5.10;
  4         10  
4 4     4   13 use Moose;
  4         6  
  4         21  
5              
6 4     4   15980 use Bot::Backbone::Types qw( EventLoop ServiceList );
  4         4  
  4         33  
7 4     4   6211 use POE qw( Loop::AnyEvent );
  4         88320  
  4         26  
8              
9             # ABSTRACT: Provides backbone services to your bot
10              
11              
12             has event_loop => (
13                 is => 'ro',
14                 isa => EventLoop,
15                 required => 1,
16                 default => 'POE::Kernel',
17             );
18              
19              
20             has services => (
21                 is => 'ro',
22                 isa => ServiceList,
23                 required => 1,
24                 default => sub { +{} },
25                 traits => [ 'Hash' ],
26                 handles => {
27                     add_service => 'set',
28                     list_services => 'values',
29                     destroy_services => 'clear',
30                     has_service => 'defined',
31                     get_service => 'get',
32                 },
33             );
34              
35              
36 0     0 1 0 sub bot { $_[0] }
37              
38              
39             sub construct_services {
40 5     5 1 150     my $self = shift;
41              
42 5         20     my $my_name = $self->meta->name;
43              
44 5         96     for my $name ($self->meta->list_services) {
45 12         28         my $service_config = $self->meta->services->{$name};
46 12 100       272         next if defined $self->services->{$name};
47              
48 9         21         my $class_name = $service_config->{service};
49 9         146         my $service = $class_name->new(
50                         %$service_config,
51                         name => $name,
52                         bot => $self,
53                     );
54              
55 9         292         $self->add_service($name, $service);
56                 }
57             }
58              
59              
60             sub run {
61 4     4 1 900     my $self = shift;
62              
63 4         21     $self->construct_services;
64 4         135     $_->initialize for ($self->list_services);
65              
66 4         130     $self->event_loop->run;
67             }
68              
69              
70             sub shutdown {
71 1     1 1 641746     my $self = shift;
72              
73 1         120     $_->shutdown for ($self->list_services);
74 1         44     $self->destroy_services;
75             }
76              
77              
78             __PACKAGE__->meta->make_immutable;
79              
80             __END__
81            
82             =pod
83            
84             =encoding UTF-8
85            
86             =head1 NAME
87            
88             Bot::Backbone::Bot - Provides backbone services to your bot
89            
90             =head1 VERSION
91            
92             version 0.160630
93            
94             =head1 SYNOPSIS
95            
96             my $bot = My::Bot->new;
97             $bot->run;
98            
99             =head1 DESCRIPTION
100            
101             When you use L<Bot::Backbone> in your code, you get a bot implementing this
102             role. It provides tools for constructing, executing, and shutting down services.
103            
104             =head1 ATTRIBUTES
105            
106             =head2 event_loop
107            
108             Bots do all their work using an event loop. Usually, this is either L<POE> or
109             L<AnyEvent>. Fortunately, these event loops tend to work well together in case
110             you need both. Just in case you need specialized startup for your bot's event
111             loop, though, this is attribute is provided to allow the event loop startup to
112             be customized.
113            
114             This is an object or class on which you may call a C<run> with no arguments. It
115             will be called to start the event loop. By default, this is just
116             "L<POE::Kernel>". It is expected that this method will block until the bot is
117             shutdown.
118            
119             =head2 services
120            
121             This is a hash of constructed services used by this bot. There should be a key
122             in this hash matching every key in the same attribute in
123             L<Bot::Backbone::Meta::Class>, once L</run> has been called.
124            
125             =head1 METHODS
126            
127             =head2 bot
128            
129             Returns itself.
130            
131             =head2 construct_services
132            
133             $bot->construct_services;
134            
135             This method iterates through the service configurations of the meta class and constructs each service from that configuration.
136            
137             You may run this prior to L</run> to construct your services prior to running. Normally, though, this method is called within L</run>.
138            
139             =head2 run
140            
141             $bot->run;
142            
143             This starts your bot running. It constructs the services if they have not yet been constructed. Then, it initializes each service. Finally, it starts the L<POE> event loop. This last part really isn't it's business and might go away in the future.
144            
145             This method will not return until the event loop terminates. The usual way to do this is to call L</shutdown>.
146            
147             =head2 shutdown
148            
149             $bot->shutdown;
150            
151             You may call this at any time while your bot is running to shutdown all the services. This notifies each service that it should shutdown (i.e., finish or terminate any pending jobs in the event loop). It then clears the L</services> hash, which should cause all services to be destroyed.
152            
153             =head1 CAVEATS
154            
155             This thing sort of kind of needs L<POE> to be any kind of useful. However, L<POE> seems to have weird drawbacks. I have some planned work-arounds for this being an explicit and required dependency, but it's there for now.
156            
157             Second, if you use the Jabber chat service, you need L<AnyEvent>. Mostly, L<AnyEvent> and L<POE> seem to get along, but it's slow and I've found that timers, in particular, just plain don't work quite right.
158            
159             =head1 AUTHOR
160            
161             Andrew Sterling Hanenkamp <hanenkamp@cpan.org>
162            
163             =head1 COPYRIGHT AND LICENSE
164            
165             This software is copyright (c) 2016 by Qubling Software LLC.
166            
167             This is free software; you can redistribute it and/or modify it under
168             the same terms as the Perl 5 programming language system itself.
169            
170             =cut
171