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 lexical
+ collated repetition transposition );
-enum 'RelationshipType' => qw( spelling orthographic grammatical repetition lexical );
+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 * alters_meaning - Indicate whether, in context, the related words cause
+the text to have different meanings. Possible values are 0 (no), 1 (slightly),
+and >1 (yes).
+
+=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
-no Moose::Util::TypeConstraints; ## see comment above
-
has 'type' => (
- is => 'rw',
- isa => 'RelationshipType',
- required => 1,
-);
+ is => 'ro',
+ isa => 'RelationshipType',
+ required => 1,
+ );
+
+has 'reading_a' => (
+ is => 'ro',
+ isa => 'Str',
+ required => 1,
+ );
-has 'global' => (
- is => 'rw',
- isa => 'Bool',
- default => 0,
-);
+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 'alters_meaning' => (
+ is => 'rw',
+ isa => 'Int',
+ default => 0,
+ );
has 'non_correctable' => (
- is => 'rw',
- isa => 'Bool',
- );
+ is => 'ro',
+ isa => 'Bool',
+ );
has 'non_independent' => (
- is => 'rw',
- isa => 'Bool',
- );
-
-has 'equal_rank' => (
- is => 'rw',
- isa => 'Bool',
- );
-
-sub FOREIGNBUILDARGS {
- my $class = shift;
- my %args = @_;
-
- # Make the label match our 'type' attribute.
- my @superclass_args;
- if( exists $args{'type'} ) {
- push( @superclass_args, 'label', $args{'type'} );
- }
- return @superclass_args;
+ is => 'ro',
+ isa => 'Bool',
+ );
+
+around 'alters_meaning' => sub {
+ my $orig = shift;
+ my $self = shift;
+ if( @_ ) {
+ if( $_[0] eq 'no' ) {
+ return $self->$orig( 0 );
+ } elsif( $_[0] eq 'slightly' ) {
+ return $self->$orig( 1 );
+ } elsif( $_[0] eq 'yes' ) {
+ return $self->$orig( 2 );
+ }
+ }
+ return $self->$orig( @_ );
+};
+
+# 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'.
+=cut
+
+sub nonlocal {
+ my $self = shift;
+ return $self->scope ne 'local';
}
no Moose;
__PACKAGE__->meta->make_immutable;
+
+1;