From e6106e4bfd22aa448fd972150e6bcc39e9fbcb45 Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Mon, 13 Aug 2012 14:23:54 -0400 Subject: Split scripts directory into bin and lib. --- (limited to 'lib/MarkdownBook/Document.pm') diff --git a/lib/MarkdownBook/Document.pm b/lib/MarkdownBook/Document.pm new file mode 100644 index 0000000..2a30396 --- /dev/null +++ b/lib/MarkdownBook/Document.pm @@ -0,0 +1,245 @@ +# 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::Section; +use Carp; + +package MarkdownBook::Document; + +sub new +{ + my ($class, $book, $type, $file, $id, $title) = @_; + my $self; + + $class = ref($class) || $class; + $self = {}; + bless($self, $class); + + $self->{'book'} = $book; + $self->{'type'} = $type; + $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 type +{ + my ($self, $type) = @_; + my $old = $self->{'type'}; + + $self->{'type'} = $type if defined($type); + + 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 id +{ + my ($self) = @_; + + return $self->{'id'}; +} + +sub title +{ + my ($self, $title) = @_; + my $old = $self->{'title'}; + + $self->{'title'} = $title if defined($title); + + return $old; +} + +sub full_title +{ + my ($self) = @_; + + if ($self->{'type'} eq 'chapter') { + return sprintf('Chapter %d - %s', $self->{'id'}, $self->{'title'}); + } elsif ($self->{'type'} eq 'appendix') { + return sprintf('Appendix %s - %s', $self->{'id'}, $self->{'title'}); + } else { + return undef; + } +} + +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 sections +{ + my ($self) = @_; + + # FIXME: Why is this necessary?! + foreach my $sec (@{$self->{'sections'}}) { + } + + return $self->{'sections'}; +} + +sub parse +{ + my ($self) = @_; + my $source_fh; + my $source_text; + + open($source_fh, '<', + $self->{'book'}->dir() . '/' . $self->{'file'} . '.mdwn') + or Carp::croak('Cannot open "' . $self->{'file'} . '" source document'); + $source_text = join('', <$source_fh>); + close($source_fh); + + # Parse headings of non-index documents. + if ($self->{'type'} ne 'index') { + $self->{'section_level_numbers'} = [0, 0]; + $self->{'section_level'} = -1; + $source_text =~ s/ + ^ + (.+) # Heading text + [ \t]* # Optional trailing whitespace + \n # Line break + (=+|-+) # Underline + [ \t]* # Optional trailing whitespace + $ + /$self->_do_heading($1, $2)/mexg; + } + + # Store parsed text. + $self->{'source_text'} = $source_text; +} + +sub _do_heading +{ + my ($self, $text, $underline) = @_; + my $level; + my $levels; + my $section_number; + my $section_title; + my $section_id; + my $section; + + # Shorten underline to one character. + $underline =~ s/^([=-]).*$/$1/; + + # Detect heading level. + if ($underline eq '=') { + $level = 1; + } else { + $level = 2; + } + + # Calculate section number. + $levels = $#{$self->{'section_level_numbers'}}; + if ($level != $self->{'section_level'}) { + foreach (@{$self->{'section_level_numbers'}}[$level .. $levels]) { + $_ = 0; + } + } + $self->{'section_level'} = $level; + ++${$self->{'section_level_numbers'}}[$level - 1]; + $section_number = join('.', @{$self->{'section_level_numbers'}}); + + # Add document ID to section number. + $section_number = $self->{'id'} . '.' . $section_number; + + # Trim off unused subsection parts. + $section_number =~ s/(?:\.0)*$//; + + # Parse out section title. + $section_title = $text; + $section_title =~ s/ + ^ + ([^\[]+) # Section title + [ \t]+ # Whitespace + \[ # Left square bracket + [^\]]+ # Section ID + \] # Right square bracket + $ + /$1/x; + + # Parse out section ID. + $section_id = $text; + $section_id =~ s/ + ^ + [^\[\]]+ # Section title + [ \t]+ # Whitespace + \[ # Left square bracket + ([^\]]+) # Section ID + \] # Right square bracket + $ + /$1/x; + + # Create and store section object. + $section = MarkdownBook::Section->new($self, + $level, $section_number, $section_id, $section_title); + push(@{$self->{'sections'}}, $section); + $self->{'book'}->add_section($section); + + # Prepend number to section title. + $text = $section_number . ' ' . $section_title; + + # Return underlined section title. + return $text . "\n" . $underline x length($text); +} + +1; -- cgit v0.9.1