1 package Text::Tradition::Collation::Reading;
5 use Text::Tradition::Collation::Position;
7 extends 'Graph::Easy::Node';
11 isa => 'Text::Tradition::Collation::Position',
12 predicate => 'has_position',
18 predicate => 'has_rank',
26 # This contains an array of reading objects; the array is a pool,
27 # shared by the reading objects inside the pool. When a reading is
28 # added to the pool, all the same_as attributes should be updated.
31 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
34 # Deal with the non-arg option for Graph::Easy's constructor.
35 around BUILDARGS => sub {
40 if( @_ == 1 && ref( $_[0] ) ne 'HASH' ) {
41 return $class->$orig( 'name' => $_[0] );
43 return $class->$orig( @_ );
47 # Take constructor args as well as a Position argument.
48 around position => sub {
51 return $self->$orig() unless @_;
54 unless( @_ == 1 && ref( $_[0] ) eq 'Text::Tradition::Collation::Position' ) {
55 # We have constructor arguments; pass them to Position.
56 @args = ( Text::Tradition::Collation::Position->new( @_ ) );
58 $self->$orig( @args );
61 # Initialize the identity pool.
63 my( $self, $args ) = @_;
64 $self->same_as( [ $self ] );
68 # Wrapper function around 'label' attribute.
72 $self->set_attribute( 'label', $_[0] );
74 $self->del_attribute( 'label' );
81 my( $self, $sigil, $backup ) = @_;
82 my @wits = $self->witnesses;
83 return 1 if grep { $_ eq $sigil } @wits;
85 return 1 if grep { $_ eq $backup } @wits;
92 my @paths = grep { $_->get_attribute( 'class' ) eq 'path' } $self->outgoing;
93 push( @paths, grep { $_->get_attribute( 'class' ) eq 'path' } $self->incoming );
95 foreach my $p ( @paths ) {
96 if( $p->has_hidden_witnesses ) {
97 foreach ( @{$p->hidden_witnesses} ) {
101 $wits{$p->label} = 1;
108 my( $self, $merged_node ) = @_;
109 # Adopt the identity pool of the other node.
110 my @now_identical = grep { $_ ne $merged_node } @{$merged_node->same_as};
111 my $new_pool = _merge_array_pool( \@now_identical, $self->same_as )
114 # TODO Adopt the relationship attributes and segment memberships of the other node.
117 ## Dealing with transposed readings. These methods are only really
118 ## applicable if we have a linear collation graph.
121 my( $self, $other_node ) = @_;
122 my $enlarged_pool = _merge_array_pool( $self->same_as,
123 $other_node->same_as );
125 # ...and set this node to point to the enlarged pool.
126 $self->same_as( $enlarged_pool );
129 sub identical_readings {
131 my @same = grep { $_ ne $self } @{$self->same_as};
135 sub _merge_array_pool {
136 my( $pool, $main_pool ) = @_;
138 foreach ( @$main_pool ) {
139 # Note which nodes are already in the main pool so that we
141 $poolhash{$_->name} = 1;
145 # Add the remaining nodes to the main pool...
146 push( @$main_pool, $_ ) unless $poolhash{$_->name};
153 my $pool = $self->same_as;
154 return $pool->[0]->name ne $self->name;
159 return $self->same_as->[0];
164 return undef unless $self->has_position;
165 return $self->position->is_colocated( @_ );
168 # Returns all readings that adjoin this one on any path.
169 sub neighbor_readings {
170 my( $self, $direction ) = @_;
171 $direction = 'both' unless $direction;
172 my @paths = grep { $_->isa( 'Text::Tradition::Collation::Path' ) } $self->edges;
174 foreach my $p ( @paths ) {
175 if( $p->to eq $self ) {
176 next if $direction eq 'forward';
177 $connected{$p->from->name} = $p->from;
178 } else { # $p->from eq $self
179 next if $direction =~ /^back/;
180 $connected{$p->to->name} = $p->to;
183 return values( %connected );
186 # Returns all readings related to the one we've got.
187 sub related_readings {
188 my( $self, $colocated ) = @_;
190 foreach my $e ( $self->edges ) {
191 next unless $e->isa( 'Text::Tradition::Collation::Relationship' );
192 next if $colocated && $e->type eq 'repetition';
193 push( @related, $e->from eq $self ? $e->to : $e->from );
198 ## Keep track of which readings are unchanged across witnesses.
201 return $self->get_attribute( 'class' ) eq 'common';
206 $self->set_attribute( 'class', 'common' );
211 $self->set_attribute( 'class', 'variant' );
215 __PACKAGE__->meta->make_immutable;
219 ######################################################
220 ## copied from Graph::Easy::Parser docs
221 ######################################################
222 # when overriding nodes, we also need ::Anon
224 package Text::Tradition::Collation::Reading::Anon;
226 use MooseX::NonMoose;
227 extends 'Text::Tradition::Collation::Reading';
228 extends 'Graph::Easy::Node::Anon';
230 __PACKAGE__->meta->make_immutable;
233 # use base qw/Text::Tradition::Collation::Reading/;
234 # use base qw/Graph::Easy::Node::Anon/;
236 ######################################################
239 package Text::Tradition::Collation::Reading::Empty;
241 use MooseX::NonMoose;
242 extends 'Graph::Easy::Node::Empty';
244 __PACKAGE__->meta->make_immutable;
247 # use base qw/Text::Tradition::Collation::Reading/;
249 ######################################################