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:
- 2004-09-22 : shmem noted that YAML::Syck might be problematic for some. Updated code to prefer YAML::Syck, but fall back on YAML if Syck is not installed.
Re: Get your Daily Tao Te Ching fix
by shmem (Chancellor) on Sep 22, 2006 at 13:01 UTC
|
Great. radiantmatrix++ - this reminds me of the 'ching' utility
way back in SunOS4.1.3 ;-)
--shmem
PS: YAML::Syck seems currently (v 0.67) broken, though. On my box
it just segfaults during the tests.
But YAML just works, too, this script not being too speed critical ;-) - perl -pi -e 's/::Syck//g' tao.pl and done.
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
---------------------------- \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
| [reply] [d/l] |
|
Huh, I haven't had any trouble with the current YAML::Syck on Win32 or OS-X. Haven't tried it on Linux or BSD, yet, but you'd think if it builds on OS-X...
In any case, I think I will add some code to try YAML::Syck, and then fall back to the usual YAML if I can't find the Syck version. Unforutnately, that means I will have to import LoadFile and DumpFile, polluting my beautiful, beautiful namespace -- you bastard. ;-)
| [reply] |
Re: Get your Daily Tao Te Ching fix
by OfficeLinebacker (Chaplain) on Sep 30, 2006 at 04:06 UTC
|
So I guess you could probably adapt that to use any book that is on Project Gutenberg? Personally I'd like to do it with a book like How to Win Friends and Influence People but I bet you that, for example, Marcus Aurelius' Meditations is in the public domain.
_________________________________________________________________________________
I like computer programming because it's like Legos for the mind.
| [reply] |
Re: Get your Daily Tao Te Ching fix
by chanio (Priest) on Nov 12, 2006 at 16:44 UTC
|
__.....-.. +-+-+-+-+-+ +-+-+-+ +-+-+ +-+-+-+-+-+
_,' `\ `-. |D|a|i|l|y| |T|a|o| |t|e| |C|h|i|n|g|
/ /['\ | \ +-+-+-+-+-+ +-+-+-+ +-+-+ +-+-+-+-+-+
.' `.:/ .' L O-----------------------------------O
| ,' | | 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. |
'--. _..-' O-----------------------------------O
And added a --B-today option to show with a banner as heading... With tkmore!
sub daily_tao
{
my $banner = shift;## NEW OPTION TO ADD A HEADER WITH THE TITLE
...
print <<HEAD if ($banner);
__.....-..
_,' `\ `-.
/ /['\ | \ +-+-+-+-+-+ +-+-+-+
.' `.:/ .' . |D|a|i|l|y| |T|a|o|
| ,' | +-+-+ +-+-+-+-+-+
| ,---'' | |T|e| |C|h|i|n|g|
| ,' | +-+-+-+-+-+-+-+ +-+
`. | ,. / |p|r|i|n|t|e|r| |@|
\ ` ,.' / +-+-+-+-+-+-+-+ +-+
'` _,'
'--. _..-'
HEAD
printf "%s: %s\n%s", @{ $chapter[$day_index] };
...
And the option...
...
'today' => \&daily_tao,
'B-today' => \&daily_tao(1), ## ADDS A BANNER
...
Then, I could also call it...
perl tao.pl --B-today | tkmore -
Or in LINUX...
perl tao.pl --B-today | perl -e'while (<>){print($_,$/) if ($_=~s/^/
+/ && $_=~s/[\r\n]//g)}'| Xdialog --rc-file ~/.ocrebox.rc --title="To
+day's TAO" --textbox - 0 0 &
Thank you for your nice script!
I adjusted the ASCII-art to display well in my non monospaced screen....
| [reply] [d/l] [select] |
|
Hey, some cool additions... but the point of not jazzing it up like that is to follow the UNIX methodology -- that is, to create a program with output that others can easily consume.
I'd rather see you either (a)abstract my script into a module and then create two scripts -- one that uses your enhancements, and one that doesn't; or (b)create a wrapper or pipe target for the output of my script to add your enhancements.
Honestly, I'd prefer option (a), as it would be trivial, then, to create GUI front-ends and the like. Maybe I'll take that on, if you don't...
<–radiant.matrix–>
Ramblings and references
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
| [reply] |
|
|