File Coverage

blib/lib/Text/Shoebox/Lexicon.pm
Criterion Covered Total %
statement 45 65 69.2
branch 14 32 43.7
condition 2 6 33.3
subroutine 14 17 82.3
pod 8 12 66.6
total 83 132 62.8


line stmt bran cond sub pod time code
1              
2             package Text::Shoebox::Lexicon;
3             require 5;
4 3     3   24466 use strict;
  3         6  
  3         155  
5 3     3   18 use vars qw(@ISA $Debug $VERSION $ENTRY_CLASS);
  3         6  
  3         230  
6 3     3   18 use Carp ();
  3         6  
  3         115  
7              
8             $Debug = 0 unless defined $Debug;
9             BEGIN {
10 3     3   93 $VERSION = "1.02";
11             }
12             $ENTRY_CLASS ||= 'Text::Shoebox::Entry';
13 3     3   1511 use Text::Shoebox 1.02 ();
  3         114  
  3         3324  
14              
15             unless($Text::Shoebox::Entry::VERSION) { require Text::Shoebox::Entry; }
16              
17             ###########################################################################
18              
19             =head1 NAME
20              
21             Text::Shoebox::Lexicon - an object-oriented interface to Shoebox lexicons
22              
23             =head1 SYNOPSIS
24              
25             use Text::Shoebox::Lexicon;
26             my $lex = Text::Shoebox::Lexicon->read_file( "haida.sf" );
27             my @entries = $lex->entries;
28             print "See, it has ", scalar( @entries ), " entries!\n";
29             $lex->dump;
30              
31             =head1 DESCRIPTION
32              
33             On object of class Text::Shoebox::Lexicon represents a SF-format lexicon.
34             This mostly just means it's a container for a list of
35             Text::Shoebox::Entry objects, which represent the entries in this lexicon.
36              
37             This class (plus Text::Shoebox::Entry) exists basically to provide an OO
38             interface around L -- but you're free to directly
39             use Text::Shoebox instead if you prefer a functional interface.
40              
41             =head1 METHODS
42              
43             =over
44              
45             =item $lex = Text::Shoebox::Lexicon->new;
46              
47             This method returns a new Text::Shoebox Lexicon object, containing
48             an empty list of entries.
49              
50             =cut
51              
52             ###########################################################################
53              
54             sub new {
55 13   33 13 1 2056 my $new = bless {}, ref($_[0]) || $_[0];;
56 13         50 $new->init;
57 13         53 return $new;
58             }
59              
60             sub init {
61 13     13 0 34 my $self = shift;
62 13         63 $self->{'e'} = [];
63             }
64              
65             #--------------------------------------------------------------------------
66              
67             =item $lex->read_file( $filespec );
68              
69             This reads entries from $filespec (e.g., "./whatever.sf") into $lex.
70             If $filespec doesn't exist or isn't readable, then this dies.
71              
72             =item $lex = Text::Shoebox::Lexicon->read_file( $filespec );
73              
74             This constructs a new lexicon object and reads entries from $filespec into
75             it. I.e., it's basically a shortcut for:
76              
77             $lex = Text::Shoebox::Lexicon->new;
78             $lex->read_file($filespec);
79              
80             =item $lex->read_handle( $filehandle );
81              
82             =item $lex = Text::Shoebox::Lexicon->read_handle( $filehandle );
83              
84             These work just like read_file except that the argument should be a
85             filehandle instead of a filespec string.
86              
87             =item $lex->write_file( $filespec );
88              
89             This writes the entries from $lex to the given filespec. If they can't
90             be written, this dies.
91              
92             =item $lex->write_handle( $filehandle );
93              
94             These work just like write_file except that the argument should be a
95             filehandle instead of a filespec string.
96              
97             =cut
98              
99             sub read_file {
100 12     12 1 59 my($self, $in) = @_;
101 12 100       46 $self = $self->new unless ref $self; # tolerate being a class method
102 12 100       84 Text::Shoebox::read_sf( 'from_file' => $in, 'into' => $self->{'e'},
103             $self->{'rs'} ? ('rs' => $self->{'rs'}) : ()
104             );
105 12         41 $self->tidy_up;
106 12         27 return $self;
107             }
108              
109             sub read_handle {
110 0     0 1 0 my($self, $in) = @_;
111 0 0       0 $self = $self->new unless ref $self; # tolerate being a class method
112 0 0       0 Text::Shoebox::read_sf( 'from_handle' => $in, 'into' => $self->{'e'},
113             $self->{'rs'} ? ('rs' => $self->{'rs'}) : ()
114             );
115 0         0 $self->tidy_up;
116 0         0 return $self;
117             }
118              
119             sub write_file {
120 6     6 1 34 my($self, $out) = @_;
121 6 50       24 Carp::confess "write_file is an object method, not a class method"
122             unless ref $self;
123 6 100       47 Text::Shoebox::write_sf( 'to_file' => $out, 'from' => $self->{'e'},
    50          
124             $self->{'rs'} ? ('rs' => $self->{'rs'}) : ()
125             ) || Carp::confess "Couldn't write_file to $out: $!";
126 6         29 return $self;
127             }
128              
129             sub write_handle {
130 0     0 1 0 my($self, $out) = @_;
131 0 0       0 Carp::confess "write_handle is an object method, not a class method"
132             unless ref $self;
133 0 0       0 Text::Shoebox::write_sf( 'to_handle' => $out, 'from' => $self->{'e'},
    0          
134             $self->{'rs'} ? ('rs' => $self->{'rs'}) : ()
135             ) || Carp::confess "Couldn't write_handle to $out: $!";
136 0         0 return $self;
137             }
138              
139             #--------------------------------------------------------------------------
140              
141             =item $lex->dump;
142              
143             This prints (not returns!) a dump of the contents of $lex.
144              
145             =cut
146              
147             sub dump {
148 0     0 1 0 my($self, $out) = @_;
149 0 0       0 Carp::confess "dump is an object method, not a class method"
150             unless ref $self;
151 0         0 print "Lexicon $self contains ", scalar @{ $self->{'e'} }, " entries:\n\n";
  0         0  
152 0         0 foreach my $e ( @{ $self->{'e'} } ) {
  0         0  
153 0         0 $e->dump;
154             }
155 0         0 return $self;
156             }
157              
158             #--------------------------------------------------------------------------
159              
160             =item @them = $lex->entries;
161              
162             This returns a list of the entry objects in $lex.
163              
164              
165             =item $them = $lex->entries_as_lol;
166              
167             This returns a reference to the array of entry objects in $lex.
168              
169             This can be useful for doing things like C.
170              
171             This is your only way of altering the entry-list in $lex, other
172             than read_file and read_handle!
173              
174             =cut
175              
176              
177             sub entries {
178 3     3 1 17 my $self = shift;
179 3 50       10 return @{ $self->{'e'} } unless @_;
  3         17  
180 0         0 @{ $self->{'e'} } = @_ ; # otherwise, be a set method
  0         0  
181 0         0 return $self;
182             }
183              
184             sub tidy_up {
185 12     12 0 20 my $self = $_[0];
186 12   33     44 my $entry_class = $self->{'entry_class'} || $ENTRY_CLASS;
187 12         17 foreach my $e (@{ $self->{'e'} }) {
  12         31  
188 24 50       52 if( ref($e) eq 'ARRAY' ) {
189 24         53 bless $e, $entry_class;
190 24 100       78 $e->scrunch unless $self->{'no_scrunch'};
191             }
192             }
193 12         26 return $self;
194             }
195              
196 50     50 1 445 sub entries_as_lol { return $_[0]{'e'} }
197              
198             #--------------------------------------------------------------------------
199             # Dumb boilerplate accessors:
200              
201             =back
202              
203             =head2 Other Attributes
204              
205             A lexicon object is mainly for just holding a list of entries. But besides
206             that list, it also contains these attributes, which you usually don't have
207             to know about:
208              
209             =over
210              
211             =item The "no_scrunch" attribute
212              
213             Right after read_file (or read_handle) has finished reading entries, it
214             goes over all of them and calls C<< $e->scrunch >> on each. (See
215             L for an explanation of the scrunch method.) But
216             you can override this by calling $lex->no_scrunch(1) to set the "no_scrunch"
217             method to a true value.
218              
219             (You can also explicitly turn this off with $lex->no_scrunch(0), or check
220             it with $lex->no_scrunch().)
221              
222              
223             =item The "rs" attribute
224              
225             When Text::Shoebox::Lexicon reads or writes a lexicon, it normally
226             lets L determine the right value for the newline string
227             (also known as the "RS", even tho for SF format it's not a record
228             separator at all), and that's usually the right thing.
229              
230             But if that's not working right and you need to override that newline-guessing
231             (notably, this might be necessary with
232             read_handle, which isn't as good as guessing as read_file is), then you
233             can set the lexicon's C attribute directly, with C<<
234             $lex->rs("\cm\cj") >>. Or you can even force it to the system-default
235             value with just C<< $lex->rs($/) >>. Or you can just check the
236             value of the C attribute with just C<< $lex->rs() >>.
237              
238             =back
239              
240             =cut
241              
242             sub no_scrunch {
243 11 50   11 0 129 return $_[0]{'no_scrunch'} if @_ == 1; # get
244 11         30 $_[0]{'no_scrunch'} = $_[1]; # set...
245 11         22 return $_[0];
246             }
247             sub rs {
248 11 50   11 0 2825 return $_[0]{'rs'} if @_ == 1; # get
249 11         30 $_[0]{'rs'} = $_[1]; # set...
250 11         23 return $_[0];
251             }
252             #--------------------------------------------------------------------------
253              
254             1;
255             __END__