File Coverage

blib/lib/Crypt/Role/CheckerboardCipher.pm
Criterion Covered Total %
statement 61 61 100.0
branch 2 2 100.0
condition 3 6 50.0
subroutine 14 14 100.0
pod 2 2 100.0
total 82 85 96.4


line stmt bran cond sub pod time code
1 3     3   45020 use 5.008;
  3         13  
  3         146  
2 3     3   17 use strict;
  3         16  
  3         87  
3 3     3   15 use warnings;
  3         15  
  3         194  
4              
5             package Crypt::Role::CheckerboardCipher;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.003';
9              
10 3     3   25 use Moo::Role;
  3         5  
  3         28  
11 3     3   3991 use Const::Fast;
  3         3079  
  3         16  
12 3     3   2972 use POSIX qw( ceil );
  3         24534  
  3         36  
13 3     3   8529 use Type::Params;
  3         313301  
  3         28  
14 3     3   3776 use Types::Common::Numeric qw( PositiveInt SingleDigit );
  3         48507  
  3         43  
15 3     3   2212 use Types::Standard qw( ArrayRef HashRef Str );
  3         9  
  3         22  
16 3     3   2753 use namespace::sweep;
  3         7  
  3         29  
17              
18             has square_size => (
19             is => 'lazy',
20             isa => PositiveInt & SingleDigit,
21             init_arg => undef,
22             );
23              
24             requires 'alphabet';
25              
26             sub _build_square_size {
27 3     3   2382 my $self = shift;
28 3         10 my $letters = @{ $self->alphabet };
  3         42  
29 3         157 return ceil(sqrt($letters));
30             }
31              
32             has square => (
33             is => 'lazy',
34             isa => ArrayRef[ ArrayRef[Str] ],
35             init_arg => undef,
36             );
37              
38             sub _build_square
39             {
40 3     3   4826 my $self = shift;
41            
42 3         8 my @alphabet = @{ $self->alphabet };
  3         46  
43 3         29 my $size = $self->square_size;
44            
45 15         64 const my @rows => map {
46 3         133 my @letters = (
47             splice(@alphabet, 0, $size),
48             ('') x $size,
49             );
50 15         75 const my @row => @letters[0..$size-1];
51 15         781 \@row;
52             } 1..$size;
53            
54 3         221 \@rows;
55             }
56              
57             my $_build_hashes = sub
58             {
59             my $self = shift;
60             my ($want) = @_;
61            
62             my (%enc, %dec);
63             my $square = $self->square;
64             my $size = $self->square_size;
65             for my $i (0 .. $size-1)
66             {
67             my $row = $square->[$i];
68             for my $j (0 .. $size-1)
69             {
70             my $clear = $row->[$j];
71             my $cipher = sprintf('%s%s', $i+1, $j+1);
72             $enc{$clear} = $cipher;
73             $dec{$cipher} = $clear;
74             }
75             }
76            
77             const my $enc => \%enc;
78             const my $dec => \%dec;
79             $self->_set_encipher_hash($enc);
80             $self->_set_decipher_hash($dec);
81             $self->$want;
82             };
83              
84             has encipher_hash => (
85             is => 'lazy',
86             isa => HashRef[Str],
87             writer => '_set_encipher_hash',
88             default => sub { shift->$_build_hashes('encipher_hash') },
89             init_arg => undef,
90             );
91              
92             has decipher_hash => (
93             is => 'lazy',
94             isa => HashRef[Str],
95             writer => '_set_decipher_hash',
96             default => sub { shift->$_build_hashes('decipher_hash') },
97             init_arg => undef,
98             );
99              
100             requires 'preprocess';
101              
102             my $_check_encipher;
103             sub encipher
104             {
105 4   66 4 1 3996 $_check_encipher ||= compile(Str);
106              
107 4         2884 my $self = shift;
108 4         24 my ($input) = $_check_encipher->(@_);
109            
110 4         69 my $str = $self->preprocess($input);
111 4         39 my $enc = $self->encipher_hash;
112 4 100       207 $str =~ s/(.)/exists $enc->{$1} ? $enc->{$1}." " : ""/eg;
  20         89  
113 4         12 chop $str;
114 4         36 return $str;
115             }
116              
117             my $_check_decipher;
118             sub decipher
119             {
120 3   33 3 1 37 $_check_decipher ||= compile(Str);
121              
122 3         2353 my $self = shift;
123 3         14 my ($input) = $_check_decipher->(@_);
124            
125 3         63 my $str = $input;
126 3         25 my $dec = $self->decipher_hash;
127 3         2202 $str =~ s/[^0-9]//g; # input should be entirely numeric
128 3         17 $str =~ s/([0-9]{2})/$dec->{$1}/eg;
  12         44  
129 3         22 return $str;
130             }
131              
132             1;
133              
134             __END__
135              
136             =pod
137              
138             =encoding utf-8
139              
140             =head1 NAME
141              
142             Crypt::Role::CheckerboardCipher - guts of the Polybius square cipher implementation
143              
144             =head1 DESCRIPTION
145              
146             =head2 Attributes
147              
148             The following attributes exist. All of them have defaults, and should
149             not be provided to the constructors of consuming classes.
150              
151             =over
152              
153             =item C<< square >>
154              
155             An arrayref of arrayrefs of letters.
156              
157             =item C<< square_size >>
158              
159             The length of one side of the square, as an integer.
160              
161             =item C<< encipher_hash >>
162              
163             Hashref used by the C<encipher> method.
164              
165             =item C<< decipher_hash >>
166              
167             Hashref used by the C<decipher> method.
168              
169             =back
170              
171             =head2 Object Methods
172              
173             =over
174              
175             =item C<< encipher($str) >>
176              
177             Enciphers a string and returns the ciphertext.
178              
179             =item C<< decipher($str) >>
180              
181             Deciphers a string and returns the plaintext.
182              
183             =item C<< _build_square_size >>
184              
185             Calculates the optimum square size for the alphabet. An alphabet of 25
186             letters can fill a five by five square, so this method would return 5.
187             An alphabet of 26 characters would partly fill a six by six square, so
188             this method would return 6.
189              
190             This method is not expected to be called by end-users but is documented
191             for people writing classes consuming this role.
192              
193             =item C<< _build_square >>
194              
195             Allocates the letters of the alphabet into a square (an arrayref of
196             arrayrefs of letters), returning the square.
197              
198             This method is not expected to be called by end-users but is documented
199             for people writing classes consuming this role.
200              
201             =back
202              
203             =head2 Required Methods
204              
205             Classes consuming this role must provide the following methods:
206              
207             =over
208              
209             =item C<< preprocess($str) >>
210              
211             Expected to return a string more suitable for enciphering.
212              
213             =item C<< alphabet >>
214              
215             Expected to returns an arrayref of the known alphabet.
216              
217             =back
218              
219             =head1 BUGS
220              
221             Please report any bugs to
222             L<http://rt.cpan.org/Dist/Display.html?Queue=Crypt-Polybius>.
223              
224             =head1 SEE ALSO
225              
226             L<http://en.wikipedia.org/wiki/Polybius_square>.
227              
228             L<Crypt::Polybius>,
229             L<Crypt::Polybius::Greek>.
230              
231             =head1 AUTHOR
232              
233             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
234              
235             =head1 COPYRIGHT AND LICENCE
236              
237             This software is copyright (c) 2014 by Toby Inkster.
238              
239             This is free software; you can redistribute it and/or modify it under
240             the same terms as the Perl 5 programming language system itself.
241              
242             =head1 DISCLAIMER OF WARRANTIES
243              
244             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
245             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
246             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
247