PNG  IHDR;IDATxܻn0K )(pA 7LeG{ §㻢|ذaÆ 6lذaÆ 6lذaÆ 6lom$^yذag5bÆ 6lذaÆ 6lذa{ 6lذaÆ `}HFkm,mӪôô! x|'ܢ˟;E:9&ᶒ}{v]n&6 h_tڠ͵-ҫZ;Z$.Pkž)!o>}leQfJTu іچ\X=8Rن4`Vwl>nG^is"ms$ui?wbs[m6K4O.4%/bC%t Mז -lG6mrz2s%9s@-k9=)kB5\+͂Zsٲ Rn~GRC wIcIn7jJhۛNCS|j08yiHKֶۛkɈ+;SzL/F*\Ԕ#"5m2[S=gnaPeғL lذaÆ 6l^ḵaÆ 6lذaÆ 6lذa; _ذaÆ 6lذaÆ 6lذaÆ RIENDB` package URI::Template; use strict; use warnings; our $VERSION = '0.24'; use URI; use URI::Escape (); use Unicode::Normalize (); use overload '""' => \&template; use Exporter 'import'; our @EXPORT = qw ( ); our @EXPORT_OK = qw ( template_process template_process_to_string ); our %EXPORT_TAGS = ( 'all' => \@EXPORT_OK, ); my $RESERVED = q(:/?#\[\]\@!\$\&'\(\)\*\+,;=); my %TOSTRING = ( '' => \&_tostring, '+' => \&_tostring, '#' => \&_tostring, ';' => \&_tostring_semi, '?' => \&_tostring_query, '&' => \&_tostring_query, '/' => \&_tostring_path, '.' => \&_tostring_path, ); sub new { my $class = shift; my $templ = shift; $templ = '' unless defined $templ; my $self = bless { template => $templ, _vars => {} } => $class; $self->_study; return $self; } sub _quote { my ( $val, $safe ) = @_; $safe ||= ''; my $unsafe = '^A-Za-z0-9\-\._' . $safe; ## Where RESERVED are allowed to pass-through, so are ## already-pct-encoded values if( $safe ) { my (@chunks) = split(/(%[0-9A-Fa-f]{2})/, $val); # even chunks are not %xx, odd chunks are return join '', map { $_ % 2 ? $chunks[$_] : URI::Escape::uri_escape_utf8( Unicode::Normalize::NFKC($chunks[$_]), $unsafe ) } 0..$#chunks; } # try to mirror python's urllib quote return URI::Escape::uri_escape_utf8( Unicode::Normalize::NFKC( $val ), $unsafe ); } sub _tostring { my ( $var, $value, $exp ) = @_; my $safe = $exp->{ safe }; if ( ref $value eq 'ARRAY' ) { return join( ',', map { _quote( $_, $safe ) } @$value ); } elsif ( ref $value eq 'HASH' ) { return join( ',', map { _quote( $_, $safe ) . ( $var->{ explode } ? '=' : ',' ) . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } elsif ( defined $value ) { return _quote( substr( $value, 0, $var->{ prefix } || length( $value ) ), $safe ); } return; } sub _tostring_semi { my ( $var, $value, $exp ) = @_; my $safe = $exp->{ safe }; my $join = $exp->{ op }; $join = '&' if $exp->{ op } eq '?'; if ( ref $value eq 'ARRAY' ) { if ( $var->{ explode } ) { return join( $join, map { $var->{ name } . '=' . _quote( $_, $safe ) } @$value ); } else { return $var->{ name } . '=' . join( ',', map { _quote( $_, $safe ) } @$value ); } } elsif ( ref $value eq 'HASH' ) { if ( $var->{ explode } ) { return join( $join, map { _quote( $_, $safe ) . '=' . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } else { return $var->{ name } . '=' . join( ',', map { _quote( $_, $safe ) . ',' . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } } elsif ( defined $value ) { return $var->{ name } unless length( $value ); return $var->{ name } . '=' . _quote( substr( $value, 0, $var->{ prefix } || length( $value ) ), $safe ); } return; } sub _tostring_query { my ( $var, $value, $exp ) = @_; my $safe = $exp->{ safe }; my $join = $exp->{ op }; $join = '&' if $exp->{ op } =~ /[?&]/; if ( ref $value eq 'ARRAY' ) { return if !@$value; if ( $var->{ explode } ) { return join( $join, map { $var->{ name } . '=' . _quote( $_, $safe ) } @$value ); } else { return $var->{ name } . '=' . join( ',', map { _quote( $_, $safe ) } @$value ); } } elsif ( ref $value eq 'HASH' ) { return if !keys %$value; if ( $var->{ explode } ) { return join( $join, map { _quote( $_, $safe ) . '=' . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } else { return $var->{ name } . '=' . join( ',', map { _quote( $_, $safe ) . ',' . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } } elsif ( defined $value ) { return $var->{ name } . '=' unless length( $value ); return $var->{ name } . '=' . _quote( substr( $value, 0, $var->{ prefix } || length( $value ) ), $safe ); } } sub _tostring_path { my ( $var, $value, $exp ) = @_; my $safe = $exp->{ safe }; my $join = $exp->{ op }; if ( ref $value eq 'ARRAY' ) { return unless @$value; return join( ( $var->{ explode } ? $join : ',' ), map { _quote( $_, $safe ) } @$value ); } elsif ( ref $value eq 'HASH' ) { return join( ( $var->{ explode } ? $join : ',' ), map { _quote( $_, $safe ) . ( $var->{ explode } ? '=' : ',' ) . _quote( $value->{ $_ }, $safe ) } sort keys %$value ); } elsif ( defined $value ) { return _quote( substr( $value, 0, $var->{ prefix } || length( $value ) ), $safe ); } return; } sub _study { my ( $self ) = @_; my @hunks = grep { defined && length } split /(\{.+?\})/, $self->template; my $pos = 1; for ( @hunks ) { next unless /^\{(.+?)\}$/; $_ = $self->_compile_expansion( $1, $pos++ ); } $self->{ studied } = \@hunks; } sub _compile_expansion { my ( $self, $str, $pos ) = @_; my %exp = ( op => '', vars => [], str => $str ); if ( $str =~ /^([+#.\/;?&|!\@])(.+)/ ) { $exp{ op } = $1; $exp{ str } = $2; } $exp{ safe } = $RESERVED if $exp{ op } =~ m{[+#]}; for my $varspec ( split( ',', delete $exp{ str } ) ) { my %var = ( name => $varspec ); if ( $varspec =~ /=/ ) { @var{ 'name', 'default' } = split( /=/, $varspec, 2 ); } if ( $var{ name } =~ s{\*$}{} ) { $var{ explode } = 1; } elsif ( $var{ name } =~ /:/ ) { @var{ 'name', 'prefix' } = split( /:/, $var{ name }, 2 ); if ( $var{ prefix } =~ m{[^0-9]} ) { die 'Non-numeric prefix specified'; } } # remove "optional" flag (for opensearch compatibility) $var{ name } =~ s{\?$}{}; $self->{ _vars }->{ $var{ name } } = $pos; push @{ $exp{ vars } }, \%var; } my $join = $exp{ op }; my $start = $exp{ op }; if ( $exp{ op } eq '+' ) { $start = ''; $join = ','; } elsif ( $exp{ op } eq '#' ) { $join = ','; } elsif ( $exp{ op } eq '?' ) { $join = '&'; } elsif ( $exp{ op } eq '&' ) { $join = '&'; } elsif ( $exp{ op } eq '' ) { $join = ','; } if ( !exists $TOSTRING{ $exp{ op } } ) { die 'Invalid operation "' . $exp{ op } . '"'; } return sub { my $variables = shift; my @return; for my $var ( @{ $exp{ vars } } ) { my $value; if ( exists $variables->{ $var->{ name } } ) { $value = $variables->{ $var->{ name } }; } $value = $var->{ default } if !defined $value; next unless defined $value; my $expand = $TOSTRING{ $exp{ op } }->( $var, $value, \%exp ); push @return, $expand if defined $expand; } return $start . join( $join, @return ) if @return; return ''; }; } sub template { my $self = shift; my $templ = shift; # Update template if ( defined $templ && $templ ne $self->{ template } ) { $self->{ template } = $templ; $self->{ _vars } = {}; $self->_study; return $self; } return $self->{ template }; } sub variables { my @vars = sort {$_[ 0 ]->{ _vars }->{ $a } <=> $_[ 0 ]->{ _vars }->{ $b } } keys %{ $_[ 0 ]->{ _vars } }; return @vars; } sub expansions { my $self = shift; return grep { ref } @{ $self->{ studied } }; } sub process { my $self = shift; return URI->new( $self->process_to_string( @_ ) ); } sub process_to_string { my $self = shift; my $arg = @_ == 1 ? $_[ 0 ] : { @_ }; my $str = ''; for my $hunk ( @{ $self->{ studied } } ) { if ( !ref $hunk ) { $str .= $hunk; next; } $str .= $hunk->( $arg ); } return $str; } sub template_process { __PACKAGE__->new(shift)->process(@_) } sub template_process_to_string { __PACKAGE__->new(shift)->process_to_string(@_) } 1; __END__ =head1 NAME URI::Template - Object for handling URI templates (RFC 6570) =head1 SYNOPSIS use URI::Template; my $template = URI::Template->new( 'http://example.com/{x}' ); my $uri = $template->process( x => 'y' ); # or my $template = URI::Template->new(); $template->template( 'http://example.com/{x}' ); my $uri = $template->process( x => 'y' ); # uri is a URI object with value 'http://example.com/y' or use URI::Template ':template_process' my $uri = template_process ( 'http://example.com/{x}', x => 'y' ); =head1 DESCRIPTION This module provides a wrapper around URI templates as described in RFC 6570: L<< http://tools.ietf.org/html/rfc6570 >>. =head1 INSTALLATION perl Makefile.PL make make test make install =head1 METHODS =head2 new( $template ) Creates a new L instance with the template passed in as the first parameter (optional). =head2 template( $template ) This method returns the original template string. If provided, it will also set and parse a new template string. =head2 variables Returns an array of unique variable names found in the template (in the order of appearance). =head2 expansions This method returns an list of expansions found in the template. Currently, these are just coderefs. In the future, they will be more interesting. =head2 process( \%vars ) Given a list of key-value pairs or an array ref of values (for positional substitution), it will URI escape the values and substitute them in to the template. Returns a URI object. =head2 process_to_string( \%vars ) Processes input like the C method, but doesn't inflate the result to a URI object. =head1 EXPORTED FUNCTIONS =head2 template_process( $template => \%vars ) This is the same as C<< URI::Template->new($template)->process(\%vars) >> But shorter, and usefull for quick and easy genrating a nice URI form parameters. Returns an L object =head2 template_process_as_string( $template => \%vars ) Same as above, but obviously, returns a string. =head1 AUTHORS =over 4 =item * Brian Cassidy Ebricas@cpan.orgE =item * Ricardo SIGNES Erjbs@cpan.orgE =back =head1 CONTRIBUTERS =over 4 =item * Theo van Hoesel ETh.J.v.Hoesel@THEMA-MEDIA.nlE =head1 COPYRIGHT AND LICENSE Copyright 2007-2018 by Brian Cassidy This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut