File Coverage

lib/Badger/App.pm
Criterion Covered Total %
statement 27 97 27.8
branch 0 16 0.0
condition 1 25 4.0
subroutine 7 19 36.8
pod 2 14 14.2
total 37 171 21.6


line stmt bran cond sub pod time code
1             package Badger::App;
2              
3 1     1   715 use Badger::Config::Schema;
  1         3  
  1         27  
4 1     1   399 use Badger::Reporter::App;
  1         2  
  1         28  
5 1     1   6 use Badger::Debug ':dump debugf';
  1         2  
  1         5  
6 1     1   354 use Badger::Apps;
  1         2  
  1         8  
7             use Badger::Class
8 1         23 version => 0.01,
9             debug => 0,
10             base => 'Badger::Prototype',
11             import => 'class CLASS',
12             utils => 'wrap',
13             accessors => 'name author date version',
14             constants => 'DELIMITER ARRAY',
15             constant => {
16             SCHEMA => 'Badger::Config::Schema',
17             APPS => 'Badger::Apps',
18             REPORTER => 'Badger::Reporter::App',
19             },
20             alias => {
21             init => \&init_app,
22             },
23             config => [
24             'base|class:CLASS',
25             'name|class:NAME|method:CLASS',
26             'author|class:AUTHOR',
27             'version|class:VERSION',
28             'date|class:DATE',
29             'about|class:ABOUT',
30             'usage|class:USAGE',
31             'actions|class:ACTIONS',
32             # 'apps|class:APPS',
33             # 'app_path|class:APP_PATH|method:CLASS',
34             ],
35             messages => {
36             missing_arg => "No value specified for %s",
37 1     1   6 };
  1         2  
38              
39              
40             sub init_app {
41 1     1 0 2 my ($self, $config) = @_;
42              
43 1         1 $self->debugf(
44             "init_app(%s)",
45             $self->dump_data($config),
46             ) if DEBUG;
47              
48 1         4 $self->configure($config)
49             ->init_options($config);
50              
51             # shared context
52 1   50     6 $self->{ app } = $config->{ app } || { };
53 1         2 $self->{ parent } = $config->{ parent };
54 1         3 $self->{ config } = $config;
55              
56             # $self->{ app }->{ $self } = 'Hello World';
57             # $self->debug("app: ", $self->dump_data($self->{ app }));
58             # my $apps = $self->{ app }->{ apps } ||= [ ];
59             # push(@$apps, $self);
60            
61 1         2 return $self;
62             }
63              
64              
65             sub init_options {
66 1     1 0 3 my ($self, $config) = @_;
67 1         11 my $options = $self->class->list_vars( OPTIONS => $config->{ options } );
68 1         12 $self->{ schema } = $self->SCHEMA->new( schema => $options );
69 1         2 $self->debug("created schema: ", $self->{ schema }) if DEBUG;
70 1         2 return $self;
71             }
72              
73              
74             sub args {
75 0     0 0   my $self = shift->prototype;
76 0 0 0       my $args = @_ == 1 && ref $_[0] eq ARRAY ? shift : [ @_ ];
77 0   0       my $options = $self->{ app }->{ options } ||= { };
78 0           my ($arg, $option, $app);
79            
80 0           $self->debug("args(", $self->dump_data_inline($args), ")") if DEBUG;
81              
82 0           my $schema = $self->{ schema };
83 0           $self->debug("using schema: $schema") if DEBUG;
84            
85 0           while (@$args) {
86 0           $arg = $args->[0];
87 0           $self->debug("option: $arg") if DEBUG;
88            
89 0 0 0       if ($option = $schema->item($arg)) {
    0          
    0          
90 0           $self->debug("got schema option: $option") if DEBUG;
91             }
92             elsif ($arg =~ /^--(.*)/) {
93 0           $self->debug("looking for option: $1") if DEBUG;
94             # TODO: look up app stack
95 0   0       $option = $schema->item($1)
96             || return $self->error_msg( invalid => argument => $arg );
97             }
98             elsif ($arg =~ /^[\w\.]+$/ && ($app = $self->app($arg))) {
99 0           shift @$args;
100             return $app->new(
101             parent => $self,
102             app => $self->{ app }
103 0           )->args($args);
104             }
105             else {
106 0           $self->debug("not found: $arg") if DEBUG;
107 0           return $self->error_msg( invalid => argument => $arg );
108             }
109              
110 0           shift @$args;
111 0           $option->args($args, $self->{ app }, $self);
112             }
113              
114 0           return $self;
115             # $self->debug("options schema for this app is: ", $schema);
116             # $self->not_implemented('in base class');
117             }
118              
119              
120             sub validate {
121 0     0 0   my $self = shift->prototype;
122 0           my $app = $self->{ app };
123 0           my $schema = $self->{ schema };
124 0           my ($item, $name);
125            
126 0           foreach $item ($schema->items) {
127 0 0         next unless $item->{ required };
128 0           $name = $item->{ name };
129             return $self->error_msg( missing_arg => $name )
130 0 0         unless defined $app->{ $name };
131             }
132              
133 0           return $app;
134             }
135              
136              
137             sub app {
138 0     0 0   shift->apps->app(@_);
139             }
140              
141              
142             sub apps {
143 0     0 0   my $self = shift;
144              
145 0   0       return $self->{ apps } ||= do {
146 0           my $class = $self->class;
147             my $apps = $class->hash_vars(
148             APPS => $self->{ config }->{ apps }
149 0           );
150             my $path = $class->list_vars(
151             APP_PATH => $self->{ config }->{ app_path }
152 0           );
153 0 0         push(@$path, $self->class->name) unless @$path;
154 0           $self->debug(
155             "creating app factory with path: ", $self->dump_data_inline($path),
156             "and apps: ", $self->dump_data_inline($apps)
157             ) if DEBUG;
158 0           $self->APPS->new(
159             path => $path,
160             apps => $apps,
161             );
162             };
163             }
164              
165              
166             sub run {
167 0     0 0   my $self = shift;
168 0           $self->validate;
169 0           $self->not_implemented('in base class');
170             }
171              
172              
173             #-----------------------------------------------------------------------
174             # output generation
175             #-----------------------------------------------------------------------
176              
177             sub reporter {
178 0     0 0   my $self = shift->prototype;
179 0 0         my $config = @_ ? params(@_) : $self->{ app };
180             return $self->{ reporter }
181 0   0       ||= class($self->REPORTER)->load->instance($config);
182             }
183              
184              
185             sub help {
186 0     0 0   my $self = shift->prototype;
187 0           $self->credits;
188 0           $self->about;
189 0           $self->usage;
190 0           $self->options;
191 0           exit;
192             }
193              
194              
195             sub credits {
196 0     0 0   my $self = shift;
197 0           $self->reporter->credits(
198             $self->name,
199             $self->version,
200             $self->author,
201             $self->date,
202             );
203             }
204              
205              
206             sub options {
207 0     0 0   my $self = shift->prototype;
208 0           my $reporter = $self->reporter;
209 0           $reporter->section('Options');
210              
211 0           foreach my $item ($self->{ schema }->items) {
212 0           $item->summary($reporter);
213             }
214 0           return;
215              
216             my $options = join(
217             "\n ",
218             grep { defined && length }
219             map { $_->summary }
220             $self->{ schema }->items
221 0   0       ) || return '';
222            
223 0           $reporter->about($options);
224             }
225              
226              
227             sub blurb {
228 0     0 0   my ($self, $type, $title) = @_;
229 0           my $reporter = $self->reporter;
230             my $blurb = $self->{ $type }
231 0   0       || $self->{ config }->{ $type }
232             || $self->class->any_var( uc $type )
233             || return '';
234 0           $blurb = wrap($blurb, 76, 2);
235 0   0       $title ||= ucfirst $type;
236            
237 0           $reporter->section($title);
238 0           $reporter->about($blurb);
239             }
240              
241              
242             sub about {
243 0     0 1   shift->blurb('about');
244             }
245              
246              
247             sub usage {
248 0     0 1   shift->blurb('usage');
249             }
250              
251              
252             1;
253              
254              
255              
256             =head1 NAME
257              
258             Badger::App - base class application module
259              
260             =head1 DESCRIPTION
261              
262             This module implements a base class for simple, self-contained applications.
263              
264             =head1 METHODS
265              
266             The following methods are defined in addition to those inherited from the
267             L and L base classes.
268              
269             =head2 about()
270              
271             This method should be re-defined in subclasses to return information about
272             the application.
273              
274             =head2 usage()
275              
276             This method should be re-defined in subclasses to return a summary of usage
277             options for the application.
278              
279             =head1 AUTHOR
280              
281             Andy Wardley L
282              
283             =head1 COPYRIGHT
284              
285             Copyright (C) 2008-2012 Andy Wardley. All Rights Reserved.
286              
287             This module is free software; you can redistribute it and/or
288             modify it under the same terms as Perl itself.
289              
290             =head1 SEE ALSO
291              
292             L,
293             L.
294              
295             =cut
296              
297             # Local Variables:
298             # mode: perl
299             # perl-indent-level: 4
300             # indent-tabs-mode: nil
301             # End:
302             #
303             # vim: expandtab shiftwidth=4:
304