Commit | Line | Data |
22222af9 |
1 | package Text::Tradition::Collation::Relationship; |
2 | |
3 | use Moose; |
4 | use Moose::Util::TypeConstraints; |
5 | |
d8ef0a2b |
6 | enum 'RelationshipScope' => [ qw( local document global ) ]; |
22222af9 |
7 | |
8 | no Moose::Util::TypeConstraints; |
9 | |
027d819c |
10 | =head1 NAME |
11 | |
12 | Text::Tradition::Collation::Relationship - represents a syntactic or semantic |
13 | relationship between two readings |
14 | |
15 | =head1 DESCRIPTION |
16 | |
17 | Text::Tradition is a library for representation and analysis of collated |
18 | texts, particularly medieval ones. A relationship connects two readings |
19 | within a collation, usually when they appear in the same place in different |
20 | texts. |
21 | |
22 | =head1 CONSTRUCTOR |
23 | |
24 | =head2 new |
25 | |
26 | Creates a new relationship. Usually called via $collation->add_relationship. |
27 | Options include: |
28 | |
22222af9 |
29 | =over 4 |
30 | |
0fa07e25 |
31 | =item * type - Can be one of spelling, orthographic, grammatical, lexical, |
32 | collated, repetition, transposition. All but the last two are only valid |
33 | relationships between readings that occur at the same point in the text. |
34 | The 'collated' relationship should only be used by parsers to align readings |
35 | in the graph when the input information would otherwise be lost, e.g. from |
36 | an alignment table. |
22222af9 |
37 | |
0fa07e25 |
38 | =item * displayform - (Optional) The reading that should be displayed if the |
39 | related nodes are treated as one. |
732e9c4e |
40 | |
0fa07e25 |
41 | =item * scope - (Optional) A meta-attribute. Can be one of 'local', |
42 | 'document', or 'global'. Denotes whether the relationship between the two |
43 | readings holds always, independent of context, either within this tradition |
44 | or across all traditions. |
4633f9e4 |
45 | |
0fa07e25 |
46 | =item * annotation - (Optional) A freeform note to attach to the relationship. |
4633f9e4 |
47 | |
94654e27 |
48 | =item * alters_meaning - Indicate whether, in context, the related words cause |
49 | the text to have different meanings. Possible values are 0 (no), 1 (slightly), |
50 | and >1 (yes). |
51 | |
0fa07e25 |
52 | =item * non_correctable - (Optional) True if the reading would not have been |
53 | corrected independently. |
22222af9 |
54 | |
0fa07e25 |
55 | =item * non_independent - (Optional) True if the variant is unlikely to have |
56 | occurred independently in unrelated witnesses. |
22222af9 |
57 | |
22222af9 |
58 | =back |
59 | |
027d819c |
60 | =head1 ACCESSORS |
61 | |
62 | =head2 type |
63 | |
64 | =head2 displayform |
65 | |
66 | =head2 scope |
67 | |
4633f9e4 |
68 | =head2 annotation |
69 | |
027d819c |
70 | =head2 non_correctable |
71 | |
72 | =head2 non_independent |
73 | |
74 | See the option descriptions above. |
75 | |
22222af9 |
76 | =cut |
77 | |
78 | has 'type' => ( |
79 | is => 'ro', |
24efa55d |
80 | isa => 'Str', |
22222af9 |
81 | required => 1, |
82 | ); |
83 | |
84 | has 'reading_a' => ( |
85 | is => 'ro', |
86 | isa => 'Str', |
87 | required => 1, |
88 | ); |
89 | |
90 | has 'reading_b' => ( |
91 | is => 'ro', |
92 | isa => 'Str', |
93 | required => 1, |
94 | ); |
95 | |
732e9c4e |
96 | has 'displayform' => ( |
97 | is => 'ro', |
98 | isa => 'Str', |
99 | predicate => 'has_displayform', |
100 | ); |
101 | |
22222af9 |
102 | has 'scope' => ( |
103 | is => 'ro', |
104 | isa => 'RelationshipScope', |
105 | default => 'local', |
106 | ); |
4633f9e4 |
107 | |
108 | has 'annotation' => ( |
109 | is => 'ro', |
110 | isa => 'Str', |
31aaf446 |
111 | predicate => 'has_annotation', |
4633f9e4 |
112 | ); |
94654e27 |
113 | |
114 | has 'alters_meaning' => ( |
115 | is => 'rw', |
116 | isa => 'Int', |
117 | default => 0, |
118 | ); |
22222af9 |
119 | |
4a5f5143 |
120 | has 'a_derivable_from_b' => ( |
22222af9 |
121 | is => 'ro', |
122 | isa => 'Bool', |
123 | ); |
4a5f5143 |
124 | |
125 | has 'b_derivable_from_a' => ( |
126 | is => 'ro', |
127 | isa => 'Bool', |
128 | ); |
129 | |
22222af9 |
130 | has 'non_independent' => ( |
131 | is => 'ro', |
132 | isa => 'Bool', |
133 | ); |
732e9c4e |
134 | |
94654e27 |
135 | around 'alters_meaning' => sub { |
136 | my $orig = shift; |
137 | my $self = shift; |
138 | if( @_ ) { |
139 | if( $_[0] eq 'no' ) { |
140 | return $self->$orig( 0 ); |
141 | } elsif( $_[0] eq 'slightly' ) { |
142 | return $self->$orig( 1 ); |
143 | } elsif( $_[0] eq 'yes' ) { |
144 | return $self->$orig( 2 ); |
145 | } |
146 | } |
147 | return $self->$orig( @_ ); |
148 | }; |
149 | |
22222af9 |
150 | # A read-only meta-Boolean attribute. |
027d819c |
151 | |
152 | =head2 colocated |
153 | |
154 | Returns true if the relationship type is one that requires that its readings |
155 | occupy the same place in the collation. |
156 | |
157 | =cut |
158 | |
22222af9 |
159 | sub colocated { |
160 | my $self = shift; |
161 | return $self->type !~ /^(repetition|transposition)$/; |
162 | } |
163 | |
027d819c |
164 | =head2 nonlocal |
165 | |
166 | Returns true if the relationship scope is anything other than 'local'. |
167 | |
168 | =cut |
169 | |
22222af9 |
170 | sub nonlocal { |
171 | my $self = shift; |
172 | return $self->scope ne 'local'; |
173 | } |
174 | |
24efa55d |
175 | =head2 is_equivalent( $otherrel ) |
176 | |
177 | Returns true if the type and scope of $otherrel match ours. |
178 | |
179 | =cut |
180 | |
181 | sub is_equivalent { |
182 | my( $self, $other, $check_ann ) = @_; |
183 | my $oksofar = $self->type eq $other->type && $self->scope eq $other->scope; |
184 | if( $check_ann ) { |
185 | return $oksofar && $self->annotation eq $other->annotation; |
186 | } else { |
187 | return $oksofar; |
188 | } |
189 | } |
190 | |
22222af9 |
191 | no Moose; |
192 | __PACKAGE__->meta->make_immutable; |
193 | |
194 | 1; |