package Squatting::View; use strict; use warnings; no warnings 'redefine'; our $AUTOLOAD; # constructor sub new { my $class = shift; my $name = shift; bless { name => $name, @_ } => $class; } # name of view sub name : lvalue { $_[0]->{name}; } # name of view sub headers : lvalue { $_[0]->{headers}; } # $content = $view->_render($template) # render $template # $content = $view->_render($template, '_') # render the generic template sub _render { my ($self, $template, $vars, $alt) = @_; $self->{template} = $template; if (exists $self->{layout} && ($template !~ /^_/)) { $template = $alt if defined $alt; $self->{layout}($self, $vars, $self->{$template}($self, $vars)); } else { $template = $alt if defined $alt; $self->{$template}($self, $vars); } } # forward to _render() sub AUTOLOAD { my ($self, $vars) = @_; my $template = $AUTOLOAD; $template =~ s/.*://; if (exists $self->{$template} && ref($self->{$template}) eq 'CODE') { $self->_render($template, $vars); } elsif (exists $self->{_}) { $self->_render($template, $vars, '_'); } else { die("$template cannot be rendered."); } } sub DESTROY { } 1; =head1 NAME Squatting::View - default view class for Squatting =head1 SYNOPSIS package App::Views; use Squatting 'views'; our @V = ( V( 'html', layout => sub { my ($self, $v, @content) = @_; "(header @content footer)"; }, home => sub { my ($self, $v) = @_; "Hello, $v->{name}"; }, _ => sub { my ($self, $v) = @_; "You tried to render $self->{template} which was not defined."; }, arbitrary_data => [ { is => 'ok' }, 2 ], ) ); =head1 DESCRIPTION In Squatting, views are objects that contain many templates. Templates are represented by subroutine references that will be installed as methods of a view object. The job of a template is to take a hashref of variables and return a string. =head1 API =head2 General Methods =head3 $view = Squatting::View->new($name, %methods) The constructor takes a name and a hash of attributes and coderefs. Note that the name must be unique within the package the view is defined. =head3 $view->name This returns the name of the view. =head3 $view->headers This returns a hashref of the outgoing HTTP headers. =head2 Template Methods =head3 $view->$template($v) Any coderef that was given to the constructor may be called by name. Templates should be passed in a hashref ($v) with variables for it to use to generate the final output. =head3 $view->layout($v, @content) If you define a template named "layout", it'll be used to wrap the content of all templates whose name do not begin with "_". You can use this feature to provide standard headers and footers for your pages. =head3 $view->_($v) If you define a template named "_", this will act as a catch-all that can be asked to render anything that wasn't explicitly defined. It's like our version of AUTOLOAD(). B: You can find out what they tried to render by inspecting $self->{template}. =head1 SEE ALSO L, L =cut # Local Variables: *** # mode: cperl *** # indent-tabs-mode: f *** # cperl-close-paren-offset: -2 *** # cperl-continued-statement-offset: 2 *** # cperl-indent-level: 2 *** # cperl-indent-parens-as-block: t *** # cperl-tab-always-indent: f *** # End: *** # vim:tabstop=8 softtabstop=2 shiftwidth=2 shiftround expandtab