The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Template::Caribou::Files;
BEGIN {
  $Template::Caribou::Files::AUTHORITY = 'cpan:YANICK';
}
{
  $Template::Caribou::Files::VERSION = '0.2.2';
}
#ABSTRACT: Role to load templates from files


use strict;
use warnings;

use MooseX::Role::Parameterized;

parameter dirs => (
    traits => [ 'Array' ],
    isa => 'ArrayRef',
    default => sub { [] },
    handles => {
        all_dirs => 'elements',
    },
);

parameter auto_reload => (
    isa => 'Bool',
    default => 0,
);

role {
    use Path::Class;
    use List::Pairwise qw/ mapp /;

    use MooseX::ClassAttribute;
    use MooseX::SemiAffordanceAccessor;

    my $p = shift;
    my %arg = @_;

    has template_dirs => (
        traits => [ 'Array' ],
        isa => 'ArrayRef',
        builder => '_build_template_dirs',
        handles => {
            all_template_dirs => 'elements',
            add_template_dirs => 'push',
        },
    );

    sub _build_template_dirs { [] }

    around _build_template_dirs => sub {
        my( $ref, $self ) = @_;

        return [ @{ $ref->($self) }, $p->all_dirs ];
    };

    before 'render' => sub {
        $_[0]->import_template_dirs( @{$p->dirs} ) #@{ $_[0]->template_dirs } ) 
            if not $Template::Caribou::IN_RENDER;
    } if $p->auto_reload;


method import_template_file => \&_import_template_file;

sub _import_template_file {
    my $self = shift;

    my( $name, $file ) = @_ == 2 ? @_ : ( undef, @_ );

    $file = file($file) unless ref $file;

    ( $name = $file->basename ) =~ s/\..*?$// unless $name;

    my $class = ref( $self ) || $self;

    my $lines = $file->slurp;

    my $signature = $lines =~ m{^#\((.*)\)\s*$}m ? $1 : '';

    my $code = <<"END_EVAL";
package $class;
use Method::Signatures;
method ($signature) {
# line 1 "@{[ $file->absolute ]}"
$lines
}
END_EVAL

    my $sub = eval $code;

    die $@ if $@;
    $self->set_template( $name => $sub );

    return $name;
}

method import_template_dirs => \&_import_template_dirs; 

sub _import_template_dirs {
    my ( $self, @dirs ) = @_;

    for my $dir ( map { dir($_) }  @dirs ) {
        $dir->recurse( callback => sub{ 
             return unless $_[0] =~ /\.bou$/;
             my $f = $_[0]->relative($dir)->stringify;
             $f =~ s/\.bou$//;
             _import_template_file( $self, $f => $_[0] );
        });
    }

};

    _import_template_dirs( $arg{consumer}->name, @{$p->dirs} );

};



1;

__END__

=pod

=head1 NAME

Template::Caribou::Files - Role to load templates from files

=head1 VERSION

version 0.2.2

=head1 SYNOPSIS

    package MyTemplate;

    use Moose;

    with 'Template::Caribou';
    with 'Template::Caribou::Files' => {
        dirs => [ 'my_templates/' ],
        auto_reload => 1,
    };

    1;

=head1 DESCRIPTION

With I<Template::Caribou::Files>, a Caribou class will automatically import
all template file (i.e., all files with a C<.bou> extension) under the given directories.

The names of the imported templates will be their path, relative to the
imported directories, without their extension. To take the example in the
L</SYNOPSIS>, if the content of C<my_templates/> is:

    ./foo.bou
    ./bar.bou
    ./baz/frob.bou

then the templates C<foo.bou>, C<bar.bou> and C<baz/frob> will be created.

=head1 METHODS

=head2 import_template_file( $name => $file )

Imports the content of I<$file> as a template. If I<$name> is not given, 
it is assumed to be the basename of the file, minus the extension. 

Returns the name of the imported template.

=head1 ROLE PARAMETERS

=head2 dirs

The array ref of directories to scan for templates. 

=head2 auto_reload

If set to true, the import directories will be rescanned and every file
re-imported before every call to C<render>. Useful during development.

Defaults to false.

=head1 AUTHOR

Yanick Champoux <yanick@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Yanick Champoux.

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