some more rehoming of functionality
[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
88sub _merge_array_pool {
89 my( $pool, $main_pool ) = @_;
90 my %poolhash;
91 foreach ( @$main_pool ) {
92 # Note which nodes are already in the main pool so that we
93 # don't re-add them.
94 $poolhash{$_->name} = 1;
95 }
96
97 foreach( @$pool ) {
98 # Add the remaining nodes to the main pool...
99 push( @$main_pool, $_ ) unless $poolhash{$_->name};
100 }
101 return $main_pool;
102}
d047cd52 103
8e1394aa 104sub has_primary {
105 my $self = shift;
106 my $pool = $self->same_as;
107 return $pool->[0]->name eq $self->name;
108}
109
110sub primary {
111 my $self = shift;
112 return $self->same_as->[0];
113}
114
d047cd52 115# Much easier to do this with a hash than with an array of Relationship objects,
116# which would be the proper OO method.
117
118sub has_relationship {
119 my( $self, $rel ) = @_;
120 return exists( $self->relationships->{ $rel } );
121}
122
123sub get_relationship {
124 my( $self, $rel ) = @_;
125 if( $self->has_relationship( $rel ) ) {
126 return $self->relationships->{ $rel };
127 }
128 return undef;
129}
130
131sub set_relationship {
132 my( $self, $rel, $value ) = @_;
133 $self->relationships->{ $rel } = $value;
134}
135
4a8828f0 136sub is_common {
137 my( $self ) = shift;
138 return $self->get_attribute( 'class' ) eq 'common';
139}
140
141sub make_common {
142 my( $self ) = shift;
143 $self->set_attribute( 'class', 'common' );
144}
145
146sub make_variant {
147 my( $self ) = shift;
148 $self->set_attribute( 'class', 'variant' );
149}
150
d047cd52 151no Moose;
152__PACKAGE__->meta->make_immutable;
153
1541;
155
156######################################################
157## copied from Graph::Easy::Parser docs
158######################################################
159# when overriding nodes, we also need ::Anon
160
161package Text::Tradition::Collation::Reading::Anon;
021bdbac 162use Moose;
163use MooseX::NonMoose;
164extends 'Text::Tradition::Collation::Reading';
165extends 'Graph::Easy::Node::Anon';
166no Moose;
167__PACKAGE__->meta->make_immutable;
d047cd52 168
021bdbac 1691;
170# use base qw/Text::Tradition::Collation::Reading/;
171# use base qw/Graph::Easy::Node::Anon/;
d047cd52 172
173######################################################
174# and :::Empty
175
176package Text::Tradition::Collation::Reading::Empty;
021bdbac 177use Moose;
178use MooseX::NonMoose;
179extends 'Graph::Easy::Node::Empty';
180no Moose;
181__PACKAGE__->meta->make_immutable;
d047cd52 182
021bdbac 1831;
184# use base qw/Text::Tradition::Collation::Reading/;
d047cd52 185
186######################################################