Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

App scaffolding templates #670

Open
wants to merge 7 commits into from

6 participants

Jonathan Scott Duff David Precious Sawyer X Alberto Simões Damien Krotkine Alexis Sukrieh
Jonathan Scott Duff

Here are some changes to the dancer script to allow for an "application template" directory. It's not well tested yet, but I wanted some feedback.

It adds the --template/-t options such that you can use "application templates" to create new apps. The application templates are subdirectories of ~/.dancer_templates and they should contain everything you'd want in a dancer app.

The use-case is if you're always building dancer apps that use blueprint.css or prototype instead of jquery or come pre-packaged with some other functionality, you build a directory in ~/.dancer_templates that contains all of the necessary files and use "dancer -t my-template -a MyApp" to create new apps.

Anyway, feedback welcome!

perlpilot added some commits
Jonathan Scott Duff perlpilot Make $name less global
The appname is passed to several subs, but others rely on the globally
scoped $name declared near the top of the program.  So, make those
others take $name as a parameter.
33e04aa
Jonathan Scott Duff perlpilot Make "meta-template" indicators more obnoxious 997688f
Jonathan Scott Duff perlpilot Use local $appname rather than global $name e9f7404
Jonathan Scott Duff perlpilot Add simple templating ability for creating new apps
Allow for a template to be specified on the command line with the -t or
--template option.  These templates are subdirectories within the
$HOME/.dancer_templates directory.

The files in the template dir are copied to the application dir with
some simple substitutions performed: filenames have APPNAME replaced by
the actual application name, within files [[%% appname %%]] and
[[%% appdir %%]] are replaced with the appropriate values for the
Actual application.  (The delimiters there are intentionally "big" so
That they don't conflict with whatever template delimiters may be used
by the templated files themselves (within views for instance))

Also, the file mode of the template files determines the file mode used
for the corresponding file in the application directory.
4a12de1
David Precious
Owner

Looks like a good feature.

The only slight drawback is that this will need to be ported to gnusosa's Dancer::Script refactoring (which reminds me, I need to find out how close we are to merging that in, it looked good)

Jonathan Scott Duff perlpilot Application templates update
* Change the template dir to be ~/.dancer/templates
* If the argument to -t starts with a /, it's assumed to be the full
  path to a template directory
2ae161a
Jonathan Scott Duff

Where is this Dancer::Script refactoring located?

David Precious
Owner
Sawyer X
Owner

Released a new dev version.
Once I release it as stable, I'm gonna merge @gnusosa's work.

Alberto Simões
Owner

@xsawyerx, can I poke you to merge @gnusosa's work? Please? With sugar on top?

Sawyer X
Owner

@ambs let's see how easy this is...

Sawyer X
Owner

@ambs, @bigpresh, @perlpilot - I've put @gnusosa's work on the branch "refactoring/script". If you could resubmit this pull request based on that branch, and adapt it to that code, I would greatly appreciate it. :)

perlpilot added some commits
Jonathan Scott Duff perlpilot Merge branch 'devel' of https://github.com/sukria/Dancer into devel 90803e4
Jonathan Scott Duff perlpilot Allow refs to pass through view unscathed
Useful for inline templates so that you don't necessarily need a
directory structure or external files.

Also, the underlying template implementation supports passing a
scalar ref, but without the high-level implementation also supporting
this, there's no way to do inline templates with hooks.
d9ebf53
Jonathan Scott Duff

I've made it such that

my $template = '<% foo %>';
template \$template, { foo => 42 };

works now.

I was trying to test some simple view code and didn't need or want to generate .tt files. I noticed that the underlying template code supported passing a scalar ref, but then your hooks won't run. The above change allows for the "full stack" template processing to happen and for the templates to be specified inline.

This is useful for extremely simple Dancer apps and, what I want it for, testing plugins that add functionality to templates.

Damien Krotkine
Owner

@ambs, @bigpresh, @perlpilot, @gnusosa @xsawyerx : where are we with this PR ? it seems to me that it can be merged alongside with gnusosa stuff ?

Alexis Sukrieh
Owner

poking here. Dams++ : can we have a brief on that one?

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 29, 2011
  1. Jonathan Scott Duff

    Make $name less global

    perlpilot authored
    The appname is passed to several subs, but others rely on the globally
    scoped $name declared near the top of the program.  So, make those
    others take $name as a parameter.
  2. Jonathan Scott Duff
  3. Jonathan Scott Duff
  4. Jonathan Scott Duff

    Add simple templating ability for creating new apps

    perlpilot authored
    Allow for a template to be specified on the command line with the -t or
    --template option.  These templates are subdirectories within the
    $HOME/.dancer_templates directory.
    
    The files in the template dir are copied to the application dir with
    some simple substitutions performed: filenames have APPNAME replaced by
    the actual application name, within files [[%% appname %%]] and
    [[%% appdir %%]] are replaced with the appropriate values for the
    Actual application.  (The delimiters there are intentionally "big" so
    That they don't conflict with whatever template delimiters may be used
    by the templated files themselves (within views for instance))
    
    Also, the file mode of the template files determines the file mode used
    for the corresponding file in the application directory.
  5. Jonathan Scott Duff

    Application templates update

    perlpilot authored
    * Change the template dir to be ~/.dancer/templates
    * If the argument to -t starts with a /, it's assumed to be the full
      path to a template directory
Commits on Dec 8, 2011
  1. Jonathan Scott Duff
  2. Jonathan Scott Duff

    Allow refs to pass through view unscathed

    perlpilot authored
    Useful for inline templates so that you don't necessarily need a
    directory structure or external files.
    
    Also, the underlying template implementation supports passing a
    scalar ref, but without the high-level implementation also supporting
    this, there's no way to do inline templates with hooks.
This page is out of date. Refresh to see the latest.
Showing with 48 additions and 14 deletions.
  1. +2 −1  lib/Dancer/Template/Abstract.pm
  2. +46 −13 script/dancer
3  lib/Dancer/Template/Abstract.pm
View
@@ -23,6 +23,7 @@ sub default_tmpl_ext { "tt" }
sub _template_name {
my ( $self, $view ) = @_;
+ return $view if ref($view);
my $def_tmpl_ext = $self->config->{extension} || $self->default_tmpl_ext();
$view .= ".$def_tmpl_ext" if $view !~ /\.\Q$def_tmpl_ext\E$/;
return $view;
@@ -33,7 +34,7 @@ sub view {
$view = $self->_template_name($view);
- return path(Dancer::App->current->setting('views'), $view);
+ return ref($view) ? $view : path(Dancer::App->current->setting('views'), $view);
}
sub layout {
59 script/dancer
View
@@ -4,6 +4,7 @@ use strict;
use warnings;
use Dancer::Template::Simple;
use File::Basename 'basename', 'dirname';
+use File::Find;
use File::Path 'mkpath';
use File::Spec::Functions;
use Getopt::Long;
@@ -12,20 +13,24 @@ use Dancer::Renderer;
use LWP::UserAgent;
use constant FILE => 1;
+my $TEMPLATES_DIR = "$ENV{HOME}/.dancer/templates";
+
# options
my $help = 0;
my $do_check_dancer_version = 1;
my $name = undef;
my $path = '.';
+my $template_name;
sub templates($);
sub app_tree($);
-sub create_node($;$);
+sub create_node($;$$);
GetOptions(
"h|help" => \$help,
"a|application=s" => \$name,
"p|path=s" => \$path,
+ "t|template=s" => \$template_name,
"x|no-check" => sub { $do_check_dancer_version = 0 },
"v|version" => \&version,
) or pod2usage( -verbose => 1 );
@@ -52,7 +57,11 @@ my $DANCER_VERSION = $Dancer::VERSION;
version_check() if $do_check_dancer_version;
safe_mkdir($DANCER_APP_DIR);
-create_node( app_tree($name), $DANCER_APP_DIR );
+if (defined $template_name) {
+ create_app_from_template( $template_name, $DANCER_APP_DIR, $name );
+} else {
+ create_node( app_tree($name), $DANCER_APP_DIR, $name );
+}
unless (eval "require YAML") {
print <<NOYAML;
@@ -73,6 +82,30 @@ NOYAML
# subs
+sub create_app_from_template {
+ my ($template_name, $appdir, $appname) = @_;
+ my $template_base = $template_name =~ m!^/!
+ ? $template_name
+ : catfile($TEMPLATES_DIR, $template_name);
+ unless (-e $template_base) {
+ die "No template named $template_name found in $TEMPLATES_DIR\n";
+ }
+ find({ no_chdir => 1, wanted => sub {
+ return if $File::Find::name eq $template_base;
+ (my $path = $File::Find::name) =~ s{^$template_base/}{};
+ $path =~ s/APPNAME/$appname/g;
+ my $appfile = catfile($appdir, $path);
+ if (-d $File::Find::name) { safe_mkdir($appfile); return }
+ my $template = do { local (@ARGV,$/) = $File::Find::name; <> };
+ write_file($appfile, $template, {
+ appdir => File::Spec->rel2abs($appdir),
+ appname => $appname,
+ });
+ # Match the mode of the template file
+ chmod +(stat($File::Find::name))[2], $appfile;
+ }}, $template_base);
+}
+
sub validate_app_name {
my $name = shift;
if ($name =~ /[^\w:]/ || $name =~ /^\d/ || $name =~ /\b:\b|:{3,}/) {
@@ -107,8 +140,8 @@ sub _dash_name {
$name;
}
-sub create_node($;$) {
- my ($node, $root) = @_;
+sub create_node($;$$) {
+ my ($node, $root, $name) = @_;
$root ||= '.';
my $manifest_name = catfile($root => 'MANIFEST');
@@ -123,12 +156,12 @@ sub create_node($;$) {
};
$add_to_manifest->($manifest_name);
- _create_node($add_to_manifest, $node, $root);
+ _create_node($add_to_manifest, $node, $root, $name);
close $manifest;
}
sub _create_node {
- my ($add_to_manifest, $node, $root) = @_;
+ my ($add_to_manifest, $node, $root, $name) = @_;
my $templates = templates($name);
@@ -137,7 +170,7 @@ sub _create_node {
if (ref($content) eq 'HASH') {
safe_mkdir($path);
- _create_node($add_to_manifest, $content, $path);
+ _create_node($add_to_manifest, $content, $path, $name);
} elsif (ref($content) eq 'CODE') {
# The content is a coderef, which, given the path to the file it
# should create, will do the appropriate thing:
@@ -241,8 +274,8 @@ sub write_file {
sub process_template {
my ($template, $tokens) = @_;
my $engine = Dancer::Template::Simple->new;
- $engine->{start_tag} = '[%';
- $engine->{stop_tag} = '%]';
+ $engine->{start_tag} = '[[%%';
+ $engine->{stop_tag} = '%%]]';
return $engine->render(\$template, $tokens);
}
@@ -335,7 +368,7 @@ WriteMakefile(
PREREQ_PM => {
'Test::More' => 0,
'YAML' => 0,
- 'Dancer' => [% dancer_version %],
+ 'Dancer' => [[%% dancer_version %%]],
},
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => '$cleanfiles-*' },
@@ -385,7 +418,7 @@ WriteMakefile(
<h3>Your application\'s environment</h3>
<ul>
- <li>Location: <code>[% appdir %]</code></li>
+ <li>Location: <code>[[%% appdir %%]]</code></li>
<li>Template engine: <code><% settings.template %></code></li>
<li>Logger: <code><% settings.logger %></code></li>
<li>Environment: <code><% settings.environment %></code></li>
@@ -425,7 +458,7 @@ WriteMakefile(
</tr>
<tr>
<td>Appdir</td>
- <td><tt>[% appdir %]</tt></td>
+ <td><tt>[[%% appdir %%]]</tt></td>
</tr>
<tr>
<td>Template engine</td>
@@ -894,7 +927,7 @@ EOH
# all the settings in this file will be loaded at Dancer's startup.
# Your application's name
-appname: \"$name\"
+appname: \"$appname\"
# The default layout to use for your application (located in
# views/layouts/main.tt)
Something went wrong with that request. Please try again.