App-Microsite-Assemble
view release on metacpan or search on metacpan
0.03 2013-08-27
Fragments are now treated as templates, so you can include other fragments (sartak)
0.02 2013-08-27
Automatically create fragments and fragment dirs in CMS mode in example (sartak)
Mark output from missing_fragment as raw (sartak)
0.01 2013-08-22
Initial release
example/assemble-example.com view on Meta::CPAN
activeMenu => sub {
my ($context, $menu) = @_;
if( $context->{'active-menu'} && $context->{'active-menu'} eq $menu ) {
return 'class=active';
}
},
},
);
if ($with_cms) {
$args{fragment_filter} = sub {
my ($content, $file, $name) = @_;
my $relative_file = $file;
$relative_file =~ s/^fragments\///;
return "<iicmsfragment path='$relative_file'>$content</iicmsfragment>";
};
$args{missing_fragment} = sub {
my ($name, $paths) = @_;
my $relative_fragment = $paths->[0];
$relative_fragment =~ s/^fragments\///;
dir($relative_fragment)->mkpath;
return "<iicmsfragment path='$relative_fragment/$name'>$name</iicmsfragment>";
};
}
my $report = App::Microsite::Assemble->assemble(%args);
# find all the fragments that were not referenced by any template
# and warn about it
my $fragment_iter = File::Next::files('fragments/');
while (defined(my $fragment = $fragment_iter->())) {
warn "Unused fragment $fragment\n"
if !$report->{seen_fragments}->{$fragment};
}
my $files = keys %{ $report->{built_files} };
if ($files == 1) {
print "Built 1 file\n";
}
else {
print "Built $files files\n";
}
lib/App/Microsite/Assemble.pm view on Meta::CPAN
use Text::Handlebars;
use Text::Xslate 'mark_raw';
sub assemble {
my $class = shift;
my $args = {
wrapper_name => 'wrapper.handlebars',
content_name => 'content.handlebars',
config_name => 'config.json',
templates_dir => 'templates/',
fragments_dir => 'fragments/',
build_dir => 'build/',
missing_fragment => sub {
my ($name, $paths) = @_;
die "Fragment named '$name' does not exist: (paths: @$paths)\n";
},
@_,
};
for my $arg (qw/templates_dir fragments_dir build_dir/) {
$args->{$arg} = dir($args->{$arg});
}
$args->{_seen_fragments} = {};
$args->{build_dir}->mkpath;
my %seen;
my $dir_iter = File::Next::dirs($args->{templates_dir});
while (defined(my $dir_name = $dir_iter->())) {
my $dir = dir($dir_name);
for my $child ($dir->children) {
lib/App/Microsite/Assemble.pm view on Meta::CPAN
$seen{$outfile} = $dir;
$outfile->spew(iomode => '>:encoding(UTF-8)', $output);
next;
}
}
}
return {
seen_fragments => $args->{_seen_fragments},
built_files => \%seen,
};
}
sub _generate_page {
my $class = shift;
my $dir = shift;
my $args = shift;
my $input_file = $dir->file($args->{content_name});
lib/App/Microsite/Assemble.pm view on Meta::CPAN
die_handler => sub {
my $error = shift;
my $template = shift @{ $args->{_current_template} };
$template = "$_ (wrapping $template)"
for @{ $args->{_current_template} };
warn "Unable to process $template\n $error";
exit 1;
},
helpers => {
%{ $args->{helpers} || {} },
fragment => sub {
my ($context, $name) = @_;
# {{fragment foo}} doesn't work, need {{fragment "foo"}}
die "{{fragment NAME}} helper needs a quoted name\n"
if !$name;
my @paths = @$path;
s{^templates\b}{fragments} for @paths;
for my $path (@paths) {
my $fragment = dir($path)->file($name);
if (-e $fragment) {
$args->{_seen_fragments}{$fragment}++;
my $content = $fragment->slurp(iomode => '<:encoding(UTF-8)');
if ($args->{fragment_filter}) {
$content = $args->{fragment_filter}->($content, $fragment, $name);
}
return mark_raw($hb->render_string($content));
}
}
my $content = $args->{missing_fragment}->($name, \@paths);
return mark_raw($hb->render_string($content));
},
},
suffix => '.partial',
path => $path,
);
}
# merge all the config.json's in this hierarchy
sub _merge_config {
lib/App/Microsite/Assemble.pm view on Meta::CPAN
App::Microsite::Assemble - Assemble a microsite with Handlebars
=head1 VERSION
version 0.03
=head1 DESCRIPTION
This module assembles F<templates/> into fully-baked pages.
Your project should contain a F<fragments/> subdirectory, filled with files that contain bits of copy. Any template can use C<{{fragment "copy-file-name"}}> to inline the text from that file.
Subdirectories of F<templates/> can establish a hierarchy of wrappers. For example, you might have F<templates/basic/contact/> which is page C<contact> wrapped by wrapper C<basic>. The F<templates/basic/contact/> directory would have a F<content.hand...
Any directory in the hierarchy can have a F<wrapper.handlebars> which wraps everything below it. So the top-level F<templates/> could have a very generic F<wrapper.handlebars> that sets up C<< <html> >> etc. Subdirectories under F<templates/> can pro...
Similarly, any directory can have a F<config.json> which will combine in the usual way; files deeper in the hierarchy override settings from their upwards directories. Config variables will be provided in the template and its wrappers. This is intend...
You can put partials in any directory under F<templates/> and they will cascade; deeper partials will shadow shallower partials.
Finally, the F<fragments/> directory structure should match F<templates/>. The search path for fragment names works just like everything else.
=head1 AUTHORS
=over 4
=item *
Shawn M Moore <code@sartak.org>
=item *
( run in 0.781 second using v1.01-cache-2.11-cpan-b16cb0d3907 )