The weekly challenge 286 - Task 1: Self Spammer

 1 #!/usr/bin/env perl
 2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-286/#TASK1
 3 #
 4 # Task 1: Self Spammer
 5 # ====================
 6 #
 7 # Write a program which outputs one word of its own script / source code at
 8 # random. A word is anything between whitespace, including symbols.
 9 #
10 ## Example 1
11 ##
12 ## If the source code contains a line such as: 'open my $fh, "<", "ch-1.pl" or die;'
13 ## then the program would output each of the words { open, my, $fh,, "<",, "ch-1.pl", or, die; }
14 ## (along with other words in the source) with some positive probability.
15 #
16 ## Example 2
17 ##
18 ## Technically 'print(" hello ");' is *not* an example program, because it does not
19 ## assign positive probability to the other two words in the script.
20 ## It will never display print(" or ");
21 #
22 ## Example 3
23 ##
24 ## An empty script is one trivial solution, and here is another:
25 ## echo "42" > ch-1.pl && perl -p -e '' ch-1.pl
26 #
27 ############################################################
28 ##
29 ## discussion
30 ##
31 ############################################################
32 #
33 # We read the program code by opening $0 for reading, then reading everything
34 # line by line. We randomly select one line, which we then split into tokens
35 # at whitespace. Then we randomly select one token and print it.
36 # Obviously, this also contains comments, which we could exclude by grepping the
37 # program for lines that don't start in '#'.
38 
39 use strict;
40 use warnings;
41 
42 self_spammer($0);
43 
44 sub self_spammer {
45    my $program = shift;
46    my @lines = ();
47    open(my $IN, "<", $program) or die "Can't open $program for reading: $!";
48    while(my $line = <$IN>) {
49       chomp($line);
50       push @lines, $line;
51    }
52    my $l = $lines[int(rand(1+$#lines))];
53    my @tokens = split /\s+/, $l;
54    my $t = $tokens[int(rand(1+$#tokens))];
55    print "$t\n";
56 }
57