add some debug code for spotting apparatus double entries
[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
e2902068 55sub text {
56 # Wrapper function around 'label' attribute.
57 my $self = shift;
58 if( @_ ) {
59 $self->set_attribute( 'label', $_[0] );
60 }
61 return $self->get_attribute( 'label' );
62}
63
784877d9 64sub merge_from {
65 my( $self, $merged_node ) = @_;
66 # Adopt the identity pool of the other node.
67 my @now_identical = grep { $_ ne $merged_node } @{$merged_node->same_as};
68 my $new_pool = _merge_array_pool( \@now_identical, $self->same_as )
69 if @now_identical;
70
d047cd52 71 # Adopt the relationship attributes of the other node.
72 my $now_rel = $merged_node->relationships;
73 foreach my $key ( %$now_rel ) {
784877d9 74 if( $self->has_relationship( $key ) ) {
75 my $related = $self->get_relationship( $key );
d047cd52 76 if( $now_rel->{$key} ne $related ) {
784877d9 77 warn( sprintf( "Merged reading %s has relationship %s to reading %s instead of %s; skipping",
78 $merged_node->name, $key,
d047cd52 79 $now_rel->{$key},
784877d9 80 $related) );
81 } # else no action needed
82 } else {
d047cd52 83 $self->set_relationship( $key, $now_rel->{$key} );
784877d9 84 }
85 }
86}
87
88sub set_identical {
89 my( $self, $other_node ) = @_;
90 my $enlarged_pool = _merge_array_pool( $self->same_as,
91 $other_node->same_as );
92
93 # ...and set this node to point to the enlarged pool.
8e1394aa 94 $self->same_as( $enlarged_pool );
784877d9 95}
96
de51424a 97sub identical_readings {
98 my $self = shift;
99 my @same = grep { $_ ne $self } @{$self->same_as};
100 return @same;
101}
102
784877d9 103sub _merge_array_pool {
104 my( $pool, $main_pool ) = @_;
105 my %poolhash;
106 foreach ( @$main_pool ) {
107 # Note which nodes are already in the main pool so that we
108 # don't re-add them.
109 $poolhash{$_->name} = 1;
110 }
111
112 foreach( @$pool ) {
113 # Add the remaining nodes to the main pool...
114 push( @$main_pool, $_ ) unless $poolhash{$_->name};
115 }
116 return $main_pool;
117}
d047cd52 118
8e1394aa 119sub has_primary {
120 my $self = shift;
121 my $pool = $self->same_as;
122 return $pool->[0]->name eq $self->name;
123}
124
125sub primary {
126 my $self = shift;
127 return $self->same_as->[0];
128}
129
d047cd52 130# Much easier to do this with a hash than with an array of Relationship objects,
131# which would be the proper OO method.
132
133sub has_relationship {
134 my( $self, $rel ) = @_;
135 return exists( $self->relationships->{ $rel } );
136}
137
138sub get_relationship {
139 my( $self, $rel ) = @_;
140 if( $self->has_relationship( $rel ) ) {
141 return $self->relationships->{ $rel };
142 }
143 return undef;
144}
145
146sub set_relationship {
147 my( $self, $rel, $value ) = @_;
148 $self->relationships->{ $rel } = $value;
149}
150
4a8828f0 151sub is_common {
152 my( $self ) = shift;
153 return $self->get_attribute( 'class' ) eq 'common';
154}
155
156sub make_common {
157 my( $self ) = shift;
158 $self->set_attribute( 'class', 'common' );
159}
160
161sub make_variant {
162 my( $self ) = shift;
163 $self->set_attribute( 'class', 'variant' );
164}
165
d047cd52 166no Moose;
167__PACKAGE__->meta->make_immutable;
168
1691;
170
171######################################################
172## copied from Graph::Easy::Parser docs
173######################################################
174# when overriding nodes, we also need ::Anon
175
176package Text::Tradition::Collation::Reading::Anon;
021bdbac 177use Moose;
178use MooseX::NonMoose;
179extends 'Text::Tradition::Collation::Reading';
180extends 'Graph::Easy::Node::Anon';
181no Moose;
182__PACKAGE__->meta->make_immutable;
d047cd52 183
021bdbac 1841;
185# use base qw/Text::Tradition::Collation::Reading/;
186# use base qw/Graph::Easy::Node::Anon/;
d047cd52 187
188######################################################
189# and :::Empty
190
191package Text::Tradition::Collation::Reading::Empty;
021bdbac 192use Moose;
193use MooseX::NonMoose;
194extends 'Graph::Easy::Node::Empty';
195no Moose;
196__PACKAGE__->meta->make_immutable;
d047cd52 197
021bdbac 1981;
199# use base qw/Text::Tradition::Collation::Reading/;
d047cd52 200
201######################################################