REST-Application

 view release on metacpan or  search on metacpan

lib/REST/Application.pm  view on Meta::CPAN

            $handler = $self->makeHandlerFromClass($thing, $smethod);
        }
    } elsif ($refType) {
        # Object with GET, PUT, etc, or getResource method.
        $handler = $self->makeHandlerFromRef($ref, $method);
    } elsif ($ref) {
        # A bare string signifying a method name
        $handler = sub { $self->$ref(@_) };
        $self->{__handlerIsOurMethod} = 1;  # See callHandler().
    }

    return $handler;
}

sub makeHandlerFromRef {
    my ($self, $ref, $method) = @_;
    return sub { $ref->$method(@_) };
}

sub makeHandlerFromClass {
    my ($self, $class, $method) = @_;
    return sub { $class->$method(@_) };
}

sub bestContentType {
    my ($self, @types) = @_;
    return ($self->simpleContentNegotiation(@types))[0] || '*/*';
}

# We don't support the full range of content negtiation because a) it's
# overkill and b) it makes it hard to specify the hooks cleanly, also see (a).
sub simpleContentNegotiation {
    my ($self, @types) = @_;
    my @accept_types = $self->getContentPrefs();
    my $score = sub { $self->scoreType(shift, @accept_types) };
    return sort {$score->($b) <=> $score->($a)} @types;
}

# The pattern matching stuff was stolen from CGI.pm
sub scoreType {
    my ($self, $type, @accept_types) = @_;
    my $score = scalar(@accept_types);
    for my $accept_type (@accept_types) {
        return $score if $type eq $accept_type;
        my $pat;
        ($pat = $accept_type) =~ s/([^\w*])/\\$1/g; # escape meta characters
        $pat =~ s/\*/.*/g; # turn it into a pattern
        return $score if $type =~ /$pat/;
        $score--;
    }
    return 0;
}

# Basic idea stolen from CGI.pm.  Its semantics made it hard to pull out the
# information I wanted without a lot of trickery, so I improved upon the
# original.  Same with libwww's HTTP::Negotiate algorithim, it's also hard to
# make go with what we want.
sub getContentPrefs {
    my $self = shift;
    my $default_weight = 1;
    my @prefs;

    # Parse the Accept header, and save type name, score, and position.
    my @accept_types = split /,/, $self->getAcceptHeader();
    my $order = 0;
    for my $accept_type (@accept_types) {
        my ($weight) = ($accept_type =~ /q=(\d\.\d+|\d+)/);
        my ($name) = ($accept_type =~ m#(\S+/[^;]+)#);
        next unless $name;
        push @prefs, { name => $name, order => $order++};
        if (defined $weight) {
            $prefs[-1]->{score} = $weight;
        } else {
            $prefs[-1]->{score} = $default_weight;
            $default_weight -= 0.001;
        }
    }

    # Sort the types by score, subscore by order, and pull out just the name
    @prefs = map {$_->{name}} sort {$b->{score} <=> $a->{score} || 
                                    $a->{order} <=> $b->{order}} @prefs;
    return @prefs, '*/*';  # Allows allow for */*
}

sub getAcceptHeader {
    my $self = shift;
    return $self->query->http('accept') || "";
}

# List _getLastRegexMatches(void)
#
# Returns a list of all the paren matches in the last regular expression who's
# matches were saved with _saveLastRegexMatches().  
sub _getLastRegexMatches {
    my $self = shift;
    my $matches = $self->{__lastRegexMatches} || [];
    return @$matches;
}

# ArrayRef _setLastRegexMatches(void)
#
# Grabs the values of $1, $2, etc. as set by the last regular expression to run
# in the current dyanamic scope.  This of course exploits that $1, $2, etc. and
# @+ are dynamically scoped.  A reference to an array is returned where the
# array values are $1, $2, $3, etc.  _getLastRegexMatches() can also be used to
# retrieve the values saved by this method.
sub _setLastRegexMatches {
    my $self = shift;
    no strict 'refs'; # For the $$_ symbolic reference below.
    my @matches = map $$_, (1 ..  scalar(@+)-1);  # See "perlvar" for @+.
    $self->{__lastRegexMatches} = \@matches;
}

1;
__END__
=pod

=head1 NAME

L<REST::Application> - A framework for building RESTful web-applications.

=head1 SYNOPSIS

    # MyRESTApp L<REST::Application> instance / mod_perl handler
    package MyRESTApp;
    use Apache;
    use Apache::Constants qw(:common);

    sub handler {
        __PACKAGE__->new(request => $r)->run();
        return OK;
    }
    
    sub getMatchText { return Apache->uri }

    sub setup {
        my $self = shift;
        $self->resourceHooks(
            qr{/rest/parts/(\d+)} => 'get_part',
            # ... other handlers here ...
        );
    }



( run in 2.607 seconds using v1.01-cache-2.11-cpan-8f98c5d2c55 )