Commit | Line | Data |
dd3b58b0 |
1 | package Text::Tradition::Collation; |
d047cd52 |
2 | |
3 | use Graph::Easy; |
dd3b58b0 |
4 | use Moose; |
5 | |
6 | has 'graph' => ( |
d047cd52 |
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 | ); |
784877d9 |
19 | |
dd3b58b0 |
20 | |
dd3b58b0 |
21 | has 'tradition' => ( |
d047cd52 |
22 | is => 'ro', |
23 | isa => 'Text::Tradition', |
24 | ); |
dd3b58b0 |
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 | |
d047cd52 |
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 | } |
784877d9 |
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 | |
dd3b58b0 |
100 | no Moose; |
101 | __PACKAGE__->meta->make_immutable; |