File Coverage

blib/lib/MooseX/ConfigFromFile.pm
Criterion Covered Total %
statement 38 39 97.4
branch 10 12 83.3
condition 4 6 66.6
subroutine 9 9 100.0
pod 1 1 100.0
total 62 67 92.5


line stmt bran cond sub pod time code
1             package MooseX::ConfigFromFile;
2             {
3             $MooseX::ConfigFromFile::VERSION = '0.13';
4             }
5             # git description: v0.12-8-g0e3a578
6              
7             BEGIN {
8 6     6   29664 $MooseX::ConfigFromFile::AUTHORITY = 'cpan:STEVAN';
9             }
10             # ABSTRACT: An abstract Moose role for setting attributes from a configfile
11              
12 6     6   3625 use Moose::Role;
  6         552387  
  6         85  
13 6     6   47792 use MooseX::Types::Path::Tiny 0.005 'Path';
  6         1467691  
  6         70  
14 6     6   19281 use MooseX::Types::Moose 'Undef';
  6         15  
  6         53  
15 6     6   36354 use Carp qw(croak);
  6         16  
  6         393  
16 6     6   37 use namespace::autoclean;
  6         13  
  6         52  
17              
18             requires 'get_config_from_file';
19              
20             has configfile => (
21             is => 'ro',
22             isa => Path|Undef,
23             coerce => 1,
24             predicate => 'has_configfile',
25             eval "require MooseX::Getopt; 1" ? (traits => ['Getopt']) : (),
26             lazy => 1,
27             # it sucks that we have to do this rather than using a builder, but some old code
28             # simply swaps in a new default sub into the attr definition
29             default => sub {
30             my $class = shift;
31             $class->_get_default_configfile if $class->can('_get_default_configfile');
32             },
33             );
34              
35             sub new_with_config {
36 16     16 1 200238 my ($class, %opts) = @_;
37              
38 16         42 my $configfile;
39              
40 16 50       70 if(defined $opts{configfile}) {
41 0         0 $configfile = $opts{configfile}
42             }
43             else {
44             # This would only succeed if the consumer had defined a new configfile
45             # sub to override the generated reader - as suggested in old
46             # documentation -- or if $class is an instance not a class name
47 16         29 $configfile = eval { $class->configfile };
  16         415  
48              
49             # this is gross, but since a lot of users have swapped in their own
50             # default subs, we have to keep calling it rather than calling a
51             # builder sub directly - and it might not even be a coderef either
52 16         252 my $cfmeta = $class->meta->find_attribute_by_name('configfile');
53 16 100 66     1180 $configfile = $cfmeta->default if not defined $configfile and $cfmeta->has_default;
54              
55 16 100       244 if (ref $configfile eq 'CODE') {
56 9         33 $configfile = $configfile->($class);
57             }
58              
59 16         171 my $init_arg = $cfmeta->init_arg;
60 16 100 66     1207 $opts{$init_arg} = $configfile if defined $configfile and defined $init_arg;
61             }
62              
63 16 100       64 if (defined $configfile) {
64 12         92 my $hash = $class->get_config_from_file($configfile);
65              
66 6     6   2381 no warnings 'uninitialized';
  6         12  
  6         752  
67 12 50       138 croak "get_config_from_file($configfile) did not return a hash (got $hash)"
68             unless ref $hash eq 'HASH';
69              
70 12         68 %opts = (%$hash, %opts);
71             }
72              
73 16         193 $class->new(%opts);
74             }
75              
76 6     6   36 no Moose::Role; 1;
  6         12  
  6         72  
77              
78             __END__
79              
80             =pod
81              
82             =encoding UTF-8
83              
84             =for :stopwords Brandon L. Black, Black Kogman L Chris Prather Karen Etheridge Tomas Doran
85             Yuval configfile
86              
87             =head1 NAME
88              
89             MooseX::ConfigFromFile - An abstract Moose role for setting attributes from a configfile
90              
91             =head1 VERSION
92              
93             version 0.13
94              
95             =head1 SYNOPSIS
96              
97             ########
98             ## A real role based on this abstract role:
99             ########
100              
101             package MooseX::SomeSpecificConfigRole;
102             use Moose::Role;
103              
104             with 'MooseX::ConfigFromFile';
105              
106             use Some::ConfigFile::Loader ();
107              
108             sub get_config_from_file {
109             my ($class, $file) = @_;
110              
111             my $options_hashref = Some::ConfigFile::Loader->load($file);
112              
113             return $options_hashref;
114             }
115              
116              
117             ########
118             ## A class that uses it:
119             ########
120             package Foo;
121             use Moose;
122             with 'MooseX::SomeSpecificConfigRole';
123              
124             # optionally, default the configfile:
125             sub _get_default_configfile { '/tmp/foo.yaml' }
126              
127             # ... insert your stuff here ...
128              
129             ########
130             ## A script that uses the class with a configfile
131             ########
132              
133             my $obj = Foo->new_with_config(configfile => '/etc/foo.yaml', other_opt => 'foo');
134              
135             =head1 DESCRIPTION
136              
137             This is an abstract role which provides an alternate constructor for creating
138             objects using parameters passed in from a configuration file. The
139             actual implementation of reading the configuration file is left to
140             concrete sub-roles.
141              
142             It declares an attribute C<configfile> and a class method C<new_with_config>,
143             and requires that concrete roles derived from it implement the class method
144             C<get_config_from_file>.
145              
146             Attributes specified directly as arguments to C<new_with_config> supersede those
147             in the configfile.
148              
149             L<MooseX::Getopt> knows about this abstract role, and will use it if available
150             to load attributes from the file specified by the command line flag C<--configfile>
151             during its normal C<new_with_options>.
152              
153             =head1 Attributes
154              
155             =head2 configfile
156              
157             This is a L<Path::Tiny> object which can be coerced from a regular path
158             string or any object that supports stringification.
159             This is the file your attributes are loaded from. You can add a default
160             configfile in the consuming class and it will be honored at the appropriate
161             time; see below at L</_get_default_configfile>.
162              
163             If you have L<MooseX::Getopt> installed, this attribute will also have the
164             C<Getopt> trait supplied, so you can also set the configfile from the
165             command line.
166              
167             =head1 Class Methods
168              
169             =head2 new_with_config
170              
171             This is an alternate constructor, which knows to look for the C<configfile> option
172             in its arguments and use that to set attributes. It is much like L<MooseX::Getopts>'s
173             C<new_with_options>. Example:
174              
175             my $foo = SomeClass->new_with_config(configfile => '/etc/foo.yaml');
176              
177             Explicit arguments will override anything set by the configfile.
178              
179             =head2 get_config_from_file
180              
181             This class method is not implemented in this role, but it is required of all
182             classes or roles that consume this role.
183             Its two arguments are the class name and the configfile, and it is expected to return
184             a hashref of arguments to pass to C<new()> which are sourced from the configfile.
185              
186             =head2 _get_default_configfile
187              
188             This class method is not implemented in this role, but can and should be defined
189             in a consuming class or role to return the default value of the configfile (if not
190             passed into the constructor explicitly).
191              
192             =head1 AUTHOR
193              
194             Brandon L. Black, <blblack@gmail.com>
195              
196             =head1 COPYRIGHT AND LICENSE
197              
198             This software is copyright (c) 2013 by Brandon L. Black.
199              
200             This is free software; you can redistribute it and/or modify it under
201             the same terms as the Perl 5 programming language system itself.
202              
203             =head1 CONTRIBUTORS
204              
205             =over 4
206              
207             =item *
208              
209             Brandon L Black <blblack@gmail.com>
210              
211             =item *
212              
213             Chris Prather <chris@prather.org>
214              
215             =item *
216              
217             Karen Etheridge <ether@cpan.org>
218              
219             =item *
220              
221             Tomas Doran <bobtfish@bobtfish.net>
222              
223             =item *
224              
225             Yuval Kogman <nothingmuch@woobling.org>
226              
227             =back
228              
229             =cut