summaryrefslogtreecommitdiffstats
path: root/scripts/MarkdownBook
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/MarkdownBook')
-rw-r--r--scripts/MarkdownBook/Book.pm193
-rw-r--r--scripts/MarkdownBook/Document.pm180
-rw-r--r--scripts/MarkdownBook/Document/Appendix.pm32
-rw-r--r--scripts/MarkdownBook/Document/Chapter.pm32
-rw-r--r--scripts/MarkdownBook/Document/Index.pm47
-rw-r--r--scripts/MarkdownBook/HTMLTree.pm72
6 files changed, 556 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+
+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;