__PACKAGE__->_encode_check(Encode::FB_CROAK | Encode::LEAVE_SRC);
# Remember to update this in Catalyst::Runtime as well!
-our $VERSION = '5.90099_001';
+our $VERSION = '5.90098';
$VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
sub import {
=head2 $c->last_error
Returns the most recent error in the stack (the one most recently added...)
-or nothing if there are no errors.
+or nothing if there are no errors. This does not modify the contents of the
+error stack.
=cut
-sub last_error { my ($err, @errs) = @{shift->error}; return $err }
+sub last_error {
+ my (@errs) = @{shift->error};
+ return scalar(@errs) ? $errs[-1]: undef;
+}
=head2 shift_errors
-shifts the most recently added error off the error stack and returns if. Returns
+shifts the most recently added error off the error stack and returns it. Returns
nothing if there are no more errors.
=cut
sub shift_errors {
my ($self) = @_;
- my ($err, @errors) = @{$self->error};
+ my @errors = @{$self->error};
+ my $err = shift(@errors);
+ $self->{error} = \@errors;
+ return $err;
+}
+
+=head2 pop_errors
+
+pops the most recently added error off the error stack and returns it. Returns
+nothing if there are no more errors.
+
+=cut
+
+sub pop_errors {
+ my ($self) = @_;
+ my @errors = @{$self->error};
+ my $err = pop(@errors);
$self->{error} = \@errors;
return $err;
}
$class->setup_finished(1);
}
-=head2 $c->uri_for( $path?, @args?, \%query_values? )
+=head2 $c->uri_for( $path?, @args?, \%query_values?, \$fragment? )
-=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? )
+=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values?, \$fragment? )
-=head2 $c->uri_for( $action, [@captures, @args], \%query_values? )
+=head2 $c->uri_for( $action, [@captures, @args], \%query_values?, \$fragment? )
Constructs an absolute L<URI> object based on the application root, the
provided path, and the additional arguments and query parameters provided.
C<< $c->request->base >>; any C<@args> are appended as additional path
components; and any C<%query_values> are appended as C<?foo=bar> parameters.
+B<NOTE> If you are using this 'stringy' first argument, we skip encoding and
+allow you to declare something like:
+
+ $c->uri_for('/foo/bar#baz')
+
+Where 'baz' is a URI fragment. We consider this first argument string to be
+'expert' mode where you are expected to create a valid URL and we for the most
+part just pass it through without a lot of internal effort to escape and encode.
+
If the first argument is a L<Catalyst::Action> it represents an action which
will have its path resolved using C<< $c->dispatcher->uri_for_action >>. The
optional C<\@captures> argument (an arrayref) allows passing the captured
$path .= '/';
}
- undef($path) if (defined $path && $path eq '');
+ my $fragment = ((scalar(@args) && ref($args[-1]) eq 'SCALAR') ? pop @args : undef );
+
+ unless(blessed $path) {
+ if ($path =~ s/#(.+)$//) {
+ if(defined($1) and $fragment) {
+ carp "Abiguious fragment declaration: You cannot define a fragment in '$path' and as an argument '$fragment'";
+ }
+ if(defined($1)) {
+ $fragment = $1;
+ }
+ }
+ }
my $params =
( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
+ undef($path) if (defined $path && $path eq '');
+
carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
my $target_action = $path->$_isa('Catalyst::Action') ? $path : undef;
}
my $query = '';
-
if (my @keys = keys %$params) {
# somewhat lifted from URI::_query's query_form
$query = '?'.join('&', map {
$base =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
$args = encode_utf8 $args;
$args =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
-
+
+ if(defined $fragment) {
+ if(blessed $path) {
+ $fragment = encode_utf8(${$fragment});
+ $fragment =~ s/([^A-Za-z0-9\-_.!~*'() ])/$URI::Escape::escapes{$1}/go;
+ $fragment =~ s/ /+/g;
+ }
+ $query .= "#$fragment";
+ }
+
my $res = bless(\"${base}${args}${query}", $class);
$res;
}