JS-YUI-Loader

 view release on metacpan or  search on metacpan

lib/JS/YUI/Loader/Manifest.pm  view on Meta::CPAN

use Moose;

use Algorithm::Dependency::Ordered;
use Algorithm::Dependency::Source::HoA;
# TODO use Hash::Dirty

has catalog => qw/is ro required 1 isa JS::YUI::Loader::Catalog/;
has loader => qw/is ro isa JS::YUI::Loader/;
has collection => qw/is ro required 1 lazy 1/, default => sub { {} };
has dirty => qw/is rw required 1 lazy 1 default 1/;
has include => qw/is ro required 1 lazy 1/, default => sub {
    my $self = shift;
    require JS::YUI::Loader::IncludeExclude;
    return JS::YUI::Loader::IncludeExclude->new(manifest => $self, do_include => 1);
};
has exclude => qw/is ro required 1 lazy 1/, default => sub {
    my $self = shift;
    require JS::YUI::Loader::IncludeExclude;
    return JS::YUI::Loader::IncludeExclude->new(manifest => $self, do_include => 0);
};

sub schedule {
    my $self = shift;
    my @schedule = $self->_calculate;
    return wantarray ? @schedule : \@schedule;
}

my $dependency;
sub _calculate {
    my $self = shift;
    if (! $self->{schedule} || $self->dirty) {
        $dependency ||= Algorithm::Dependency::Ordered->new(
            source => Algorithm::Dependency::Source::HoA->new($self->catalog->dependency_graph),
        );
        my $schedule = $dependency->schedule(keys %{ $self->collection }) || [];
        my @schedule = map { $self->catalog->entry($_) } @$schedule;
        my (@css_schedule, @js_schedule);
        for (@schedule) {
            if ($_->css) {
                push @css_schedule, $_;
            }
            else {
                push @js_schedule, $_;
            }
        }
#        my @css_schedule = grep { $_->css } @schedule;
#        my @js_schedule = grep { $_->js } @schedule;
        @css_schedule = sort { $a->rank <=> $b->rank } @css_schedule;

        for (@js_schedule) {
            push @css_schedule, $self->catalog->entry($_->name . "-skin") if $_->skin;
        }
    
        $self->{schedule} = [ map { $_->name } @css_schedule, @js_schedule ];
    }
    return @{ $self->{schedule} };
}

sub parse {
    my $self = shift;
    my @_collection = map { split m/\n/ } @_;

    my @collection;
    for (@_collection) {
        next if m/^\s*#/;
        next if m/^\s*<!--/;
        next if m/^\s*$/;
        chomp;

        my $name = $_;

        if      ($name =~ m/^\s*<script/) { ($name) = $name =~ m{src="(?:[^"]*)([^/]+)\.js"} }
        elsif   ($name =~ m/^\s*<link/)   { ($name) = $name =~ m{href="(?:[^"]*)([^/]+)\.css"} }

        $name =~ s/-beta\b//;
        $name =~ s/-min\b//;
        $name =~ s/-debug\b//;

        push @collection, $name;

    }

    $self->select(@collection);
}

sub select {
    my $self = shift;
    for my $name (@_) {
        warn "Can't find \"$name\" in the catalog" and next unless $self->catalog->entry($name);
        $self->collection->{$name} = "";
    }
}

sub clear {
    my $self = shift;
    $self->{collection} = {};
}

1;

__END__

BEGIN { 
    my $json = JSON->new;
    my $catalog = $json->decode(map { local $_ = $_; s/'/"/g; $_ } (<<_END_));
{
        'animation': {
            'type': 'js',
            'path': 'animation/animation-min.js',
            'requires': ['dom', 'event']
        },

        'autocomplete': {
            'type': 'js',
            'path': 'autocomplete/autocomplete-min.js',
            'requires': ['dom', 'event'],
            'optional': ['connection', 'animation'],
            'skinnable': true
        },

        'base': {



( run in 1.461 second using v1.01-cache-2.11-cpan-71847e10f99 )