File Coverage

blib/lib/MooseX/ConfigFromFile.pm
Criterion Covered Total %
statement 37 38 97.3
branch 10 12 83.3
condition 4 6 66.6
subroutine 8 8 100.0
pod 1 1 100.0
total 60 65 92.3


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