File Coverage

blib/lib/Acme/Tie/Eleet.pm
Criterion Covered Total %
statement 119 123 96.7
branch 71 86 82.5
condition 30 39 76.9
subroutine 17 18 94.4
pod n/a
total 237 266 89.1


line stmt bran cond sub pod time code
1             #
2             # This file is part of Acme::Tie::Eleet.
3             # Copyright (c) 2001-2007 Jerome Quelin, all rights reserved.
4             #
5             # This program is free software; you can redistribute it and/or modify
6             # it under the same terms as Perl itself.
7             #
8             #
9              
10             package Acme::Tie::Eleet;
11              
12 8     8   16667 use strict;
  8         17  
  8         323  
13 8     8   48 use warnings;
  8         13  
  8         264  
14              
15 8     8   54 use Carp;
  8         12  
  8         660  
16 8     8   17780 use IO::Handle;
  8         82409  
  8         32749  
17              
18             our $VERSION = '1.0.2';
19              
20              
21             # Our to allow user to hack/overwrite it.
22             our @beg = ( "hey man, ", "hey dude, ", "cool, ", '$#$!#!$ ', "sure, ", "hey, ",
23             "yeah, ", "yeah man, ", "yeah dude, ", "listen, ", "listen pal, " );
24             our @end = ( ", fear us.", ", d'ya think so?", ' $#$!#!$!' );
25             our @sentences = ( "Fear us!", "All your base are belong to us!",
26             "Resistance is futile; you will be assimilated.",
27             "Resistance is futile.", "Whololo!" );
28             our %words =
29             ( apps => "appz",
30             are => "r",
31             awesome => "awesum",
32             because => "cuz",
33             capital => "capitull",
34             cool => [ "kool", "kewl" ], # Anon arrays accepted.
35             dude => "dood",
36             elite => "eleet",
37             every => "evry",
38             everybody => "evry budy",
39             freak => "phreak",
40             games => "gamez",
41             hacker => "haxor",
42             hackers => "haxors",
43             letter => "lettr",
44             letters => "lettrs",
45             phone => "fone",
46             rule => "rulez",
47             see => "c",
48             the => "da",
49             wares => "warez",
50             you => "u",
51             );
52              
53              
54             # Populate the hash.
55             my %letter =
56             ( a => [ "4", "@" ],
57             c => "(",
58             e => "3",
59             g => "6",
60             h => [ "|-|", "]-[" ],
61             k => [ "|<", "]{" ],
62             i => "!",
63             l => [ "1", "|" ],
64             m => [ "|V|", "|\\/|" ],
65             n => "|\\|",
66             o => "0",
67             s => [ "5", "Z" ],
68             t => [ "7", "+"],
69             u => "\\_/",
70             v => "\\/",
71             w => [ "vv", "\\/\\/" ],
72             'y' => "j",
73             z => "2",
74             );
75              
76              
77             #--
78             # Constructor
79              
80             sub _new {
81             # Create object.
82 27     27   235 my $self = {
83             letters => 25, # transform o to 0, l to 1, etc.
84             spacer => "1/0", # %age 0=no extra spaces, 'm/n'=m extra+n noextra, 60=3/5 at random
85             case_mixer => 50, # %age 0=nothing, 'm/n'=m ucase+n lcase, 25=1/4 at random
86             words => 1, # transform cool to kewl or kool, etc.
87             add_before => 15, # add comments before sentence.
88             add_after => 15, # add comments after sentences.
89             extra_sent => 10, # extra sentences.
90             @_, # overwrite with user values.
91             # internals, do not modify.
92             _space => "m0",
93             _case_mix => "m0"
94             };
95              
96             # Check patterns.
97 27 100       471 $self->{spacer} =~ m!^(((\d+)/(\d+))|(\d+))$!
98             or croak "spacer: wrong pattern $self->{spacer}";
99 26 100 100     333 $self->{spacer} =~ m!^(\d+)/(\d+)$! && $1+$2 == 0
100             and croak "spacer: illegal pattern $self->{spacer}";
101 25 100       349 $self->{case_mixer} =~ m!^(((\d+)/(\d+))|(\d+))$!
102             or croak "case_mixer: wrong pattern $self->{case_mixer}";
103 24 100 100     283 $self->{case_mixer} =~ m!^(\d+)/(\d+)$! && $1+$2 == 0
104             and croak "case_mixer: illegal pattern $self->{case_mixer}";
105              
106             # Init internals.
107 23 100 100     106 $self->{spacer} =~ m!^(\d+)/(\d+)$! && $1 == 0
108             and $self->{_space} = "n0";
109 23 100 100     100 $self->{case_mixer} =~ m!^(\d+)/(\d+)$! && $1 == 0
110             and $self->{_case_mix} = "n0";
111              
112             # Return the hash ref.
113 23         47 return $self;
114             }
115              
116              
117             sub TIEHANDLE {
118             # Process args.
119 1     1   1450 my $pkg = shift;
120 1         4 my $fh = shift;
121 1 50       7 ref $pkg and croak "Not an instance method";
122              
123 1 50       3 $fh or croak "Filehandle is not an optional paramater";
124 1         11 $fh->autoflush(1);
125              
126 1         52 my $self = &_new; # magic call.
127 1         2 $self->{FH} = $fh;
128              
129             # Return it.
130 1         6 return bless( $self, $pkg );
131             }
132              
133              
134             sub TIESCALAR {
135             # Process args.
136 26     26   5458 my $pkg = shift;
137 26 50       87 ref $pkg and croak "Not an instance method";
138              
139 26         47 my $self = &_new; # magic call.
140 22         42 $self->{value} = undef;
141              
142             # Return it.
143 22         90 return bless( $self, $pkg );
144             }
145              
146              
147             #--
148             # Handlers.
149              
150             # Catch scalar fetching.
151             sub FETCH {
152 21     21   485 my $self = shift;
153 21         75 return $self->_transform( $self->{value} );
154             }
155              
156             # Catch calls to print.
157             sub PRINT {
158 0     0   0 my $self = shift;
159 0         0 my $fh = $self->{FH};
160 0 0       0 $_[0] or return;
161 0         0 print $fh $self->_transform(join "", @_);
162             }
163              
164             # Catch scalar storing.
165             sub STORE {
166 21     21   196 $_[0]{value} = $_[1];
167             }
168              
169              
170             #--
171             # Modification plugins.
172              
173             #
174             # All plugins will get (not counting the object that will always be
175             # the first argument) a string to modify. Each string will contain one
176             # and only one sentence.
177             #
178              
179             # Add preambles randomly.
180             sub _apply_add_before {
181 1     1   4 my ($self, $target) = @_;
182 1 50       60 if ( rand(100) < $self->{add_before} ) {
183 1         3 my $before = $beg[ rand( int(@beg) ) ];
184 1         4 $target = $before.$target;
185             }
186 1         4 return $target;
187             }
188              
189             # Add end of sentences randomly.
190             sub _apply_add_after {
191 1     1   20 my ($self, $target) = @_;
192 1 50       7 if ( rand(100) < $self->{add_after} ) {
193 1         4 my $after = $end[ rand( int(@end) ) ];
194 1         2 $target .= $after;
195             }
196 1         4 return $target;
197             }
198              
199             # Mix case as wanted.
200             sub _apply_case_mixer {
201 5     5   6 my ($self, $target) = @_;
202              
203 5 100       17 if ( $self->{case_mixer} =~ m!^(\d+)/(\d+)$! ) {
204             # Fixed pattern.
205 3         25 my $what = "";
206 3         7 my ($m, $n) = ( $1, $2 );
207 3         7 for my $c (split //, $target) {
208 15         37 $self->{_case_mix} =~ m/^([mn])(\d+)$/;
209 15 100       34 $what .= ($1 eq "m") ? uc($c) : $c;
210 15         10 my $new;
211 15         20 my $count = $2 + 1;
212 15 100       24 if ( $1 eq "m" ) {
213 8 50       18 $2+1 != $m and $new = "m$count";
214 8 100 66     34 $2+1 == $m && $n == 0 and $new = "m0";
215 8 100 66     34 $2+1 == $m && $n != 0 and $new = "n0";
216             } else {
217 7 50       14 $2+1 != $n and $new = "n$count";
218 7 100 66     33 $2+1 == $n && $m == 0 and $new = "n0";
219 7 100 66     26 $2+1 == $n && $m != 0 and $new = "m0";
220             }
221 15         28 $self->{_case_mix} = $new;
222             }
223 3         7 $target = $what;
224             } else {
225             # Put extra space at random.
226 2 50       8 $target =~ s/(.)/rand(100)<$self->{case_mixer}?uc($1):$1/eg;
  10         32  
227             }
228 5         14 return $target;
229             }
230              
231             # Add whole sentences randomly.
232             sub _apply_extra_sent {
233 21     21   33 my $self = shift;
234 21 100       366 if ( rand(100) < $self->{extra_sent} ) {
235 1         5 return $sentences[rand( @sentences ) ];
236             }
237 20         40 return undef;
238             }
239              
240             # Transform o to 0, l to 1, etc. That's 31337!
241             sub _apply_letters {
242 2     2   3 my ($self, $target) = @_;
243              
244 2         7 return join "", map { rand(100) < $self->{letters} && exists $letter{$_} ?
  3         15  
245             ( ref($letter{$_}) eq ref([]) ) ?
246 10 100 66     62 $letter{$_}[rand( @{$letter{$_}} ) ] :
    100          
247             $letter{$_}
248             : $_ } split //, $target;
249             }
250              
251             # Put extra space between chars.
252             sub _apply_spacer {
253 5     5   6 my ($self, $target) = @_;
254              
255 5 100       21 if ( $self->{spacer} =~ m!^(\d+)/(\d+)$! ) {
256             # Fixed pattern.
257 3         32 my $what = "";
258 3         8 my ($m, $n) = ( $1, $2 );
259 3         11 for my $c (split //, $target) {
260 20         61 $self->{_space} =~ m/^([mn])(\d+)$/;
261 20 100       48 $what .= ($1 eq "m") ? "$c " : $c;
262 20         20 my $new;
263 20         30 my $count = $2 + 1;
264 20 100       38 if ( $1 eq "m" ) {
265 10 50       25 $2+1 != $m and $new = "m$count";
266 10 100 66     59 $2+1 == $m && $n == 0 and $new = "m0";
267 10 100 66     48 $2+1 == $m && $n != 0 and $new = "n0";
268             } else {
269 10 50       23 $2+1 != $n and $new = "n$count";
270 10 100 66     53 $2+1 == $n && $m == 0 and $new = "n0";
271 10 100 66     47 $2+1 == $n && $m != 0 and $new = "m0";
272             }
273 20         43 $self->{_space} = $new;
274             }
275 3         9 $target = $what;
276             } else {
277             # Put extra space at random.
278 2 100       9 $target =~ s/(.)/rand(100)<$self->{spacer}?"$1 ":$1/eg;
  10         38  
279             }
280 5         16 return $target;
281             }
282              
283             # Transform words according to %words.
284             sub _apply_words {
285 2     2   4 my ($self, $target) = @_;
286 2         3 my @what = ();
287 2         5 for my $word ( split / /, $target ) {
288 2 50       6 if ( exists( $words{$word} ) ) {
289 2         4 my $subst = $words{$word};
290 2 100       32 $word = ref($subst) eq ref([]) ?
291             $subst->[ rand( int(@$subst) ) ]
292             : $subst;
293             }
294 2         7 push @what, $word;
295             }
296 2         8 return join " ", @what;
297             }
298              
299             # Main entry point for string transformation.
300             sub _transform {
301 21     21   32 my ($self, $line) = @_;
302              
303 21 50       47 $line or return; # Case undef.
304 21         27 my $sentence;
305 21         89 my @what = split "([.?!\n])", lc $line;
306 21         79 while ( my ($what, $punc) = splice @what, 0, 2 ) {
307             # Build the sentence.
308 21 100       58 $self->{add_before} and $what = $self->_apply_add_before($what);
309 21 100       55 $self->{add_after} and $what = $self->_apply_add_after($what);
310              
311 21 50       54 defined($punc) and $what .= $punc;
312              
313 21         92 my $extra = $self->_apply_extra_sent();
314 21 100       51 $extra and $what .= " $extra";
315              
316             # Transform chars.
317 21         39 foreach my $plugin ( qw( words spacer letters case_mixer ) ) {
318 84         126 my $meth = "_apply_$plugin";
319 84 100       252 $self->{$plugin} and $what = $self->$meth($what);
320             }
321 21         83 $sentence .= $what;
322             }
323 21         147 return $sentence;
324             }
325              
326             # By default, tie standard filedescriptors.
327             # tie *STDOUT, __PACKAGE__, *STDOUT;
328             # tie *STDERR, __PACKAGE__, *STDERR;
329              
330              
331             1;
332             __END__