tests passing with new library, yay
[scpubgit/stemmatology.git] / lib / Text / Tradition / Collation / Reading.pm
CommitLineData
784877d9 1package Text::Tradition::Collation::Reading;
2
8e1394aa 3use Moose;
d047cd52 4use Moose::Util::TypeConstraints;
784877d9 5use MooseX::NonMoose;
6
7extends 'Graph::Easy::Node';
8
9subtype 'Position'
10 => as 'Str',
11 => where { $_ =~ /^\d+\,\d+$/ },
12 message { 'Position must be of the form x,y' };
13
14has 'position' => (
d047cd52 15 is => 'rw',
16 isa => 'Position',
4a8828f0 17 predicate => 'has_position',
d047cd52 18 );
784877d9 19
20# This contains an array of reading objects; the array is a pool,
21# shared by the reading objects inside the pool. When a reading is
22# added to the pool, all the same_as attributes should be updated.
23has 'same_as' => (
d047cd52 24 is => 'rw',
25 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
26 );
784877d9 27
8e1394aa 28# # This is a hash mapping of 'relationship => reading'.
29# # TODO we should validate the relationships sometime.
d047cd52 30has 'relationships' => (
31 is => 'ro',
32 isa => 'HashRef[Text::Tradition::Collation::Reading]',
33 default => sub { {} },
34 );
35
8e1394aa 36# Deal with the non-arg option for Graph::Easy's constructor.
37around BUILDARGS => sub {
38 my $orig = shift;
39 my $class = shift;
40
41 my %args;
42 if( @_ == 1 && ref( $_[0] ) ne 'HASH' ) {
43 return $class->$orig( 'name' => $_[0] );
44 } else {
45 return $class->$orig( @_ );
46 }
47};
48
d047cd52 49# Initialize the identity pool.
50sub BUILD {
51 my( $self, $args ) = @_;
8e1394aa 52 $self->same_as( [ $self ] );
d047cd52 53}
784877d9 54
55sub merge_from {
56 my( $self, $merged_node ) = @_;
57 # Adopt the identity pool of the other node.
58 my @now_identical = grep { $_ ne $merged_node } @{$merged_node->same_as};
59 my $new_pool = _merge_array_pool( \@now_identical, $self->same_as )
60 if @now_identical;
61
d047cd52 62 # Adopt the relationship attributes of the other node.
63 my $now_rel = $merged_node->relationships;
64 foreach my $key ( %$now_rel ) {
784877d9 65 if( $self->has_relationship( $key ) ) {
66 my $related = $self->get_relationship( $key );
d047cd52 67 if( $now_rel->{$key} ne $related ) {
784877d9 68 warn( sprintf( "Merged reading %s has relationship %s to reading %s instead of %s; skipping",
69 $merged_node->name, $key,
d047cd52 70 $now_rel->{$key},
784877d9 71 $related) );
72 } # else no action needed
73 } else {
d047cd52 74 $self->set_relationship( $key, $now_rel->{$key} );
784877d9 75 }
76 }
77}
78
79sub set_identical {
80 my( $self, $other_node ) = @_;
81 my $enlarged_pool = _merge_array_pool( $self->same_as,
82 $other_node->same_as );
83
84 # ...and set this node to point to the enlarged pool.
8e1394aa 85 $self->same_as( $enlarged_pool );
784877d9 86}
87
de51424a 88sub identical_readings {
89 my $self = shift;
90 my @same = grep { $_ ne $self } @{$self->same_as};
91 return @same;
92}
93
784877d9 94sub _merge_array_pool {
95 my( $pool, $main_pool ) = @_;
96 my %poolhash;
97 foreach ( @$main_pool ) {
98 # Note which nodes are already in the main pool so that we
99 # don't re-add them.
100 $poolhash{$_->name} = 1;
101 }
102
103 foreach( @$pool ) {
104 # Add the remaining nodes to the main pool...
105 push( @$main_pool, $_ ) unless $poolhash{$_->name};
106 }
107 return $main_pool;
108}
d047cd52 109
8e1394aa 110sub has_primary {
111 my $self = shift;
112 my $pool = $self->same_as;
113 return $pool->[0]->name eq $self->name;
114}
115
116sub primary {
117 my $self = shift;
118 return $self->same_as->[0];
119}
120
d047cd52 121# Much easier to do this with a hash than with an array of Relationship objects,
122# which would be the proper OO method.
123
124sub has_relationship {
125 my( $self, $rel ) = @_;
126 return exists( $self->relationships->{ $rel } );
127}
128
129sub get_relationship {
130 my( $self, $rel ) = @_;
131 if( $self->has_relationship( $rel ) ) {
132 return $self->relationships->{ $rel };
133 }
134 return undef;
135}
136
137sub set_relationship {
138 my( $self, $rel, $value ) = @_;
139 $self->relationships->{ $rel } = $value;
140}
141
4a8828f0 142sub is_common {
143 my( $self ) = shift;
144 return $self->get_attribute( 'class' ) eq 'common';
145}
146
147sub make_common {
148 my( $self ) = shift;
149 $self->set_attribute( 'class', 'common' );
150}
151
152sub make_variant {
153 my( $self ) = shift;
154 $self->set_attribute( 'class', 'variant' );
155}
156
d047cd52 157no Moose;
158__PACKAGE__->meta->make_immutable;
159
1601;
161
162######################################################
163## copied from Graph::Easy::Parser docs
164######################################################
165# when overriding nodes, we also need ::Anon
166
167package Text::Tradition::Collation::Reading::Anon;
021bdbac 168use Moose;
169use MooseX::NonMoose;
170extends 'Text::Tradition::Collation::Reading';
171extends 'Graph::Easy::Node::Anon';
172no Moose;
173__PACKAGE__->meta->make_immutable;
d047cd52 174
021bdbac 1751;
176# use base qw/Text::Tradition::Collation::Reading/;
177# use base qw/Graph::Easy::Node::Anon/;
d047cd52 178
179######################################################
180# and :::Empty
181
182package Text::Tradition::Collation::Reading::Empty;
021bdbac 183use Moose;
184use MooseX::NonMoose;
185extends 'Graph::Easy::Node::Empty';
186no Moose;
187__PACKAGE__->meta->make_immutable;
d047cd52 188
021bdbac 1891;
190# use base qw/Text::Tradition::Collation::Reading/;
d047cd52 191
192######################################################