From c0edd7e3b41aa0dcf511718079893a20bcd34127 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Fri, 10 Aug 2012 03:09:38 -0400 Subject: Add post-processing script and modules. --- diff --git a/scripts/MarkdownBook/Book.pm b/scripts/MarkdownBook/Book.pm new file mode 100644 index 0000000..f2d723a --- /dev/null +++ b/scripts/MarkdownBook/Book.pm @@ -0,0 +1,193 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::Document::Index; +use MarkdownBook::Document::Chapter; +use MarkdownBook::Document::Appendix; +use HTML::Template; + +package MarkdownBook::Book; + +sub new +{ + my ($class, $dir) = @_; + my $self; + my $control_fh; + + $class = ref($class) || $class; + $self = {}; + bless($self,$class); + $self->{'dir'} = $dir; + $self->{'docs'} = []; + + open($control_fh, '<', $dir . '/control'); + while (<$control_fh>) { + chomp($_); + if (m/^Title: /) { + s/^Title: (.*)$/$1/; + $self->{'title'} = $_; + } + } + close($control_fh); + + return $self; +} + +sub dir +{ + my ($self, $dir) = @_; + my $old = $self->{'dir'}; + + $self->{'dir'} = $dir if defined($dir); + + return $old; +} + +sub title +{ + my ($self, $title) = @_; + my $old = $self->{'title'}; + + $self->{'title'} = $title if defined($title); + + return $old; +} + +sub create_documents +{ + my ($self) = @_; + my $series_fh; + my $file; + my $title; + my $i; + my $doc; + my $doc_prev; + my @letters; + + $i = 0; + $doc = MarkdownBook::Document::Index->new($self); + $doc_prev = $doc; + push(@{$self->{'docs'}}, $doc); + + open($series_fh, '<', $self->{'dir'} . '/chapters'); + while (<$series_fh>) { + chomp($_); + ($file, $title) = split(/[ \t]+/, $_, 2); + $doc = MarkdownBook::Document::Chapter->new($self, $file, + ++$i, $title); + $doc->prev($doc_prev); + $doc_prev->next($doc) if defined $doc_prev; + $doc_prev = $doc; + push(@{$self->{'docs'}}, $doc); + } + close($series_fh); + + $i = -1; + @letters = ('A' .. 'Z'); + + if (-e $self->{'dir'} . '/appendices') { + open($series_fh, '<', $self->{'dir'} . '/apendices'); + while (<$series_fh>) { + chomp($_); + ($file, $title) = split(/[ \t]+/, $_, 2); + $doc = MarkdownBook::Document::Appendix->new($self, $file, + $letters[++$i], $title); + $doc->prev($doc_prev); + $doc_prev->next($doc) if defined $doc_prev; + $doc_prev = $doc; + push(@{$self->{'docs'}}, $doc); + } + close($series_fh); + } +} + +sub list_documents +{ + my ($self) = @_; + my $doc; + + foreach $doc (@{$self->{'docs'}}) { + printf("Document:\n File: %s\n Title: %s\n Full Title: %s\n", + $doc->file(), $doc->title(), $doc->full_title()); + printf(" Prev: %s\n", $doc->prev()->file()) if defined $doc->prev(); + printf(" Next: %s\n", $doc->next()->file()) if defined $doc->next(); + } +} + +sub parse_documents +{ + my ($self) = @_; + my $doc; + + foreach $doc (@{$self->{'docs'}}) { + $doc->parse_html(); + } +} + +sub number_sections +{ + my ($self) = @_; + my $doc; + + foreach $doc (@{$self->{'docs'}}) { + $doc->number_sections(); + } +} + +sub write_templated_documents +{ + my ($self) = @_; + my $doc_tmpl; + my $doc; + my $doc_fh; + + $doc_tmpl = HTML::Template->new(filename => 'include/document.tmpl'); + + foreach $doc (@{$self->{'docs'}}) { + + $doc_tmpl->param( + IS_INDEX => (ref($doc_tmpl) eq 'MarkdownBook::Document::Index')); + + $doc_tmpl->param(BOOK_TITLE => $self->{'title'}); + $doc_tmpl->param(TITLE => $doc->title()); + $doc_tmpl->param(CHAPT_TITLE => $doc->full_title()); + + if (defined($doc->prev())) { + $doc_tmpl->param(PREV_LINK => $doc->prev()->file() . '.html'); + $doc_tmpl->param(PREV_TITLE => $doc->prev()->title()); + } else { + $doc_tmpl->param(PREV_LINK => undef); + $doc_tmpl->param(PREV_TITLE => undef); + } + if (defined($doc->next())) { + $doc_tmpl->param(NEXT_LINK => $doc->next()->file() . '.html'); + $doc_tmpl->param(NEXT_TITLE => $doc->next()->title()); + } else { + $doc_tmpl->param(NEXT_LINK => undef); + $doc_tmpl->param(NEXT_TITLE => undef); + } + + $doc_tmpl->param(BODY => $doc->output()); + + open($doc_fh, '>', $doc->file_path() . '.html'); + $doc_tmpl->output(print_to => $doc_fh); + close($doc_fh); + } +} + +1; diff --git a/scripts/MarkdownBook/Document.pm b/scripts/MarkdownBook/Document.pm new file mode 100644 index 0000000..f9b9a13 --- /dev/null +++ b/scripts/MarkdownBook/Document.pm @@ -0,0 +1,180 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::HTMLTree; +use HTML::TreeBuilder; + +package MarkdownBook::Document; + +sub new +{ + my ($class, $book, $file, $id, $title) = @_; + my $self; + + $class = ref($class) || $class; + $self = {}; + bless($self,$class); + $self->{'book'} = $book; + $self->{'file'} = $file; + $self->{'id'} = $id; + $self->{'title'} = $title; + + return $self; +} + +sub book +{ + my ($self, $book) = @_; + my $old = $self->{'book'}; + + $self->{'book'} = $book if defined($book); + + return $old; +} + +sub file +{ + my ($self, $file) = @_; + my $old = $self->{'file'}; + + $self->{'file'} = $file if defined($file); + + return $old; +} + +sub file_path +{ + my ($self) = @_; + + return $self->{'book'}->dir() . '/' . $self->{'file'}; +} + +sub title +{ + my ($self, $title) = @_; + my $old = $self->{'title'}; + + $self->{'title'} = $title if defined($title); + + return $old; +} + +sub prev +{ + my ($self, $other) = @_; + my $old = $self->{'prev'}; + + $self->{'prev'} = $other if defined($other); + + return $old; +} + +sub next +{ + my ($self, $other) = @_; + my $old = $self->{'next'}; + + $self->{'next'} = $other if defined($other); + + return $old; +} + +sub parse_html +{ + my ($self) = @_; + my $file = $self->{'book'}->dir() . '/' . $self->{'file'} . '.html.in'; + + $self->{'tree'} = HTML::TreeBuilder->new(); + $self->{'tree'}->parse_file($file); +} + +sub number_sections +{ + my ($self) = @_; + + my @headers; + my $header; + my @secnums = (0, 0); + my $curlev = -1; + my $newlev; + my $secstr; + my @children; + my $sectitle; + my $secid; + + @{$self->{'tree_body'}} = MarkdownBook::HTMLTree::find_elements_by_tag_names( + $self->{'tree'}, ('body')); + @headers = MarkdownBook::HTMLTree::find_elements_by_tag_names( + @{$self->{'tree_body'}}[0], ('h1', 'h2')); + + foreach $header (@headers) { + + # Calculate section number. + $newlev = $header->tag(); + $newlev =~ s/^h(\d)$/$1/; + if ($newlev != $curlev) { + foreach (@secnums[$newlev .. $#secnums]) { + $_ = 0; + } + } + $curlev = $newlev; + ++$secnums[$newlev - 1]; + $secstr = join('.', @secnums); + $secstr =~ s/(\.0)*$//; + + MarkdownBook::HTMLTree::each_text(sub { + + # Prefix section title with section number. + my $sectitle = $_[1]; + $sectitle =~ s/^([^\[]+)[ ]*\[[^\]]+\]$/$_[2].$secstr $1/; + + # Set "id" attribute. + if ($_[1] =~ m/^[^\[\]]*\[([^\]]+)\][^\[\]]*$/) { + my $secid = $_[1]; + $secid =~ s/^[^\[\]]*\[([^\]]+)\][^\[\]]*$/$1/; + ${$_[0]}->attr('id', $secid); + } + + # Set section title. + $_[1] = $sectitle; + + }, $header, $self->{'id'}); + + } +} + +sub output +{ + my ($self) = @_; + + my $elem; + my %opt_end_tags; + my $out; + + # Don't omit any end tags. + %opt_end_tags = map([$_ => 0], %HTML::Element::optionalEndTag); + + foreach $elem (@{$self->{'tree_body'}}[0]->content_list()) { + # It's safe to assume (ref($elem) eq 'HTML::Element'). + $out .= $elem->as_HTML('<>&', '', \%opt_end_tags) . "\n"; + } + + return $out; +} + +1; diff --git a/scripts/MarkdownBook/Document/Appendix.pm b/scripts/MarkdownBook/Document/Appendix.pm new file mode 100644 index 0000000..37d3cf8 --- /dev/null +++ b/scripts/MarkdownBook/Document/Appendix.pm @@ -0,0 +1,32 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::Document; + +package MarkdownBook::Document::Appendix; + +our @ISA = qw(MarkdownBook::Document); + +sub full_title +{ + my ($self) = @_; + + return sprintf('Appendix %s - %s', $self->{'id'}, $self->{'title'}); +} + +1; diff --git a/scripts/MarkdownBook/Document/Chapter.pm b/scripts/MarkdownBook/Document/Chapter.pm new file mode 100644 index 0000000..90a5f5c --- /dev/null +++ b/scripts/MarkdownBook/Document/Chapter.pm @@ -0,0 +1,32 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::Document; + +package MarkdownBook::Document::Chapter; + +our @ISA = qw(MarkdownBook::Document); + +sub full_title +{ + my ($self) = @_; + + return sprintf('Chapter %d - %s', $self->{'id'}, $self->{'title'}); +} + +1; diff --git a/scripts/MarkdownBook/Document/Index.pm b/scripts/MarkdownBook/Document/Index.pm new file mode 100644 index 0000000..e005396 --- /dev/null +++ b/scripts/MarkdownBook/Document/Index.pm @@ -0,0 +1,47 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::Document; + +package MarkdownBook::Document::Index; + +our @ISA = qw(MarkdownBook::Document); + +sub new +{ + my ($class, $book) = @_; + my $self; + + $class = ref($class) || $class; + $self = {}; + bless($self,$class); + $self->{'book'} = $book; + $self->{'file'} = 'index'; + $self->{'title'} = $book->title(); + + return $self; +} + +sub full_title +{ + my ($self) = @_; + + return undef; +} + +1; diff --git a/scripts/MarkdownBook/HTMLTree.pm b/scripts/MarkdownBook/HTMLTree.pm new file mode 100644 index 0000000..27db3e1 --- /dev/null +++ b/scripts/MarkdownBook/HTMLTree.pm @@ -0,0 +1,72 @@ +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use HTML::Element; + +package MarkdownBook::HTMLTree; + +sub find_elements_by_tag_names +{ + my ($elem, @tagnames) = @_; + + my @list = $elem->content_list(); + my $tag; + my @retlist = (); + + foreach (@list) { + if (ref($_) ne 'HTML::Element') { + next; + } + $tag = $_->tag(); + if (grep($_ eq $tag, @tagnames)) { + push(@retlist, $_); + } + } + + return @retlist; +} + +sub each_text +{ + my ($code, $elem, @args) = @_; + + my $child = $elem; + my $root = $elem; + + _each_text_recursive($code, $child, $root, @args); +} + +sub _each_text_recursive +{ + my ($code, $elem, $root, @args) = @_; + + my $child; + my $i = -1; + + foreach $child ($elem->content_list()) { + ++$i; + if (ref($_) eq 'HTML::Element') { + _each_text_recursive($code, $child, $root, @args); + } else { + $code->(\$root, $child, @args); + $elem->splice_content($i, 1, $child); + } + } +} + +1; diff --git a/scripts/postproc.pl b/scripts/postproc.pl new file mode 100755 index 0000000..d45b022 --- /dev/null +++ b/scripts/postproc.pl @@ -0,0 +1,33 @@ +#! /usr/bin/perl +# +# Copyright (C) 2012 Patrick "P. J." McDermott +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; +use warnings; + +use MarkdownBook::Book; + +my $doc_dir; +my $book; + +($doc_dir) = @ARGV; + +$book = MarkdownBook::Book->new($doc_dir); + +$book->create_documents(); +$book->parse_documents(); +$book->number_sections(); +$book->write_templated_documents(); -- cgit v0.9.1