File Coverage

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


line stmt bran cond sub pod time code
1             package Bag::Similarity;
2              
3 6     6   19977 use strict;
  6         15  
  6         230  
4 6     6   31 use warnings;
  6         14  
  6         172  
5              
6 6     6   228 use 5.008_005;
  6         16  
  6         331  
7             our $VERSION = '0.020';
8              
9 6     6   34 use Carp 'croak';
  6         8  
  6         3476  
10              
11             sub new {
12 6     6 1 1558 my $class = shift;
13             # uncoverable condition false
14 6 100 66     53 bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class;
  2 100       19  
15             }
16              
17             sub similarity {
18 102     102 1 11391 my ($self, $any1, $any2, $width) = @_;
19              
20 102         220 return $self->from_tokens(
21             $self->_any($any1,$width),
22             $self->_any($any2,$width)
23             );
24             }
25              
26             sub _any {
27 218     218   264 my ($self, $any, $width) = @_;
28              
29 218 100       659 if (ref($any) eq 'ARRAY') {
    100          
    100          
30 58         133 return $any;
31             }
32             elsif (ref($any) eq 'HASH') {
33 13         57 return [grep { $any->{$_} } keys %$any];
  15         59  
34             }
35             elsif (ref($any)) {
36 1         6 return [];
37             }
38             else {
39 146         273 return [$self->ngrams($any,$width)];
40             }
41             }
42              
43             sub ngrams {
44 157     157 1 184 my ($self, $word, $width) = @_;
45              
46 157 100 100     840 $width = 1 unless ($width && $width =~ m/^[1-9][0-9]*$/x);
47 157   100     308 $word ||= '';
48              
49 157 100       397 return ($word) unless ($width <= length($word));
50              
51 138         280 return map {substr $word,$_,$width;} (0..length($word)-$width);
  496         1209  
52             }
53              
54             sub from_tokens {
55 106     106 1 542 my ($self, $tokens1, $tokens2) = @_;
56              
57 106 100 100     282 return 1 if (!(scalar @$tokens1 || scalar @$tokens2));
58 100 100 100     725 return 0 unless (scalar @$tokens1 && scalar @$tokens2 );
59              
60 88         244 return $self->from_bags(
61             $tokens1,
62             $tokens2,
63             );
64             }
65              
66 1     1 1 435 sub from_bags { croak 'Method "from_bags" not implemented in subclass' }
67              
68             sub intersection {
69 66     66 1 74 my ($self, $tokens1, $tokens2) = @_;
70 66         61 my %bag1;
71             my %bag2;
72 66         72 $bag1{$_}++ for @{$tokens1};
  66         410  
73 66         114 $bag2{$_}++ for @{$tokens2};
  66         236  
74 66         80 my $intersection = 0;
75 66         161 for (keys %bag1) {
76 196 100       420 next unless (exists $bag2{$_} );
77 92 100       217 $intersection += ( $bag2{$_} < $bag1{$_}) ? $bag2{$_} : $bag1{$_};
78             }
79 66         309 return $intersection;
80             }
81              
82             sub combined_length {
83 46     46 1 43 scalar(@{$_[1]}) + scalar(@{$_[2]});
  46         74  
  46         175  
84             }
85              
86             sub min {
87 20         29 (scalar(@{$_[1]}) < scalar(@{$_[2]}))
  20         39  
  2         13  
88 20 100   20 1 17 ? scalar(@{$_[1]}) : scalar(@{$_[2]});
  18         127  
89             }
90              
91             1;
92              
93             __END__