File Coverage

blib/lib/Launcher/Cascade.pm
Criterion Covered Total %
statement 37 46 80.4
branch 6 10 60.0
condition 3 9 33.3
subroutine 9 10 90.0
pod 4 4 100.0
total 59 79 74.6


line stmt bran cond sub pod time code
1             package Launcher::Cascade;
2              
3             =head1 NAME
4              
5             Launcher::Cascade - a framework for launching processes that depend on one another
6              
7             =head1 SYNOPSIS
8              
9             use Launcher::Cascade::Simple;
10             use Launcher::Cascade::Container;
11              
12             my $launcher1 = Launcher::Cascade::Simple->new(
13             -launch_hook => sub { ... }, # what to do to launch
14             -test_hook => sub { ... }, # what to do to test that it succeeded
15             );
16             my $launcher2 = Launcher::Cascade::Simple->new(
17             -launch_hook => sub { ... }, # what to do to launch
18             -test_hook => sub { ... }, # what to do to test that it succeeded
19             -dependencies => [ $launcher1 ], # second launcher depends on success of first
20             );
21              
22             my $container = new Launcher::Cascade::Container
23             -launchers => [ $launcher1, $launcher2 ];
24              
25             $container->run_session();
26              
27             =head1 DESCRIPTION
28              
29             This module provides a framework to launch processes, test whether they
30             succeeded or not and report on that. Each process is modeled as an object and
31             can depend on other processes to start, i.e., a process will not be started
32             until all the processes it depends upon have successfully been started.
33              
34             Process launchers must be implemented as C objects (or
35             subclassses thereof). Their launch() method will actually launch the process,
36             and their test() method will check whether it succeeded or not. Each launcher
37             can be made to depend on one or more other launchers: it will then refuse to
38             launch() until the others have been test()ed successfully.
39              
40             All the launchers should be given to a C, which will
41             run them in turn and test their status when applicable, until either all of the
42             Launchers have succeeded or one of them has failed.
43              
44             The distribution provides C to ease the launching
45             of external (and possibly remote, by means of ssh) commands and the reading of
46             files. FileReaders should be used in launch() or test() methods of Launchers.
47              
48             This base class provides a constructor for its subclasses that accepts named
49             arguments, as well as function to easily create attributes and their accessors.
50             All the real functionality has to be implemented in subclasses.
51              
52             =cut
53              
54 12     12   21418 use strict;
  12         36  
  12         412  
55 12     12   67 use warnings;
  12         23  
  12         2614  
56              
57             =head2 Constructor
58              
59             =over 4
60              
61             =item B I
62              
63             Creates and returns an instance. I should be a list of named parameters.
64             The values will be passed to the accessors of the same name. Leading dashes
65             will be removed from the names, and they will be converted to lowercase before
66             invoking the accessor.
67              
68             =back
69              
70             =cut
71              
72             sub new {
73              
74 29     29 1 36478 my $proto = shift;
75 29   33     186 my $class = ref($proto)||$proto;
76              
77 29         102 my $self = bless {}, $class;
78              
79 29         145 while ( @_ ) {
80 56         174 my ($key, $value) = (lc(shift), shift);
81 56         268 $key =~ s/^-+//;
82 56         286 $self->$key($value);
83             }
84            
85 29         863 return $self;
86             }
87              
88             =head2 Functions
89              
90             =over 4
91              
92             =item B I
93              
94             Make accessors in the caller's namespace.
95              
96             I should contain names of accessors. make_accessors() will generate an
97             accessor for each name in I, that will return the corresponding
98             attribute's value when called without argument, and set the attribute's value
99             when called with an argument (in that latter case, the former value is
100             returned). Example:
101              
102             package MyPackage;
103              
104             use Launcher::Cascade;
105             our @ISA = qw/ Launcher::Cascade /; # inherits constructor
106              
107             Launcher::Cascade::make_accessors qw/ first_name last_name /;
108              
109             1;
110              
111             Meanwhile, in a nearby piece of code:
112              
113             use MyPackage;
114              
115             my $object = new MyPackage -first_name => 'Zaphod';
116             print $object->first_name(); # Zaphod
117              
118             print $object->last_name('Beeblebrox'); # undef
119             print $object->last_name(); # Beeblebrox
120              
121             =cut
122              
123             sub make_accessors {
124              
125 23     23 1 92 my ($package) = caller();
126 23         69 foreach my $name ( @_ ) {
127 61         144 my $method = join '::', $package, $name;
128 12     12   73 no strict 'refs';
  12         34  
  12         10025  
129             *$method = sub {
130 305     305   481 my $self = shift;
131 305         1647 my $old = $self->{"_$name"};
132 305 100       824 $self->{"_$name"} = $_[0] if @_;
133 305         1495 return $old;
134 61         510 };
135             }
136             }
137              
138             =item B I
139              
140             Reads a file containing the definition of default values for subclasses
141             attributes. The file should contain name, value pairs, one by line, separated
142             by an equal sign. Whitespace is ignored at the beginning or end of the line and
143             on either side of the equal sign. Lines starting with a hash sign are ignored,
144             as well as blank lines.
145              
146             The name should be the fully qualified accessor method name, i.e., the package
147             and name of the accessor separated by a double colon.
148              
149             # This is an example
150              
151             MyPackage::first_name = Zaphod
152             MyPackage::last_name = Beeblebrox
153              
154             =cut
155              
156             my %default;
157             sub read_default_file {
158              
159 0     0 1 0 my $filename = shift;
160              
161 0 0       0 open my $fh, '<', $filename or die "Cannot read $filename: $!";
162 0         0 while ( <$fh> ) {
163 0         0 chomp;
164 0         0 s/^\s+|\s+$//g;
165 0 0 0     0 next if /^#/ || /^$/;
166 0         0 my ($k, $v) = split /\s*=\s*/, $_, 2;
167 0         0 $default{$k} = $v;
168             }
169 0         0 close $fh;
170             }
171              
172             =item B I
173              
174             Does the same as make_accessors(), but elements in I should go in pairs,
175             accessor names together with their default values. If the attribute's value has
176             not explicitly been set, the accessor will return the default value as read
177             from the defaults file (see read_default_file()) or the default value provided
178             in I. The defaults file overrides the value from I.
179              
180             package MyPackage;
181              
182             use Launcher::Cascade;
183             our @ISA = qw/ Launcher::Cascade /;
184              
185             Launcher::Cascade::make_accessors_with_defaults(
186             first_name => 'Zaphod',
187             last_name => 'Beeblebrox',
188             );
189              
190             Meanwhile, in a nearby piece of code:
191              
192             use MyPackage;
193            
194             my $o = new MyPackage;
195             print $o->first_name(); # Zaphod
196              
197             =cut
198              
199             sub make_accessors_with_defaults {
200              
201 40     40 1 122 my ($package) = caller();
202 40         165 my %attr = @_;
203 40         357 while ( my ($name, $default) = each %attr ) {
204 150         422 my $method = join '::', $package, $name;
205 12     12   129 no strict 'refs';
  12         24  
  12         2209  
206             *$method = sub {
207 343241     343241   594790 my $self = shift;
208 343241 100 66     1108407 my $old = defined($self->{"_$name"}) ? $self->{"_$name"} : $default{$method} || $default;
209 343241 100       842590 $self->{"_$name"} = $_[0] if @_;
210 343241         3730368 return $old;
211 150         1480 };
212             }
213             }
214              
215             =back
216              
217             =head1 VERSION
218              
219             0.02
220              
221             =cut
222              
223             our $VERSION = 0.02;
224              
225             =head1 SEE ALSO
226              
227             =head1 AUTHOR
228              
229             Cédric Bouvier C<< >>
230              
231             =head1 COPYRIGHT & LICENSE
232              
233             Copyright (C) 2006 Cédric Bouvier, All Rights Reserved.
234              
235             This program is free software; you can redistribute it and/or modify it under
236             the same terms as Perl itself.
237              
238             =cut
239              
240             1; # end of Launcher::Cascade