File Coverage

blib/lib/Goo/ConfigFile.pm
Criterion Covered Total %
statement 24 83 28.9
branch 0 22 0.0
condition 0 3 0.0
subroutine 8 18 44.4
pod 9 9 100.0
total 41 135 30.3


line stmt bran cond sub pod time code
1             package Goo::ConfigFile;
2              
3             ###############################################################################
4             # Nigel Hamilton
5             #
6             # Copyright Nigel Hamilton 2005
7             # All Rights Reserved
8             #
9             # Author: Nigel Hamilton
10             # Filename: Goo::ConfigFile.pm
11             # Description: Goo Config - parse .goo files. Based loosely on .ini files.
12             # We want # comments and fields = values
13             #
14             # Date Change
15             # -----------------------------------------------------------------------------
16             # 30/07/2005 Realised this was not going to be good enough
17             # 17/10/2005 Added method: getProgram
18             #
19             ###############################################################################
20              
21 1     1   6 use strict;
  1         2  
  1         32  
22              
23 1     1   7 use File::Find;
  1         2  
  1         55  
24 1     1   473 use Goo::List;
  1         3  
  1         24  
25 1     1   40 use Goo::Object;
  1         2  
  1         19  
26 1     1   6 use Data::Dumper;
  1         1  
  1         48  
27 1     1   5 use Goo::Prompter;
  1         3  
  1         28  
28 1     1   5 use Goo::FileUtilities;
  1         2  
  1         24  
29 1     1   5 use base qw(Goo::Object);
  1         2  
  1         1251  
30              
31             my $GOO_ROOT = "$ENV{HOME}/.goo/things";
32              
33              
34             ###############################################################################
35             #
36             # new - return a goo_config_file
37             #
38             ###############################################################################
39              
40             sub new {
41              
42 0     0 1   my ($class, $filename) = @_;
43              
44             # strip the path
45 0           $filename =~ s/.*\///;
46              
47 0           my $this = $class->SUPER::new();
48              
49 0 0         unless ($filename =~ /\.goo$/) {
50 0           die("Invalid Goo config file. $filename must end with .goo.");
51             }
52              
53 0           my $full_path = $GOO_ROOT . '/goo/' . $filename;
54              
55 0 0         unless (-e $full_path) {
56 0           Goo::Prompter::say("No Goo configuration file found for $full_path.");
57 0           Goo::Prompter::say("To make a new type of Thing enter: goo -m $filename.");
58 0           exit;
59             }
60              
61 0           $this->parse($full_path);
62              
63 0           return $this;
64              
65             }
66              
67              
68             ###############################################################################
69             #
70             # get_action_handler - return the handler for this command
71             #
72             ###############################################################################
73              
74             sub get_action_handler {
75              
76 0     0 1   my ($this, $command) = @_;
77              
78             # return the action handler for this command
79 0           return $this->{commands}->{$command};
80              
81             }
82              
83              
84             ###############################################################################
85             #
86             # has_locations - does it have any
87             #
88             ###############################################################################
89              
90             sub has_locations {
91              
92 0     0 1   my ($this) = @_;
93              
94             # return the locations for this Thing!
95 0           return ref($this->{locations}) eq "ARRAY";
96              
97             }
98              
99              
100             ###############################################################################
101             #
102             # get_locations - return a list of all the locations of the config file
103             #
104             ###############################################################################
105              
106             sub get_locations {
107              
108 0     0 1   my ($this) = @_;
109              
110             # return the locations for this Thing!
111 0 0         return @{ $this->{locations} }
  0            
112             if ($this->has_locations());
113              
114             # other return nothing
115 0           return undef;
116              
117             }
118              
119              
120             ###############################################################################
121             #
122             # parse - slurp in a file and parse it
123             #
124             ###############################################################################
125              
126             sub parse {
127              
128 0     0 1   my $this = shift; # ARG1: get object reference
129 0           my $full_path = shift; # ARG2: get full path to *.goo cfg file
130              
131 0           my @locations;
132              
133             my $location_finder = sub { # define anonymous sub
134             # for File::Find
135 0     0     my $subdir = $File::Find::name; # memoize current file
136 0 0         push @locations, $subdir if (-d $subdir); # add if directory
137              
138 0           };
139              
140             # parse the config file line by line
141 0           for my $line (Goo::FileUtilities::get_file_as_lines($full_path)) {
142             next
143 0 0 0       if ($line =~ /^\s*\#/ or # skip commented out or
144             $line =~ /^\s*$/); # empty lines
145              
146             # strip whitespace
147 0           $line =~ s/\s*=\s*/=/;
148 0           $line =~ s/^\s+//;
149 0           $line =~ s/\s+$//;
150              
151             # split out key value pairs
152 0           my ($field, $value) = split(/=/, $line);
153              
154 0 0         if ($field =~ /location/) {
    0          
155              
156             # field is a location entry
157 0 0         $value = "$ENV{HOME}/.goo/$value"
158             if ($value !~ /^\//); # prepend ~/.goo if relative path
159 0 0         $value = "$ENV{HOME}/.goo" if ($value eq '~'); # put in ~/.goo if "tilde" given
160 0           &find($location_finder, $value); # recursive directory finder
161              
162             } elsif ($field =~ /\[(.)\]/) { # field is a command
163 0           my $letter = $1; # match the command letter
164              
165 0 0         if ($letter !~ /[A-Z\d]/) {
166 0           die("Invalid command [$letter] in config file: $full_path. Commands must be uppercase."
167             );
168             }
169              
170             # [E]dit = $this->{actions}->{E}->{command} = "[E]dit";
171 0           $this->{actions}->{$letter}->{command} = $field;
172              
173             # [E]dit = $this->{actions}->{E}->{action} = "ProgramEditor";
174 0           $this->{actions}->{$letter}->{action} = $value;
175              
176             # remember the full command string too
177 0           $this->{commands}->{$field} = $value;
178              
179             } else {
180 0           $this->{$field} = $value;
181             }
182             }
183              
184             # make sure we only have unique locations
185 0 0         if (scalar(@locations) > 0) {
186              
187 0           my @unique_list = Goo::List::get_unique(@locations);
188 0           $this->{locations} = \@unique_list;
189              
190             }
191              
192             }
193              
194              
195             ###############################################################################
196             #
197             # write_to_file - very simple writer for single key value additions
198             #
199             ###############################################################################
200              
201             sub write_to_file {
202              
203 0     0 1   my ($filename, $key, $value) = @_;
204              
205 0           my $full_path = $GOO_ROOT . "/" . $filename;
206              
207             # get all the lines that don't match the key
208 0           my @lines = grep { $_ !~ /^$key/ } Goo::FileUtilities::get_file_as_lines($full_path);
  0            
209              
210             # add the new value for the key
211 0           push(@lines, "$key \t = \t $value \n");
212              
213             # save the file
214 0           Goo::FileUtilities::write_lines_as_file($full_path, @lines);
215              
216             }
217              
218              
219             ###############################################################################
220             #
221             # get_program - return the program that handles an action
222             #
223             ###############################################################################
224              
225             sub get_program {
226              
227 0     0 1   my ($this, $letter) = @_;
228              
229 0           return $this->{actions}->{$letter}->{action};
230              
231             }
232              
233              
234             ###############################################################################
235             #
236             # get_commands - return all the commands for this config file
237             #
238             ###############################################################################
239              
240             sub get_commands {
241              
242 0     0 1   my ($this) = @_;
243              
244 0           return keys %{ $this->{commands} };
  0            
245              
246             }
247              
248              
249             ###############################################################################
250             #
251             # has_table - does it have a database "table"
252             #
253             ###############################################################################
254              
255             sub has_table {
256              
257 0     0 1   my ($this) = @_;
258              
259             # has a table field been defined for this Thing?
260 0           return exists $this->{table};
261              
262             }
263              
264             1;
265              
266              
267              
268             __END__
269              
270             =head1 NAME
271              
272             Goo::ConfigFile - Parse and load .goo files. Based loosely on .ini files.
273              
274             =head1 SYNOPSIS
275              
276             use Goo::ConfigFile;
277              
278             =head1 DESCRIPTION
279              
280             All Things have a corresponding ".goo" file based on their file suffix. Perl modules, for example, have the configuration
281             file "pm.goo", scripts "pl.goo", Javascript files "js.goo", log files "log.goo" and Goo configuration files "goo.goo".
282              
283             All .goo files are stored in the user's home directory: ~/.goo/things/goo/.
284              
285             A .goo configuration file includes a list of actions (e.g., E[X]it) and an action handler (e.g., Exiter.pm). For
286             file-based Things (see Goo::FileThing) the configuration file includes a "location" field(s) where Things of this type can
287             be found.
288              
289             For database Things (see Goo::DatabaseThing) the configuration file includes a "table" field where Things of this type can
290             be found.
291              
292             Each action specified in .goo file contain an action letter in square brackets (e.g., [E]dit). This letter can be used
293             directly on the command line to invoke the action handler on the Thing (e.g., goo -e Object.pm).
294              
295              
296             =head1 METHODS
297              
298             =over
299              
300             =item new
301              
302             constructor
303              
304             =item get_action_handler
305              
306             return the action handler for a given command
307              
308             =item has_locations
309              
310             does it have any directory locations?
311              
312             =item get_locations
313              
314             return a list of all the directory locations found in the config file
315              
316             =item parse
317              
318             slurp in a .goo config file and parse it
319              
320             =item write_to_file
321              
322             very simplistic writer for single key value additions
323              
324             =item get_program
325              
326             return the program that handles an action
327              
328             =item get_commands
329              
330             return all the commands for this config file
331              
332             =item has_table
333              
334             does it have a database "table"?
335              
336             =back
337              
338             =head1 AUTHOR
339              
340             Nigel Hamilton <nigel@trexy.com>
341              
342             =head1 SEE ALSO
343