File Coverage

blib/lib/Bag/Similarity.pm
Criterion Covered Total %
statement 53 53 100.0
branch 24 24 100.0
condition 11 12 100.0
subroutine 13 13 100.0
pod 8 8 100.0
total 109 110 100.0


line stmt bran cond sub pod time code
1             package Bag::Similarity;
2              
3 6     6   69798 use strict;
  6         22  
  6         181  
4 6     6   28 use warnings;
  6         10  
  6         140  
5              
6 6     6   145 use 5.008_005;
  6         19  
7             our $VERSION = '0.022';
8              
9 6     6   33 use Carp 'croak';
  6         29  
  6         4505  
10              
11             sub new {
12 6     6 1 1825 my $class = shift;
13             # uncoverable condition false
14 6 100 66     46 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       16  
15             }
16              
17             sub similarity {
18 102     102 1 17382 my ($self, $any1, $any2, $width) = @_;
19              
20 102         247 return $self->from_tokens(
21             $self->_any($any1,$width),
22             $self->_any($any2,$width)
23             );
24             }
25              
26             sub _any {
27 218     218   380 my ($self, $any, $width) = @_;
28              
29 218 100       562 if (ref($any) eq 'ARRAY') {
    100          
    100          
30 58         138 return $any;
31             }
32             elsif (ref($any) eq 'HASH') {
33 13         43 return [grep { $any->{$_} } keys %$any];
  15         48  
34             }
35             elsif (ref($any)) {
36 1         5 return [];
37             }
38             else {
39 146         295 return [$self->ngrams($any,$width)];
40             }
41             }
42              
43             sub ngrams {
44 157     157 1 262 my ($self, $word, $width) = @_;
45              
46 157 100 100     766 $width = 1 unless ($width && $width =~ m/^[1-9][0-9]*$/x);
47 157   100     328 $word ||= '';
48              
49 157 100       367 return ($word) unless ($width <= length($word));
50              
51 138         295 return map {substr $word,$_,$width;} (0..length($word)-$width);
  496         1366  
52             }
53              
54             sub from_tokens {
55 106     106 1 757 my ($self, $tokens1, $tokens2) = @_;
56              
57 106 100 100     304 return 1 if (!(scalar @$tokens1 || scalar @$tokens2));
58 100 100 100     408 return 0 unless (scalar @$tokens1 && scalar @$tokens2 );
59              
60 88         230 return $self->from_bags(
61             $tokens1,
62             $tokens2,
63             );
64             }
65              
66 1     1 1 408 sub from_bags { croak 'Method "from_bags" not implemented in subclass' }
67              
68             sub intersection {
69 66     66 1 109 my ($self, $tokens1, $tokens2) = @_;
70 66         100 my %bag1;
71             my %bag2;
72 66         99 $bag1{$_}++ for @{$tokens1};
  66         284  
73 66         108 $bag2{$_}++ for @{$tokens2};
  66         194  
74 66         99 my $intersection = 0;
75 66         177 for (keys %bag1) {
76 196 100       359 next unless (exists $bag2{$_} );
77 92 100       189 $intersection += ( $bag2{$_} < $bag1{$_}) ? $bag2{$_} : $bag1{$_};
78             }
79 66         272 return $intersection;
80             }
81              
82             sub combined_length {
83 46     46 1 63 scalar(@{$_[1]}) + scalar(@{$_[2]});
  46         69  
  46         171  
84             }
85              
86             sub min {
87 20         34 (scalar(@{$_[1]}) < scalar(@{$_[2]}))
  20         50  
88 20 100   20 1 38 ? scalar(@{$_[1]}) : scalar(@{$_[2]});
  2         13  
  18         127  
89             }
90              
91             1;
92              
93             __END__