add files
|
1 |
package Mojo::Loader; |
2 |
use Mojo::Base -base; |
|
3 | ||
4 |
use File::Basename 'fileparse'; |
|
5 |
use File::Spec::Functions qw(catdir catfile splitdir); |
|
6 |
use Mojo::Exception; |
|
7 |
use Mojo::Util qw(b64_decode class_to_path); |
|
8 | ||
9 |
my (%BIN, %CACHE); |
|
10 | ||
11 |
sub data { $_[1] ? $_[2] ? _all($_[1])->{$_[2]} : _all($_[1]) : undef } |
|
12 | ||
13 |
sub is_binary { keys %{_all($_[1])} ? !!$BIN{$_[1]}{$_[2]} : undef } |
|
14 | ||
15 |
sub load { |
|
16 |
my ($self, $module) = @_; |
|
17 | ||
18 |
# Check module name |
|
19 |
return 1 if !$module || $module !~ /^\w(?:[\w:']*\w)?$/; |
|
20 | ||
21 |
# Load |
|
22 |
return undef if $module->can('new') || eval "require $module; 1"; |
|
23 | ||
24 |
# Exists |
|
25 |
return 1 if $@ =~ /^Can't locate \Q@{[class_to_path $module]}\E in \@INC/; |
|
26 | ||
27 |
# Real error |
|
28 |
return Mojo::Exception->new($@); |
|
29 |
} |
|
30 | ||
31 |
sub search { |
|
32 |
my ($self, $namespace) = @_; |
|
33 | ||
34 |
my (@modules, %found); |
|
35 |
for my $directory (@INC) { |
|
36 |
next unless -d (my $path = catdir $directory, split(/::|'/, $namespace)); |
|
37 | ||
38 |
# List "*.pm" files in directory |
|
39 |
opendir(my $dir, $path); |
|
40 |
for my $file (grep /\.pm$/, readdir $dir) { |
|
41 |
next if -d catfile splitdir($path), $file; |
|
42 |
my $class = "${namespace}::" . fileparse $file, qr/\.pm/; |
|
43 |
push @modules, $class unless $found{$class}++; |
|
44 |
} |
|
45 |
} |
|
46 | ||
47 |
return \@modules; |
|
48 |
} |
|
49 | ||
50 |
sub _all { |
|
51 |
my $class = shift; |
|
52 | ||
53 |
my $handle = do { no strict 'refs'; \*{"${class}::DATA"} }; |
|
54 |
return $CACHE{$class} || {} if $CACHE{$class} || !fileno $handle; |
|
55 |
seek $handle, 0, 0; |
|
56 |
my $data = join '', <$handle>; |
|
57 | ||
58 |
# Ignore everything before __DATA__ (Windows will seek to start of file) |
|
59 |
$data =~ s/^.*\n__DATA__\r?\n/\n/s; |
|
60 | ||
61 |
# Ignore everything after __END__ |
|
62 |
$data =~ s/\n__END__\r?\n.*$/\n/s; |
|
63 | ||
64 |
# Split files |
|
65 |
(undef, my @files) = split /^@@\s*(.+?)\s*\r?\n/m, $data; |
|
66 | ||
67 |
# Find data |
|
68 |
my $all = $CACHE{$class} = {}; |
|
69 |
while (@files) { |
|
70 |
my ($name, $data) = splice @files, 0, 2; |
|
71 |
$all->{$name} = $name =~ s/\s*\(\s*base64\s*\)$// |
|
72 |
&& ++$BIN{$class}{$name} ? b64_decode($data) : $data; |
|
73 |
} |
|
74 | ||
75 |
return $all; |
|
76 |
} |
|
77 | ||
78 |
1; |
|
79 | ||
80 |
=encoding utf8 |
|
81 | ||
82 |
=head1 NAME |
|
83 | ||
84 |
Mojo::Loader - Loader |
|
85 | ||
86 |
=head1 SYNOPSIS |
|
87 | ||
88 |
use Mojo::Loader; |
|
89 | ||
90 |
# Find modules in a namespace |
|
91 |
my $loader = Mojo::Loader->new; |
|
92 |
for my $module (@{$loader->search('Some::Namespace')}) { |
|
93 | ||
94 |
# Load them safely |
|
95 |
my $e = $loader->load($module); |
|
96 |
warn qq{Loading "$module" failed: $e} and next if ref $e; |
|
97 | ||
98 |
# And extract files from the DATA section |
|
99 |
say $loader->data($module, 'some_file.txt'); |
|
100 |
} |
|
101 | ||
102 |
=head1 DESCRIPTION |
|
103 | ||
104 |
L<Mojo::Loader> is a class loader and plugin framework. |
|
105 | ||
106 |
=head1 METHODS |
|
107 | ||
108 |
L<Mojo::Loader> inherits all methods from L<Mojo::Base> and implements the |
|
109 |
following new ones. |
|
110 | ||
111 |
=head2 data |
|
112 | ||
113 |
my $all = $loader->data('Foo::Bar'); |
|
114 |
my $index = $loader->data('Foo::Bar', 'index.html'); |
|
115 | ||
116 |
Extract embedded file from the C<DATA> section of a class. |
|
117 | ||
118 |
say for keys %{$loader->data('Foo::Bar')}; |
|
119 | ||
120 |
=head2 is_binary |
|
121 | ||
122 |
my $bool = $loader->is_binary('Foo::Bar', 'test.png'); |
|
123 | ||
124 |
Check if embedded file from the C<DATA> section of a class was Base64 encoded. |
|
125 | ||
126 |
=head2 load |
|
127 | ||
128 |
my $e = $loader->load('Foo::Bar'); |
|
129 | ||
130 |
Load a class and catch exceptions. Note that classes are checked for a C<new> |
|
131 |
method to see if they are already loaded. |
|
132 | ||
133 |
if (my $e = $loader->load('Foo::Bar')) { |
|
134 |
die ref $e ? "Exception: $e" : 'Not found!'; |
|
135 |
} |
|
136 | ||
137 |
=head2 search |
|
138 | ||
139 |
my $modules = $loader->search('MyApp::Namespace'); |
|
140 | ||
141 |
Search for modules in a namespace non-recursively. |
|
142 | ||
143 |
=head1 SEE ALSO |
|
144 | ||
145 |
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>. |
|
146 | ||
147 |
=cut |