File Coverage

blib/lib/Net/Social/Mapper.pm
Criterion Covered Total %
statement 62 83 74.7
branch 13 22 59.0
condition 13 23 56.5
subroutine 13 15 86.6
pod 5 5 100.0
total 106 148 71.6


line stmt bran cond sub pod time code
1             package Net::Social::Mapper;
2              
3 12     12   38504 use strict;
  12         24  
  12         474  
4 12     12   11705 use Email::Valid;
  12         1645153  
  12         511  
5 12     12   11270 use LWP::UserAgent;
  12         660029  
  12         534  
6 12     12   141 use Encode qw(decode_utf8);
  12         28  
  12         1464  
7 12     12   9845 use Net::Social::Mapper::SiteMap;
  12         56  
  12         11389  
8              
9             our $VERSION = '0.5';
10              
11             =head1 NAME
12              
13             Net::Social::Mapper - utilities for dealing with internet persona
14              
15             =head1 SYNOPSIS
16              
17              
18             my $mapper = Net::Social::Mapper->new;
19             my $persona = $mapper->persona('daveman692', 'livejournal');
20              
21             print $persona->user; # daveman692
22             print $persona->service; # livejournal
23             print $persona->domain; # livejournal.com
24             print $persona->name; # LiveJournal
25              
26             # Print out any feeds available (if any exist)
27             print "Feeds : ".join(", ", @feeds);
28              
29             # What type are the feed items
30             print "Feeds contain : ".join(", ", $persona->types);
31              
32             # These other options may or may not be available
33             print "Home page : ".$persona->homepage;
34             print "Profile url : ".$persona->profile;
35             print "Full Name : ".$persona->full_name;
36             print "Service id : ".$persona->id;
37             print "Photo url : ".$persona->photo;
38             print "FOAF url : ".$persona->foaf;
39              
40             # If you have network access then you can query
41             # who they are elsewhere on the web
42             my @personas = $persona->elsewhere;
43              
44             # Other examples ...
45              
46             my $persona = $mapper->persona('daveman692', 'flickr');
47             print $persona->user; # daveman692
48             print $persona->id; # 36381329@N00
49              
50             my $persona = $mapper->persona('http://davidrecordon.com');
51             print $persona->user; # http://davidrecordon.com
52             print $persona->service; # website
53             print $persona->domain; # davidrecordon.com
54              
55             my $persona = $mapper->persona('test@example.com');
56             print $persona->user; # test@example.com
57             print $persona->service; # email
58             print $persona->id; # test
59             print $person->domain; # example.com
60              
61             # Moreover Net::Social::Mapper tries to work out the service from the url so that ...
62             my $persona = $mapper->persona('http://daveman692.livejournal.com');
63             my $persona = $mapper->persona('http://daveman692.livejournal.com/data/rss');
64             my $persona = $mapper->persona('http://daveman692.livejournal.com/data/atom');
65             my $persona = $mapper->persona('http://www.livejournal.com/userinfo.bml?user=daveman692');
66             # ... all return
67             print $persona->user; # daveman692
68             print $persona->service; # livejournal
69             print $persona->domain; # livejournal.com
70             print $persona->name; # LiveJournal
71              
72             =head1 METHODS
73              
74             =cut
75              
76             =head2 new
77              
78             Get a new C object.
79              
80             =cut
81             sub new {
82 9     9 1 11697 my $class = shift;
83 9         29 my %opts = @_;
84 9         37 my $self = bless \%opts, $class;
85 9         39 $self->_init;
86 9         56 return $self;
87             }
88              
89 9     9   18 sub _init { }
90              
91             =head2 persona [service]
92              
93             Return a C object representing the user.
94              
95             Returns undef if it doesn't know anything about the service.
96              
97             =cut
98             sub persona {
99 23     23 1 5917 my $self = shift;
100 23         47 my $user = shift;
101 23         51 my $service = shift;
102              
103 23 100       100 unless (defined $service) {
104 18 100 66     153 if ($user =~ m!@! && $user !~ m!/!) {
105 7         15 my $original = $user;
106 7         37 my @pieces = split '@', $user;
107 7         20 $service = pop @pieces;
108 7         25 $user = join '@', @pieces;
109 7         30 my $persona = $self->_load_persona($user, $service);
110 7 100       71 return $persona if $persona;
111 3         14 $user = $original;
112             }
113 14 100       158 if (Email::Valid->address($user)) {
114 3         3407 $service = 'email';
115             } else {
116 11         9169 $service = 'website';
117             }
118             }
119 19         153 return $self->_load_persona($user, $service);
120             }
121              
122             sub _load_persona {
123 26     26   47 my $self = shift;
124 26   50     103 my $user = shift || return;
125 26         56 my $service = shift;
126 26         95 my %classmap = $self->classmap;
127              
128 26 100       133 ($user, $service) = $self->sitemap->url_to_service($user) if $service eq 'website';
129              
130 26   100     1041 my $class = $classmap{lc($service)} || 'Net::Social::Mapper::Persona::Generic';
131 26         2480 eval "require $class";
132 26 50       162 return undef if $@;
133 26         325 return $class->new($user, lc($service), _mapper => $self);
134             }
135              
136             =head2 sitemap
137              
138             The C object containing everything we know about various services.
139              
140             =cut
141             sub sitemap {
142 29     29 1 50 my $self = shift;
143 29   33     309 return $self->{_sitemap} || Net::Social::Mapper::SiteMap->new;
144             }
145              
146             =head2 classmap [key value]
147              
148             Return a hash of (lowercase) service names to classes;
149              
150             Alternatively if you pass in a key, value pair then that
151             will be added to the map.
152              
153             Passing in C as the value will delete the key.
154              
155             =cut
156             sub classmap {
157 26     26 1 46 my $self = shift;
158 26   100     190 $self->{_class_map} ||= {
159             email => 'Net::Social::Mapper::Persona::Email',
160             website => 'Net::Social::Mapper::Persona::Website',
161             flickr => 'Net::Social::Mapper::Persona::Flickr',
162             myspace => 'Net::Social::Mapper::Persona::Myspace',
163             };
164 26 50       90 if (@_) {
165 0         0 my %tmp = @_;
166 0         0 foreach my $key (keys %tmp) {
167 0         0 my $value = $tmp{$key};
168 0 0       0 if (defined $value) {
169 0         0 $self->{_class_map}->{$key} = $value;
170             } else {
171 0         0 delete $self->{_class_map}->{$key};
172             }
173             }
174             }
175 26         42 return %{$self->{_class_map}};
  26         187  
176             }
177              
178             =head2 get
179              
180             Get the contents of the url or undef on failure;
181              
182             =cut
183             sub get {
184 4     4 1 32 my $self = shift;
185 4   50     16 my $url = shift || return;
186 4   50     14 my $r = $self->_get($url) || return;
187 0         0 return $r->decoded_content;
188             }
189              
190             sub _get {
191 4     4   7 my $self = shift;
192 4   50     77 my $url = shift || return;
193 4   66     41 my $ua = $self->{_ua} ||= LWP::UserAgent->new(parse_head => 0);
194 4         485 $self->{_ua}->env_proxy(1);
195 4         9561 my $r = $self->{_ua}->get("$url");
196 4 50       1881655 return unless $r->is_success;
197 0           return $r;
198             }
199              
200              
201             # a list of all content types that are feeds
202             sub _feed_types {(
203 0     0     "text/xml" => 1,
204             "application/xml" => 1,
205             "application/rdf+xml" => 1,
206             "application/rss+xml" => 1,
207             "application/atom+xml" => 1,
208             "application/x.atom+xml" => 1,
209             )};
210              
211             sub _get_feeds {
212 0     0     my $self = shift;
213 0           my $url = shift;
214 0           my %types = $self->_feed_types;
215 0           my $r = $self->_get($url);
216 0   0       my $mime = $r->header('Content-Type') || "";
217 0           $mime =~ s!;.*$!!;
218 0 0         return ($url) if $types{$mime};
219 0           my $page = $r->decoded_content;
220              
221 0           my $tmp = eval { decode_utf8($page) };
  0            
222 0 0         $tmp = $page unless defined $tmp;
223              
224 0           return Feed::Find->find_in_html(\$tmp, $url);
225             }
226              
227             =head1 AUTHOR
228              
229             Simon Wistow
230              
231             =head1 COPYRIGHT
232              
233             Copyright 2008, Six Apart Ltd.
234              
235             Released under the same terms as Perl itself.
236              
237             =cut
238              
239              
240             1;