huge pile of pod updates
Tara L Andrews [Fri, 3 Feb 2012 02:00:50 +0000 (03:00 +0100)]
13 files changed:
MANIFEST.SKIP [new file with mode: 0644]
lib/Text/Tradition/Collation.pm
lib/Text/Tradition/Collation/Reading.pm
lib/Text/Tradition/Collation/Relationship.pm
lib/Text/Tradition/Collation/RelationshipStore.pm
lib/Text/Tradition/Directory.pm
lib/Text/Tradition/Error.pm
lib/Text/Tradition/Parser/Tabular.pm
lib/Text/Tradition/Parser/Util.pm
lib/Text/Tradition/Stemma.pm
lib/Text/Tradition/StemmaUtil.pm
t/03podcoverage.t
t/stemma.t

diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644 (file)
index 0000000..cb8c062
--- /dev/null
@@ -0,0 +1,5 @@
+lib/Text/Tradition/Parser/BaseText.pm
+lib/Text/Tradition/Parser/CollateText.pm
+lib/Text/Tradition/Parser/CTE.pm
+lib/Text/Tradition/Parser/KUL.pm
+lib/Text/Tradition/Analysis.pm
index 0692c7c..1b98dd0 100644 (file)
@@ -549,7 +549,7 @@ sub as_dot {
     foreach my $edge ( @edges ) {
        # Do we need to output this edge?
        if( $used{$edge->[0]} && $used{$edge->[1]} ) {
-               my $label = $self->path_display_label( $self->path_witnesses( $edge ) );
+               my $label = $self->_path_display_label( $self->path_witnesses( $edge ) );
                        my $variables = { %edge_attrs, 'label' => $label };
                        # Account for the rank gap if necessary
                        if( $self->reading( $edge->[1] )->has_rank 
@@ -574,13 +574,13 @@ sub as_dot {
     }
     # Add substitute start and end edges if necessary
     foreach my $node ( keys %substart ) {
-       my $witstr = $self->path_display_label ( $self->reading_witnesses( $self->reading( $node ) ) );
+       my $witstr = $self->_path_display_label ( $self->reading_witnesses( $self->reading( $node ) ) );
        my $variables = { %edge_attrs, 'label' => $witstr };
         my $varopts = _dot_attr_string( $variables );
         $dot .= "\t\"#SUBSTART#\" -> \"$node\" $varopts;";
        }
     foreach my $node ( keys %subend ) {
-       my $witstr = $self->path_display_label ( $self->reading_witnesses( $self->reading( $node ) ) );
+       my $witstr = $self->_path_display_label ( $self->reading_witnesses( $self->reading( $node ) ) );
        my $variables = { %edge_attrs, 'label' => $witstr };
         my $varopts = _dot_attr_string( $variables );
         $dot .= "\t\"$node\" -> \"#SUBEND#\" $varopts;";
@@ -604,6 +604,13 @@ sub _dot_attr_string {
        return( '[ ' . join( ', ', @attrs ) . ' ]' );
 }
 
+=head2 path_witnesses( $edge )
+
+Returns the list of sigils whose witnesses are associated with the given edge.
+The edge can be passed as either an array or an arrayref of ( $source, $target ).
+
+=cut
+
 sub path_witnesses {
        my( $self, @edge ) = @_;
        # If edge is an arrayref, cope.
@@ -615,7 +622,7 @@ sub path_witnesses {
        return @wits;
 }
 
-sub path_display_label {
+sub _path_display_label {
        my $self = shift;
        my @wits = sort @_;
        my $maj = scalar( $self->tradition->witnesses ) * 0.6;
@@ -806,7 +813,7 @@ sub as_graphml {
        }
        
        # Add the relationship graph to the XML
-       $self->relations->as_graphml( $graphml_ns, $root, \%node_hash, 
+       $self->relations->_as_graphml( $graphml_ns, $root, \%node_hash, 
                $node_data_keys{'id'}, \%edge_data_keys );
 
     # Save and return the thing
@@ -1411,16 +1418,16 @@ is( $c->common_successor( 'n21', 'n26' )->id,
 sub common_predecessor {
        my $self = shift;
        my( $r1, $r2 ) = $self->_objectify_args( @_ );
-       return $self->common_in_path( $r1, $r2, 'predecessors' );
+       return $self->_common_in_path( $r1, $r2, 'predecessors' );
 }
 
 sub common_successor {
        my $self = shift;
        my( $r1, $r2 ) = $self->_objectify_args( @_ );
-       return $self->common_in_path( $r1, $r2, 'successors' );
+       return $self->_common_in_path( $r1, $r2, 'successors' );
 }
 
-sub common_in_path {
+sub _common_in_path {
        my( $self, $r1, $r2, $dir ) = @_;
        my $iter = $r1->rank > $r2->rank ? $r1->rank : $r2->rank;
        $iter = $self->end->rank - $iter if $dir eq 'successors';
@@ -1455,10 +1462,12 @@ sub throw {
 no Moose;
 __PACKAGE__->meta->make_immutable;
 
-=head1 BUGS / TODO
+=head1 LICENSE
 
-=over
+This package is free software and is provided "as is" without express
+or implied warranty.  You can redistribute it and/or modify it under
+the same terms as Perl itself.
 
-=item * Get rid of $backup in reading_sequence
+=head1 AUTHOR
 
-=back
+Tara L Andrews E<lt>aurum@cpan.orgE<gt>
index 1d700a6..80f737c 100644 (file)
@@ -160,24 +160,50 @@ sub is_meta {
        return $self->is_start || $self->is_end || $self->is_lacuna || $self->is_ph;    
 }
 
-# Some syntactic sugar
+=head1 Convenience methods
+
+=head2 related_readings
+
+Calls Collation's related_readings with $self as the first argument.
+
+=cut
+
 sub related_readings {
        my $self = shift;
        return $self->collation->related_readings( $self, @_ );
 }
 
+=head2 predecessors
+
+Returns a list of Reading objects that immediately precede $self in the collation.
+
+=cut
+
 sub predecessors {
        my $self = shift;
        my @pred = $self->collation->sequence->predecessors( $self->id );
        return map { $self->collation->reading( $_ ) } @pred;
 }
 
+=head2 successors
+
+Returns a list of Reading objects that immediately follow $self in the collation.
+
+=cut
+
 sub successors {
        my $self = shift;
        my @succ = $self->collation->sequence->successors( $self->id );
        return map { $self->collation->reading( $_ ) } @succ;
 }
 
+=head2 set_identical( $other_reading)
+
+Backwards compatibility method, to add a transposition relationship
+between $self and $other_reading.  Don't use this.
+
+=cut
+
 sub set_identical {
        my( $self, $other ) = @_;
        return $self->collation->add_relationship( $self, $other, 
index efefaab..07c6293 100644 (file)
@@ -10,6 +10,25 @@ enum 'RelationshipScope' => qw( local tradition global );
 
 no Moose::Util::TypeConstraints;
 
+=head1 NAME
+
+Text::Tradition::Collation::Relationship - represents a syntactic or semantic
+relationship between two readings
+    
+=head1 DESCRIPTION
+
+Text::Tradition is a library for representation and analysis of collated
+texts, particularly medieval ones.  A relationship connects two readings
+within a collation, usually when they appear in the same place in different
+texts.
+
+=head1 CONSTRUCTOR
+
+=head2 new
+
+Creates a new relationship. Usually called via $collation->add_relationship.
+Options include:
+
 =over 4
 
 =item * type - Can be one of spelling, orthographic, grammatical, meaning, lexical, collated, repetition, transposition.  All but the last two are only valid relationships between readings that occur at the same point in the text.
@@ -24,6 +43,20 @@ no Moose::Util::TypeConstraints;
 
 =back
 
+=head1 ACCESSORS
+
+=head2 type
+
+=head2 displayform
+
+=head2 scope
+
+=head2 non_correctable
+
+=head2 non_independent
+
+See the option descriptions above.
+
 =cut
 
 has 'type' => (
@@ -69,11 +102,25 @@ has 'non_independent' => (
        );
        
 # A read-only meta-Boolean attribute.
+
+=head2 colocated
+
+Returns true if the relationship type is one that requires that its readings
+occupy the same place in the collation.
+
+=cut
+
 sub colocated {
        my $self = shift;
        return $self->type !~ /^(repetition|transposition)$/;
 }
 
+=head2 nonlocal
+
+Returns true if the relationship scope is anything other than 'local'.
+
+=cut
+
 sub nonlocal {
        my $self = shift;
        return $self->scope ne 'local';
index 981fded..6f46c14 100644 (file)
@@ -347,7 +347,7 @@ sub merge_readings {
        $self->delete_reading( $deleted );
 }
 
-sub as_graphml { 
+sub _as_graphml { 
        my( $self, $graphml_ns, $xmlroot, $node_hash, $nodeid_key, $edge_keys ) = @_;
        
     my $rgraph = $xmlroot->addNewChild( $graphml_ns, 'graph' );
index 1685624..f01d19b 100644 (file)
@@ -207,4 +207,12 @@ sub throw {
 
 1;
        
-               
\ No newline at end of file
+=head1 LICENSE
+
+This package is free software and is provided "as is" without express
+or implied warranty.  You can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Tara L Andrews E<lt>aurum@cpan.orgE<gt>
index 18cb10e..42a9997 100644 (file)
@@ -25,7 +25,11 @@ Text::Tradition::Error - throwable error class for CollateX package
 
 A basic exception class to throw around, as it were.
 
-=cut
+=head1 LICENSE
+
+This package is free software and is provided "as is" without express
+or implied warranty.  You can redistribute it and/or modify it under
+the same terms as Perl itself.
 
 =head1 AUTHOR
 
index ba58660..723c0aa 100644 (file)
@@ -177,7 +177,7 @@ sub parse {
     # add them to the witness paths.
     foreach my $idx ( 1 .. $#{$alignment_table} ) {
         my $row = $alignment_table->[$idx];
-        my $nodes = make_nodes( $c, $row, $idx );
+        my $nodes = _make_nodes( $c, $row, $idx );
         foreach my $w ( 0 .. $#{$row} ) {
             # push the appropriate node onto the appropriate witness path
             my $word = $row->[$w];
@@ -243,7 +243,7 @@ sub parse {
        }
 }
 
-sub make_nodes {
+sub _make_nodes {
     my( $collation, $row, $index ) = @_;
     my %unique;
     my $commonctr = 0; # Holds the number of unique readings + gaps, ex. lacunae.
index a01cbd4..2cca6e8 100644 (file)
@@ -36,11 +36,11 @@ sub collate_variants {
     # transposed reading nodes to be merged into one (producing a
     # nonlinear, bidirectional graph) or not (producing a relatively
     # linear, unidirectional graph.)
-    return $collation->linear ? collate_linearly( @_ )
-        : collate_nonlinearly( @_ );
+    return $collation->linear ? _collate_linearly( @_ )
+        : _collate_nonlinearly( @_ );
 }
 
-sub collate_linearly {
+sub _collate_linearly {
     my( $collation, $lemma_set, @variant_sets ) = @_;
 
     my @unique;
@@ -87,7 +87,7 @@ sub collate_linearly {
     return $substitutions;
 }
 
-sub collate_nonlinearly {
+sub _collate_nonlinearly {
     my( $collation, $lemma_set, @variant_sets ) = @_;
     
     my @unique;
@@ -132,6 +132,12 @@ sub _collation_hash {
     return cmp_str( $node );
 }
 
+=head2 B<cmp_str>
+
+Don't use this. Really.
+
+=cut
+
 sub cmp_str {
     my( $reading ) = @_;
     my $word = $reading->text();
@@ -166,6 +172,12 @@ sub check_for_repeated {
     return @repeated;
 }
 
+=head2 B<add_hash_entry>( $hash, $key, $entry )
+
+Very simple utility for adding $entry to the list at $hash->{$key}.
+
+=cut
+
 sub add_hash_entry {
     my( $hash, $key, $entry ) = @_;
     if( exists $hash->{$key} ) {
@@ -175,24 +187,6 @@ sub add_hash_entry {
     }
 }
 
-sub is_monotonic {
-    my( @readings ) = @_;
-    my( $common, $min, $max ) = ( -1, -1, -1 );
-    foreach my $rdg ( @readings ) {
-#         print STDERR "Checking reading " . $rdg->id . "/" . $rdg->text . " - " 
-#         . $rdg->position->reference ."\n";
-        return 0 if $rdg->position->common < $common;
-        if( $rdg->position->common == $common ) {
-            return 0 if $rdg->position->min <= $min;
-            return 0 if $rdg->position->max <= $max;
-        }
-        $common = $rdg->position->common;
-        $min = $rdg->position->min;
-        $max = $rdg->position->max;
-    }
-    return 1;
-}
-
 1;
 
 =head1 BUGS / TODO
index 35c0f1e..b875e4e 100644 (file)
@@ -10,6 +10,91 @@ use Text::Tradition::Error;
 use Text::Tradition::StemmaUtil qw/ character_input phylip_pars parse_newick /;
 use Moose;
 
+=head1 NAME
+
+Text::Tradition::Stemma - a representation of a I<stemma codicum> for a Text::Tradition
+
+=head1 SYNOPSIS
+
+  use Text::Tradition;
+  my $t = Text::Tradition->new( 
+    'name' => 'this is a text',
+    'input' => 'TEI',
+    'file' => '/path/to/tei_parallel_seg_file.xml' );
+
+  my $s = $tradition->add_stemma( dotfile => '/path/to/stemma.dot' );
+    
+=head1 DESCRIPTION
+
+Text::Tradition is a library for representation and analysis of collated
+texts, particularly medieval ones.  The Collation is the central feature of
+a Tradition, where the text, its sequence of readings, and its relationships
+between readings are actually kept.
+
+=head1 DOT SYNTAX
+
+The easiest way to define a stemma (which is a directed acyclic graph, denoting 
+the scholar's hypothesis concerning which text(s) were copied from which other(s)) 
+is to use a special form of the 'dot' syntax of GraphViz.  
+
+Each stemma opens with the line
+
+ digraph Stemma {
+and continues with a list of all manuscript witnesses in the stemma, whether
+extant witnesses or missing archetypes or hyparchetypes.  Each of these is
+listed by its sigil on its own line, e.g.:
+
+  alpha [ class=hypothetical ]
+  1 [ class=hypothetical,label=* ]
+  Ms4 [ class=extant ]
+  
+Extant witnesses are listed with class=extant; missing or postulated witnesses
+are listed with class=hypothetical.  Anonymous hyparchetypes must be given a 
+unique name or number, but can be represented as anonymous with the addition 
+of 'label=*' to their lines.  Greek letters or other special characters may be
+used as names, but they must always be wrapped in double quotes.
+
+Links between manuscripts are then listed with arrow notation, as below. These 
+lines show the direction of copying, one step at a time, for the entire stemma.
+
+  alpha -> 1
+  1 -> Ms4
+  
+The final line in the definition should be the closing brace:
+
+ }
+  
+Thus for a set of extant manuscripts A, B, and C, where A and B were copied 
+from the archetype O and C was copied from B, the definition would be:
+
+ digraph Stemma {
+     O [ class=hypothetical]
+     A [ class=extant ]
+     B [ class=extant ]
+     C [ class=extant ]
+     O -> A
+     O -> B
+     B -> C
+ }
+
+=head1 CONSTRUCTOR
+
+=head2 new
+
+The constructor.  This should generally be called from Text::Tradition, but
+if called directly it takes the following options:
+
+=over
+
+=item * collation - The collation with which the stemma is associated.
+
+=item * dot - A filehandle open to a DOT representation of the stemma graph.
+
+=back
+
+=cut
+
 has collation => (
     is => 'ro',
     isa => 'Text::Tradition::Collation',
@@ -40,11 +125,11 @@ sub BUILD {
     my( $self, $args ) = @_;
     # If we have been handed a dotfile, initialize it into a graph.
     if( exists $args->{'dot'} ) {
-        $self->graph_from_dot( $args->{'dot'} );
+        $self->_graph_from_dot( $args->{'dot'} );
     }
 }
 
-sub graph_from_dot {
+sub _graph_from_dot {
        my( $self, $dotfh ) = @_;
        my $reader = Graph::Reader::Dot->new();
        my $graph = $reader->read_graph( $dotfh );
@@ -60,6 +145,27 @@ sub graph_from_dot {
        }
 }
 
+=head1 METHODS
+
+=head2 as_dot( \%options )
+
+Returns a normal dot representation of the stemma layout, suitable for rendering
+with GraphViz.  Options include:
+
+=over
+
+=item * graph - A hashref of global graph options.
+
+=item * node - A hashref of global node options.
+
+=item * edge - A hashref of global edge options.
+
+=back
+
+See the GraphViz documentation for the list of available options.
+
+=cut
+
 sub as_dot {
     my( $self, $opts ) = @_;
     
@@ -111,9 +217,12 @@ sub as_dot {
     return join( "\n", @dotlines );
 }
 
+=head2 editable
+
+Returns a version of the graph rendered in our definition format.
+
+=cut
 
-# Another version of dot output meant for graph editing, thus
-# much simpler.
 sub editable {
        my $self = shift;
        my @dotlines;
@@ -155,7 +264,12 @@ sub _by_vertex {
        return $a->[0].$a->[1] cmp $b->[0].$b->[1];
 }
 
-# Render the stemma as SVG.
+=head2 as_svg
+
+Returns an SVG representation of the graph, calling as_dot first.
+
+=cut
+
 sub as_svg {
     my( $self, $opts ) = @_;
     my $dot = $self->as_dot( $opts );
@@ -172,6 +286,12 @@ sub as_svg {
     return $svg;
 }
 
+=head2 witnesses
+
+Returns a list of the extant witnesses represented in the stemma.
+
+=cut
+
 sub witnesses {
     my $self = shift;
     my @wits = grep { $self->graph->get_vertex_attribute( $_, 'class' ) eq 'extant' }
@@ -179,6 +299,14 @@ sub witnesses {
     return @wits;
 }
 
+=head2 distance_trees( program => $program )
+
+Returns a set of undirected graphs, which are the result of running a distance
+tree calculation program on the collation.  Currently the only supported
+program is phylip_pars.
+
+=cut
+
 #### Methods for calculating phylogenetic trees ####
 
 before 'distance_trees' => sub {
@@ -199,6 +327,13 @@ before 'distance_trees' => sub {
     }
 };
 
+=head2 run_phylip_pars
+
+Runs Phylip Pars on the collation, returning the results in Newick format.
+Used for the distance_trees calculation.
+
+=cut
+
 sub run_phylip_pars {
        my $self = shift;
        my $cdata = character_input( $self->collation->make_alignment_table() );
@@ -217,3 +352,13 @@ no Moose;
 __PACKAGE__->meta->make_immutable;
     
 1;
+
+=head1 LICENSE
+
+This package is free software and is provided "as is" without express
+or implied warranty.  You can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Tara L Andrews E<lt>aurum@cpan.orgE<gt>
index 15e7f89..e48c0ff 100644 (file)
@@ -16,7 +16,20 @@ use Text::Tradition::Error;
 @EXPORT_OK = qw/ make_character_matrix character_input phylip_pars 
                                 parse_newick newick_to_svg /;
 
-sub make_character_matrix {
+=head1 NAME
+
+Text::Tradition::StemmaUtil - standalone utilities for distance tree calculations
+
+=head1 DESCRIPTION
+
+This package contains a set of utilities for running phylogenetic analysis on
+text collations.
+
+=head1 SUBROUTINES
+
+=cut
+
+sub _make_character_matrix {
     my( $table ) = @_;
     # Push the names of the witnesses to initialize the rows of the matrix.
     my @matrix = map { [ _normalize_witname( $_->{'witness'} ) ] } 
@@ -27,7 +40,7 @@ sub make_character_matrix {
         my @pos_readings = map { $_->{'tokens'}->[$token_index] }
                                                        @{$table->{'alignment'}};
         my @pos_text = map { $_ ? $_->{'t'} : $_ } @pos_readings;
-        my @chars = convert_characters( \@pos_text );
+        my @chars = _convert_characters( \@pos_text );
         foreach my $idx ( 0 .. $#matrix ) {
             push( @{$matrix[$idx]}, $chars[$idx] );
         }
@@ -45,7 +58,7 @@ sub _normalize_witname {
     return sprintf( "%-10s", $witname );
 }
 
-sub convert_characters {
+sub _convert_characters {
     my $row = shift;
     # This is a simple algorithm that treats every reading as different.
     # Eventually we will want to be able to specify how relationships
@@ -78,9 +91,17 @@ sub convert_characters {
     return @chars;
 }
 
+=head2 character_input( $alignment_table )
+
+Returns a character matrix string suitable for Phylip programs, which 
+corresponds to the given alignment table.  See Text::Tradition::Collation 
+for a description of the alignment table format.
+
+=cut
+
 sub character_input {
     my $table = shift;
-    my $character_matrix = make_character_matrix( $table );
+    my $character_matrix = _make_character_matrix( $table );
     my $input = '';
     my $rows = scalar @{$character_matrix};
     my $columns = scalar @{$character_matrix->[0]} - 1;
@@ -91,6 +112,12 @@ sub character_input {
     return $input;
 }
 
+=head2 phylip_pars( $character_matrix )
+
+Runs Phylip Pars on the given character matrix.  Returns results in Newick format.
+
+=cut
+
 sub phylip_pars {
        my( $charmatrix ) = @_;
     # Set up a temporary directory for all the default Phylip files.
@@ -158,6 +185,12 @@ sub phylip_pars {
     throw( join( '', @error ) );
 }
 
+=head2 parse_newick( $newick_string )
+
+Parses the given Newick tree(s) into one or more undirected Graph objects.
+
+=cut
+
 sub parse_newick {
     my $newick = shift;
     my @trees;
@@ -173,6 +206,13 @@ sub parse_newick {
     return \@trees;
 }
 
+=head2 newick_to_svg( $newick_string )
+
+Uses the FigTree utility (if installed) to transform the given Newick tree(s)
+into a graph visualization.
+
+=cut
+
 sub newick_to_svg {
        my $newick = shift;
     my $program = File::Which::which( 'figtree' );
@@ -220,3 +260,14 @@ sub throw {
                );
 }
 
+1;
+
+=head1 LICENSE
+
+This package is free software and is provided "as is" without express
+or implied warranty.  You can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Tara L Andrews E<lt>aurum@cpan.orgE<gt>
index 4e1c6e7..4728bbf 100644 (file)
@@ -7,4 +7,23 @@ eval "use Test::Pod::Coverage 1.04";
 plan skip_all => 'Test::Pod::Coverage 1.04 required' if $@;
 plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD};
 
-all_pod_coverage_ok();
+my %mods;
+map { $mods{$_} = 1 } all_modules();
+if( -e 'MANIFEST.SKIP' ) {
+       open( SKIP, 'MANIFEST.SKIP' ) or die "Could not open skip file";
+       while(<SKIP>) {
+               chomp;
+               next unless /^lib/;
+               s/^lib\///;
+               s/\.pm//;
+               s/\//::/g;
+               delete $mods{$_};
+       }
+       close SKIP;
+}
+               
+foreach my $mod ( keys %mods ) {
+       pod_coverage_ok( $mod, { also_private => [ qw/ BUILD throw / ] } );
+}
+
+done_testing();
\ No newline at end of file
index 741fbad..23fd8d9 100644 (file)
@@ -5,7 +5,7 @@ use File::Which;
 use Test::More;
 use lib 'lib';
 use Text::Tradition;
-use Text::Tradition::StemmaUtil qw/ make_character_matrix /;
+use Text::Tradition::StemmaUtil;
 use XML::LibXML;
 use XML::LibXML::XPathContext;
 
@@ -30,7 +30,7 @@ ok( $stemma->isa( 'Text::Tradition::Stemma' ), 'Got the right sort of object' );
 is( $stemma->graph, '1-2,1-A,2-B,2-C', "Got the correct graph" );
 
 # Test for character matrix creation
-my $m = make_character_matrix( $c->make_alignment_table() );
+my $m = Text::Tradition::StemmaUtil::_make_character_matrix( $c->make_alignment_table() );
  ## check number of rows
 is( scalar @$m, 3, "Found three witnesses in char matrix" );
  ## check number of columns