@@ -8,12 +8,16 @@ use Config::Any;
8
8
use Hash::Merge::Simple;
9
9
use Carp ' croak' ;
10
10
use Module::Runtime qw{ use_module } ;
11
+ use Ref::Util qw/ is_arrayref / ;
12
+ use Scalar::Util qw/ blessed / ;
11
13
12
14
use Dancer2::Core::Factory;
13
15
use Dancer2::Core;
14
16
use Dancer2::Core::Types;
15
17
use Dancer2::ConfigUtils ' normalize_config_entry' ;
16
18
19
+ our $MAX_CONFIGS = $ENV {DANCER_MAX_CONFIGS } || 100;
20
+
17
21
has location => (
18
22
is => ' ro' ,
19
23
isa => Str,
@@ -71,17 +75,59 @@ has config_readers => (
71
75
sub _build_config {
72
76
my ($self ) = @_ ;
73
77
74
- my $default = $self -> default_config;
75
- my $config = Hash::Merge::Simple-> merge(
76
- $default ,
77
- map {
78
- warn " Merging config from @{[ $_ ->name() ]}\n " if $ENV {DANCER_CONFIG_VERBOSE };
79
- $_ -> read_config()
80
- } @{ $self -> config_readers }
81
- );
78
+ my $config = $self -> default_config;
82
79
83
- $config = $self -> _normalize_config($config );
84
- return $config ;
80
+ my $nbr_config = 0;
81
+
82
+ my @readers = @{ $self -> config_readers };
83
+
84
+ my $config_to_object = sub {
85
+ my $thing = $_ ;
86
+
87
+ return $thing if blessed $thing ;
88
+
89
+ $thing = { $thing => {} } unless ref $thing ;
90
+
91
+ die " additional_config_readers entry can have only one key\n "
92
+ if 1 < keys %$thing ;
93
+
94
+ my ( $class , $args ) = %$thing ;
95
+
96
+ return use_module($class )-> new(
97
+ location => $self -> location,
98
+ environment => $self -> environment,
99
+ %$args ,
100
+ );
101
+ };
102
+
103
+ while ( my $r = shift @readers ) {
104
+ 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
+ warn " Reading config from @{[ $r ->name() ]}\n " if $ENV {DANCER_CONFIG_VERBOSE };
116
+ my $local_config = $r -> read_config;
117
+
118
+ if ( my $additionals = delete $local_config -> {additional_config_readers } ) {
119
+
120
+ warn " Additional config readers found\n " if $ENV {DANCER_CONFIG_VERBOSE };
121
+
122
+ unshift @readers , map { $config_to_object -> ($_ ) } is_arrayref($additionals ) ? @$additionals : ($additionals );
123
+ }
124
+
125
+ $config = Hash::Merge::Simple-> merge(
126
+ $config , $local_config
127
+ );
128
+ }
129
+
130
+ return $self -> _normalize_config($config );
85
131
}
86
132
87
133
sub _normalize_config {
@@ -116,26 +162,18 @@ __END__
116
162
117
163
=head1 DESCRIPTION
118
164
119
- This class provides a C<config > attribute that - when accessing
120
- the first time - feeds itself by executing one or more
121
- B< ConfigReader > packages .
165
+ This class provides a C<config > attribute that
166
+ is populated by executing one or more B< ConfigReader > packages.
167
+ The default ConfigReader used by default is C< Dancer2:: ConfigReader::File::Simple > .
122
168
123
169
Also provides a C<setting() > method which is supposed to be used by externals to
124
170
read/write config entries.
125
171
126
- You can control which B<ConfigReader >
127
- class or classes to use to create the config.
128
-
129
- Use C<DANCER_CONFIG_READERS > environment variable to define
130
- which class or classes you want.
131
-
132
- DANCER_CONFIG_READERS='Dancer2::ConfigReader::File::Simple,Dancer2::ConfigReader::CustomConfig'
133
-
134
- If you want several, separate them with a comma (",").
135
- Configs are added in left-to-write order where the previous
136
- config items get overwritten by subsequent ones.
172
+ If more than one config reader is used, their configurations are merged
173
+ in left-to-write order where the previous config items get overwritten by subsequent ones.
137
174
138
- For example, if config
175
+ For example, assuming we are using 3 config readers,
176
+ if the first config reader returns
139
177
140
178
item1: content1
141
179
item2: content2
@@ -149,7 +187,7 @@ For example, if config
149
187
subitem1: subcontent1
150
188
subitem2: subcontent2
151
189
152
- was followed by config
190
+ and the second returns
153
191
154
192
item2: content9
155
193
item3:
@@ -161,7 +199,7 @@ was followed by config
161
199
subsubitem5: subsubcontent5
162
200
item4: content4
163
201
164
- then the final config would be
202
+ then the final config is
165
203
166
204
item1: content1
167
205
item2: content9
@@ -175,12 +213,36 @@ then the final config would be
175
213
subsubitem5: subsubcontent5
176
214
item4: content4
177
215
178
- The default B<ConfigReader > is C<Dancer2::ConfigReader::File::Simple > .
179
216
180
- You can also create your own custom B<ConfigReader > classes.
217
+ =head2 Configuring the ConfigReaders via DANCER_CONFIG_READERS
218
+
219
+ You can control which B<ConfigReader >
220
+ class or classes to use to create the config
221
+ via the C<DANCER_CONFIG_READERS > environment.
222
+
223
+ DANCER_CONFIG_READERS='Dancer2::ConfigReader::File::Simple,Dancer2::ConfigReader::CustomConfig'
224
+
225
+ If you want several, separate them with a comma (",").
226
+
227
+ =head2 Bootstrapping the ConfigReaders via C<additional_config_readers >
228
+
229
+ If the key C<additional_config_readers > is found in one in one or more of the configurations provided by the ConfigReaders, it'll be
230
+ instantiated and added to the list of configurations to merge. This way you can, for example, create a basic F<config.yml> that is
231
+
232
+ additional_config_readers:
233
+ - Dancer2::ConfigReader::SQLite:
234
+ path: /path/to/sqlite.db
235
+ table: config
236
+
237
+ The default ConfigReader L<Dancer2::ConfigReader::File::Simple> will pick that file and proceed to instantiate C<Dancer2::ConfigReader::SQLite >
238
+ with the provided parameters.
239
+
240
+ C<additional_config_readers > can take one or a list of reader configurations, which can be either the name of the ConfigReader's class, or the
241
+ key/value pair of the class name and its constructor's arguments.
242
+
243
+ =head2 Creating your own custom B<ConfigReader > classes.
181
244
182
- If you want, you can also extend class C<Dancer2::ConfigReader::File::Simple > .
183
- Here is an example:
245
+ Here's an example extending class C<Dancer2::ConfigReader::File::Simple > .
184
246
185
247
package Dancer2::ConfigReader::FileExtended;
186
248
use Moo;
0 commit comments