File Coverage

lib/Amon2/Setup/Flavor.pm
Criterion Covered Total %
statement 101 131 77.1
branch 14 36 38.8
condition 4 9 44.4
subroutine 23 30 76.6
pod 3 14 21.4
total 145 220 65.9


line stmt bran cond sub pod time code
1 3     3   1325 use strict;
  3         5  
  3         87  
2 3     3   14 use warnings;
  3         5  
  3         70  
3 3     3   14 use utf8;
  3         6  
  3         17  
4              
5             package Amon2::Setup::Flavor;
6 3     3   1786 use Text::Xslate;
  3         36650  
  3         159  
7 3     3   24 use File::Spec;
  3         8  
  3         82  
8 3     3   17 use File::Basename;
  3         6  
  3         244  
9 3     3   21 use File::Path ();
  3         3  
  3         79  
10 3     3   1391 use Amon2;
  3         8  
  3         87  
11 3     3   18 use Plack::Util ();
  3         6  
  3         39  
12 3     3   15 use Carp ();
  3         4  
  3         45  
13 3     3   1238 use Amon2::Trigger;
  3         9  
  3         186  
14 3     3   1449 use MRO::Compat;
  3         5243  
  3         88  
15 3     3   1567 use File::ShareDir ();
  3         71403  
  3         113  
16 3     3   1434 use Module::CPANfile 0.9020;
  3         43104  
  3         4537  
17              
18             sub assets {
19 1     1 0 2 my $self = shift;
20              
21 1         7 my @assets = qw(
22             jQuery Bootstrap ES5Shim MicroTemplateJS StrftimeJS SprintfJS
23             MicroLocationJS MicroDispatcherJS XSRFTokenJS
24             );
25 1         5 @assets;
26             }
27              
28             sub infof {
29 58     58 0 88 my $caller = do {
30 58         78 my $x;
31 58         145 for (1..10) {
32 123         223 $x = caller($_);
33 123 100       275 last if $x ne __PACKAGE__;
34             }
35 58         106 $x;
36             };
37 58         112 $caller =~ s/^Amon2::Setup:://;
38 58         1926 print "[$caller] ";
39 58 50       540 @_==1 ? print(@_) : printf(@_);
40 58         437 print "\n";
41             }
42              
43             sub new {
44 1     1 0 1473 my $class = shift;
45 1 50       26 my %args = @_ ==1 ? %{$_[0]} : @_;
  0         0  
46              
47 1         7 $args{amon2_version} = $Amon2::VERSION;
48              
49 1         3 for (qw/module/) {
50 1 50       5 die "Missing mandatory parameter $_" unless exists $args{$_};
51             }
52 1         3 $args{module} =~ s!-!::!g;
53              
54             # $module = "Foo::Bar"
55             # $dist = "Foo-Bar"
56             # $path = "Foo/Bar"
57 1         5 my @pkg = split /::/, $args{module};
58 1         3 $args{dist} = join "-", @pkg;
59 1         3 $args{path} = join "/", @pkg;
60 1         6 my $self = bless { %args }, $class;
61 1         6 $self->{xslate} = $self->_build_xslate();
62 1         11 $self->load_assets();
63 1         9 $self;
64             }
65              
66             sub _build_xslate {
67 1     1   2 my $self = shift;
68              
69 1         5 my $xslate = Text::Xslate->new(
70             syntax => 'Kolon',
71             type => 'text',
72             tag_start => '<%',
73             tag_end => '%>',
74             line_start => '%%',
75             path => [ File::Spec->catdir(File::ShareDir::dist_dir('Amon2'), 'flavor') ],
76             module => [
77             'Amon2::Util' => ['random_string'],
78             ],
79             );
80 1         8419 $xslate;
81             }
82              
83 0     0 0 0 sub run { die "This is abstract base method" }
84              
85             sub mkpath {
86 0     0 1 0 my ($self, $path) = @_;
87 0 0       0 Carp::croak("path should not be ref") if ref $path;
88 0         0 infof("mkpath: $path");
89 0         0 File::Path::mkpath($path);
90             }
91              
92             sub render_string {
93 0     0 0 0 my $self = shift;
94 0         0 my $template = shift;
95 0 0       0 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
96 0         0 return $self->{xslate}->render_string($template, {%$self, %args});
97             }
98              
99             sub render_file {
100 0     0 0 0 my ($self, $dstname, $filename, $params) = @_;
101 0 0       0 Carp::croak("filename should not be reference") if ref $filename;
102 0 0       0 $dstname =~ s/<<([^>]+)>>/$self->{lc($1)} or die "$1 is not defined. But you want to use $1 in filename."/ge;
  0         0  
103              
104 0 0       0 my $content = $self->{xslate}->render($filename, {%$self, $params ? %$params : () });
105 0         0 $self->write_file_raw($dstname, $content);
106             }
107              
108             sub write_file {
109 0     0 1 0 my ($self, $filename, $template) = (shift, shift, shift);
110 0 0       0 Carp::croak("filename should not be reference") if ref $filename;
111              
112 0 0       0 $filename =~ s/<<([^>]+)>>/$self->{lc($1)} or die "$1 is not defined. But you want to use $1 in filename."/ge;
  0         0  
113              
114 0         0 my $content = $self->render_string($template, @_);
115 0         0 $self->write_file_raw($filename, $content);
116             }
117              
118             sub write_file_raw {
119 47     47 1 98 my ($self, $filename, $content, $input_mode) = @_;
120 47 50       92 Carp::croak("filename should not be reference") if ref $filename;
121 47   50     79 $input_mode ||= '>:encoding(utf-8)';
122              
123 47         159 infof("writing $filename");
124              
125 47         1438 my $dirname = dirname($filename);
126 47 50       1889 File::Path::mkpath($dirname) if $dirname;
127              
128 1 50   1   8 open my $ofh, $input_mode, $filename or die "Cannot open file: $filename: $!";
  1         3  
  1         8  
  47         2676  
129 47         18344 print {$ofh} $content;
  47         16230  
130 47         1534 close $ofh;
131             }
132              
133             sub load_assets {
134 1     1 0 3 my ($self) = @_;
135 1         5 for my $asset ($self->assets) {
136 9         29 $self->load_asset($asset);
137             }
138             }
139              
140             sub load_asset {
141 11     11 0 34 my ($self, $asset) = @_;
142 11         44 infof("Loading asset: $asset");
143 11         52 my $klass = Plack::Util::load_class($asset, 'Amon2::Setup::Asset');
144              
145 11 100       150 my $require_newline = $self->{tags} ? 1 : 0;
146 11         72 $self->{tags} .= $klass->tags;
147 11 50 66     105 $self->{tags} .= "\n" if $require_newline && $self->{tags} !~ /\n\z/;
148              
149             # $klass->run($self);
150             }
151              
152             sub write_asset {
153 2     2 0 15 my ($self, $asset, $base) = @_;
154 2 50       9 $asset || die "Missing asset name";
155 2   50     14 $base ||= 'static/';
156              
157 2         7 my $klass = Plack::Util::load_class($asset, 'Amon2::Setup::Asset');
158 2         67 my $files = $klass->files;
159 2         12 while (my ($fname, $content) = each %$files) {
160 47 100       232 my $layer = $fname =~ /\.js\z/ ? '>:encoding(utf-8)' : '>:raw';
161 47         255 $self->write_file_raw("$base/$fname", $content, $layer);
162             }
163             }
164              
165             sub write_assets {
166 0     0 0   my ($self, $dst) = @_;
167              
168 0           for my $asset ($self->assets) {
169 0           $self->write_asset($asset, $dst);
170             }
171             }
172              
173             sub create_cpanfile {
174 0     0 0   my ($self, $runtime_deps) = @_;
175 0   0       $runtime_deps ||= +{};
176              
177 0           my $cpanfile = Module::CPANfile->from_prereqs(
178             {
179             runtime => {
180             requires => {
181             'perl' => '5.010_001',
182             'Amon2' => $Amon2::VERSION,
183             'Text::Xslate' => '2.0009',
184             'Starlet' => '0.20',
185             'Module::Functions' => 2,
186             %$runtime_deps,
187             },
188             },
189             configure => {
190             requires => {
191             'Module::Build' => '0.38',
192             'Module::CPANfile' => '0.9010',
193             },
194             },
195             test => {
196             requires => {
197             'Test::More' => '0.98',
198             },
199             },
200             }
201             );
202 0           $self->write_file('cpanfile', $cpanfile->to_string());
203             }
204              
205             1;
206             __END__
207              
208             =head1 NAME
209              
210             Amon2::Setup::Flavor - Abstract base class for flavors.
211              
212             =head1 DESCRIPTION
213              
214             This is an abstract base class for flavors. But you don't need to inherit this class. Amon2 uses duck typing. You should implement only C<< Class->run >> method.
215              
216             In Amon2, flavor means setup script.
217              
218             =head1 METHODS
219              
220             This class provides some useful methods to write setup script.
221              
222             =over 4
223              
224             =item C<< $flavor->init() >>
225              
226             Hook point to initialize module directory.
227              
228             =item C<< $flavor->mkpath($dir) >>
229              
230             same as C<< `mkdir -p $dir` >>.
231              
232             =item C<< $flavor->write_file($fnametmpl, $template) >>
233              
234             C<< $fnametmpl >> will be replace with the parameters.
235              
236             Generate file using L<Text::Xslate>.
237              
238             For more details, read the source Luke! Or please write docs...
239              
240             =item C<< $flavor->write_file_raw($fname, $content) >>
241              
242             Write C<< $content >> to the C<< $fname >>.
243              
244             =back
245