File Coverage

blib/lib/Acme/MetaSyntactic/RemoteList.pm
Criterion Covered Total %
statement 65 72 90.2
branch 14 22 63.6
condition 10 24 41.6
subroutine 15 16 93.7
pod 8 8 100.0
total 112 142 78.8


line stmt bran cond sub pod time code
1             =encoding iso-8859-1
2              
3             =cut
4              
5             package Acme::MetaSyntactic::RemoteList;
6 19     19   83 use strict;
  19         26  
  19         531  
7 19     19   74 use warnings;
  19         28  
  19         540  
8 19     19   78 use Carp;
  19         41  
  19         2221  
9              
10             our $VERSION = '1.003';
11              
12             # method that extracts the items from the remote content and returns them
13             sub extract {
14 3   66 3 1 284 my $class = ref $_[0] || $_[0];
15 19     19   97 no strict 'refs';
  19         21  
  19         3776  
16 3         5 my $func = ${"$class\::Remote"}{extract};
  3         17  
17              
18             # provide a very basic default
19             my $meth = ref $func eq 'CODE'
20 10     10   4415 ? sub { my %seen; return grep { !$seen{$_}++ } $func->( $_[1], $_[2] ); }
  10         97  
  46         262  
21 3 100   1   28 : sub { return $_[1] }; # very basic default
  1         3  
22              
23             # put the method in the subclass symbol table (at runtime)
24 3         5 *{"$class\::extract"} = $meth;
  3         13  
25              
26             # now run the function^Wmethod
27 3         15 goto &$meth;
28             }
29              
30             # methods related to the source URL
31             sub source {
32 19   66 19 1 113 my $class = ref $_[0] || $_[0];
33 19     19   106 no strict 'refs';
  19         23  
  19         1486  
34              
35 19         17 return ${"$class\::Remote"}{source};
  19         150  
36             }
37              
38             sub sources {
39 6   33 6 1 27 my $class = ref $_[0] || $_[0];
40 19     19   79 no strict 'refs';
  19         33  
  19         14397  
41              
42 6         10 my $src = ${"$class\::Remote"}{source};
  6         20  
43 6 100       22 if ( ref $src eq 'ARRAY' ) {
    50          
44 3         15 return @$src;
45             }
46             elsif ( ref $src eq 'HASH' ) {
47             return grep $_,
48             defined $_[1] && $_[1] ne ':all'
49 0         0 ? ref $_[1] ? @$src{ @{ $_[1] } }
50 0 0 0     0 : $src->{ $_[1] }
    0          
51             : values %$src;
52             }
53 3         9 return $src;
54             }
55              
56 15     15 1 142 sub has_remotelist { return defined $_[0]->source(); }
57              
58             # main method: return the list from the remote source
59             sub remote_list {
60 7   66 7 1 44 my $class = ref $_[0] || $_[0];
61 7 100       25 return unless $class->has_remotelist();
62              
63             # check that we can access the network
64 6         35 eval {
65 6         61 require LWP::UserAgent;
66 6 50       33 die "version 5.802 required ($LWP::VERSION installed)\n"
67             if $LWP::VERSION < 5.802;
68             };
69 6 50       27 if ($@) {
70 0         0 carp "LWP::UserAgent not available: $@";
71 0         0 return;
72             }
73              
74             # figure out the default category (for an instance)
75 6 100 33     59 my $category = ref $_[0] ? $_[1] || $_[0]->{category} : $_[1];
76              
77             # fetch the content
78 6         64 my @items;
79 6         30 my @srcs = $class->sources($category);
80 6         51 my $ua = LWP::UserAgent->new( env_proxy => 1 );
81 6         35690 foreach my $src (@srcs) {
82 8 50       64 my $request = HTTP::Request->new(
83             ref $src
84             ? ( POST => $src->[0],
85             [ content_type => 'application/x-www-form-urlencoded' ],
86             $src->[1]
87             )
88             : ( GET => $src )
89             );
90              
91 8         11595 my $res = $ua->request( $request );
92 8 100       36845 if ( ! $res->is_success() ) {
93 2         30 carp "Failed to get content at $src (" . $res->status_line();
94 2         1186 return;
95             }
96              
97             # extract, cleanup and return the data
98             # if decoding the content fails, we just deal with the raw content
99 6   33     76 push @items =>
      33        
100             $class->extract( $res->decoded_content() || $res->content(),
101             $category || () );
102              
103             }
104              
105             # return unique items
106 4         7 my %seen;
107 4         7 return grep { !$seen{$_}++ } @items;
  30         141  
108             }
109              
110             #
111             # transformation subroutines
112             #
113             sub tr_nonword {
114 137     137 1 162 my $str = shift;
115 137         162 $str =~ tr/a-zA-Z0-9_/_/c;
116 137         250 $str;
117             }
118              
119             sub tr_accent {
120 137     137 1 33184 my $str = shift;
121 137         167 $str =~ tr{ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝàáâãäåçèéêëìíîïñòóôõöøùúûüýÿ}
122             {AAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy};
123 137         261 return $str;
124             }
125              
126             my %utf2asc = (
127             "æ" => 'ae',
128             "Æ" => 'AE',
129             "\xc5\xa0" => 'S',
130             "\x{0160}" => 'S',
131             # for pokemons
132             "\x{0101}" => 'a',
133             "\x{012b}" => 'i',
134             "\x{014d}" => 'o',
135             "\x{016b}" => 'u',
136             "\xe2\x99\x80" => 'female',
137             "\xe2\x99\x82" => 'male',
138             "\x{2640}" => 'female',
139             "\x{2642}" => 'male',
140             );
141             my $utf_re = qr/(@{[join( '|', sort keys %utf2asc )]})/;
142              
143             sub tr_utf8_basic {
144 0     0 1   my $str = shift;
145 0           $str =~ s/$utf_re/$utf2asc{$1}/go;
146 0           return $str;
147             }
148              
149             1;
150              
151             __END__