File Coverage

blib/lib/Dancer2/ConfigReader.pm
Criterion Covered Total %
statement 68 69 98.5
branch 14 20 70.0
condition n/a
subroutine 16 16 100.0
pod n/a
total 98 105 93.3


line stmt bran cond sub pod time code
1             # ABSTRACT: Config reader for Dancer2 App
2             package Dancer2::ConfigReader;
3             $Dancer2::ConfigReader::VERSION = '2.0.1';
4 158     158   244496 use Moo;
  158         14628  
  158         1354  
5              
6 158     158   70138 use File::Spec;
  158         402  
  158         5322  
7 158     158   86812 use Config::Any;
  158         1708742  
  158         7296  
8 158     158   86184 use Hash::Merge::Simple;
  158         92008  
  158         11697  
9 158     158   1275 use Carp 'croak';
  158         328  
  158         11732  
10 158     158   1115 use Module::Runtime qw{ use_module };
  158         346  
  158         1187  
11 158     158   10143 use Ref::Util qw/ is_arrayref /;
  158         5616  
  158         8531  
12 158     158   1038 use Scalar::Util qw/ blessed /;
  158         373  
  158         7787  
13              
14 158     158   87719 use Dancer2::Core::Factory;
  158         668  
  158         5946  
15 158     158   991 use Dancer2::Core;
  158         319  
  158         3747  
16 158     158   69649 use Dancer2::Core::Types;
  158         768  
  158         1809  
17 158     158   2356224 use Dancer2::ConfigUtils 'normalize_config_entry';
  158         2710  
  158         150569  
18              
19             our $MAX_CONFIGS = $ENV{DANCER_MAX_CONFIGS} || 100;
20              
21             has location => (
22             is => 'ro',
23             isa => Str,
24             required => 1,
25             );
26              
27             has default_config => (
28             is => 'ro',
29             isa => HashRef,
30             required => 1,
31             );
32              
33             has config_location => (
34             is => 'ro',
35             isa => ReadableFilePath,
36             lazy => 1,
37             default => sub { $_[0]->location },
38             );
39              
40             # The type for this attribute is Str because we don't require
41             # an existing directory with configuration files for the
42             # environments. An application without environments is still
43             # valid and works.
44             has environments_location => (
45             is => 'ro',
46             isa => Str,
47             lazy => 1,
48             default => sub {
49             $ENV{DANCER_ENVDIR}
50             || File::Spec->catdir( $_[0]->config_location, 'environments' );
51             },
52             );
53              
54             has config => (
55             is => 'ro',
56             isa => HashRef,
57             lazy => 1,
58             builder => '_build_config',
59             );
60              
61             has environment => (
62             is => 'ro',
63             isa => Str,
64             required => 1,
65             );
66              
67             has config_readers => (
68             is => 'ro',
69             lazy => 1,
70             isa => ArrayRef,
71             builder => '_build_config_readers',
72             );
73              
74             # The config builder
75             sub _build_config {
76 258     258   21822 my ($self) = @_;
77              
78 258         1154 my $config = $self->default_config;
79              
80 258         715 my $nbr_config = 0;
81              
82 258         547 my @readers = @{ $self->config_readers };
  258         6038  
83              
84             my $config_to_object = sub {
85 102     102   165 my $thing = $_;
86              
87 102 50       287 return $thing if blessed $thing;
88              
89 102 50       371 $thing = { $thing => {} } unless ref $thing;
90              
91 102 50       281 die "additional_config_readers entry must have exactly one key\n"
92             if keys %$thing != 1;
93              
94 102         276 my( $class, $args ) = %$thing;
95              
96 102         361 return use_module($class)->new(
97             location => $self->location,
98             environment => $self->environment,
99             %$args,
100             );
101 257         75208 };
102              
103 257         1549 while( my $r = shift @readers ) {
104 360 100       4621 die <<"END" if $nbr_config++ >= $MAX_CONFIGS;
105             MAX_CONFIGS exceeded: read over $MAX_CONFIGS configurations
106              
107             Looks like you have an infinite recursion in your configuration system.
108             Re-run with DANCER_CONFIG_VERBOSE=1 to see what is going on.
109              
110             If your application really read that many configs (may \$dog have mercy
111             on your soul), you can increase the limit via the environment variable
112             DANCER_MAX_CONFIGS.
113              
114             END
115 359 50       2015 warn "Reading config from @{[ $r->name() ]}\n" if $ENV{DANCER_CONFIG_VERBOSE};
  0         0  
116 359         1764 my $local_config = $r->read_config;
117              
118 358 100       3089 if( my $additionals = delete $local_config->{additional_config_readers} ) {
119              
120 101 50       249 warn "Additional config readers found\n" if $ENV{DANCER_CONFIG_VERBOSE};
121              
122 101 100       301 unshift @readers, map { $config_to_object->($_) } is_arrayref($additionals) ? @$additionals : ($additionals);
  102         264  
123             }
124              
125 358         22559 $config = Hash::Merge::Simple->merge(
126             $config, $local_config
127             );
128             }
129              
130 255         14533 return $self->_normalize_config($config);
131             }
132              
133             sub _normalize_config {
134 255     255   822 my ( $self, $config ) = @_;
135              
136 255         594 foreach my $key ( keys %{$config} ) {
  255         1172  
137 2491         4357 my $value = $config->{$key};
138 2491         5506 $config->{$key} = normalize_config_entry( $key, $value );
139             }
140 255         11912 return $config;
141             }
142              
143             sub _build_config_readers {
144 258     258   3323 my ($self) = @_;
145              
146             my @config_reader_names = $ENV{'DANCER_CONFIG_READERS'}
147 258 100       1634 ? (split qr{,}msx, $ENV{'DANCER_CONFIG_READERS'})
148             : ( q{Dancer2::ConfigReader::Config::Any} );
149              
150 258 50       1278 warn "ConfigReaders to use: @config_reader_names\n" if $ENV{DANCER_CONFIG_VERBOSE};
151             return [
152 258         1877 map use_module($_)->new(
153             location => $self->location,
154             environment => $self->environment,
155             ), @config_reader_names
156             ];
157             }
158              
159             1;
160              
161             __END__