File: Params.pm

package info (click to toggle)
libhtml-formhandler-perl 0.40057-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 2,320 kB
  • ctags: 685
  • sloc: perl: 8,849; makefile: 2
file content (153 lines) | stat: -rw-r--r-- 3,972 bytes parent folder | download
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
package    # hide from Pause
    HTML::FormHandler::Params;
# ABSTRACT: params handling

use Moose;
use Carp;

has 'separator' => ( isa => 'Str', is => 'rw', default => '.' );

sub split_name {
    my ( $self, $name, $sep ) = @_;

    $sep ||= $self->separator;
    $sep = "\Q$sep";

    if ( $sep eq '[]' ) {
        return grep { defined } (
            $name =~ /
         ^ (\w+)        # root param
         | \[ (\w+) \]  # nested
         /gx
        );
    }

    # These next two regexes are the escaping aware equivalent
    # to the following:
    # my ($first, @segments) = split(/\./, $name, -1);

    # m// splits on unescaped '.' chars. Can't fail b/c \G on next
    # non ./ * -> escaped anything -> non ./ *
    $name =~ m/^ ( [^\\$sep]* (?: \\(?:.|$) [^\\$sep]* )* ) /gx;
    my $first = $1;
    $first =~ s/\\(.)/$1/g;    # remove escaping

    my (@segments) = $name =~
        # . -> ( non ./ * -> escaped anything -> non ./ * )
        m/\G (?:[$sep]) ( [^\\$sep]* (?: \\(?:.|$) [^\\$sep]* )* ) /gx;
    # Escapes removed later, can be used to avoid using as array index

    return ( $first, @segments );
}

sub expand_hash {
    my ( $self, $flat, $sep ) = @_;

    my $deep = {};
    $sep ||= $self->separator;

    for my $name ( keys %$flat ) {

        my ( $first, @segments ) = $self->split_name( $name, $sep );

        my $box_ref = \$deep->{$first};
        for (@segments) {
            if ( /^(0|[1-9]\d*)$/ ) {
                $$box_ref = [] unless defined $$box_ref;
                croak "HFH: param clash for $name=$_"
                    unless ref $$box_ref eq 'ARRAY';
                $box_ref = \( $$box_ref->[$1] );
            }
            else {
                s/\\(.)/$1/g if $sep;    # remove escaping
                $$box_ref = {} unless defined $$box_ref;
                $$box_ref = { '' => $$box_ref } if ( !ref $$box_ref );
                croak "HFH: param clash for $name=$_"
                    unless ref $$box_ref eq 'HASH';
                $box_ref = \( $$box_ref->{$_} );
            }
        }
        if ( defined $$box_ref ) {
            croak "HFH: param clash for $name value $flat->{$name}"
                if ref $$box_ref ne 'HASH';
            $box_ref = \( $$box_ref->{''} );
        }
        $$box_ref = $flat->{$name};
    }
    return $deep;
}

sub collapse_hash {
    my $self = shift;
    my $deep = shift;
    my $flat = {};

    $self->_collapse_hash( $deep, $flat, () );
    return $flat;
}

sub join_name {
    my ( $self, @array ) = @_;
    my $sep = substr( $self->separator, 0, 1 );
    return join $sep, @array;
}

sub _collapse_hash {
    my ( $self, $deep, $flat, @segments ) = @_;

    if ( !ref $deep ) {
        my $name = $self->join_name(@segments);
        $flat->{$name} = $deep;
    }
    elsif ( ref $deep eq 'HASH' ) {
        for ( keys %$deep ) {
            # escape \ and separator chars (once only, at this level)
            my $name = $_;
            if ( defined( my $sep = $self->separator ) ) {
                $sep = "\Q$sep";
                $name =~ s/([\\$sep])/\\$1/g;
            }
            $self->_collapse_hash( $deep->{$_}, $flat, @segments, $name );
        }
    }
    elsif ( ref $deep eq 'ARRAY' ) {
        for ( 0 .. $#$deep ) {
            $self->_collapse_hash( $deep->[$_], $flat, @segments, $_ )
                if defined $deep->[$_];
        }
    }
    else {
        croak "Unknown reference type for ", $self->join_name(@segments), ":", ref $deep;
    }
}

__PACKAGE__->meta->make_immutable;
use namespace::autoclean;
1;

__END__

=pod

=encoding UTF-8

=head1 NAME

HTML::FormHandler::Params - params handling

=head1 VERSION

version 0.40057

=head1 AUTHOR

FormHandler Contributors - see HTML::FormHandler

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Gerda Shank.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut