1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
package Mojolicious::Plugin::Config;
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::File qw(path);
use Mojo::Util qw(decode);
sub load { $_[0]->parse(decode('UTF-8', path($_[1])->slurp), @_[1, 2, 3]) }
sub parse {
my ($self, $content, $file, $conf, $app) = @_;
# Run Perl code in sandbox
my $config = eval 'package Mojolicious::Plugin::Config::Sandbox; no warnings;'
. "sub app; local *app = sub { \$app }; use Mojo::Base -strict; $content";
die qq{Can't load configuration from file "$file": $@} if $@;
die qq{Configuration file "$file" did not return a hash reference} unless ref $config eq 'HASH';
return $config;
}
sub register {
my ($self, $app, $conf) = @_;
# Override
return _plugins($app, $app->config) if $app->config->{config_override};
# Config file
my $file = $conf->{file} || $ENV{MOJO_CONFIG};
$file ||= $app->moniker . '.' . ($conf->{ext} || 'conf');
# Mode specific config file
my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : '';
my $home = $app->home;
$file = $home->child($file) unless path($file)->is_abs;
$mode = $home->child($mode) if $mode && !path($mode)->is_abs;
$mode = undef unless $mode && -e $mode;
# Read config file
my $config = {};
if (-e $file) { $config = $self->load($file, $conf, $app) }
# Check for default and mode specific config file
elsif (!$conf->{default} && !$mode) { die qq{Configuration file "$file" missing, maybe you need to create it?\n} }
# Merge everything
$config = {%$config, %{$self->load($mode, $conf, $app)}} if $mode;
$config = {%{$conf->{default}}, %$config} if $conf->{default};
return _plugins($app, $app->config($config)->config);
}
sub _plugins {
my ($app, $config) = @_;
if (my $plugins = $config->{plugins}) {
die qq{Configuration value "plugins" is not an array reference} unless ref $plugins eq 'ARRAY';
for my $plugin (@$plugins) {
die qq{Configuration value "plugins" contains an entry that is not a hash reference} unless ref $plugin eq 'HASH';
$app->plugin((keys %$plugin)[0], (values %$plugin)[0]);
}
}
return $app->config;
}
1;
=encoding utf8
=head1 NAME
Mojolicious::Plugin::Config - Perl-ish configuration plugin
=head1 SYNOPSIS
# myapp.conf (it's just Perl returning a hash)
{
# Just a value
foo => "bar",
# Nested data structures are fine too
baz => ['♥'],
# You have full access to the application
music_dir => app->home->child('music')
};
# Mojolicious
my $config = $app->plugin('Config');
say $config->{foo};
# Mojolicious::Lite
my $config = plugin 'Config';
say $config->{foo};
# foo.html.ep
%= config->{foo}
# The configuration is available application-wide
my $config = app->config;
say $config->{foo};
# Everything can be customized with options
my $config = plugin Config => {file => '/etc/myapp.stuff'};
=head1 DESCRIPTION
L<Mojolicious::Plugin::Config> is a Perl-ish configuration plugin.
The application object can be accessed via C<$app> or the C<app> function, L<strict>, L<warnings>, L<utf8> and Perl
5.16 L<features|feature> are automatically enabled. A default configuration filename in the application home directory
will be generated from the value of L<Mojolicious/"moniker"> (C<$moniker.conf>). You can extend the normal
configuration file C<$moniker.conf> with C<mode> specific ones like C<$moniker.$mode.conf>, which will be detected
automatically.
These configuration values are currently reserved:
=over 2
=item C<config_override>
If this configuration value has been set in L<Mojolicious/"config"> when this plugin is loaded, it will not do anything
besides loading deployment specific plugins.
=item C<plugins>
plugins => [{SetUserGroup => {user => 'sri', group => 'staff'}}]
One or more deployment specific plugins that should be loaded right after this plugin has been loaded.
=back
The code of this plugin is a good example for learning to build new plugins, you're welcome to fork it.
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available by default.
=head1 OPTIONS
L<Mojolicious::Plugin::Config> supports the following options.
=head2 default
# Mojolicious::Lite
plugin Config => {default => {foo => 'bar'}};
Default configuration, making configuration files optional.
=head2 ext
# Mojolicious::Lite
plugin Config => {ext => 'stuff'};
File extension for generated configuration filenames, defaults to C<conf>.
=head2 file
# Mojolicious::Lite
plugin Config => {file => 'myapp.conf'};
plugin Config => {file => '/etc/foo.stuff'};
Path to configuration file, absolute or relative to the application home directory, defaults to the value of the
C<MOJO_CONFIG> environment variable or C<$moniker.conf> in the application home directory.
=head1 METHODS
L<Mojolicious::Plugin::Config> inherits all methods from L<Mojolicious::Plugin> and implements the following new ones.
=head2 load
$plugin->load($file, $conf, $app);
Loads configuration file and passes the content to L</"parse">.
sub load ($self, $file, $conf, $app) {
...
return $self->parse($content, $file, $conf, $app);
}
=head2 parse
$plugin->parse($content, $file, $conf, $app);
Parse configuration file.
sub parse ($self, $content, $file, $conf, $app) {
...
return $hash;
}
=head2 register
my $config = $plugin->register(Mojolicious->new);
my $config = $plugin->register(Mojolicious->new, {file => '/etc/app.conf'});
Register plugin in L<Mojolicious> application and merge configuration.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
=cut
|