#!/usr/local/bin/perl use strict; use warnings; BEGIN { # Try to load YAML::Syck (faster, preferred), fall back to YAML otherwise # thanks to PerlMonks' shmem for pointing out potential YAML::Syck trouble eval { require YAML::Syck; YAML::Syck->import( qw[LoadFile DumpFile] ); }; if ($@) { # fall back to YAML require YAML; YAML->import( qw[LoadFile DumpFile] ); } } use Getopt::Long; # how do we want to operate? usage() unless @ARGV; GetOptions( 'help|usage|?|h' => \&usage, 'reset' => sub { for (<*.yaml>) { unlink while -f } }, 'today' => \&daily_tao, 'chapter' => \&my_tao, 'license' => sub { print join('',); exit; }, ); #======================================================================== # load_tao - loads or regenerates cache of tao chapters, returns as list sub load_tao { if ( -f 'tao.yaml') { # load chapters from disk cache, if we have them return @{ LoadFile('tao.yaml') }; } else { # otherwise, get them from the web and build the cache return @{ get_web_tao() }; } } #======================================================================== # daily_tao - shows a new dao chapter if the date has advanced by at # least one day since the last run. Uses 'day.yaml' for # cache. sub daily_tao { my @chapter = load_tao(); my $day_index = 0; my $time = time; my $now = $time; # load last run info, if any. if ( -f 'day.yaml' ) { ($day_index, $time) = @{ LoadFile('day.yaml') } } my @now = localtime($now); my @last = localtime($time); if ( $last[7] != $now[7] || $last[5] != $now[5]) { # it's not the same day as last we ran $day_index++; if ($day_index > $#chapter) { $day_index = 0 } # roll over $time = $now; # we will record the *current* time } printf "%s: %s\n%s", @{ $chapter[$day_index] }; DumpFile('day.yaml', [ $day_index, $time ]); } #======================================================================== # my_tao - shows the chapter specified on the command line ($ARGV[0]) # with no parameter, shows the first chapter # with a numeric parameter, shows chap. for that record number # with a paramter ending in '.', shows record with that chap. id # Dies if there's an invalid chap. id or spec. sub my_tao { my @chapter = load_tao(); my $chapter = (@ARGV ? shift @ARGV : 0); if ($chapter =~ /\./) { # this is a chapter spec my $chindex = 0; for (0..$#chapter) { $chindex = $_; last if "$chapter[$_][0]." eq $chapter; } die "$chapter is not a valid chapter spec\n" if "$chapter[$chindex][0]." ne $chapter; $chapter = $chindex; } elsif ($chapter =~ /\D/) { # doesn't look like a spec, but isn't just a number - invalid die "'$chapter' is neither a valid spec nor a valid numeric id\n"; } die "The last record is no.$#chapter, but you asked for no.$chapter\n" if $chapter > $#chapter; printf "%s: %s\n%s", @{$chapter[$chapter]}; } #======================================================================== # get_web_tao - retrieves the "GNL" tao te ching from the web and # creates the disk cache of the chapters in 'tao.yaml' # if a local file 'taote-v4.html' exists, will use that # instead of fetching from the web sub get_web_tao { require HTML::TokeParser::Simple; my $p = HTML::TokeParser::Simple->new( -f 'taote-v4.html' ?(file => 'taote-v4.html') :(url => 'http://acc6.its.brooklyn.cuny.edu/~phalsall/texts/taote-v4.html') ); # skip notices and such, but record them to license.txt my $LIC; while (my $token = $p->get_token) { last if $token->is_end_tag('h2'); if ($token->is_start_tag('pre')) { # start of license text and copyright notice open $LIC, '>license.txt' or die ("Can't write license.txt: $!"); } elsif ($token->is_end_tag('pre')) { # end of license text and copyright notice close $LIC; undef $LIC; } elsif ($token->is_text && defined $LIC) { # body text for license and copyright print $LIC $token->as_is; } } # add chapters to data struct in form [id, title, text] my @chapter; while (my $token = $p->get_token) { next unless $token->is_start_tag('h3'); #title start (my $title = $p->peek(1)) =~ s{^(.+?)\.\s}{}g; my $num = $1; my $text = ''; #finish end of title while ($token = $p->get_token) { last if $token->is_end_tag('h3') } #grab text *as* text while ($token = $p->get_token) { last if $p->peek =~ /

/i; next if $token->is_tag; $text.=$token->as_is; } push @chapter, [ $num, $title, $text ]; } DumpFile('tao.yaml', \@chapter); return \@chapter; } #======================================================================== # usage - prints a nice usage message and exits the app sub usage { print <