Catalyst-View-Markdown

 view release on metacpan or  search on metacpan

lib/Catalyst/View/Markdown.pm  view on Meta::CPAN

package Catalyst::View::Markdown;

use strict;
use warnings;

use base qw/Catalyst::View/;
use Text::Markdown;
use File::Find;
use MRO::Compat;
use Scalar::Util qw/blessed weaken/;

our $VERSION = '0.01';
$VERSION = eval $VERSION;

__PACKAGE__->mk_accessors('markdown_filename');
__PACKAGE__->mk_accessors('include_path');

*paths = \&include_path;

=head1 NAME

Catalyst::View::Markdown - Markdown View Class

=head1 SYNOPSIS

# use the helper to create your View

    myapp_create.pl view MD Markdown

# add custom configration in View/MD.pm

    __PACKAGE__->config(
        # any Markdown configuration items go here
        FILENAME_EXTENSION => '.md',
        empty_element_suffix => '/>',
        tab_width => 4,
        trust_list_start_value => 1,
    );

# add include path configuration in MyApp.pm

    __PACKAGE__->config(
        'View::MD' => {
            INCLUDE_PATH => [
                __PACKAGE__->path_to( 'root', 'src' ),
                __PACKAGE__->path_to( 'root', 'lib' ),
            ],
        },
    );

# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm

    sub message : Global {
        my ( $self, $c ) = @_;
        $c->stash->{markdown_filename} = 'message';
        $c->forward( $c->view('MD') );
    }

=cut

sub _coerce_paths {
    my ( $paths, $dlim ) = shift;
    return () if ( !$paths );
    return @{$paths} if ( ref $paths eq 'ARRAY' );

    # tweak delim to ignore C:/
    unless ( defined $dlim ) {
        $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
    }
    return split( /$dlim/, $paths );
}

sub new {
    my ( $class, $c, $arguments ) = @_;
    my $config = {
        FILENAME_EXTENSION => '',
        CLASS              => 'Text::Markdown',
        %{ $class->config },
        %{$arguments},
    };
    if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
        my $delim = $config->{DELIMITER};
        my @include_path
            = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
        if ( !@include_path ) {
            my $root = $c->config->{root};
            my $base = Path::Class::dir( $root, 'base' );
            @include_path = ( "$root", "$base" );
        }
        $config->{INCLUDE_PATH} = \@include_path;
    }

    if ( $c->debug && $config->{DUMP_CONFIG} ) {
        $c->log->debug( "Markdown Config: ", CORE::dump($config) );
    }

    my $self = $class->next::method(
        $c, { %$config },
    );

    # Set base include paths. Local'd in render if needed
    $self->include_path($config->{INCLUDE_PATH});

    $self->config($config);

    # Creation of template outside of call to new so that we can pass [ $self ]
    # as INCLUDE_PATH config item, which then gets ->paths() called to get list
    # of include paths to search for templates.

    # Use a weakend copy of self so we dont have loops preventing GC from working
    my $copy = $self;
    Scalar::Util::weaken($copy);
    $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];

    $self->{markdown} =
        $config->{CLASS}->new($config) || do {
            my $error = $config->{CLASS}->error();
            $c->log->error($error);
            $c->error($error);
            return undef;
        };


    return $self;
}

sub process {
    my ( $self, $c ) = @_;

    my $mdfile = $c->stash->{markdown_filename}
      ||  $c->action . $self->config->{FILENAME_EXTENSION};

    unless (defined $mdfile) {
        $c->log->debug('No Markdown file specified for rendering') if $c->debug;
        return 0;
    }

    local $@;
    my $output = eval { $self->render($c, $mdfile) };

    unless ( $c->response->content_type ) {
        $c->response->content_type('text/html; charset=utf-8');
    }

    $c->response->body($output);

    return 1;
}

sub render {
    my ($self, $c, $mdfile, $args) = @_;

    $c->log->debug(qq/Rendering Markdown file "$mdfile"/) if $c && $c->debug;

    my $mdtext;
    if ( ref $mdfile eq 'SCALAR' ) {
        $mdtext = $$mdfile;
    }
    else {

        my $filename;
        # Find the first readable file with the right filename under the include paths
        find(
             sub { $filename = $File::Find::name if !$filename && $_ eq $mdfile && -r $File::Find::name},
            @{$self->include_path}
        );

        # If we found a match...
        if ($filename) {
            open my $in,  '<',  $filename;
            $mdtext = join '', do { local $/; <$in> }; # slurp!
            close $in;



( run in 2.278 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )