pass configfile value through to new()
[gitmo/MooseX-ConfigFromFile.git] / lib / MooseX / ConfigFromFile.pm
CommitLineData
c35b639e 1package MooseX::ConfigFromFile;
2
3use Moose::Role;
2f049fc1 4use MooseX::Types::Path::Tiny 'Path';
0e88ec88 5use Try::Tiny qw/ try /;
870afbfa 6use Carp qw(croak);
bc5ab785 7use namespace::autoclean;
8
c35b639e 9requires 'get_config_from_file';
10
11has configfile => (
12 is => 'ro',
2f049fc1 13 isa => Path,
c35b639e 14 coerce => 1,
15 predicate => 'has_configfile',
742b859c 16 do { try { require MooseX::Getopt; (traits => ['Getopt']) } },
c35b639e 17);
18
19sub new_with_config {
20 my ($class, %opts) = @_;
21
fc44be6f 22 my $configfile;
23
24 if(defined $opts{configfile}) {
25 $configfile = $opts{configfile}
26 }
27 else {
7acf2fe9 28 # This would only succeed if the consumer had defined a new configfile
29 # sub to override the generated reader
f1040206 30 $configfile = try { $class->configfile };
7acf2fe9 31
32 # this is gross, but since a lot of users have swapped in their own
33 # default subs, we have to keep calling it rather than calling a
34 # builder sub directly - and it might not even be a coderef either
35 my $cfmeta = $class->meta->find_attribute_by_name('configfile');
a665bd30 36 $configfile = $cfmeta->default if not defined $configfile and $cfmeta->has_default;
7acf2fe9 37
56e4351b 38 if (ref $configfile eq 'CODE') {
83f0ce54 39 $configfile = $configfile->($class);
56e4351b 40 }
8b4a3e76 41
42 my $init_arg = $cfmeta->init_arg;
43 $opts{$init_arg} = $configfile if defined $configfile and defined $init_arg;
fc44be6f 44 }
45
0e88ec88 46 if (defined $configfile) {
870afbfa 47 my $hash = $class->get_config_from_file($configfile);
48
49 no warnings 'uninitialized';
50 croak "get_config_from_file($configfile) did not return a hash (got $hash)"
51 unless ref $hash eq 'HASH';
52
53 %opts = (%$hash, %opts);
c35b639e 54 }
fc44be6f 55
c35b639e 56 $class->new(%opts);
57}
58
59no Moose::Role; 1;
60
61__END__
62
63=pod
64
65=head1 NAME
66
67MooseX::ConfigFromFile - An abstract Moose role for setting attributes from a configfile
68
69=head1 SYNOPSIS
70
71 ########
72 ## A real role based on this abstract role:
73 ########
74
75 package MooseX::SomeSpecificConfigRole;
76 use Moose::Role;
2b11fcd0 77
c35b639e 78 with 'MooseX::ConfigFromFile';
2b11fcd0 79
c35b639e 80 use Some::ConfigFile::Loader ();
81
82 sub get_config_from_file {
83 my ($class, $file) = @_;
84
85 my $options_hashref = Some::ConfigFile::Loader->load($file);
86
87 return $options_hashref;
88 }
89
90
91 ########
92 ## A class that uses it:
93 ########
94 package Foo;
95 use Moose;
96 with 'MooseX::SomeSpecificConfigRole';
97
fc44be6f 98 # optionally, default the configfile:
7acf2fe9 99 around configfile => sub { '/tmp/foo.yaml' };
fc44be6f 100
c35b639e 101 # ... insert your stuff here ...
102
103 ########
104 ## A script that uses the class with a configfile
105 ########
106
107 my $obj = Foo->new_with_config(configfile => '/etc/foo.yaml', other_opt => 'foo');
108
109=head1 DESCRIPTION
110
2b11fcd0 111This is an abstract role which provides an alternate constructor for creating
c35b639e 112objects using parameters passed in from a configuration file. The
113actual implementation of reading the configuration file is left to
491a1083 114concrete sub-roles.
c35b639e 115
116It declares an attribute C<configfile> and a class method C<new_with_config>,
117and requires that concrete roles derived from it implement the class method
118C<get_config_from_file>.
119
491a1083 120Attributes specified directly as arguments to C<new_with_config> supersede those
fc44be6f 121in the configfile.
122
c35b639e 123L<MooseX::Getopt> knows about this abstract role, and will use it if available
491a1083 124to load attributes from the file specified by the command line flag C<--configfile>
c35b639e 125during its normal C<new_with_options>.
126
127=head1 Attributes
128
129=head2 configfile
130
491a1083 131This is a L<Path::Tiny> object which can be coerced from a regular path
2f049fc1 132string or any object that supports stringification.
133This is the file your attributes are loaded from. You can add a default
7acf2fe9 134configfile in the consuming class and it will be honored at the appropriate time
135(note that a simple sub declaration is not sufficient, as there is already a
136sub by that name being added by Moose as the attribute reader)
fc44be6f 137
7acf2fe9 138 around configfile => sub { '/etc/myapp.yaml' };
c35b639e 139
4d0a4f55 140Note that you can alternately just provide a C<configfile> method which returns
141the config file when called - this will be used in preference to the default of
142the attribute.
143
742b859c 144If you have L<MooseX::Getopt> installed, this attribute will also have the
145C<Getopt> trait supplied, so you can also set the configfile from the
146command line.
147
c35b639e 148=head1 Class Methods
149
150=head2 new_with_config
151
152This is an alternate constructor, which knows to look for the C<configfile> option
153in its arguments and use that to set attributes. It is much like L<MooseX::Getopts>'s
154C<new_with_options>. Example:
155
156 my $foo = SomeClass->new_with_config(configfile => '/etc/foo.yaml');
157
491a1083 158Explicit arguments will override anything set by the configfile.
c35b639e 159
160=head2 get_config_from_file
161
491a1083 162This class method is not implemented in this role, but it is required of all
163classes or roles that consume this role.
164Its two arguments are the class name and the configfile, and it is expected to return
fc44be6f 165a hashref of arguments to pass to C<new()> which are sourced from the configfile.
c35b639e 166
4d0a4f55 167=head1 COPYRIGHT
c35b639e 168
6210e5a5 169Copyright (c) - the MooseX::ConfigFromFile "AUTHOR" and "CONTRIBUTORS" as listed below.
c35b639e 170
171=head1 AUTHOR
172
173Brandon L. Black, E<lt>blblack@gmail.comE<gt>
174
4d0a4f55 175=head1 CONTRIBUTORS
176
177=over
178
a4f0ac9f 179=item Tomas Doran
4d0a4f55 180
181=item Karen Etheridge
182
183=item Chris Prather
184
185=item Zbigniew Lukasiak
186
187=back
188
c35b639e 189=head1 LICENSE
190
191This library is free software; you can redistribute it and/or modify
192it under the same terms as Perl itself.
193
194=cut