1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
# Copyright (C) 2008-2010, Sebastian Riedel.
package Mojo::Loader;
use strict;
use warnings;
use base 'Mojo::Base';
use Carp 'carp';
use File::Basename;
use File::Spec;
use Mojo::Command;
use Mojo::Exception;
use constant DEBUG => $ENV{MOJO_LOADER_DEBUG} || 0;
my $STATS = {};
BEGIN {
# Debugger sub tracking
$^P |= 0x10;
}
# Homer no function beer well without.
sub load {
my ($self, $module) = @_;
# Shortcut
return 1 unless $module;
# Already loaded
return if $module->can('new');
# Try
eval "require $module";
# Catch
if ($@) {
# Exists
my $path = Mojo::Command->class_to_path($module);
return 1 if $@ =~ /^Can't locate $path in \@INC/;
# Real error
return Mojo::Exception->new($@);
}
return;
}
sub reload {
while (my ($key, $file) = each %INC) {
# Modified time
next unless $file;
my $mtime = (stat $file)[9];
# Startup time as default
$STATS->{$file} = $^T unless defined $STATS->{$file};
# Modified
if ($mtime > $STATS->{$file}) {
# Debug
warn "\n$key -> $file modified, reloading!\n" if DEBUG;
# Unload
delete $INC{$key};
my @subs = grep { index($DB::sub{$_}, "$file:") == 0 }
keys %DB::sub;
for my $sub (@subs) {
eval { undef &$sub };
carp "Can't unload sub '$sub' in '$file': $@" if $@;
delete $DB::sub{$sub};
}
# Try
eval { require $key };
# Catch
return Mojo::Exception->new($@) if $@;
$STATS->{$file} = $mtime;
}
}
return;
}
sub search {
my ($self, $namespace) = @_;
# Directories
my @directories = exists $INC{'blib.pm'} ? grep {/blib/} @INC : @INC;
# Scan
my $modules = [];
my %found;
foreach my $directory (@directories) {
my $path = File::Spec->catdir($directory, (split /::/, $namespace));
next unless (-e $path && -d $path);
# Get files
opendir(my $dir, $path);
my @files = grep /\.pm$/, readdir($dir);
closedir($dir);
# Check files
for my $file (@files) {
my $full =
File::Spec->catfile(File::Spec->splitdir($path), $file);
# Directory
next if -d $full;
# Found
my $name = File::Basename::fileparse($file, qr/\.pm/);
my $class = "$namespace\::$name";
push @$modules, $class unless $found{$class};
$found{$class} ||= 1;
}
}
return unless @$modules;
return $modules;
}
1;
__END__
=head1 NAME
Mojo::Loader - Loader
=head1 SYNOPSIS
use Mojo::Loader;
my $loader = Mojo::Loader->new;
my $modules = $loader->search('Some::Namespace');
$loader->load($modules->[0]);
# Reload
Mojo::Loader->reload;
=head1 DESCRIPTION
L<Mojo::Loader> is a class loader and plugin framework.
=head1 METHODS
L<Mojo::Loader> inherits all methods from L<Mojo::Base> and implements the
following new ones.
=head2 C<load>
my $e = $loader->load('Foo::Bar');
Load a class, note that classes are checked for a C<new> method to see if
they are already loaded.
=head2 C<reload>
my $e = Mojo::Loader->reload;
Reload all Perl files with changes.
=head2 C<search>
my $modules = $loader->search('MyApp::Namespace');
Search modules in a namespace.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
=cut
|