File Coverage

blib/lib/Dancer/Config.pm
Criterion Covered Total %
statement 124 124 100.0
branch 29 32 90.6
condition 36 81 44.4
subroutine 28 28 100.0
pod 0 11 0.0
total 217 276 78.6


line stmt bran cond sub pod time code
1             package Dancer::Config;
2             our $AUTHORITY = 'cpan:SUKRIA';
3             #ABSTRACT: how to configure Dancer to suit your needs
4             $Dancer::Config::VERSION = '1.3520';
5 193     193   140117 use strict;
  193         450  
  193         5849  
6 193     193   1029 use warnings;
  193         392  
  193         5306  
7 193     193   997 use base 'Exporter';
  193         528  
  193         19320  
8 193     193   1353 use vars '@EXPORT_OK';
  193         426  
  193         11276  
9              
10 193     193   92324 use Hash::Merge::Simple;
  193         100393  
  193         9642  
11 193     193   85807 use Dancer::Config::Object 'hashref_to_object';
  193         635  
  193         10504  
12 193     193   83410 use Dancer::Deprecation;
  193         503  
  193         6324  
13 193     193   79938 use Dancer::Template;
  193         555  
  193         5421  
14 193     193   1268 use Dancer::ModuleLoader;
  193         416  
  193         4126  
15 193     193   84953 use Dancer::FileUtils 'path';
  193         629  
  193         11956  
16 193     193   1423 use Carp;
  193         418  
  193         9439  
17 193     193   1180 use Dancer::Exception qw(:all);
  193         467  
  193         20031  
18              
19 193     193   102011 use Encode;
  193         2808702  
  193         304375  
20              
21             @EXPORT_OK = qw(setting);
22              
23             my $SETTINGS = {};
24              
25             # mergeable settings
26             my %MERGEABLE = map { ($_ => 1) } qw( plugins handlers );
27             my %_LOADED;
28              
29 596     596 0 6470 sub settings {$SETTINGS}
30              
31             my $setters = {
32             logger => sub {
33             my ($setting, $value) = @_;
34             require Dancer::Logger;
35             Dancer::Logger->init($value, settings());
36             },
37             log_file => sub {
38             require Dancer::Logger;
39             Dancer::Logger->init(setting("logger"), settings());
40             },
41             session => sub {
42             my ($setting, $value) = @_;
43             require Dancer::Session;
44             Dancer::Session->init($value, settings());
45             },
46             template => sub {
47             my ($setting, $value) = @_;
48             require Dancer::Template;
49             Dancer::Template->init($value, settings());
50             },
51             route_cache => sub {
52             my ($setting, $value) = @_;
53             require Dancer::Route::Cache;
54             Dancer::Route::Cache->reset();
55             },
56             serializer => sub {
57             my ($setting, $value) = @_;
58             require Dancer::Serializer;
59             Dancer::Serializer->init($value);
60             },
61             # This setting has been deprecated in favor of global_warnings.
62             import_warnings => sub {
63             my ($setting, $value) = @_;
64              
65             Dancer::Deprecation->deprecated(
66             message => "import_warnings has been deprecated, please use global_warnings instead."
67             );
68              
69             $^W = $value ? 1 : 0;
70             },
71             global_warnings => sub {
72             my ($setting, $value) = @_;
73             $^W = $value ? 1 : 0;
74             },
75             traces => sub {
76             my ($setting, $traces) = @_;
77             $Dancer::Exception::Verbose = $traces ? 1 : 0;
78             },
79             };
80             $setters->{log_path} = $setters->{log_file};
81              
82             my $normalizers = {
83             charset => sub {
84             my ($setting, $charset) = @_;
85             length($charset || '')
86             or return $charset;
87             my $encoding = Encode::find_encoding($charset);
88             defined $encoding
89             or raise core_config => "Charset defined in configuration is wrong : couldn't identify '$charset'";
90             my $name = $encoding->name;
91             # Perl makes a distinction between the usual perl utf8, and the strict
92             # utf8 charset. But we don't want to make this distinction
93             $name eq 'utf-8-strict'
94             and $name = 'utf-8';
95             return $name;
96             },
97             session_same_site => sub {
98             my ($setting, $same_site_setting) = @_;
99             if ($same_site_setting =~ m{^(strict|lax|none)$}i) {
100             return ucfirst lc $same_site_setting;
101             } else {
102             raise core_config => "Invalid session_same_site value $same_site_setting";
103             }
104             },
105             };
106              
107             sub normalize_setting {
108 1875     1875 0 4964 my ($class, $setting, $value) = @_;
109              
110             $value = $normalizers->{$setting}->($setting, $value)
111 1875 100       4959 if exists $normalizers->{$setting};
112              
113 1875         4114 return $value;
114             }
115              
116             # public accessor for get/set
117             sub setting {
118 13845 100   13845 0 47628 if (@_ == 1) {
119 12057         22854 return _get_setting(shift @_);
120             }
121             else {
122             # can be useful for debug! Use Logger, instead?
123 1788 50       5563 die "Odd number in 'set' assignment" unless scalar @_ % 2 == 0;
124              
125 1788         2906 my $count = 0;
126 1788         4013 while (@_) {
127 1805         3032 my $setting = shift;
128 1805         2788 my $value = shift;
129              
130 1805         4961 _set_setting ($setting, $value);
131              
132             # At the moment, with any kind of hierarchical setter,
133             # there is no case where the same trigger will be run more
134             # than once. If/when a hierarchical setter is implemented,
135             # we should create a list of the hooks that should be run,
136             # and run them at the end of this while, only (efficiency
137             # purposes).
138 1805         4486 _trigger_hooks($setting, $value);
139 1800         4614 $count++
140             }
141 1783         7442808 return $count; # just to return anything, the number of items set.
142             }
143             }
144              
145             sub _trigger_hooks {
146 1807     1807   3319 my ($setting, $value) = @_;
147              
148 1807 100       6450 $setters->{$setting}->(@_) if defined $setters->{$setting};
149             }
150              
151             sub _set_setting {
152 1806     1806   3600 my ($setting, $value) = @_;
153              
154 1806 50       3967 return unless @_ == 2;
155              
156             # normalize the value if needed
157 1806         5405 $value = Dancer::Config->normalize_setting($setting, $value);
158 1806         5226 $SETTINGS->{$setting} = $value;
159 1806         2875 return $value;
160             }
161              
162             sub _get_setting {
163 12058     12058   18318 my $setting = shift;
164              
165 12058         49842 return $SETTINGS->{$setting};
166             }
167              
168 223   66 223 0 1202 sub conffile { path(setting('confdir') || setting('appdir'), 'config.yml') }
169              
170             sub environment_file {
171 17     17 0 214 my $env = setting('environment');
172             # XXX for compatibility reason, we duplicate the code from `init_envdir` here
173             # we don't know how if some application don't already do some weird stuff like
174             # the test in `t/15_plugins/02_config.t`.
175 17   66     50 my $envdir = setting('envdir') || path(setting('appdir'), 'environments');
176 17         76 return path($envdir, "$env.yml");
177             }
178              
179             sub init_confdir {
180 199 100   199 0 737 return setting('confdir') if setting('confdir');
181 4   66     35 setting confdir => $ENV{DANCER_CONFDIR} || setting('appdir');
182             }
183              
184             sub init_envdir {
185 199 100   199 0 679 return setting('envdir') if setting('envdir');
186 129 100       605 my $appdirpath = defined setting('appdir') ?
187             path( setting('appdir'), 'environments' ) :
188             path('environments');
189              
190 129   33     1559 setting envdir => $ENV{DANCER_ENVDIR} || $appdirpath;
191             }
192              
193             sub load {
194 199     199 0 2186 init_confdir();
195 199         1093 init_envdir();
196              
197             # look for the conffile
198 199 100       1123 return 1 unless -f conffile;
199              
200             # load YAML
201 11         138 my $module = load_yaml_module();
202              
203 10 100       30 unless ($_LOADED{conffile()}) {
204 5         20 load_settings_from_yaml(conffile, $module);
205 5         26 $_LOADED{conffile()}++;
206             }
207              
208 10         53 my $env = environment_file;
209              
210             # don't load the same env twice
211 10 50       63 unless( $_LOADED{$env} ) {
212 10 100       291 if (-f $env ) {
    100          
213 4         21 load_settings_from_yaml($env, $module);
214 4         13 $_LOADED{$env}++;
215             }
216             elsif (setting('require_environment')) {
217             # failed to load the env file, and the main config said we needed it.
218 1         250 confess "Could not load environment file '$env', and require_environment is set";
219             }
220             }
221              
222 9         60 foreach my $key (grep { $setters->{$_} } keys %$SETTINGS) {
  203         304  
223 28         126 $setters->{$key}->($key, $SETTINGS->{$key});
224             }
225 9 100       63 if ( $SETTINGS->{strict_config} ) {
226 2         11 $SETTINGS = hashref_to_object($SETTINGS);
227             }
228              
229 9         56 return 1;
230             }
231              
232             sub load_settings_from_yaml {
233 14     14 0 7083 my ($file, $module) = @_;
234              
235 14   66     49 $module ||= load_yaml_module();
236              
237 14         28 my $config;
238             {
239 193     193   1992 no strict 'refs';
  193         550  
  193         109268  
  14         24  
240 14 100       30 $config = eval { &{ $module . '::LoadFile' }($file) }
  14         30  
  14         77  
241             or confess "Unable to parse the configuration file: $file: $@";
242             }
243              
244             $SETTINGS = Hash::Merge::Simple::merge( $SETTINGS, {
245             map {
246 9         17893 $_ => Dancer::Config->normalize_setting( $_, $config->{$_} )
  31         105  
247             } keys %$config
248             } );
249              
250 9         773 return scalar keys %$config;
251             }
252              
253             sub load_yaml_module {
254 12     12 0 43 my ($module) = @_;
255              
256 12   100     123 $module ||= $SETTINGS->{engines}{YAML}{module} || 'YAML';
      33        
257              
258 12         70 my ( $result, $error ) = Dancer::ModuleLoader->load($module);
259 12 100       333 confess "Could not load $module: $error"
260             unless $result;
261              
262 11         32 return $module;
263             }
264              
265             sub load_default_settings {
266 193   50 193 0 2961 $SETTINGS->{server} ||= $ENV{DANCER_SERVER} || '0.0.0.0';
      33        
267 193   50     1762 $SETTINGS->{port} ||= $ENV{DANCER_PORT} || '3000';
      33        
268 193   50     2323 $SETTINGS->{content_type} ||= $ENV{DANCER_CONTENT_TYPE} || 'text/html';
      33        
269 193   50     2854 $SETTINGS->{charset} ||= $ENV{DANCER_CHARSET} || '';
      33        
270 193   33     1537 $SETTINGS->{startup_info} ||= !$ENV{DANCER_NO_STARTUP_INFO};
271 193   50     2023 $SETTINGS->{daemon} ||= $ENV{DANCER_DAEMON} || 0;
      33        
272 193   50     2133 $SETTINGS->{apphandler} ||= $ENV{DANCER_APPHANDLER} || 'Standalone';
      33        
273 193   50     2455 $SETTINGS->{warnings} ||= $ENV{DANCER_WARNINGS} || 0;
      33        
274 193   50     2194 $SETTINGS->{auto_reload} ||= $ENV{DANCER_AUTO_RELOAD} || 0;
      33        
275 193   50     2059 $SETTINGS->{traces} ||= $ENV{DANCER_TRACES} || 0;
      33        
276 193   33     1429 $SETTINGS->{server_tokens} ||= !$ENV{DANCER_NO_SERVER_TOKENS};
277 193   50     1963 $SETTINGS->{logger} ||= $ENV{DANCER_LOGGER} || 'file';
      33        
278             $SETTINGS->{environment} ||=
279             $ENV{DANCER_ENVIRONMENT}
280             || $ENV{PLACK_ENV}
281 193   50     3392 || 'development';
      33        
282              
283 193         1278 setting $_ => {} for keys %MERGEABLE;
284 193         887 setting template => 'simple';
285             }
286              
287             load_default_settings();
288              
289             1;
290              
291             __END__