File Coverage

blib/lib/Games/Word/Wordlist.pm
Criterion Covered Total %
statement 78 121 64.4
branch 16 50 32.0
condition 0 6 0.0
subroutine 19 22 86.3
pod 10 10 100.0
total 123 209 58.8


line stmt bran cond sub pod time code
1             package Games::Word::Wordlist;
2             BEGIN {
3 9     9   314750 $Games::Word::Wordlist::AUTHORITY = 'cpan:DOY';
4             }
5             {
6             $Games::Word::Wordlist::VERSION = '0.06';
7             }
8 9     9   85 use strict;
  9         20  
  9         310  
9 9     9   50 use warnings;
  9         16  
  9         293  
10 9     9   5012 use Games::Word qw/all_permutations all_subpermutations/;
  9         24  
  9         1009  
11 9     9   20571 use List::MoreUtils qw/uniq/;
  9         13222  
  9         15540  
12             # ABSTRACT: manages a list of words
13              
14              
15              
16             sub new {
17 6     6 1 109 my $class = shift;
18 6         16 my $word_list = shift;
19 6         47 my $self = {
20             cache => 1,
21             @_,
22              
23             file => $word_list,
24             word_list => [],
25             word_hash => {},
26             };
27              
28 6 50       35 if (ref($word_list) eq 'ARRAY') {
29 6         17 $self->{cache} = 1;
30 6         17 $self->{file} = '';
31 6         14 $self->{word_list} = $word_list;
32 6         59 $self->{word_hash}{$_} = 1 for @$word_list;
33             }
34             else {
35 0 0       0 die "Can't read word list: $word_list" unless -r $word_list;
36 0 0 0     0 if ($self->{cache} && -s $word_list) {
37 0 0       0 open my $fh, '<', $word_list or die "Opening $word_list failed";
38 0         0 while (<$fh>) {
39 0         0 chomp;
40 0         0 $self->{word_hash}{$_} = 1;
41             }
42 0         0 $self->{word_list} = [keys %{$self->{word_hash}}];
  0         0  
43             }
44             }
45              
46 6         21 bless $self, $class;
47 6         20 return $self;
48             }
49              
50              
51             sub add_words {
52 1     1 1 2 my $self = shift;
53 1         3 my $word_list = shift;
54              
55 1 50       5 die "Can't add words to a non-cached word list" unless $self->{cache};
56              
57 1 50       4 if (ref($word_list) eq 'ARRAY') {
58 1         8 $self->{word_hash}{$_} = 1 for @$word_list;
59             }
60             else {
61 0 0       0 open my $fh, '<', $word_list or die "Opening $word_list failed";
62 0         0 $self->{word_hash}{$_} = 1 for <$fh>;
63             }
64 1         19 $self->{word_list} = [keys %{$self->{word_hash}}];
  1         5  
65              
66 1         3 return;
67             }
68              
69              
70             sub remove_words {
71 1     1 1 2 my $self = shift;
72              
73 1 50       6 die "Can't remove words from a non-cached word list" unless $self->{cache};
74              
75 1         7 delete $self->{word_hash}{$_} for (@_);
76 1         3 $self->{word_list} = [keys %{$self->{word_hash}}];
  1         4  
77              
78 1         4 return;
79             }
80              
81              
82             sub words {
83 3     3 1 8 my $self = shift;
84              
85 3 50       14 return @{$self->{word_list}} if $self->{cache};
  3         21  
86 0 0       0 open my $fh, '<', $self->{file} or die "Opening $self->{file} failed";
87 0         0 while (<$fh>) {}
88              
89 0         0 return $.;
90             }
91              
92             sub _random_word_cache {
93 15     15   23 my $self = shift;
94 15         20 my $length = shift;
95              
96 15         18 my @word_list;
97 15 100       34 if (defined $length) {
98 3         210 @word_list = $self->words_like(qr/^\w{$length}$/);
99 3 100       17 return unless @word_list;
100             }
101             else {
102 12         18 @word_list = @{$self->{word_list}};
  12         44  
103 12 100       42 return unless @word_list;
104             }
105              
106 13         271 return $word_list[int rand @word_list];
107             }
108              
109             sub _random_word_nocache {
110 0     0   0 my $self = shift;
111 0         0 my $length = shift;
112              
113 0 0       0 open my $fh, '<', $self->{file} or die "Opening $self->{file} failed";
114 0 0       0 return unless -s $self->{file};
115 0         0 my $word;
116 0         0 my $lineno = 0;
117 0         0 while (<$fh>) {
118 0 0 0     0 next unless !defined $length || /^\w{$length}$/;
119 0         0 $lineno++;
120 0 0       0 $word = $_ if int(rand $lineno) == 0;
121             }
122 0 0       0 return unless defined $word;
123 0         0 chomp $word;
124              
125 0         0 return $word;
126             }
127              
128              
129             sub random_word {
130 15     15 1 19990 my $self = shift;
131              
132 15 50       98 return $self->_random_word_cache(@_) if $self->{cache};
133 0         0 return $self->_random_word_nocache(@_);
134             }
135              
136             sub _is_word_cache {
137 99     99   104 my $self = shift;
138 99         111 my $word = shift;
139              
140 99         247 return $self->{word_hash}{$word};
141             }
142              
143             sub _is_word_nocache {
144 0     0   0 my $self = shift;
145 0         0 my $word = shift;
146              
147 0 0       0 open my $fh, '<', $self->{file} or die "Opening $self->{file} failed";
148 0         0 while (<$fh>) {
149 0         0 chomp;
150 0 0       0 return 1 if $_ eq $word;
151             }
152              
153 0         0 return 0;
154             }
155              
156              
157             sub is_word {
158 99     99 1 114 my $self = shift;
159              
160 99 50       304 return $self->_is_word_cache(@_) if $self->{cache};
161 0         0 return $self->_is_word_nocache(@_);
162             }
163              
164             sub _each_word_cache {
165 3     3   3 my $self = shift;
166 3         4 my $code = shift;
167              
168 3         6 &$code($_) for @{$self->{word_list}};
  3         12  
169              
170 3         8 return;
171             }
172              
173             sub _each_word_nocache {
174 0     0   0 my $self = shift;
175 0         0 my $code = shift;
176              
177 0 0       0 open my $fh, '<', $self->{file} or die "Opening $self->{file} failed";
178 0         0 while (<$fh>) {
179 0         0 chomp;
180 0         0 &$code($_);
181             }
182              
183 0         0 return;
184             }
185              
186              
187             sub each_word {
188 3     3 1 6 my $self = shift;
189              
190 3 50       19 return $self->_each_word_cache(@_) if $self->{cache};
191 0         0 return $self->_each_word_nocache(@_);
192             }
193              
194              
195             sub anagrams {
196 1     1 1 6 my $self = shift;
197 1         2 my $word = shift;
198              
199 1         8 return grep {$self->is_word($_)} all_permutations($word);
  24         47  
200             }
201              
202              
203             sub words_like {
204 3     3 1 6 my $self = shift;
205 3         4 my $re = shift;
206              
207 3         7 my @words = ();
208 3 100   12   17 $self->each_word(sub { push @words, $_[0] if $_[0] =~ $re });
  12         71  
209              
210 3         15 return @words;
211             }
212              
213              
214             sub subwords_of {
215 1     1 1 6 my $self = shift;
216 1         1 my $string = shift;
217              
218 1         5 return grep {$self->is_word($_)} all_subpermutations($string);
  65         108  
219             }
220              
221              
222             1;
223              
224             __END__