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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
use 5.008001;
use strict;
use warnings;
package CPAN::Common::Index::Mux::Ordered;
# ABSTRACT: Consult indices in order and return the first result
our $VERSION = '0.010';
use parent 'CPAN::Common::Index';
use Class::Tiny qw/resolvers/;
use Module::Load ();
#pod =attr resolvers
#pod
#pod An array reference of CPAN::Common::Index::* objects
#pod
#pod =cut
sub BUILD {
my $self = shift;
my $resolvers = $self->resolvers;
$resolvers = [] unless defined $resolvers;
if ( ref $resolvers ne 'ARRAY' ) {
Carp::croak("The 'resolvers' argument must be an array reference");
}
for my $r (@$resolvers) {
if ( !eval { $r->isa("CPAN::Common::Index") } ) {
Carp::croak("Resolver '$r' is not a CPAN::Common::Index object");
}
}
$self->resolvers($resolvers);
return;
}
#pod =method assemble
#pod
#pod $index = CPAN::Common::Index::Mux::Ordered->assemble(
#pod MetaDB => {},
#pod Mirror => { mirror => "http://www.cpan.org" },
#pod );
#pod
#pod This class method provides a shorthand for constructing a multiplexer.
#pod The arguments must be pairs of subclass suffixes and arguments. For
#pod example, "MetaDB" means to use "CPAN::Common::Index::MetaDB". Empty
#pod arguments must be given as an empty hash reference.
#pod
#pod =cut
sub assemble {
my ( $class, @backends ) = @_;
my @resolvers;
while (@backends) {
my ( $subclass, $config ) = splice @backends, 0, 2;
my $full_class = "CPAN::Common::Index::${subclass}";
eval { Module::Load::load($full_class); 1 }
or Carp::croak($@);
my $object = $full_class->new($config);
push @resolvers, $object;
}
return $class->new( { resolvers => \@resolvers } );
}
sub validate_attributes {
my ($self) = @_;
my $resolvers = $self->resolvers;
return 1;
}
# have to think carefully about the sematics of regex search when indices
# are stacked; only one result for any given package (or package/version)
sub search_packages {
my ( $self, $args ) = @_;
Carp::croak("Argument to search_packages must be hash reference")
unless ref $args eq 'HASH';
my @found;
if ( $args->{name} and ref $args->{name} eq '' ) {
# looking for exact match, so we just want the first hit
for my $source ( @{ $self->resolvers } ) {
if ( my @result = $source->search_packages($args) ) {
# XXX double check against remaining $args
push @found, @result;
last;
}
}
}
else {
# accumulate results from all resolvers
my %seen;
for my $source ( @{ $self->resolvers } ) {
my @result = $source->search_packages($args);
push @found, grep { !$seen{ $_->{package} }++ } @result;
}
}
return wantarray ? @found : $found[0];
}
# have to think carefully about the sematics of regex search when indices
# are stacked; only one result for any given package (or package/version)
sub search_authors {
my ( $self, $args ) = @_;
Carp::croak("Argument to search_authors must be hash reference")
unless ref $args eq 'HASH';
my @found;
if ( $args->{name} and ref $args->{name} eq '' ) {
# looking for exact match, so we just want the first hit
for my $source ( @{ $self->resolvers } ) {
if ( my @result = $source->search_authors($args) ) {
# XXX double check against remaining $args
push @found, @result;
last;
}
}
}
else {
# accumulate results from all resolvers
my %seen;
for my $source ( @{ $self->resolvers } ) {
my @result = $source->search_authors($args);
push @found, grep { !$seen{ $_->{package} }++ } @result;
}
}
return wantarray ? @found : $found[0];
}
1;
# vim: ts=4 sts=4 sw=4 et:
__END__
=pod
=encoding UTF-8
=head1 NAME
CPAN::Common::Index::Mux::Ordered - Consult indices in order and return the first result
=head1 VERSION
version 0.010
=head1 SYNOPSIS
use CPAN::Common::Index::Mux::Ordered;
use Data::Dumper;
$index = CPAN::Common::Index::Mux::Ordered->assemble(
MetaDB => {},
Mirror => { mirror => "http://cpan.cpantesters.org" },
);
=head1 DESCRIPTION
This module multiplexes multiple CPAN::Common::Index objects, returning
results in order.
For exact match queries, the first result is returned. For search queries,
results from each index object are concatenated.
=head1 ATTRIBUTES
=head2 resolvers
An array reference of CPAN::Common::Index::* objects
=head1 METHODS
=head2 assemble
$index = CPAN::Common::Index::Mux::Ordered->assemble(
MetaDB => {},
Mirror => { mirror => "http://www.cpan.org" },
);
This class method provides a shorthand for constructing a multiplexer.
The arguments must be pairs of subclass suffixes and arguments. For
example, "MetaDB" means to use "CPAN::Common::Index::MetaDB". Empty
arguments must be given as an empty hash reference.
=for Pod::Coverage attributes validate_attributes search_packages search_authors BUILD
=head1 AUTHOR
David Golden <dagolden@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2013 by David Golden.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004
=cut
|