add error handling for reading morphology update
[scpubgit/stemmatology.git] / lib / Text / Tradition / Collation / Relationship.pm
index 7001782..422c0c1 100644 (file)
@@ -2,81 +2,150 @@ package Text::Tradition::Collation::Relationship;
 
 use Moose;
 use Moose::Util::TypeConstraints;
-## CAREFUL in our use of Moose::Util::TypeConstraints.  That 'from'
-## clashes with Graph::Easy::Edge 'from', so we'll need to unimport
-## TypeConstraints after defining the types.  Or else we would have to
-## finally split out our types into another module.
-use MooseX::NonMoose;
-
-extends 'Graph::Easy::Edge';
-
-enum 'RelationshipType' => qw( spelling orthographic grammatical repetition lexical );
-
-subtype 'RelationshipVector',
-    => as 'ArrayRef',
-    => where { @$_ == 2
-              && $_->[0]->isa( 'Text::Tradition::Collation::Reading' )
-              && $_->[1]->isa( 'Text::Tradition::Collation::Reading' )
-            },
-    message { 'Argument should be [ SourceReading, TargetReading ]' };
-
-subtype 'RelationshipTokenVector',
-    => as 'ArrayRef',
-    => where { @$_ == 2 },
-    message { 'Argument should be [ \'source\', \'target\' ]' };
-
-no Moose::Util::TypeConstraints;  ## see comment above
-                  
-has 'sort' => (
-    is => 'rw',
-    isa => 'RelationshipType',
-    required => 1,
-);
-
-has 'orig_relation' => (
-    is => 'rw',
-    isa => 'RelationshipVector',
-    required => 1,
-);
-
-has 'related_readings' => (
-    is => 'rw',
-    isa => 'RelationshipTokenVector',
-);
-
-has 'global' => (
-    is => 'rw',
-    isa => 'Bool',
-    default => 0,
-);
-
-sub FOREIGNBUILDARGS {
-    my $class = shift;
-    my %args = @_;
-
-    # Make the label match our 'sort' attribute.
-    my @superclass_args;
-    if( exists $args{'sort'} ) {
-       push( @superclass_args, 'label', $args{'sort'} );
-    }
-    return @superclass_args;
+
+enum 'RelationshipType' => qw( spelling orthographic grammatical lexical
+                                                          collated repetition transposition );
+
+enum 'RelationshipScope' => qw( local document global );
+
+no Moose::Util::TypeConstraints;
+
+=head1 NAME
+
+Text::Tradition::Collation::Relationship - represents a syntactic or semantic
+relationship between two readings
+    
+=head1 DESCRIPTION
+
+Text::Tradition is a library for representation and analysis of collated
+texts, particularly medieval ones.  A relationship connects two readings
+within a collation, usually when they appear in the same place in different
+texts.
+
+=head1 CONSTRUCTOR
+
+=head2 new
+
+Creates a new relationship. Usually called via $collation->add_relationship.
+Options include:
+
+=over 4
+
+=item * type - Can be one of spelling, orthographic, grammatical, lexical, 
+collated, repetition, transposition.  All but the last two are only valid 
+relationships between readings that occur at the same point in the text. 
+The 'collated' relationship should only be used by parsers to align readings 
+in the graph when the input information would otherwise be lost, e.g. from
+an alignment table.
+
+=item * displayform - (Optional) The reading that should be displayed if the 
+related nodes are treated as one.
+
+=item * scope - (Optional) A meta-attribute.  Can be one of 'local', 
+'document', or 'global'. Denotes whether the relationship between the two 
+readings holds always, independent of context, either within this tradition 
+or across all traditions.
+
+=item * annotation - (Optional) A freeform note to attach to the relationship.
+
+=item * non_correctable - (Optional) True if the reading would not have been 
+corrected independently.
+
+=item * non_independent - (Optional) True if the variant is unlikely to have 
+occurred independently in unrelated witnesses.
+
+=back
+
+=head1 ACCESSORS
+
+=head2 type
+
+=head2 displayform
+
+=head2 scope
+
+=head2 annotation
+
+=head2 non_correctable
+
+=head2 non_independent
+
+See the option descriptions above.
+
+=cut
+
+has 'type' => (
+       is => 'ro',
+       isa => 'RelationshipType',
+       required => 1,
+       );
+
+has 'reading_a' => (
+       is => 'ro',
+       isa => 'Str',
+       required => 1,
+       );
+
+has 'reading_b' => (
+       is => 'ro',
+       isa => 'Str',
+       required => 1,
+       );
+
+has 'displayform' => (
+       is => 'ro',
+       isa => 'Str',
+       predicate => 'has_displayform',
+       );
+
+has 'scope' => (
+       is => 'ro',
+       isa => 'RelationshipScope', 
+       default => 'local',
+       );
+       
+has 'annotation' => (
+       is => 'ro',
+       isa => 'Str',
+       predicate => 'has_annotation',
+       );
+
+has 'non_correctable' => (
+       is => 'ro',
+       isa => 'Bool',
+       );
+
+has 'non_independent' => (
+       is => 'ro',
+       isa => 'Bool',
+       );
+       
+# A read-only meta-Boolean attribute.
+
+=head2 colocated
+
+Returns true if the relationship type is one that requires that its readings
+occupy the same place in the collation.
+
+=cut
+
+sub colocated {
+       my $self = shift;
+       return $self->type !~ /^(repetition|transposition)$/;
 }
 
-sub BUILD {
-    my( $self, $args ) = @_;
+=head2 nonlocal
 
-    $self->set_attribute( 'class', 'relationship' );
+Returns true if the relationship scope is anything other than 'local'.
 
-    my( $source, $target ) = @{$self->orig_relation};
-    if( $source->has_position && $target->has_position
-       && $source->position ne $target->position ) {
-       die "Cannot set relationship between readings in different positions";
-    }
-    unless( $self->related_readings ) {
-       $self->related_readings( [ $self->orig_relation->[0]->label,
-                                  $self->orig_relation->[1]->label ] );
-    }
+=cut
+
+sub nonlocal {
+       my $self = shift;
+       return $self->scope ne 'local';
 }
 
 no Moose;
 __PACKAGE__->meta->make_immutable;
+
+1;