Skip to content

Commit

Permalink
fixed support for binary files in inflate command
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Sep 14, 2013
1 parent cbc1752 commit a740baf
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 55 deletions.
4 changes: 4 additions & 0 deletions Changes
@@ -1,4 +1,8 @@

4.38 2013-09-14
- Added is_binary method to Mojo::Loader.
- Fixed support for binary files in inflate command.

4.37 2013-09-13
- Improved design of built-in templates.

Expand Down
35 changes: 23 additions & 12 deletions lib/Mojo/Loader.pm
Expand Up @@ -6,11 +6,16 @@ use File::Spec::Functions qw(catdir catfile splitdir);
use Mojo::Exception;
use Mojo::Util qw(b64_decode class_to_path);

my %CACHE;
my (%BIN, %CACHE);

sub data {
my ($self, $class, $data) = @_;
return $class ? $data ? _all($class)->{$data} : _all($class) : undef;
my ($self, $class, $name) = @_;
return $class ? $name ? _all($class)->{$name} : _all($class) : undef;
}

sub is_binary {
my ($self, $class, $name) = @_;
return keys %{_all($class)} ? !!$BIN{$class}{$name} : undef;
}

sub load {
Expand Down Expand Up @@ -56,25 +61,25 @@ sub _all {
my $handle = do { no strict 'refs'; \*{"${class}::DATA"} };
return $CACHE{$class} || {} unless fileno $handle;
seek $handle, 0, 0;
my $content = join '', <$handle>;
my $data = join '', <$handle>;
close $handle;

# Ignore everything before __DATA__ (Windows will seek to start of file)
$content =~ s/^.*\n__DATA__\r?\n/\n/s;
$data =~ s/^.*\n__DATA__\r?\n/\n/s;

# Ignore everything after __END__
$content =~ s/\n__END__\r?\n.*$/\n/s;
$data =~ s/\n__END__\r?\n.*$/\n/s;

# Split files
my @data = split /^@@\s*(.+?)\s*\r?\n/m, $content;
shift @data;
my @files = split /^@@\s*(.+?)\s*\r?\n/m, $data;
shift @files;
# Find data
my $all = $CACHE{$class} = {};
while (@data) {
my ($name, $content) = splice @data, 0, 2;
$content = b64_decode $content if $name =~ s/\s*\(\s*base64\s*\)$//;
$all->{$name} = $content;
while (@files) {
my ($name, $data) = splice @files, 0, 2;
$all->{$name} = $name =~ s/\s*\(\s*base64\s*\)$//
&& ++$BIN{$class}{$name} ? b64_decode($data) : $data;
}

return $all;
Expand Down Expand Up @@ -122,6 +127,12 @@ Extract embedded file from the C<DATA> section of a class.
say for keys %{$loader->data('Foo::Bar')};
=head2 is_binary
my $success = $loader->is_binary('Foo::Bar', 'test.png');
Check if embedded file from the C<DATA> section of a class was Base64 encoded.
=head2 load
my $e = $loader->load('Foo::Bar');
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious.pm
Expand Up @@ -41,7 +41,7 @@ has static => sub { Mojolicious::Static->new };
has types => sub { Mojolicious::Types->new };

our $CODENAME = 'Top Hat';
our $VERSION = '4.37';
our $VERSION = '4.38';

sub AUTOLOAD {
my $self = shift;
Expand Down
15 changes: 9 additions & 6 deletions lib/Mojolicious/Command/inflate.pm
Expand Up @@ -14,14 +14,17 @@ sub run {
my %all;
my $app = $self->app;
my $loader = Mojo::Loader->new;
%all = (%{$loader->data($_)}, %all)
for @{$app->renderer->classes}, @{$app->static->classes};
for my $class (@{$app->renderer->classes}, @{$app->static->classes}) {
while (my ($name, $data) = each %{$loader->data($class)}) {
$all{$name}
= $loader->is_binary($class, $name) ? $data : encode('UTF-8', $data);
}
}

# Turn them into real files
for my $file (keys %all) {
my $prefix = $file =~ /\.\w+\.\w+$/ ? 'templates' : 'public';
my $path = $self->rel_file("$prefix/$file");
$self->write_file($path, encode('UTF-8', $all{$file}));
for my $name (keys %all) {
my $prefix = $name =~ /\.\w+\.\w+$/ ? 'templates' : 'public';
$self->write_file($self->rel_file("$prefix/$name"), $all{$name});
}
}

Expand Down
93 changes: 57 additions & 36 deletions t/mojo/loader.t
Expand Up @@ -82,45 +82,66 @@ is $loader->load('::Mojolicious::Lite::'), 1, 'nothing to load';
is $loader->load('Mojolicious::Lite'), undef, 'loaded successfully';

# UNIX DATA templates
my $unix = "@@ template1\nFirst Template\n@@ template2\r\nSecond Template\n";
open my $data, '<', \$unix;
no strict 'refs';
*{"Example::Package::UNIX::DATA"} = $data;
is $loader->data('Example::Package::UNIX', 'template1'), "First Template\n",
'right template';
is $loader->data('Example::Package::UNIX', 'template2'), "Second Template\n",
'right template';
is_deeply [sort keys %{$loader->data('Example::Package::UNIX')}],
[qw(template1 template2)], 'right DATA files';
close $data;
{
my $unix = "@@ template1\nFirst Template\n@@ template2\r\nSecond Template\n";
open my $data, '<', \$unix;
no strict 'refs';
*{"Example::Package::UNIX::DATA"} = $data;
ok !$loader->is_binary('Example::Package::UNIX', 'template1'),
'file is not binary';
is $loader->data('Example::Package::UNIX', 'template1'), "First Template\n",
'right template';
is $loader->data('Example::Package::UNIX', 'template2'),
"Second Template\n", 'right template';
is_deeply [sort keys %{$loader->data('Example::Package::UNIX')}],
[qw(template1 template2)], 'right DATA files';
}

# Windows DATA templates
my $windows
= "@@ template3\r\nThird Template\r\n@@ template4\r\nFourth Template\r\n";
open $data, '<', \$windows;
no strict 'refs';
*{"Example::Package::Windows::DATA"} = $data;
is $loader->data('Example::Package::Windows', 'template3'),
"Third Template\r\n", 'right template';
is $loader->data('Example::Package::Windows', 'template4'),
"Fourth Template\r\n", 'right template';
is_deeply [sort keys %{$loader->data('Example::Package::Windows')}],
[qw(template3 template4)], 'right DATA files';
close $data;
{
my $windows
= "@@ template3\r\nThird Template\r\n@@ template4\r\nFourth Template\r\n";
open my $data, '<', \$windows;
no strict 'refs';
*{"Example::Package::Windows::DATA"} = $data;
is $loader->data('Example::Package::Windows', 'template3'),
"Third Template\r\n", 'right template';
is $loader->data('Example::Package::Windows', 'template4'),
"Fourth Template\r\n", 'right template';
is_deeply [sort keys %{$loader->data('Example::Package::Windows')}],
[qw(template3 template4)], 'right DATA files';
}

# Mixed whitespace
my $mixed = "@\@template5\n5\n\n@@ template6\n6\n@@ template7\n7";
open $data, '<', \$mixed;
no strict 'refs';
*{"Example::Package::Mixed::DATA"} = $data;
is $loader->data('Example::Package::Mixed', 'template5'), "5\n\n",
'right template';
is $loader->data('Example::Package::Mixed', 'template6'), "6\n",
'right template';
is $loader->data('Example::Package::Mixed', 'template7'), '7',
'right template';
is_deeply [sort keys %{$loader->data('Example::Package::Mixed')}],
[qw(template5 template6 template7)], 'right DATA files';
close $data;
{
my $mixed = "@\@template5\n5\n\n@@ template6\n6\n@@ template7\n7";
open my $data, '<', \$mixed;
no strict 'refs';
*{"Example::Package::Mixed::DATA"} = $data;
is $loader->data('Example::Package::Mixed', 'template5'), "5\n\n",
'right template';
is $loader->data('Example::Package::Mixed', 'template6'), "6\n",
'right template';
is $loader->data('Example::Package::Mixed', 'template7'), '7',
'right template';
is_deeply [sort keys %{$loader->data('Example::Package::Mixed')}],
[qw(template5 template6 template7)], 'right DATA files';
}

# Base64
{
my $b64 = "@\@test.bin (base64)\n4pml";
open my $data, '<', \$b64;
no strict 'refs';
*{"Example::Package::Base64::DATA"} = $data;
ok !$loader->is_binary('Example::Package::DoesNotExist', 'test.bin'),
'file is not binary';
ok $loader->is_binary('Example::Package::Base64', 'test.bin'),
'file is binary';
is $loader->data('Example::Package::Base64', 'test.bin'), "\xe2\x99\xa5",
'right template';
is_deeply [sort keys %{$loader->data('Example::Package::Base64')}],
['test.bin'], 'right DATA files';
}

done_testing();

0 comments on commit a740baf

Please sign in to comment.