File Coverage

blib/lib/Mojolicious/Plugin/INIConfig.pm
Criterion Covered Total %
statement 59 59 100.0
branch 28 36 77.7
condition 16 25 64.0
subroutine 7 7 100.0
pod 3 3 100.0
total 113 130 86.9


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::INIConfig;
2 2     2   2267 use Mojo::Base 'Mojolicious::Plugin::Config';
  2         5  
  2         15  
3 2     2   3385 use Config::Tiny;
  2         1565  
  2         66  
4 2     2   17 use File::Spec::Functions 'file_name_is_absolute';
  2         5  
  2         101  
5 2     2   12 use Encode 'encode', 'decode';
  2         4  
  2         1209  
6              
7             our $VERSION = '0.06';
8              
9             sub parse {
10 5     5 1 892 my ($self, $content, $file, $conf, $app) = @_;
11              
12 5         25 my $ct = Config::Tiny->new;
13 5         28 my $conf_str = decode('UTF-8', $self->render($content, $file, $conf, $app));
14 5         524 my $config_ct = $ct->read_string($conf_str);
15 5         296 my $config = {%$config_ct};
16            
17 5         18 my $err = $ct->errstr;
18 5 50 33     27 die qq{Couldn't parse config "$file": $err} if !$config && $err;
19 5 50 33     31 die qq{Invalid config "$file".} if !$config || ref $config ne 'HASH';
20              
21 5         28 return $config;
22             }
23              
24             sub register {
25 6     6 1 29819 my ($self, $app, $conf) = @_;
26              
27 6 50       30 return $app->config if $app->config->{config_override};
28              
29             # Config file
30 6   66     89 my $file = $conf->{file} || $ENV{MOJO_CONFIG};
31 6   50     40 $file ||= $app->moniker . '.' . ($conf->{ext} || 'ini');
      66        
32              
33             # Mode specific config file
34 6 100       59 my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : '';
35              
36 6         62 my $home = $app->home;
37 6 100       41 $file = $home->rel_file($file) unless file_name_is_absolute $file;
38 6 100 100     265 $mode = $home->rel_file($mode) if $mode && !file_name_is_absolute $mode;
39 6 100 100     82 $mode = undef unless $mode && -e $mode;
40              
41             # Read config file
42 6         84 my $config = {};
43              
44 6 100 66     25 if (-e $file) { $config = $self->load($file, $conf, $app) }
  3 100       48  
45              
46             # Check for default and mode specific config file
47             elsif (!$conf->{default} && !$mode) {
48 2         44 die qq{Config file "$file" missing, maybe you need to create it?\n};
49             }
50              
51             # Merge everything
52 4 100       57 if ($mode) {
53 2         14 my $mode_config = $self->load($mode, $conf, $app);
54 2         8 for my $key (keys %$mode_config) {
55             $config->{$key}
56 2 50       5 = {%{$config->{$key} || {}}, %{$mode_config->{$key} || {}}};
  2 50       9  
  2         15  
57             }
58             }
59 4 100       15 if ($conf->{default}) {
60 2         5 my $default_config = $conf->{default};
61 2         8 for my $key (keys %$default_config) {
62             $config->{$key}
63 2 50       4 = {%{$default_config->{$key} || {}}, %{$config->{$key} || {}}, };
  2 100       8  
  2         18  
64             }
65             }
66 4         19 my $current = $app->defaults(config => $app->config)->config;
67 4         141 for my $key (keys %$config) {
68 4         32 %{$current->{$key}}
69 4 100       8 = (%{$current->{$key} || {}}, %{$config->{$key} || {}});
  4 50       24  
  4         16  
70             }
71              
72 4         38 return $current;
73             }
74              
75             sub render {
76 5     5 1 11 my ($self, $content, $file, $conf, $app) = @_;
77              
78             # Application instance and helper
79 5         9 my $prepend = q[my $app = shift; no strict 'refs'; no warnings 'redefine';];
80 5         10 $prepend .= q[sub app; *app = sub { $app }; use Mojo::Base -strict;];
81              
82             # Render and encode for INI decoding
83 5   50     47 my $mt = Mojo::Template->new($conf->{template} || {})->name($file);
84 5         89 my $ini = $mt->prepend($prepend . $mt->prepend)->render($content, $app);
85 5 50       5039 return ref $ini ? die $ini : encode 'UTF-8', $ini;
86             }
87              
88             1;
89              
90             =head1 NAME
91              
92             Mojolicious::Plugin::INIConfig - Mojolicious plugin to load INI format config file
93              
94             =head1 SYNOPSIS
95              
96             # myapp.ini
97             [section]
98             foo=bar
99             music_dir=<%= app->home->rel_dir('music') %>
100              
101             # Mojolicious
102             my $config = $self->plugin('INIConfig');
103              
104             # Mojolicious::Lite
105             my $config = plugin 'INIConfig';
106              
107             # foo.html.ep
108             %= $config->{section}{foo}
109              
110             # The configuration is available application wide
111             my $config = app->config;
112              
113             # Everything can be customized with options
114             my $config = plugin INIConfig => {file => '/etc/myapp.conf'};
115              
116             =head1 DESCRIPTION
117              
118             L is a INI configuration plugin that
119             preprocesses its input with L.
120              
121             The application object can be accessed via C<$app> or the C function. You
122             can extend the normal config file C with C specific ones
123             like C. A default configuration filename will be generated
124             from the value of L.
125              
126             The code of this plugin is a good example for learning to build new plugins,
127             you're welcome to fork it.
128              
129             If the configuration value C has been set in "config" in Mojo when this plugin is loaded, it will not do anything.
130              
131             =head1 OPTIONS
132              
133             L inherits all options from
134             L and supports the following new ones.
135              
136             =head2 default
137              
138             # Mojolicious::Lite
139             plugin Config => {default => {section => {foo => 'bar'}}};
140              
141             Default configuration, making configuration files optional.
142              
143             =head2 template
144              
145             # Mojolicious::Lite
146             plugin INIConfig => {template => {line_start => '.'}};
147              
148             Attribute values passed to L object used to preprocess
149             configuration files.
150              
151             =head1 METHODS
152              
153             L inherits all methods from
154             L and implements the following new ones.
155              
156             =head2 parse
157              
158             $plugin->parse($content, $file, $conf, $app);
159              
160             Process content with C and parse it with L.
161              
162             sub parse {
163             my ($self, $content, $file, $conf, $app) = @_;
164             ...
165             $content = $self->render($content, $file, $conf, $app);
166             ...
167             return $hash;
168             }
169              
170             =head2 register
171              
172             my $config = $plugin->register(Mojolicious->new);
173             my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'});
174              
175             Register plugin in L application.
176              
177             =head2 render
178              
179             $plugin->render($content, $file, $conf, $app);
180              
181             Process configuration file with L.
182              
183             sub render {
184             my ($self, $content, $file, $conf, $app) = @_;
185             ...
186             return $content;
187             }
188              
189             =head2 OP
190              
191             =head1 BUGS
192              
193             Please tell me bugs if you find bug.
194              
195             C<< >>
196              
197             L
198              
199             =head1 COPYRIGHT & LICENSE
200              
201             Copyright 2013-2017 Yuki Kimoto, all rights reserved.
202              
203             This program is free software; you can redistribute it and/or modify it
204             under the same terms as Perl itself.
205              
206             =cut