File Coverage

blib/lib/File/UserConfig.pm
Criterion Covered Total %
statement 59 69 85.5
branch 24 40 60.0
condition n/a
subroutine 17 17 100.0
pod 7 7 100.0
total 107 133 80.4


line stmt bran cond sub pod time code
1             package File::UserConfig;
2              
3             =pod
4              
5             =head1 NAME
6              
7             File::UserConfig - Get a user's existing config directory, or copy in defaults
8              
9             # The most simple Do What I Mean usage.
10             $configdir = File::UserConfig->configdir;
11            
12             # Or without taking advantage of convention-based defaults
13             $configdir = File::UserConfig->new(
14             dist => 'My-Application',
15             module => 'My::Application',
16             dirname => '.myapp',
17             sharedir => $defaults_here,
18             )->configdir;
19              
20             =head1 DESCRIPTION
21              
22             Many modules or applications maintain a user-spec configuration data
23             directory. And the implementation pattern is generally the same.
24              
25             A directory like F is created and populating by
26             a set of default files the first time an application runs, and from there
27             on, the files in that directory are modified.
28              
29             C provides standard, light and sub-classable default
30             implementation of this concept that Does The Right Thing with the
31             directory names.
32              
33             =head2 Applying Perl Conventions
34              
35             C applies and automates the following conventions.
36              
37             B<1. We are using the distribution name?>
38              
39             The use of C is based on distribution name (more on that
40             later) so we need to know it.
41              
42             The CPAN convention is for a dist to be named C after the
43             main module C in the distribution, but sometimes this
44             varies, and sometimes you will want to call C from
45             other than the main module. But unless you say otherwise,
46             C will assume that if you call it from "Module::Name",
47             that is probably the main module, and thus your dist is probably called
48             "Module-Name".
49              
50             B<2. What config directory name is used>
51              
52             On platforms which keep application-specific data in its own directory,
53             well away from the data the user actually create themself, we just use
54             the dist name.
55              
56             On Unix, which has a combined home directory, we remap the dist name to
57             be a lowercase hidden name with all '-' chars as '_'.
58              
59             So on unix only, "Module::Name" will become ".module_name". Most of the
60             time, this will end up what you would have used anyway.
61              
62             B<3. Where does the config directory live>
63              
64             C knows where your home directory is by using
65             L. And more specifically, on platforms that support
66             application data being kept in a subdirectory, it will use that as well.
67              
68             On Unix, Windows, and Mac OS X, it will just Do The Right Thing.
69              
70             B<4. Where do the defaults come from?>
71              
72             The ability for a distribution to provide a directory full of default
73             files is provided in Perl by L.
74              
75             Of course, we're also assuming you are using L so you
76             have access to its C command, and that the only thing
77             your dist is going to install to it will be the default config dir.
78              
79             =head1 METHODS
80              
81             The 6 accessors all feature implicit constructors.
82              
83             In other words, the two following lines are equivalent.
84              
85             # Explicitly
86             $configdir = File::UserConfig->new( ... )->configdir;
87            
88             # Auto-construction
89             $configdir = File::UserConfig->configdir( ... );
90            
91             # Thus, using all default params we can just
92             $configdir = File::UserConfig->configdir;
93              
94             =cut
95              
96 2     2   29309 use 5.005;
  2         8  
  2         74  
97 2     2   11 use strict;
  2         5  
  2         59  
98 2     2   19 use Carp ();
  2         3  
  2         33  
99 2     2   11 use File::Spec ();
  2         3  
  2         38  
100 2     2   2034 use File::Copy::Recursive ();
  2         18932  
  2         147  
101 2     2   2456 use File::HomeDir ();
  2         15161  
  2         46  
102 2     2   2082 use File::ShareDir ();
  2         18063  
  2         58  
103              
104 2     2   22 use vars qw{$VERSION};
  2         4  
  2         92  
105             BEGIN {
106 2     2   1569 $VERSION = '0.06';
107             }
108              
109              
110              
111              
112              
113             #####################################################################
114             # Constructor
115              
116             =pod
117              
118             =head2 new
119              
120             my $config = File::UserConfig->new(
121             dist => 'Not-This-Class',
122             dirname => '.myconfig',
123             sharedir => 'defaultconfig',
124             homedir => $username,
125             );
126              
127             The C constructor takes a set of optional named params, and finds
128             the user's configuration directory, creating it by copying in a default
129             directory if an existing one cannot be found.
130              
131             In almost every case, you will want to use all the defaults and let
132             everything be determined automatically for you. The sample above tries
133             to show some of the limited number of situations in which you might want
134             to consider providing your own values.
135              
136             But most times, you don't want to or need to. Try it without params
137             first, and add some params if it isn't working for you.
138              
139             If you want to do some custom actions after you copy in the directory,
140             the subclass and add it after you call the parent C method.
141              
142             Returns a new C object, or dies on error.
143              
144             =cut
145              
146             sub new {
147 2     2 1 5953 my $class = shift;
148 2         26 my $self = bless { @_ }, $class;
149              
150             # If we don't have a dist, use the caller.
151 2 50       13 unless ( $self->dist ) {
152             # Guess from the caller
153 0         0 $self->{dist} = $self->_caller;
154 0         0 $self->{dist} =~ s/::/-/;
155             }
156              
157             # If we don't have a module, use the caller
158 2 100       12 unless ( $self->module ) {
159             # Guess from the caller
160 1         3 $self->{module} = $self->_caller;
161             }
162              
163             # If we don't have a sharedir, get it
164             # from the dist.
165 2 100       8 unless ( $self->sharedir ) {
166 1         12 $self->{sharedir} = File::ShareDir::dist_dir($self->dist);
167             }
168              
169             # If we don't have a directory name, derive one
170 2 100       172 unless ( $self->dirname ) {
171             # Derive from the caller based on HomeDir naming scheme
172 1 50       10 my $scheme = $File::HomeDir::IMPLEMENTED_BY
173             or die "Failed to find File::HomeDir naming scheme";
174 1 50       42 if ( $scheme->isa('File::HomeDir::Darwin') ) {
    50          
    50          
175             # Keep the same
176 0         0 $self->{dirname} = $self->dist;
177             } elsif ( $scheme->isa('File::HomeDir::Windows') ) {
178             # Keep the same
179 0         0 $self->{dirname} = $self->dist;
180             } elsif ( $scheme->isa('File::HomeDir::Unix') ) {
181 1         7 $self->{dirname} = '.' . lc $self->dist; # Hidden lowercase
182 1         15 $self->{dirname} =~ s/-/_/g; # Foo-Bar -> .foo_bar
183             } else {
184 0         0 die "Unsupported HomeDir naming scheme $scheme";
185             }
186             }
187              
188             # Find the config dir
189 2 50       11 unless ( $self->configdir ) {
190 2 50       10 unless ( $self->homedir ) {
191 0         0 $self->{homedir} = File::HomeDir->my_data;
192             }
193 2         5 $self->{configdir} = File::Spec->catdir(
194             $self->homedir, $self->dirname,
195             );
196             }
197              
198             # Does the config directory already exist?
199 2 50       8 if ( -d $self->configdir ) {
    50          
200             # Shortcut and return
201 0         0 return $self;
202             } elsif ( -f $self->configdir ) {
203 0         0 my $configdir = $self->configdir;
204 0         0 Carp::croak("Existing file $configdir is blocking creation of config directory");
205             }
206              
207             # Copy in the files from the sharedir
208 2 50       7 File::Copy::Recursive::dircopy( $self->sharedir, $self->configdir )
209             or Carp::croak("Failed to copy user data to " . $self->configdir);
210              
211 2         3032 $self;
212             }
213              
214             =pod
215              
216             =head2 dist
217              
218             $name = File::UserConfig->new(...)->dist;
219            
220             $name = File::UserConfig->dist(...);
221              
222             The C accessor returns the name of the distribution.
223              
224             =cut
225              
226             sub dist {
227 7 50   7 1 875 my $self = ref $_[0] ? shift : shift()->new(@_);
228 7         53 $self->{dist};
229             }
230              
231             =pod
232              
233             =head2 module
234              
235             $name = File::UserConfig->new(...)->module;
236            
237             $name = File::UserConfig->module(...);
238              
239             The C accessor returns the name of the module.
240              
241             Although the default dirname is based off the dist name, the module
242             name is the one used to find the shared dir.
243              
244             =cut
245              
246             sub module {
247 2 50   2 1 6 my $self = ref $_[0] ? shift : shift()->new(@_);
248 2         10 $self->{module};
249             }
250              
251             =pod
252              
253             =head2 dirname
254              
255             $dir = File::UserConfig->new(...)->dirname;
256            
257             $dir = File::UserConfig->dirname(...);
258              
259             The C accessor returns the name to be used for the config
260             directory name, below the homedir. For example C<'.foo_bar'>.
261              
262             =cut
263              
264             sub dirname {
265 5 50   5 1 14 my $self = ref $_[0] ? shift : shift()->new(@_);
266 5         37 $self->{dirname};
267             }
268              
269             =pod
270              
271             =head2 sharedir
272              
273             $dir = File::UserConfig->new(...)->sharedir;
274            
275             $dist = File::UserConfig->sharedir(...);
276              
277             The C accessor returns the name of the directory where the
278             shared default configuration is held.
279              
280             Returns a path string, verified to exist before being returned.
281              
282             =cut
283              
284             sub sharedir {
285 7 50   7 1 20 my $self = ref $_[0] ? shift : shift()->new(@_);
286 7         74 $self->{sharedir};
287             }
288              
289             =pod
290              
291             =head2 homedir
292              
293             $dir = File::UserConfig->new(...)->homedir;
294            
295             $dist = File::UserConfig->homedir(...);
296              
297             The C accessor returns the location of the home direcotry, that
298             the config dir will be created or found below.
299              
300             Returns a path string, verified to exist before being returned.
301              
302             =cut
303              
304             sub homedir {
305 8 50   8 1 426 my $self = ref $_[0] ? shift : shift()->new(@_);
306 8         51 $self->{homedir};
307             }
308              
309             =pod
310              
311             =head2 configdir
312              
313             $dir = File::UserConfig->new(...)->configdir;
314            
315             $dist = File::UserConfig->configdir(...);
316              
317             The C accessor returns the name of the directory where the
318             shared default configuration is held.
319              
320             Returns a path string, verified to exist before being returned.
321              
322             =cut
323              
324             sub configdir {
325 20 50   20 1 23707 my $self = ref $_[0] ? shift : shift()->new(@_);
326 20         1852 $self->{configdir};
327             }
328              
329              
330              
331              
332              
333             #####################################################################
334             # Support Methods
335              
336             sub _caller {
337 3     3   788 my $i = 0;
338 3         29 while ( my @c = caller($i++) ) {
339 4 100       45 next if $c[0]->isa(__PACKAGE__);
340 3         19 return $c[0];
341             }
342 0           die "Failed to find caller";
343             }
344              
345             1;
346              
347             =pod
348              
349             =head1 SUPPORT
350              
351             Bugs should always be submitted via the CPAN bug tracker
352              
353             L
354              
355             For other issues, contact the maintainer
356              
357             =head1 AUTHOR
358              
359             Adam Kennedy Eadamk@cpan.orgE
360              
361             =head1 SEE ALSO
362              
363             L, L
364              
365             =head1 COPYRIGHT
366              
367             Copyright 2006 - 2008 Adam Kennedy.
368              
369             This program is free software; you can redistribute
370             it and/or modify it under the same terms as Perl itself.
371              
372             The full text of the license can be found in the
373             LICENSE file included with this module.
374              
375             =cut