I'm a big fan of the Tao te Ching, and after finding a free version (called GNL), I decided to write a tool that would give me a new chapter each day I ran it, in order, and start over when I reached the end.
I personally use this in a cron job to change my /etc/motd message.
When run for the first time with either the --daily or --chapter parameters, it will retrieve a copy of the GNL from the web, parse it into its chapters (saving the license to 'license.txt'), and store a YAML cache of that work. If you're running from behind a proxy, you can use some other proxy-enabled tool to save the GNL from the link in the first paragraph to a file named 'taote-v4.html' -- when put in the exec directory, the app will prefer that local copy.
--today causes the program to print the next chapter of the TTC if it's not the same day as the last time it was run.
--chapter lets you get a specific chapter (see usage for details)
To clean up and start fresh, use the --reset parameter.
Run without parameters or with '--usage', '--help', '-h', or '-?' for a usage message.
Depends on CPAN modules YAML-Syck (fast libsyck) or YAML (slower, pure-perl), and HTML-TokeParser-Simple (for parsing the HTML version of GNL). The last dependency is only needed for parsing the HTML document -- it is not needed once tao.yaml exists.
#!/usr/local/bin/perl use strict; use warnings; BEGIN { # Try to load YAML::Syck (faster, preferred), fall back to YAML othe +rwise # thanks to PerlMonks' shmem for pointing out potential YAML::Syck t +rouble 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('',<DATA>); exit; }, ); #===================================================================== +=== # load_tao - loads or regenerates cache of tao chapters, returns as li +st 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 numbe +r # 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 =~ /<h3>/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 <<USAGE_DOC; Daily Tao te Ching chapter printer. Uses the GNL version of the Tao Te Ching (TTC) from: http://acc6.its.brooklyn.cuny.edu/~phalsall/texts/taote-v4.html See the file license.txt after first run for the GNL license. $0 [--today] [--chapter id|spec] [--reset] $0 --license $0 [--help] [--usage] [-h] [-?] --chapter Display a specific chapter from the TTC, either by recor +d id (0-81) or by chapter number followed by a period. For ex +ample, to see TTC chapter 64b, use --chapter 64b. (including th +e period). Displays the last chapter if an invalid chapte +r number is specified. --today If the date has advanced at least one day since the last + time we got a new chapter, display the next chapter from the +TTC. --reset Delete all the disk caches: this will cause the next run + (or this run, if followed by one of the other options) to st +art at the beginning of the TTC and fetch a new copy from th +e web (or from the local file taote-v4.html) --license Display the license for this application (license for th +e GNL text is saved to license.txt once it is retrieved) --usage Display this message: aliases are --help, -h, and -? USAGE_DOC exit; } __DATA__ Copyright (c) 2006 RadiantMatrix (http://radiantmatrix.org) Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or s +ell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be include +d in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRES +S OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILIT +Y, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHAL +L THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISIN +G FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. ((See license.txt once the GNL has been retrieved for the GNL license +terms))
Updates:
A collection of thoughts and links from the minds of geeks
The Code that can be seen is not the true Code
I haven't found a problem yet that can't be solved by a well-placed trebuchet
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Get your Daily Tao Te Ching fix
by shmem (Chancellor) on Sep 22, 2006 at 13:01 UTC | |
by radiantmatrix (Parson) on Sep 22, 2006 at 15:43 UTC | |
Re: Get your Daily Tao Te Ching fix
by OfficeLinebacker (Chaplain) on Sep 30, 2006 at 04:06 UTC | |
Re: Get your Daily Tao Te Ching fix
by chanio (Priest) on Nov 12, 2006 at 16:44 UTC | |
by radiantmatrix (Parson) on Nov 14, 2006 at 16:29 UTC |