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   20455 use strict;
  6         13  
  6         191  
4 6     6   26 use warnings;
  6         8  
  6         173  
5              
6 6     6   173 use 5.008_005;
  6         19  
7             our $VERSION = '0.021';
8              
9 6     6   42 use Carp 'croak';
  6         9  
  6         4376  
10              
11             sub new {
12 6     6 1 1733 my $class = shift;
13             # uncoverable condition false
14 6 100 66     43 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       13  
15             }
16              
17             sub similarity {
18 102     102 1 19520 my ($self, $any1, $any2, $width) = @_;
19              
20 102         265 return $self->from_tokens(
21             $self->_any($any1,$width),
22             $self->_any($any2,$width)
23             );
24             }
25              
26             sub _any {
27 218     218   270 my ($self, $any, $width) = @_;
28              
29 218 100       646 if (ref($any) eq 'ARRAY') {
    100          
    100          
30 58         128 return $any;
31             }
32             elsif (ref($any) eq 'HASH') {
33 13         49 return [grep { $any->{$_} } keys %$any];
  15         58  
34             }
35             elsif (ref($any)) {
36 1         5 return [];
37             }
38             else {
39 146         272 return [$self->ngrams($any,$width)];
40             }
41             }
42              
43             sub ngrams {
44 157     157 1 200 my ($self, $word, $width) = @_;
45              
46 157 100 100     857 $width = 1 unless ($width && $width =~ m/^[1-9][0-9]*$/x);
47 157   100     314 $word ||= '';
48              
49 157 100       364 return ($word) unless ($width <= length($word));
50              
51 138         310 return map {substr $word,$_,$width;} (0..length($word)-$width);
  496         1224  
52             }
53              
54             sub from_tokens {
55 106     106 1 978 my ($self, $tokens1, $tokens2) = @_;
56              
57 106 100 100     336 return 1 if (!(scalar @$tokens1 || scalar @$tokens2));
58 100 100 100     557 return 0 unless (scalar @$tokens1 && scalar @$tokens2 );
59              
60 88         271 return $self->from_bags(
61             $tokens1,
62             $tokens2,
63             );
64             }
65              
66 1     1 1 316 sub from_bags { croak 'Method "from_bags" not implemented in subclass' }
67              
68             sub intersection {
69 66     66 1 76 my ($self, $tokens1, $tokens2) = @_;
70 66         67 my %bag1;
71             my %bag2;
72 66         61 $bag1{$_}++ for @{$tokens1};
  66         440  
73 66         105 $bag2{$_}++ for @{$tokens2};
  66         259  
74 66         85 my $intersection = 0;
75 66         356 for (keys %bag1) {
76 196 100       413 next unless (exists $bag2{$_} );
77 92 100       214 $intersection += ( $bag2{$_} < $bag1{$_}) ? $bag2{$_} : $bag1{$_};
78             }
79 66         319 return $intersection;
80             }
81              
82             sub combined_length {
83 46     46 1 49 scalar(@{$_[1]}) + scalar(@{$_[2]});
  46         71  
  46         197  
84             }
85              
86             sub min {
87 20         25 (scalar(@{$_[1]}) < scalar(@{$_[2]}))
  20         29  
88 20 100   20 1 20 ? scalar(@{$_[1]}) : scalar(@{$_[2]});
  2         12  
  18         92  
89             }
90              
91             1;
92              
93             __END__