document and unit-test Witness.pm
[scpubgit/stemmatology.git] / lib / Text / Tradition / Witness.pm
CommitLineData
dd3b58b0 1package Text::Tradition::Witness;
2use Moose;
7854e12e 3use Moose::Util::TypeConstraints;
dd3b58b0 4
7158714d 5=head1 NAME
6
7Text::Tradition::Witness - a manuscript witness to a text tradition
8
9=head1 SYNOPSIS
10
11 use Text::Tradition::Witness;
12 my $w = Text::Tradition::Witness->new(
13 'sigil' => 'A',
14 'identifier' => 'Oxford MS Ex.1932',
15 );
16
17=head1 DESCRIPTION
18
19Text::Tradition::Witness is an object representation of a manuscript
20witness to a text tradition. A manuscript has a sigil (a short code that
21represents it in the wider tradition), an identifier (e.g. the library ID),
22and probably a text.
23
24=head1 METHODS
25
26=head2 new
27
28Create a new witness. Options include:
29
30=over
31
32=item * sigil - A short code to represent the manuscript. Required.
33
34=item * text - An array of strings (words) that contains the text of the
35manuscript.
36
37=item * source - A reference to the text, such as a filename, if it is not
38given in the 'text' option.
39
40=item * identifier - The recognized name of the manuscript, e.g. a library
41identifier.
42
43=item * other_info - A freeform string for any other description of the
44manuscript.
45
46=back
47
48=head2 sigil
49
50Accessor method for the witness sigil.
51
52=head2 text
53
54Accessor method to get and set the text array.
55
56=head2 source
57
58Accessor method to get and set the text source.
59
60=head2 identifier
61
62Accessor method for the witness identifier.
63
64=head2 other_info
65
66Accessor method for the general witness description.
67
68=head2 path
69
70An array of Text::Tradition::Collation::Reading objects which, taken in
71sequence, represent the text.
72
73=head2 uncorrected_path
74
75An array of Text::Tradition::Collation::Reading objects which, taken in
76sequence, represent the text before any scribal corrections were made.
77
78=begin testing
79
80use_ok( 'Text::Tradition::Witness', "can use module" );
81
82my @text = qw( This is a line of text );
83my $wit = Text::Tradition::Witness->new(
84 'sigil' => 'A',
85 'text' => \@text,
86 );
87is( ref( $wit ), 'Text::Tradition::Witness', 'Created a witness' );
88if( $wit ) {
89 is( $wit->sigil, 'A', "Witness has correct sigil" );
90 is( join( ' ', @{$wit->text} ), join( ' ', @text ), "Witness has correct text" );
91}
92
93=end testing
94
95=cut
96
784877d9 97# Sigil. Required identifier for a witness.
dd3b58b0 98has 'sigil' => (
7158714d 99 is => 'ro',
100 isa => 'Str',
101 required => 1,
102 );
dd3b58b0 103
7158714d 104# Text. This is an array of strings (i.e. word tokens).
d047cd52 105# TODO Think about how to handle this for the case of pre-prepared
106# collations, where the tokens are in the graph already.
dd3b58b0 107has 'text' => (
7158714d 108 is => 'rw',
109 isa => 'ArrayRef[Str]',
110 predicate => 'has_text',
111 );
dd3b58b0 112
d047cd52 113# Source. This is where we read in the witness, if not from a
114# pre-prepared collation. It is probably a filename.
115has 'source' => (
7158714d 116 is => 'ro',
117 isa => 'Str',
118 predicate => 'has_source',
119 );
784877d9 120
7158714d 121# Path. This is an array of Reading nodes that should mirror the
1ed3973e 122# text above.
4a8828f0 123has 'path' => (
7158714d 124 is => 'rw',
125 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
126 predicate => 'has_path',
127 );
4a8828f0 128
b15511bf 129has 'uncorrected_path' => (
7158714d 130 is => 'rw',
131 isa => 'ArrayRef[Text::Tradition::Collation::Reading]',
132 predicate => 'has_ante_corr',
133 );
f6066bac 134
135# Manuscript name or similar
136has 'identifier' => (
7158714d 137 is => 'ro',
138 isa => 'Str',
139 );
f6066bac 140
141# Any other info we have
142has 'other_info' => (
7158714d 143 is => 'ro',
144 isa => 'Str',
145 );
146
e2902068 147
784877d9 148sub BUILD {
7158714d 149 my $self = shift;
150 if( $self->has_source ) {
151 # Read the file and initialize the text.
152 my $rc;
153 eval { no warnings; $rc = open( WITNESS, $self->source ); };
154 # If we didn't open a file, assume it is a string.
155 if( $rc ) {
156 my @words;
157 while(<WITNESS>) {
158 chomp;
159 push( @words, split( /\s+/, $_ ) );
160 }
161 close WITNESS;
162 $self->text( \@words );
163 } # else the text is in the source string, probably
164 # XML, and we are doing nothing with it.
165 }
166}
167
168=begin testing
169
170use Text::Tradition;
171
172my $simple = 't/data/simple.txt';
173my $s = Text::Tradition->new(
174 'name' => 'inline',
175 'input' => 'Tabular',
176 'file' => $simple,
177 );
178my $wit_c = $s->witness( 'C' );
179is( ref( $wit_c ), 'Text::Tradition::Witness' ),;
180if( $wit_c ) {
181 ok( !$wit_c->has_text, "Text property not yet set" );
182 my $c_arr = $wit_c->text;
183 is( $c_arr->[0], 'Je', "Text constructed from path" );
184 ok( $wit_c->has_text, "Text property now set" );
784877d9 185}
186
7158714d 187=end testing
188
189=cut
190
de51424a 191# If the text is not present, and the path is, and this is a 'get'
192# request, generate text from path.
193around text => sub {
7158714d 194 my $orig = shift;
195 my $self = shift;
de51424a 196
7158714d 197 if( $self->has_path && !$self->has_text && !@_ ) {
198 my @words = map { $_->label } grep { !$_->is_meta } @{$self->path};
199 $self->$orig( \@words );
200 }
201
202 $self->$orig( @_ );
de51424a 203};
204
dd3b58b0 205no Moose;
206__PACKAGE__->meta->make_immutable;
7158714d 207
208=head1 BUGS / TODO
209
210=over
211
212=item * Get rid of either text or path, as they are redundant.
213
214=item * Re-think the mechanism for pre-correction readings etc.
215
216=back
217
218=head1 LICENSE
219
220This package is free software and is provided "as is" without express
221or implied warranty. You can redistribute it and/or modify it under
222the same terms as Perl itself.
223
224=head1 AUTHOR
225
226Tara L Andrews E<lt>aurum@cpan.orgE<gt>