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   1287 use strict;
  3         7  
  3         88  
2 3     3   15 use warnings;
  3         7  
  3         71  
3 3     3   16 use utf8;
  3         3  
  3         18  
4              
5             package Amon2::Setup::Flavor;
6 3     3   1759 use Text::Xslate;
  3         36920  
  3         177  
7 3     3   26 use File::Spec;
  3         8  
  3         62  
8 3     3   18 use File::Basename;
  3         13  
  3         306  
9 3     3   25 use File::Path ();
  3         5  
  3         90  
10 3     3   1521 use Amon2;
  3         9  
  3         97  
11 3     3   19 use Plack::Util ();
  3         5  
  3         39  
12 3     3   15 use Carp ();
  3         4  
  3         54  
13 3     3   1225 use Amon2::Trigger;
  3         9  
  3         196  
14 3     3   21 use mro;
  3         6  
  3         16  
15 3     3   1596 use File::ShareDir ();
  3         78419  
  3         114  
16 3     3   1570 use Module::CPANfile 0.9020;
  3         43067  
  3         4628  
17              
18             sub assets {
19 1     1 0 3 my $self = shift;
20              
21 1         8 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 102 my $caller = do {
30 58         102 my $x;
31 58         153 for (1..10) {
32 123         234 $x = caller($_);
33 123 100       296 last if $x ne __PACKAGE__;
34             }
35 58         114 $x;
36             };
37 58         126 $caller =~ s/^Amon2::Setup:://;
38 58         1957 print "[$caller] ";
39 58 50       532 @_==1 ? print(@_) : printf(@_);
40 58         394 print "\n";
41             }
42              
43             sub new {
44 1     1 0 1667 my $class = shift;
45 1 50       10 my %args = @_ ==1 ? %{$_[0]} : @_;
  0         0  
46              
47 1         4 $args{amon2_version} = $Amon2::VERSION;
48              
49 1         22 for (qw/module/) {
50 1 50       16 die "Missing mandatory parameter $_" unless exists $args{$_};
51             }
52 1         5 $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         5 $args{dist} = join "-", @pkg;
59 1         4 $args{path} = join "/", @pkg;
60 1         7 my $self = bless { %args }, $class;
61 1         6 $self->{xslate} = $self->_build_xslate();
62 1         7 $self->load_assets();
63 1         11 $self;
64             }
65              
66             sub _build_xslate {
67 1     1   2 my $self = shift;
68              
69 1         8 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         8891 $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 105 my ($self, $filename, $content, $input_mode) = @_;
120 47 50       105 Carp::croak("filename should not be reference") if ref $filename;
121 47   50     89 $input_mode ||= '>:encoding(utf-8)';
122              
123 47         155 infof("writing $filename");
124              
125 47         1502 my $dirname = dirname($filename);
126 47 50       1990 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         9  
  47         2732  
129 47         18778 print {$ofh} $content;
  47         15856  
130 47         1501 close $ofh;
131             }
132              
133             sub load_assets {
134 1     1 0 3 my ($self) = @_;
135 1         12 for my $asset ($self->assets) {
136 9         29 $self->load_asset($asset);
137             }
138             }
139              
140             sub load_asset {
141 11     11 0 35 my ($self, $asset) = @_;
142 11         43 infof("Loading asset: $asset");
143 11         52 my $klass = Plack::Util::load_class($asset, 'Amon2::Setup::Asset');
144              
145 11 100       163 my $require_newline = $self->{tags} ? 1 : 0;
146 11         81 $self->{tags} .= $klass->tags;
147 11 50 66     119 $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 17 my ($self, $asset, $base) = @_;
154 2 50       10 $asset || die "Missing asset name";
155 2   50     19 $base ||= 'static/';
156              
157 2         10 my $klass = Plack::Util::load_class($asset, 'Amon2::Setup::Asset');
158 2         60 my $files = $klass->files;
159 2         15 while (my ($fname, $content) = each %$files) {
160 47 100       280 my $layer = $fname =~ /\.js\z/ ? '>:encoding(utf-8)' : '>:raw';
161 47         242 $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