AI-MicroStructure
view release on metacpan or search on metacpan
bin/remote.pl view on Meta::CPAN
package AI::MicroStructure::KnowHow;
use strict;
use AI::MicroStructure (); # do not export metaname and friends
#use AI::MicroStructure::RemoteKnowledge;
use List::Util qw( shuffle );
use Carp;
#our @ISA = qw( AI::MicroStructure::RemoteKnowledge );
sub init {
my $class = caller(0);
my $data = AI::MicroStructure->load_data($class);
no strict 'refs';
my $sep = ${"$class\::Separator"} ||= '/';
my $tail = qr/$sep?[^$sep]*$/;
# compute all categories
my @categories = ( [ $data->{names}, '' ] );
while ( my ( $h, $k ) = @{ shift @categories or []} ) {
if ( ref $h eq 'HASH' ) {
push @categories,
map { [ $h->{$_}, ( $k ? "$k$sep$_" : $_ ) ] } keys %$h;
}
else { # leaf
my @items = split /\s+/, $h;
while ($k) {
push @{ ${"$class\::KnowHow"}{$k} }, @items;
$k =~ s!$tail!!;
}
}
}
${"$class\::Default"} = $data->{default} || ':all';
${"$class\::Theme"} = ( split /::/, $class )[-1];
*{"$class\::import"} = sub {
my $callpkg = caller(0);
my $theme = ${"$class\::Theme"};
my $meta = $class->new;
*{"$callpkg\::meta$theme"} = sub { $meta->name(@_) };
};
${"$class\::meta"} = $class->new();
}
sub name {
my ( $self, $count ) = @_;
my $class = ref $self;
if ( !$class ) { # called as a class method!
$class = $self;
no strict 'refs';
$self = ${"$class\::meta"};
}
no strict 'refs';
if ( defined $count && $count !~ /A-Za-z/ && $count == 0 ) {
return wantarray
? shuffle @{ $self->{base} }
: scalar @{ $self->{base} };
}
$count ||= 1;
my $Knowledge = $self->{cache};
if ( @{ $self->{base} } ) {
push @$Knowledge, shuffle @{ $self->{base} } while @$Knowledge < $count;
}
splice( @$Knowledge, 0, $count );
}
sub new {
my $class = shift;
no strict 'refs';
my $self = bless { @_, cache => [] }, $class;
# compute some defaults
$self->{category} ||= ${"$class\::Default"};
# fall back to last resort (FIXME should we carp()?)
$self->{category} = ${"$class\::Default"}
if $self->{category} ne ':all'
&& !exists ${"$class\::KnowHow"}{ $self->{category} };
$self->_compute_base();
return $self;
}
sub _compute_base {
my ($self) = @_;
my $class = ref $self;
# compute the base Knowledge for this category
no strict 'refs';
my %seen;
$self->{base} = [
grep { !$seen{$_}++ }
map { @{ ${"$class\::KnowHow"}{$_} } }
$self->{category} eq ':all'
? ( keys %{"$class\::KnowHow"} )
: ( $self->{category} )
];
return;
}
sub category { $_[0]->{category} }
sub categories {
my $class = shift;
$class = ref $class if ref $class;
no strict 'refs';
return keys %{"$class\::KnowHow"};
}
sub has_category {
my ($class, $category) = @_;
$class = ref $class if ref $class;
no strict 'refs';
return exists ${"$class\::KnowHow"}{$category};
}
sub theme {
my $class = ref $_[0] || $_[0];
no strict 'refs';
return ${"$class\::Theme"};
}
1;
package AI::MicroStructure::KnowHow;
use strict;
use warnings;
use Carp;
# method that extracts the items from the remote content and returns them
sub extract {
my $class = ref $_[0] || $_[0];
no strict 'refs';
my $func = ${"$class\::Remote"}{extract};
# provide a very basic default
my $meth = ref $func eq 'CODE'
? sub { my %seen; return grep { !$seen{$_}++ } $func->( $_[1] ); }
: sub { return $_[1] }; # very basic default
# put the method in the subclass symbol table (at runtime)
*{"$class\::extract"} = $meth;
# now run the function^Wmethod
goto &$meth;
}
# methods related to the source URL
sub source {
my $class = ref $_[0] || $_[0];
no strict 'refs';
return ${"$class\::Remote"}{source};
}
sub sources {
my $class = ref $_[0] || $_[0];
no strict 'refs';
my $src = ${"$class\::Remote"}{source};
if ( ref $src eq 'ARRAY' ) {
return @$src;
}
elsif ( ref $src eq 'HASH' ) {
return
map { ref $_ ? @$_ : $_ } $_[1] ? $src->{ $_[1] } : values %$src;
}
return $src;
}
sub has_remoteKnowledge { return defined $_[0]->source(); }
# main method: return the Knowledge from the remote source
sub remote_Knowledge {
my $class = ref $_[0] || $_[0];
return unless $class->has_remoteKnowledge();
# check that we can access the network
eval {
require LWP::UserAgent;
die "version 5.802 required ($LWP::VERSION installed)\n"
if $LWP::VERSION < 5.802;
};
if ($@) {
carp "LWP::UserAgent not available: $@";
return;
}
# fetch the content
my @items;
my @srcs = $class->sources($_[1]);
my $ua = LWP::UserAgent->new( env_proxy => 1 );
foreach my $src (@srcs) {
my $res = $ua->request( HTTP::Request->new( GET => $src ) );
if ( ! $res->is_success() ) {
carp "Failed to get content at $src (" . $res->status_line();
return;
}
# extract, cleanup and return the data
# if decoding the content fails, we just deal with the raw content
push @items =>
$class->extract( $res->decoded_content() || $res->content() );
}
# return unique items
my %seen;
return grep { !$seen{$_}++ } @items;
}
#
# transformation subroutines
#
sub tr_nonword {
my $str = shift;
$str =~ tr/a-zA-Z0-9_/_/c;
$str;
}
sub tr_accent {
my $str = shift;
$str =~ tr{ÃÃÃÃÃÃ
ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃà áâãäåçèéêëìÃîïñòóôõöøùúûüýÿ}
{AAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy};
return $str;
}
my %utf2asc = (
"\xc3\x89" => 'E',
"\xc3\xa0" => 'a',
"\xc3\xa1" => 'a',
"\xc3\xa9" => 'e',
"\xc3\xaf" => 'i',
"\xc3\xad" => 'i',
"\xc3\xb6" => 'o',
"\xc3\xb8" => 'o',
"\xc5\xa0" => 'S',
"\x{0160}" => 'S',
# for pokemons
"\x{0101}" => 'a',
"\x{012b}" => 'i',
"\x{014d}" => 'o',
"\x{016b}" => 'u',
"\xe2\x99\x80" => 'female',
"\xe2\x99\x82" => 'male',
"\x{2640}" => 'female',
"\x{2642}" => 'male',
);
my $utf_re = qr/(@{[join( '|', sort keys %utf2asc )]})/;
sub tr_utf8_basic {
my $str = shift;
$str =~ s/$utf_re/$utf2asc{$1}/go;
return $str;
}
1;
package main;
use Data::Printer;
my $ps = AI::MicroStructure::KnowHow->new();
my @go = $ps->remote_Knowledge();
print @go;
p $ps;
1;
__DATA__
package AI::MicroStructure::Knowledge;
use strict;
use AI::MicroStructure (); # do not export metaname and friends
#use AI::MicroStructure::RemoteKnowledge;
use List::Util qw( shuffle );
use Carp;
our @ISA = qw( AI::MicroStructure::RemoteKnowledge );
sub init {
my ($self, $data) = @_;
my $class = caller(0);
$data ||= AI::MicroStructure->load_data($class);
croak "The optional argument to init() must be a hash reference"
if ref $data ne 'HASH';
no strict 'refs';
no warnings;
${"$class\::Theme"} = ( split /::/, $class )[-1];
@{"$class\::Knowledge"} = split /\s+/, $data->{names};
*{"$class\::import"} = sub {
my $callpkg = caller(0);
my $theme = ${"$class\::Theme"};
my $meta = $class->new();
*{"$callpkg\::meta$theme"} = sub { $meta->name(@_) };
};
${"$class\::meta"} = $class->new();
}
sub name {
my ( $self, $count ) = @_;
my $class = ref $self;
if( ! $class ) { # called as a class method!
$class = $self;
no strict 'refs';
$self = ${"$class\::meta"};
}
no strict 'refs';
if( defined $count && $count == 0 ) {
return
wantarray ? shuffle @{"$class\::Knowledge"} : scalar @{"$class\::Knowledge"};
}
$count ||= 1;
my $Knowledge = $self->{cache};
{
no strict 'refs';
if (@{"$class\::Knowledge"}) {
push @$Knowledge, shuffle @{"$class\::Knowledge"} while @$Knowledge < $count;
}
}
splice( @$Knowledge, 0, $count );
}
sub new {
my $class = shift;
bless { cache => [] }, $class;
}
sub theme {
my $class = ref $_[0] || $_[0];
no strict 'refs';
return ${"$class\::Theme"};
}
1;
package AI::MicroStructure::pornstars;
use strict;
#use AI::MicroStructure::KnowHow;
our @ISA = qw( AI::MicroStructure::KnowHow );
__PACKAGE__->init();
our %Remote = (
source => {
female => 'http://en.wikipedia.org/wiki/Knowledge_of_female_porn_stars',
male => 'http://en.wikipedia.org/wiki/Knowledge_of_male_porn_stars'
},
extract => sub {
return
map { AI::MicroStructure::RemoteKnowledge::tr_accent($_) }
map { AI::MicroStructure::RemoteKnowledge::tr_utf8_basic($_) }
grep { ! /^Knowledge_|_Groups$/ }
map { s/[-\s']/_/g; s/[."]//g; $_ }
$_[0]
=~ m{^<li>(?:<[^>]*>)?(.*?)(?:(?: ?[-,(<]| aka | see ).*)?</li>}mig
},
,
);
1;
package main;
use Data::Printer;
my $ps = AI::MicroStructure::pornstars->new();
my @go = $ps->extract();
p @go;
p $ps;
1;
__DATA__
# names female
Abigail_Clayton
Adara_Michaels
Addison_Rose
Adele_Stevens
Adriana_Sage
Adrienne_Bellaire
Africa_Sexxx
Ai_Iijima
Aimee_Sweet
Aja
Akira_Fubuki
Alana_Evans
Alaura_Eden
Alex_Dane
Alex_Jordan
Alex_Taylor
Alexa_May
Alexa_Rae
Alexa_Weix
Alexandra_Nice
Alexandra_Silk
Alexis_Amore
Alexis_DeVell
Alexis_Malone
Alexis_May
Alicia_Alighatti
Alicia_Monet
Alicia_Rhodes
Alicia_Rio
Alisha_Klass
Alison_Angel
Aliyah_Yi
Allie
Allie_Sin
Allison_Wyte
Ally_Mac_Tyana
Allysin_Chaynes
Amber_Lynn
( run in 1.230 second using v1.01-cache-2.11-cpan-39bf76dae61 )