File Coverage

blib/lib/Mail/Karmasphere/Query.pm
Criterion Covered Total %
statement 107 185 57.8
branch 33 104 31.7
condition 2 6 33.3
subroutine 21 27 77.7
pod 9 19 47.3
total 172 341 50.4


line stmt bran cond sub pod time code
1             package Mail::Karmasphere::Query;
2              
3 5     5   25 use strict;
  5         8  
  5         162  
4 5     5   26 use warnings;
  5         11  
  5         166  
5 5     5   22 use vars qw(@ISA @EXPORT_OK %EXPORT_TAGS $ID);
  5         9  
  5         345  
6 5     5   24 use Carp;
  5         8  
  5         409  
7 5     5   67 use Exporter;
  5         17  
  5         356  
8              
9             BEGIN {
10 5     5   89 @ISA = qw(Exporter);
11 5         13 @EXPORT_OK = qw(guess_identity_type);
12 5         112 %EXPORT_TAGS = (
13             'all' => \@EXPORT_OK,
14             );
15             }
16              
17 5     5   33 use Mail::Karmasphere::Client qw(:all);
  5         8  
  5         11205  
18              
19             $ID = 0;
20              
21             sub new {
22 12     12 0 3545 my $class = shift;
23 12 50       46 my $args = ($#_ == 0) ? { %{ (shift) } } : { @_ };
  0         0  
24              
25             #use Data::Dumper;
26             #print Dumper($args);
27              
28 12         37 my $self = bless { }, $class;
29              
30 12 50       42 if (exists $args->{Id}) {
31 0         0 $self->id(delete $args->{Id});
32             }
33              
34 12 50       33 if (exists $args->{Identities}) {
35 0         0 my $identities = delete $args->{Identities};
36 0 0       0 die "Identities must be a listref, not " . ref($identities)
37             unless ref($identities) eq 'ARRAY';
38 0         0 for my $identity (@$identities) {
39 0 0       0 if (ref($identity) eq 'ARRAY') {
40 0         0 $self->identity(@$identity);
41             }
42             else {
43 0         0 $self->identity($identity);
44             }
45             }
46             }
47              
48 12 50       47 if (exists $args->{Composites}) {
49 0         0 my $composites = delete $args->{Composites};
50 0 0       0 die "Composites must be a listref"
51             unless ref($composites) eq 'ARRAY';
52 0         0 $self->composite($_) for @$composites;
53             }
54              
55 12 50       34 if (exists $args->{Composite}) {
56 0         0 $self->composite(delete $args->{Composite});
57             }
58              
59 12 50       35 if (exists $args->{Feeds}) {
60 0         0 my $feeds = delete $args->{Feeds};
61 0 0       0 die "Feeds must be a listref"
62             unless ref($feeds) eq 'ARRAY';
63 0         0 $self->feed($_) for @$feeds;
64             }
65              
66 12 50       26 if (exists $args->{Combiners}) {
67 0         0 my $combiners = delete $args->{Combiners};
68 0 0       0 die "Combiners must be a listref"
69             unless ref($combiners) eq 'ARRAY';
70 0         0 $self->combiner($_) for @$combiners;
71             }
72              
73 12 50       31 if (exists $args->{Combiner}) {
74 0         0 $self->combiner(delete $args->{Combiner});
75             }
76              
77 12 50       24 if (exists $args->{Flags}) {
78 0         0 $self->flags(delete $args->{Flags});
79             }
80              
81 12         35 my @remain = keys %$args;
82 12 50       38 if (@remain) {
83 0         0 carp "Unrecognised arguments to constructor: @remain";
84             }
85              
86 12         48 return $self;
87             }
88              
89             sub guess_identity_type {
90 0     0 0 0 my $identity = shift;
91              
92 0 0       0 if ($identity =~ /^[0-9\.]{7,15}$/) {
    0          
    0          
    0          
    0          
93 0         0 return IDT_IP4;
94             }
95             elsif ($identity =~ /^[0-9a-f:]{2,64}$/i) {
96 0         0 return IDT_IP6;
97             }
98             elsif ($identity =~ /^https?:\/\//) {
99 0         0 return IDT_URL;
100             }
101             elsif ($identity =~ /@/) {
102 0         0 return IDT_EMAIL;
103             }
104             elsif ($identity =~ /\./) {
105 0         0 return IDT_DOMAIN;
106             }
107              
108 0         0 return undef;
109             }
110              
111             sub id {
112 11     11 1 25 my $self = shift;
113 11 50       51 if (@_) {
    50          
114 0         0 $self->{Id} = shift;
115             }
116             elsif (!defined $self->{Id}) {
117 11         64 $self->{Id} = 'mkc' . $ID++ . "-" . time();
118             }
119 11         55 return $self->{Id};
120             }
121              
122             sub identity {
123 8     8 1 43 my ($self, $identity, @tags) = @_;
124 8 50       19 unless (ref($identity) eq 'ARRAY') {
125 8         5 my $type;
126 8 50       17 if (@tags) {
127 8         10 $type = shift @tags;
128             }
129             else {
130 0         0 warn "Guessing identity type for $identity";
131 0         0 $type = guess_identity_type($identity);
132             }
133 8         14 $identity = [ $identity, $type ];
134             }
135 8 50       21 push(@$identity, @tags) if @tags;
136 8         10 for (@{ $self->{Identities} }) {
  8         28  
137             # If the data and the type match
138 6 100 66     25 if (($_->[0] eq $identity->[0]) &&
139             ($_->[1] eq $identity->[1])) {
140             # Combine the tags from the new identity;
141 5         6 shift @$identity; shift @$identity;
  5         5  
142 5         6 push(@{ $_ }, @$identity);
  5         23  
143 5         12 return;
144             }
145             }
146 3         5 push(@{ $self->{Identities} }, $identity);
  3         9  
147             }
148              
149             sub identities {
150 1     1 1 4 my $self = shift;
151 1 50       4 if (@_) {
152 0         0 $self->{Identities} = [ ];
153 0         0 $self->identity($_) for @_;
154             }
155 1         6 return $self->{Identities};
156             }
157              
158             sub has_identities {
159 10     10 0 16 my $self = shift;
160 10 50       51 return undef unless exists $self->{Identities};
161 0 0       0 return undef unless @{ $self->{Identities} };
  0         0  
162 0         0 return 1;
163             }
164              
165             sub composite {
166 0     0 1 0 my ($self, @composites) = @_;
167 0         0 for my $composite (@composites) {
168             # Validate
169 0 0       0 if (ref($composite)) {
    0          
    0          
170 0         0 die "Composite may not be a reference";
171             }
172             elsif ($composite =~ /^[0-9]+$/) {
173 0         0 warn "Using numeric ids for composites should be avoided.";
174             }
175             elsif ($composite =~ /\./) {
176             }
177             else {
178 0         0 warn "Composite name does not contain a dot. Invalid?";
179             }
180 0         0 push(@{ $self->{Composites} }, $composite);
  0         0  
181             }
182             }
183              
184             sub composites {
185 0     0 1 0 my $self = shift;
186 0 0       0 if (@_) {
187 0         0 $self->{Composites} = [ ];
188 0         0 $self->composite(@_);
189             }
190 0         0 return $self->{Composites};
191             }
192              
193             sub has_composites {
194 10     10 0 13 my $self = shift;
195 10 50       46 return undef unless exists $self->{Composites};
196 0 0       0 return undef unless @{ $self->{Composites} };
  0         0  
197 0         0 return 1;
198             }
199              
200             sub feed {
201 104     104 0 440 my ($self, @feeds) = @_;
202 104         117 for my $feed (@feeds) {
203             # Validate.
204             # if ($feed =~ /^[0-9]+$/) {
205             # warn "Numeric feed ids are deprecated.";
206             # }
207 104         91 push(@{ $self->{Feeds} }, $feed);
  104         355  
208             }
209             }
210              
211             sub feeds {
212 1     1 1 2 my $self = shift;
213 1 50       4 if (@_) {
214 0         0 $self->{Feeds} = [ ];
215 0         0 $self->feed(@_);
216             }
217 1         10 return $self->{Feeds};
218             }
219              
220             sub has_feeds {
221 10     10 0 13 my $self = shift;
222 10 100       44 return undef unless exists $self->{Feeds};
223 1 50       2 return undef unless @{ $self->{Feeds} };
  1         5  
224 1         7 return 1;
225             }
226              
227             sub combiner {
228 3     3 1 13 my ($self, @combiners) = @_;
229 3         5 for my $combiner (@combiners) {
230             # Validate.
231 3         4 push(@{ $self->{Combiners} }, $combiner);
  3         13  
232             }
233             }
234              
235             sub combiners {
236 0     0 1 0 my $self = shift;
237 0 0       0 if (@_) {
238 0         0 $self->{Combiners} = [ ];
239 0         0 $self->combiner(@_);
240             }
241 0         0 return $self->{Combiners};
242             }
243              
244             sub has_combiners {
245 10     10 0 20 my $self = shift;
246 10 50       45 return undef unless exists $self->{Combiners};
247 0 0       0 return undef unless @{ $self->{Combiners} };
  0         0  
248 0         0 return 1;
249             }
250              
251             sub flags {
252 0     0 1 0 my $self = shift;
253 0 0       0 if (@_) {
254 0         0 my $flags = shift;
255 0 0       0 die "Flags must be an integer" unless $flags =~ /^[0-9]+$/;
256 0         0 $self->{Flags} = $flags;
257             }
258 0         0 return $self->{Flags};
259             }
260              
261             sub has_flags {
262 10     10 0 24 my $self = shift;
263 10 50       40 return undef unless exists $self->{Flags};
264 0 0       0 return undef unless defined $self->{Flags};
265 0         0 return 1;
266             }
267              
268             sub identities_as_humanreadable_string {
269 0     0 0 0 my $self = shift;
270 0 0       0 my @identities = @{ $self->{Identities} || [] };
  0         0  
271 0   0     0 return join ",", (map { join "=", ($_->[1], $_->[0], ($_->[2] || ())) } @identities);
  0         0  
272             }
273              
274             sub _as_string_sizeof {
275 4     4   7 my $ref = shift;
276 4 100       12 return "0" unless defined $ref;
277 3         9 return scalar(@$ref);
278             }
279              
280             sub as_string {
281 1     1 0 5 my ($self) = @_;
282 1         3 my $out = "Query id '" . $self->id . "': ";
283 1         4 $out .= _as_string_sizeof($self->{Identities}) . ' identities, ';
284 1         4 $out .= _as_string_sizeof($self->{Feeds}) . ' feeds, ';
285 1         5 $out .= _as_string_sizeof($self->{Composites}) . " composites, ";
286 1         3 $out .= _as_string_sizeof($self->{Combiners}) . " combiners\n";
287 1 50       5 if ($self->{Identities}) {
288 1         1 for (@{ $self->{Identities} }) {
  1         4  
289 1         3 my ($id, $t, @t) = @$_;
290 1         4 $out .= "Identity: $id ($t)";
291 1 50       6 $out .= " (= @t)" if @t;
292 1         3 $out .= "\n";
293             }
294             }
295 1 50       5 if ($self->{Composites}) {
296 0         0 $out .= "Composites: " .
297 0         0 join(' ', sort @{ $self->{Composites} } ) .
298             "\n";
299             }
300 1 50       4 if ($self->{Feeds}) {
301 1         10 $out .= "Feeds: " .
302 1         2 join(' ', sort @{ $self->{Feeds} } ) .
303             "\n";
304             }
305 1 50       6 if ($self->{Combiners}) {
306 1         7 $out .= "Combiners: " .
307 1         8 join(' ', sort @{ $self->{Combiners} } ) .
308             "\n";
309             }
310 1         3 return $out;
311             }
312              
313             =head1 NAME
314              
315             Mail::Karmasphere::Query - Karmasphere Query Object
316              
317             =head1 SYNOPSIS
318              
319             my $query = new Mail::Karmasphere::Query(...);
320              
321             =head1 DESCRIPTION
322              
323             The Perl Karma Client API consists of three objects: The Query, the
324             Response and the Client. The user constructs a Query and passes it to
325             a Client, which returns a Response. See L
326             for more information.
327              
328             =head1 CONSTRUCTOR
329              
330             The class method new(...) constructs a new Query object. All arguments
331             are optional. The following parameters are recognised as arguments
332             to new():
333              
334             =over 4
335              
336             =item Identities
337              
338             A listref of identities, each of which is an [ identity, type ] pair.
339              
340             =item Composites
341              
342             A listref of composite keynames.
343              
344             =item Composite
345              
346             A single composite keyname.
347              
348             =item Flags
349              
350             The query flags.
351              
352             =item Id
353              
354             The id of this query, returned in the response. The id is autogenerated
355             in a new query if not provided, and may be retrieved using $query->id.
356              
357             =item Feeds
358              
359             A listref of feed ids.
360              
361             =item Combiners
362              
363             A listref of combiner names.
364              
365             =item Combiner
366              
367             A single combiner name.
368              
369             =back
370              
371             =head1 METHODS
372              
373             =head2 PRIMARY METHODS
374              
375             These methods are the ones you must understand in order to use
376             Mail::Karmashere::Client.
377              
378             =over 4
379              
380             =item $query->identity($data, $type, @tags)
381              
382             Adds an identity to this query.
383              
384             =item $query->composite(@composites)
385              
386             Adds one or more composites to this query.
387              
388             =item $query->flags($flags)
389              
390             Sets or returns the flags of this query.
391              
392             =back
393              
394             =head2 OTHER METHODS
395              
396             These methods permit more flexibility and access to more features.
397              
398             =over 4
399              
400             =item $query->id([$id])
401              
402             Sets or returns the id of this query. If the query has no id, an id
403             will be generated by the client and will appear in the response.
404              
405             =item $query->identities(@identities)
406              
407             Sets or returns the identities of this query.
408              
409             =item $query->composites(@composites)
410              
411             Sets or returns the composites of this query.
412              
413             =item $query->feeds(@feeds)
414              
415             Sets or returns the feeds of this query.
416              
417             =item $query->feeds(@feeds)
418              
419             Adds a feed to this query.
420              
421             =item $query->combiners(@combiners)
422              
423             Sets or returns the combiners of this query.
424              
425             =item $query->combiner(@combiners)
426              
427             Adds combiners to this query.
428              
429             =back
430              
431             =head1 BUGS
432              
433             This document is incomplete.
434              
435             =head1 SEE ALSO
436              
437             L
438             L
439             http://www.karmasphere.com/
440              
441             =head1 COPYRIGHT
442              
443             Copyright (c) 2005 Shevek, Karmasphere. All rights reserved.
444              
445             This program is free software; you can redistribute it and/or modify
446             it under the same terms as Perl itself.
447              
448             =cut
449              
450             1;