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   2038 use Mojo::Base 'Mojolicious::Plugin::Config';
  2         4  
  2         14  
3 2     2   3184 use Config::Tiny;
  2         1512  
  2         64  
4 2     2   16 use File::Spec::Functions 'file_name_is_absolute';
  2         4  
  2         102  
5 2     2   11 use Encode 'encode', 'decode';
  2         5  
  2         1177  
6              
7             our $VERSION = '0.05';
8              
9             sub parse {
10 5     5 1 868 my ($self, $content, $file, $conf, $app) = @_;
11              
12 5         23 my $ct = Config::Tiny->new;
13 5         26 my $conf_str = decode('UTF-8', $self->render($content, $file, $conf, $app));
14 5         461 my $config_ct = $ct->read_string($conf_str);
15 5         287 my $config = {%$config_ct};
16            
17 5         17 my $err = $ct->errstr;
18 5 50 33     27 die qq{Couldn't parse config "$file": $err} if !$config && $err;
19 5 50 33     30 die qq{Invalid config "$file".} if !$config || ref $config ne 'HASH';
20              
21 5         25 return $config;
22             }
23              
24             sub register {
25 6     6 1 27159 my ($self, $app, $conf) = @_;
26              
27 6 50       27 return $app->config if $app->config->{config_override};
28              
29             # Config file
30 6   66     79 my $file = $conf->{file} || $ENV{MOJO_CONFIG};
31 6   50     36 $file ||= $app->moniker . '.' . ($conf->{ext} || 'ini');
      66        
32              
33             # Mode specific config file
34 6 100       61 my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : '';
35              
36 6         58 my $home = $app->home;
37 6 100       63 $file = $home->rel_file($file) unless file_name_is_absolute $file;
38 6 100 100     263 $mode = $home->rel_file($mode) if $mode && !file_name_is_absolute $mode;
39 6 100 100     81 $mode = undef unless $mode && -e $mode;
40              
41             # Read config file
42 6         84 my $config = {};
43              
44 6 100 66     22 if (-e $file) { $config = $self->load($file, $conf, $app) }
  3 100       46  
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       48 if ($mode) {
53 2         12 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       10  
  2         14  
57             }
58             }
59 4 100       13 if ($conf->{default}) {
60 2         4 my $default_config = $conf->{default};
61 2         6 for my $key (keys %$default_config) {
62             $config->{$key}
63 2 50       4 = {%{$default_config->{$key} || {}}, %{$config->{$key} || {}}, };
  2 100       7  
  2         60  
64             }
65             }
66 4         17 my $current = $app->defaults(config => $app->config)->config;
67 4         127 for my $key (keys %$config) {
68 4         26 %{$current->{$key}}
69 4 100       8 = (%{$current->{$key} || {}}, %{$config->{$key} || {}});
  4 50       21  
  4         15  
70             }
71              
72 4         28 return $current;
73             }
74              
75             sub render {
76 5     5 1 12 my ($self, $content, $file, $conf, $app) = @_;
77              
78             # Application instance and helper
79 5         10 my $prepend = q[my $app = shift; no strict 'refs'; no warnings 'redefine';];
80 5         11 $prepend .= q[sub app; *app = sub { $app }; use Mojo::Base -strict;];
81              
82             # Render and encode for INI decoding
83 5   50     43 my $mt = Mojo::Template->new($conf->{template} || {})->name($file);
84 5         87 my $ini = $mt->prepend($prepend . $mt->prepend)->render($content, $app);
85 5 50       4614 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 create routes automatically
93              
94             =head1 CAUTION
95              
96             B
97              
98             =head1 SYNOPSIS
99              
100             # myapp.ini
101             [section]
102             foo=bar
103             music_dir=<%= app->home->rel_dir('music') %>
104              
105             # Mojolicious
106             my $config = $self->plugin('INIConfig');
107              
108             # Mojolicious::Lite
109             my $config = plugin 'INIConfig';
110              
111             # foo.html.ep
112             %= $config->{section}{foo}
113              
114             # The configuration is available application wide
115             my $config = app->config;
116              
117             # Everything can be customized with options
118             my $config = plugin INIConfig => {file => '/etc/myapp.conf'};
119              
120             =head1 DESCRIPTION
121              
122             L is a INI configuration plugin that
123             preprocesses its input with L.
124              
125             The application object can be accessed via C<$app> or the C function. You
126             can extend the normal config file C with C specific ones
127             like C. A default configuration filename will be generated
128             from the value of L.
129              
130             The code of this plugin is a good example for learning to build new plugins,
131             you're welcome to fork it.
132              
133             =head1 OPTIONS
134              
135             L inherits all options from
136             L and supports the following new ones.
137              
138             =head2 default
139              
140             # Mojolicious::Lite
141             plugin Config => {default => {section => {foo => 'bar'}}};
142              
143             Default configuration, making configuration files optional.
144              
145             =head2 template
146              
147             # Mojolicious::Lite
148             plugin INIConfig => {template => {line_start => '.'}};
149              
150             Attribute values passed to L object used to preprocess
151             configuration files.
152              
153             =head1 METHODS
154              
155             L inherits all methods from
156             L and implements the following new ones.
157              
158             =head2 parse
159              
160             $plugin->parse($content, $file, $conf, $app);
161              
162             Process content with C and parse it with L.
163              
164             sub parse {
165             my ($self, $content, $file, $conf, $app) = @_;
166             ...
167             $content = $self->render($content, $file, $conf, $app);
168             ...
169             return $hash;
170             }
171              
172             =head2 register
173              
174             my $config = $plugin->register(Mojolicious->new);
175             my $config = $plugin->register(Mojolicious->new, {file => '/etc/foo.conf'});
176              
177             Register plugin in L application.
178              
179             =head2 render
180              
181             $plugin->render($content, $file, $conf, $app);
182              
183             Process configuration file with L.
184              
185             sub render {
186             my ($self, $content, $file, $conf, $app) = @_;
187             ...
188             return $content;
189             }
190              
191             =head1 BACKWARDS COMPATIBILITY POLICY
192              
193             If a feature is DEPRECATED, you can know it by DEPRECATED warnings.
194             DEPRECATED feature is removed after C,
195             but if at least one person use the feature and tell me that thing
196             I extend one year each time he tell me it.
197              
198             DEPRECATION warnings can be suppressed
199             by C
200             environment variable.
201              
202             EXPERIMENTAL features will be changed without warnings.
203              
204             =head1 BUGS
205              
206             Please tell me bugs if you find bug.
207              
208             C<< >>
209              
210             L
211              
212             =head1 COPYRIGHT & LICENSE
213              
214             Copyright 2013-2013 Yuki Kimoto, all rights reserved.
215              
216             This program is free software; you can redistribute it and/or modify it
217             under the same terms as Perl itself.
218              
219             =cut