1 package Text::Tradition::Collation::Reading;
6 extends 'Graph::Easy::Node';
11 predicate => 'has_rank',
19 # This contains an array of reading objects; the array is a pool,
20 # shared by the reading objects inside the pool. When a reading is
21 # added to the pool, all the same_as attributes should be updated.
24 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
27 # Deal with the non-arg option for Graph::Easy's constructor.
28 around BUILDARGS => sub {
33 if( @_ == 1 && ref( $_[0] ) ne 'HASH' ) {
34 return $class->$orig( 'name' => $_[0] );
36 return $class->$orig( @_ );
40 # A lacuna node is also a meta node.
41 before is_lacuna => sub {
42 my( $self, $arg ) = @_;
48 # Initialize the identity pool.
50 my( $self, $args ) = @_;
51 $self->same_as( [ $self ] );
55 # Wrapper function around 'label' attribute.
59 $self->set_attribute( 'label', $_[0] );
61 $self->del_attribute( 'label' );
68 my( $self, $sigil, $backup ) = @_;
69 my @wits = $self->witnesses;
70 return 1 if grep { $_ eq $sigil } @wits;
72 return 1 if grep { $_ eq $backup } @wits;
79 my @paths = grep { $_->get_attribute( 'class' ) eq 'path' } $self->outgoing;
80 push( @paths, grep { $_->get_attribute( 'class' ) eq 'path' } $self->incoming );
82 foreach my $p ( @paths ) {
83 if( $p->has_hidden_witnesses ) {
84 foreach ( @{$p->hidden_witnesses} ) {
95 my( $self, $merged_node ) = @_;
96 # Adopt the identity pool of the other node.
97 my @now_identical = grep { $_ ne $merged_node } @{$merged_node->same_as};
98 my $new_pool = _merge_array_pool( \@now_identical, $self->same_as )
101 # TODO Adopt the relationship attributes and segment memberships of the other node.
104 ## Dealing with transposed readings. These methods are only really
105 ## applicable if we have a linear collation graph.
108 my( $self, $other_node ) = @_;
109 my $enlarged_pool = _merge_array_pool( $self->same_as,
110 $other_node->same_as );
112 # ...and set this node to point to the enlarged pool.
113 $self->same_as( $enlarged_pool );
116 sub identical_readings {
118 my @same = grep { $_ ne $self } @{$self->same_as};
122 sub _merge_array_pool {
123 my( $pool, $main_pool ) = @_;
125 foreach ( @$main_pool ) {
126 # Note which nodes are already in the main pool so that we
128 $poolhash{$_->name} = 1;
132 # Add the remaining nodes to the main pool...
133 push( @$main_pool, $_ ) unless $poolhash{$_->name};
140 my $pool = $self->same_as;
141 return $pool->[0]->name ne $self->name;
146 return $self->same_as->[0];
149 # Looks from the outside like an accessor for a Boolean, but really
150 # sets the node's class. Should apply to start, end, and lacunae.
155 if( defined $arg && $arg ) {
156 $self->set_attribute( 'class', 'meta' );
157 } elsif ( defined $arg ) {
158 $self->del_attribute( 'class' );
160 return $self->sub_class eq 'meta';
163 # Returns all readings that adjoin this one on any path.
164 sub neighbor_readings {
165 my( $self, $direction ) = @_;
166 $direction = 'both' unless $direction;
167 my @paths = grep { $_->isa( 'Text::Tradition::Collation::Path' ) } $self->edges;
169 foreach my $p ( @paths ) {
170 if( $p->to eq $self ) {
171 next if $direction eq 'forward';
172 $connected{$p->from->name} = $p->from;
173 } else { # $p->from eq $self
174 next if $direction =~ /^back/;
175 $connected{$p->to->name} = $p->to;
178 return values( %connected );
181 # Returns all readings related to the one we've got.
182 sub related_readings {
183 my( $self, $colocated, $queried ) = @_;
184 $queried = { $self->name => 1 } unless $queried;
186 # Get the nodes directly related to this one
187 foreach my $e ( $self->edges ) {
188 next unless $e->isa( 'Text::Tradition::Collation::Relationship' );
189 next if $colocated && $e->type eq 'repetition';
190 my $n = $e->from eq $self ? $e->to : $e->from;
191 next if $queried->{$n->name};
192 push( @related, $n );
194 # Now query those nodes for their relations, recursively
195 map { $queried->{$_->name} = 1 } @related;
197 foreach ( @related ) {
198 push( @also_related, $_->related_readings( $colocated, $queried ) );
200 push( @related, @also_related );
204 ## Keep track of which readings are unchanged across witnesses.
207 return $self->get_attribute( 'class' ) eq 'common';
210 ## TODO Rationalize make_common, is_meta, etc.
213 $self->set_attribute( 'class', 'common' );
218 $self->set_attribute( 'class', 'variant' );
222 __PACKAGE__->meta->make_immutable;
226 ######################################################
227 ## copied from Graph::Easy::Parser docs
228 ######################################################
229 # when overriding nodes, we also need ::Anon
231 package Text::Tradition::Collation::Reading::Anon;
233 use MooseX::NonMoose;
234 extends 'Text::Tradition::Collation::Reading';
235 extends 'Graph::Easy::Node::Anon';
237 __PACKAGE__->meta->make_immutable;
240 # use base qw/Text::Tradition::Collation::Reading/;
241 # use base qw/Graph::Easy::Node::Anon/;
243 ######################################################
246 package Text::Tradition::Collation::Reading::Empty;
248 use MooseX::NonMoose;
249 extends 'Graph::Easy::Node::Empty';
251 __PACKAGE__->meta->make_immutable;
254 # use base qw/Text::Tradition::Collation::Reading/;
256 ######################################################