package MooX::Role::CachedURL;
$MooX::Role::CachedURL::VERSION = '0.03';
use 5.006;
use Moo::Role;
use File::HomeDir;
use File::Spec::Functions 'catfile';
use HTTP::Tiny;
use Time::Duration::Parse;
use Carp;

has 'url'     => (is => 'ro');
has 'path'    => (is => 'rw');
has 'max_age' => (is => 'ro');

sub BUILD
{
    my $self = shift;

    # If constructor didn't specify a local file, then mirror the file
    if (not $self->path) {
        my $basename = $self->url;
           $basename =~ s!^.*[/\\]!!;

        my $classid  = ref($self);
           $classid  =~ s/::/-/g;

        $self->path( catfile(File::HomeDir->my_dist_data( $classid, { create => 1 } ), $basename) );

        if (defined($self->max_age) && -f $self->path) {
            my $max_age_in_seconds = parse_duration($self->max_age);
            return unless time() - $max_age_in_seconds > (stat($self->path))[9];
        }

        my $response;
        eval { $response = HTTP::Tiny->new()->mirror($self->url, $self->path) };
        if (not $response->{success}) {
            croak "failed to mirror @{[ $self->url ]}: $response->{status} $response->{reason}";
        }
    }
}

1;

=head1 NAME

MooX::Role::CachedURL - a role providing a locally cached copy of a remote file

=head1 SYNOPSIS

 package MyClass;
 use Moo;
 with 'MooX::Role::CachedURL';
 has '+url' => (default => sub { 'http://www.cpan.org/robots.txt' });
 
 sub my_method {
    my $self = shift;
    
    # $self->path has the path to the local copy of the file
 }

Then in the user of MyClass:

 use MyClass;
 my $object = MyClass->new(max_age => '2 days');
 
 print "local file is ", $object->path, "\n";

=head1 DESCRIPTION

This role represents a remote file that you want to cache locally, and then process.
This is common functionality that I'm pulling out of my L<PAUSE::Users>,
L<PAUSE::Permissions> and L<PAUSE::Packages> modules.

PAUSE::Users provides a simple interface to the C<00whois.xml> file that is generated by PAUSE.
It caches the file locally, then provides a mechanism for iterating over all users in the file.

If you look right now,
you'll notice that none of those modules use this role yet;
I'll be gradually refactoring them once this role is on CPAN.

=head1 ATTRIBUTES

=head2 url

This specifies the URL that should be cached locally.
It should be over-ridden in the composing class, as shown in the SYNOPSIS above.

=head2 max_age

Specifies the maximum age of the local copy, in seconds.
We won't even look for a new remote copy if the cached copy is younger than this.

You can specify max_age using any of the notations supported by L<Time::Duration::Parse>.
For example:

 max_age => '2 hours',

=head1 TODO

=over 4

=item * Switch to LWP for general URL handling, not just HTTP

=item * Ability for a class to transform content when caching

=back

=head1 REPOSITORY

L<https://github.com/neilbowers/MooX-Role-CachedURL>

=head1 AUTHOR

Neil Bowers E<lt>neilb@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2014 by Neil Bowers <neilb@cpan.org>.

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
