Skip to content

Commit d372434

Browse files
committed
Merge branch 'feature/new-config-system'
2 parents d10ab92 + 3fd487d commit d372434

File tree

25 files changed

+1160
-473
lines changed

25 files changed

+1160
-473
lines changed

lib/Dancer2.pm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ Dancer2 is easy and fun:
134134
135135
use Dancer2;
136136
get '/' => sub { "Hello World" };
137-
dance;
137+
dance;
138138
139139
This is the main module for the Dancer2 distribution. It contains logic for
140140
creating a new Dancer2 application.
@@ -367,6 +367,7 @@ We are also on IRC: #dancer on irc.perl.org.
367367
Michael Kröll
368368
Michał Wojciechowski
369369
Mike Katasonov
370+
Mikko Koivunalho
370371
Mohammad S Anwar
371372
mokko
372373
Nick Patch

lib/Dancer2/ConfigReader.pm

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# ABSTRACT: Config reader for Dancer2 App
2+
package Dancer2::ConfigReader;
3+
4+
use Moo;
5+
6+
use File::Spec;
7+
use Config::Any;
8+
use Hash::Merge::Simple;
9+
use Carp 'croak';
10+
use Module::Runtime qw{ use_module };
11+
12+
use Dancer2::Core::Factory;
13+
use Dancer2::Core;
14+
use Dancer2::Core::Types;
15+
use Dancer2::ConfigUtils 'normalize_config_entry';
16+
17+
has location => (
18+
is => 'ro',
19+
isa => Str,
20+
required => 1,
21+
);
22+
23+
has default_config => (
24+
is => 'ro',
25+
isa => HashRef,
26+
required => 1,
27+
);
28+
29+
has config_location => (
30+
is => 'ro',
31+
isa => ReadableFilePath,
32+
lazy => 1,
33+
default => sub { $_[0]->location },
34+
);
35+
36+
# The type for this attribute is Str because we don't require
37+
# an existing directory with configuration files for the
38+
# environments. An application without environments is still
39+
# valid and works.
40+
has environments_location => (
41+
is => 'ro',
42+
isa => Str,
43+
lazy => 1,
44+
default => sub {
45+
$ENV{DANCER_ENVDIR}
46+
|| File::Spec->catdir( $_[0]->config_location, 'environments' );
47+
},
48+
);
49+
50+
has config => (
51+
is => 'ro',
52+
isa => HashRef,
53+
lazy => 1,
54+
builder => '_build_config',
55+
);
56+
57+
has environment => (
58+
is => 'ro',
59+
isa => Str,
60+
required => 1,
61+
);
62+
63+
has config_readers => (
64+
is => 'ro',
65+
lazy => 1,
66+
isa => ArrayRef,
67+
builder => '_build_config_readers',
68+
);
69+
70+
# The config builder
71+
sub _build_config {
72+
my ($self) = @_;
73+
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+
);
82+
83+
$config = $self->_normalize_config($config);
84+
return $config;
85+
}
86+
87+
sub _normalize_config {
88+
my ( $self, $config ) = @_;
89+
90+
foreach my $key ( keys %{$config} ) {
91+
my $value = $config->{$key};
92+
$config->{$key} = normalize_config_entry( $key, $value );
93+
}
94+
return $config;
95+
}
96+
97+
sub _build_config_readers {
98+
my ($self) = @_;
99+
100+
my @config_reader_names = $ENV{'DANCER_CONFIG_READERS'}
101+
? (split qr{,}msx, $ENV{'DANCER_CONFIG_READERS'})
102+
: ( q{Dancer2::ConfigReader::Config::Any} );
103+
104+
warn "ConfigReaders to use: @config_reader_names\n" if $ENV{DANCER_CONFIG_VERBOSE};
105+
return [
106+
map use_module($_)->new(
107+
location => $self->location,
108+
environment => $self->environment,
109+
), @config_reader_names
110+
];
111+
}
112+
113+
1;
114+
115+
__END__
116+
117+
=head1 DESCRIPTION
118+
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.
122+
123+
Also provides a C<setting()> method which is supposed to be used by externals to
124+
read/write config entries.
125+
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::Config::Any,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.
137+
138+
For example, if config
139+
140+
item1: content1
141+
item2: content2
142+
item3:
143+
subitem1: subcontent1
144+
subitem2: subcontent2
145+
subitem3:
146+
subsubitem1:
147+
subsubcontent1
148+
item4:
149+
subitem1: subcontent1
150+
subitem2: subcontent2
151+
152+
was followed by config
153+
154+
item2: content9
155+
item3:
156+
subitem2: subcontent8
157+
subitem3:
158+
subsubitem1:
159+
subsubcontent7
160+
subitem4:
161+
subsubitem5: subsubcontent5
162+
item4: content4
163+
164+
then the final config would be
165+
166+
item1: content1
167+
item2: content9
168+
item3:
169+
subitem1: subcontent1
170+
subitem2: subcontent8
171+
subitem3:
172+
subsubitem1:
173+
subsubcontent7
174+
subitem4:
175+
subsubitem5: subsubcontent5
176+
item4: content4
177+
178+
The default B<ConfigReader> is C<Dancer2::ConfigReader::Config::Any>.
179+
180+
You can also create your own custom B<ConfigReader> classes.
181+
182+
If you want, you can also extend class C<Dancer2::ConfigReader::Config::Any>.
183+
Here is an example:
184+
185+
package Dancer2::ConfigReader::FileExtended;
186+
use Moo;
187+
extends 'Dancer2::ConfigReader::Config::Any';
188+
has name => (
189+
is => 'ro',
190+
default => sub {'FileExtended'},
191+
);
192+
around read_config => sub {
193+
my ($orig, $self) = @_;
194+
my $config = $orig->($self, @_);
195+
$config->{'dummy'}->{'item'} = 123;
196+
return $config;
197+
};
198+
199+
Another (more complex) example is in class C<Dancer2::ConfigReader::Config::Any>.
200+
201+
=head1 ATTRIBUTES
202+
203+
=attr location
204+
205+
Absolute path to the directory where the server started.
206+
207+
=attr config_location
208+
209+
Gets the location from the configuration. Same as C<< $object->location >>.
210+
211+
=attr environments_location
212+
213+
Gets the directory where the environment files are stored.
214+
215+
=attr config
216+
217+
Returns the whole configuration.
218+
This must not be used directly.
219+
Instead, use this via C<Dancer2::Core::Role::HasConfig> role
220+
which manages configuration after it is created.
221+
222+
=attr environment
223+
224+
Returns the name of the environment.

0 commit comments

Comments
 (0)