make some progress, also make perl -cw work
[scpubgit/stemmatology.git] / lib / Text / Tradition / Collation.pm
1 package Text::Tradition::Collation;
2
3 use Graph::Easy;
4 use Moose;
5
6 has 'graph' => (
7     is => 'ro',
8     isa => 'Graph::Easy',
9     handles => {
10         add_node => 'add_reading',
11         del_node => 'del_reading',
12         add_edge => 'add_path',
13         del_edge => 'del_path',
14         nodes => 'readings',
15         edges => 'paths',
16     },
17     default => sub { Graph::Easy->new( undirected => 0 ) },
18     );
19                 
20
21 has 'tradition' => (
22     is => 'ro',
23     isa => 'Text::Tradition',
24     );
25
26 # The collation can be created two ways:
27 # 1. Collate a set of witnesses (with CollateX I guess) and process
28 #    the results as in 2.
29 # 2. Read a pre-prepared collation in one of a variety of formats,
30 #    and make the graph from that.
31
32 # The graph itself will (for now) be immutable, and the positions
33 # within the graph will also be immutable.  We need to calculate those
34 # positions upon graph construction.  The equivalences between graph
35 # nodes will be mutable, entirely determined by the user (or possibly
36 # by some semantic pre-processing provided by the user.)  So the
37 # constructor should just make an empty equivalences object.  The
38 # constructor will also need to make the witness objects, if we didn't
39 # come through option 1.
40
41 sub BUILD {
42     my( $self, $args ) = @_;
43
44     # Call the appropriate parser on the given data
45     my @formats = grep { /^(GraphML|CSV|CTE|TEI)$/ } keys( %$args );
46     my $format = shift( @formats );
47     unless( $format ) {
48         warn "No data given to create a graph; will initialize an empty one";
49     }
50     if( $format =~ /^(CSV|CTE)$/ && !exists $args->{'base'} ) {
51         warn "Cannot make a graph from $format without a base text";
52         return;
53     }
54
55     # Initialize our graph object.
56     $self->graph->set_attribute( 'node', 'shape', 'ellipse' );
57     # Starting point for all texts
58     my $last_node = $self->graph->add_node( '#START#' );
59
60     # Now do the parsing.
61     my @sigla;
62     if( $format ) {
63         my @parseargs;
64         if( $format =~ /^(CSV|CTE)$/ ) {
65             @parseargs = ( 'base' => $args->{'base'},
66                       'data' => $args->{$format},
67                       'format' => $format );
68             $format = 'BaseText';
69         } else {
70             @parseargs = ( $args->{ $format } ); 
71         }
72         my $mod = "Text::Tradition::Parser::$format";
73         load( $mod );
74         # TODO parse needs to return witness IDs
75         @sigla = $mod->can('parse')->( $self->graph, @parseargs );
76     }
77
78     # Do we need to initialize the witnesses?
79     unless( $args->{'have_witnesses'} ) {
80         # initialize Witness objects for all our witnesses
81         my @witnesses;
82         foreach my $sigil ( @sigla ) {
83             push( @witnesses, Text::Tradition::Witness->new( 'sigil' => $sigil ) );
84         }
85         $self->tradition->witnesses( \@witnesses );
86     }
87 }
88
89 # Wrappers around some methods
90
91 sub merge_readings {
92     my $self = shift;
93     my $first_node = shift;
94     my $second_node = shift;
95     $first_node->merge_from( $second_node );
96     unshift( @_, $first_node, $second_node );
97     return $self->graph->merge_nodes( @_ );
98 }
99
100 no Moose;
101 __PACKAGE__->meta->make_immutable;