summaryrefslogtreecommitdiff
path: root/lib/JWebmail/Plugin/INIConfig.pm
blob: fe0fb1a69cfd298996dd363b3e6f792b21218ac7 (plain)
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
package JWebmail::Plugin::INIConfig;
use Mojo::Base 'Mojolicious::Plugin::Config';

use List::Util 'all';

use Config::Tiny;


sub parse {
    my ($self, $content, $file, $conf, $app) = @_;

    my $ct = Config::Tiny->new;
    my $config = $ct->read_string($content, 'utf8');
    die qq{Can't parse config "$file": } . $ct->errstr unless defined $config;

    $config = _process_config($config) unless $conf->{flat};

    return $config;
}


sub _process_config {
    my $val_prev = shift;
    my %val = %$val_prev;

    # arrayify section with number keys
    for my $key (keys %val) {
        if (keys %{$val{$key}} && all { $_ =~ /\d+/} keys %{$val{$key}}) {
            my $tmp = $val{$key};
            $val{$key} = [];

            for (keys %$tmp) {
                $val{$key}[$_] = $tmp->{$_};
            }
        }
    }

    # merge top section
    my $top_section = $val{'_'};
    delete $val{'_'};
    for (keys %$top_section) {
        $val{$_} = $top_section->{$_} unless $val{$_};
    }

    # make implicit nesting explicit
    for my $key (grep { $_ =~ /^\w+(::\w+)+$/} keys %val) {

        my @sections = split m/::/, $key;
        my $x = \%val;
        my $y;
        for (@sections) {
            $x->{$_} = {} unless ref $x->{$_};# eq 'HASH';
            $y = $x;
            $x = $x->{$_};
        }
        # merge
        if (ref $val{$key} eq 'ARRAY') {
            $y->{$sections[-1]} = [];
            $x = $y->{$sections[-1]};
            for ( keys @{ $val{$key} } ) {
                $x->[$_] = $val{$key}[$_];
            }
        }
        else {
            for ( keys %{ $val{$key} } ) {
                $x->{$_} = $val{$key}{$_};
            }
        }
        delete $val{$key};
    }

    return \%val
}


1

__END__

=encoding utf-8

=head1 NAME

INIConfig - Reads in ini config files.

=head1 SYNOPSIS

  $app->plugin('INIConfig');

  @@ my_app.conf

  # global section
  key = val ; line comment
  [section]
  other_key = other_val
  [other::section]
  0 = key1
  1 = key2
  2 = key3

=head1 DESCRIPTION

INI configuration is simple with limited nesting and propper comments.
For more precise specification on the syntax see the Config::Tiny documentation
on metacpan.

=head1 OPTIONS

=head2 default

Sets default configuration values.

=head2 ext

Sets file extension defaults to '.conf'.

=head2 file

Sets file name default '$app->moniker'.

=head2 flat

Keep configuration to exactly two nesting levels for all
and disable auto array conversion.

=head1 METHODS

=head2 parse

overrides the parse method of Mojolicious::Plugin::Config

=head1 DEPENDENCIES

Config::Tiny

=cut