File Coverage

blib/lib/Mojolicious/Plugin/INIConfig.pm
Criterion Covered Total %
statement 58 58 100.0
branch 27 34 79.4
condition 16 25 64.0
subroutine 7 7 100.0
pod 3 3 100.0
total 111 127 87.4


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::INIConfig;
2 2     2   2590 use Mojo::Base 'Mojolicious::Plugin::Config';
  2         4  
  2         17  
3 2     2   3561 use Config::Tiny;
  2         1893  
  2         87  
4 2     2   22 use File::Spec::Functions 'file_name_is_absolute';
  2         6  
  2         134  
5 2     2   16 use Encode 'encode', 'decode';
  2         5  
  2         1679  
6              
7             our $VERSION = '0.04';
8              
9             sub parse {
10 5     5 1 1176 my ($self, $content, $file, $conf, $app) = @_;
11              
12 5         32 my $ct = Config::Tiny->new;
13 5         33 my $conf_str = decode('UTF-8', $self->render($content, $file, $conf, $app));
14 5         593 my $config_ct = $ct->read_string($conf_str);
15 5         380 my $config = {%$config_ct};
16            
17 5         23 my $err = $ct->errstr;
18 5 50 33     37 die qq{Couldn't parse config "$file": $err} if !$config && $err;
19 5 50 33     39 die qq{Invalid config "$file".} if !$config || ref $config ne 'HASH';
20              
21 5         37 return $config;
22             }
23              
24             sub register {
25 6     6 1 28767 my ($self, $app, $conf) = @_;
26            
27             # Config file
28 6   66     34 my $file = $conf->{file} || $ENV{MOJO_CONFIG};
29 6   50     40 $file ||= $app->moniker . '.' . ($conf->{ext} || 'ini');
      66        
30              
31             # Mode specific config file
32 6 100       85 my $mode = $file =~ /^(.*)\.([^.]+)$/ ? join('.', $1, $app->mode, $2) : '';
33              
34 6         69 my $home = $app->home;
35 6 100       50 $file = $home->rel_file($file) unless file_name_is_absolute $file;
36 6 100 100     331 $mode = $home->rel_file($mode) if $mode && !file_name_is_absolute $mode;
37 6 100 100     100 $mode = undef unless $mode && -e $mode;
38              
39             # Read config file
40 6         102 my $config = {};
41              
42 6 100 66     28 if (-e $file) { $config = $self->load($file, $conf, $app) }
  3 100       59  
43              
44             # Check for default and mode specific config file
45             elsif (!$conf->{default} && !$mode) {
46 2         44 die qq{Config file "$file" missing, maybe you need to create it?\n};
47             }
48              
49             # Merge everything
50 4 100       75 if ($mode) {
51 2         20 my $mode_config = $self->load($mode, $conf, $app);
52 2         12 for my $key (keys %$mode_config) {
53             $config->{$key}
54 2 50       6 = {%{$config->{$key} || {}}, %{$mode_config->{$key} || {}}};
  2 50       14  
  2         19  
55             }
56             }
57 4 100       18 if ($conf->{default}) {
58 2         5 my $default_config = $conf->{default};
59 2         7 for my $key (keys %$default_config) {
60             $config->{$key}
61 2 50       5 = {%{$default_config->{$key} || {}}, %{$config->{$key} || {}}, };
  2 100       9  
  2         22  
62             }
63             }
64 4         37 my $current = $app->defaults(config => $app->config)->config;
65 4         175 for my $key (keys %$config) {
66 4         35 %{$current->{$key}}
67 4 100       10 = (%{$current->{$key} || {}}, %{$config->{$key} || {}});
  4 50       26  
  4         23  
68             }
69              
70 4         39 return $current;
71             }
72              
73             sub render {
74 5     5 1 15 my ($self, $content, $file, $conf, $app) = @_;
75              
76             # Application instance and helper
77 5         11 my $prepend = q[my $app = shift; no strict 'refs'; no warnings 'redefine';];
78 5         15 $prepend .= q[sub app; *app = sub { $app }; use Mojo::Base -strict;];
79              
80             # Render and encode for INI decoding
81 5   50     58 my $mt = Mojo::Template->new($conf->{template} || {})->name($file);
82 5         108 my $ini = $mt->prepend($prepend . $mt->prepend)->render($content, $app);
83 5 50       6101 return ref $ini ? die $ini : encode 'UTF-8', $ini;
84             }
85              
86             1;
87              
88             =head1 NAME
89              
90             Mojolicious::Plugin::INIConfig - Mojolicious Plugin to create routes automatically
91              
92             =head1 CAUTION
93              
94             B
95              
96             =head1 SYNOPSIS
97              
98             # myapp.ini
99             [section]
100             foo=bar
101             music_dir=<%= app->home->rel_dir('music') %>
102              
103             # Mojolicious
104             my $config = $self->plugin('INIConfig');
105              
106             # Mojolicious::Lite
107             my $config = plugin 'INIConfig';
108              
109             # foo.html.ep
110             %= $config->{section}{foo}
111              
112             # The configuration is available application wide
113             my $config = app->config;
114              
115             # Everything can be customized with options
116             my $config = plugin INIConfig => {file => '/etc/myapp.conf'};
117              
118             =head1 DESCRIPTION
119              
120             L is a INI configuration plugin that
121             preprocesses its input with L.
122              
123             The application object can be accessed via C<$app> or the C function. You
124             can extend the normal config file C with C specific ones
125             like C. A default configuration filename will be generated
126             from the value of L.
127              
128             The code of this plugin is a good example for learning to build new plugins,
129             you're welcome to fork it.
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             =head1 BACKWARDS COMPATIBILITY POLICY
190              
191             If a feature is DEPRECATED, you can know it by DEPRECATED warnings.
192             DEPRECATED feature is removed after C,
193             but if at least one person use the feature and tell me that thing
194             I extend one year each time he tell me it.
195              
196             DEPRECATION warnings can be suppressed
197             by C
198             environment variable.
199              
200             EXPERIMENTAL features will be changed without warnings.
201              
202             =head1 BUGS
203              
204             Please tell me bugs if you find bug.
205              
206             C<< >>
207              
208             L
209              
210             =head1 COPYRIGHT & LICENSE
211              
212             Copyright 2013-2013 Yuki Kimoto, all rights reserved.
213              
214             This program is free software; you can redistribute it and/or modify it
215             under the same terms as Perl itself.
216              
217             =cut