source: text-formbuilder/trunk/lib/Class/ParseText/Base.pm @ 82

Last change on this file since 82 was 82, checked in by peichman, 19 years ago

added a $parser->{debug} attribute to Class::ParseText::Base that controls $::RD_TRACE
added as_script and as_module methods that return the Perl code without writing to a file
changed required field message and markers

File size: 5.5 KB
Line 
1package Class::ParseText::Base;
2
3use strict;
4use warnings;
5use Carp;
6
7use base qw(Class::Base);
8use vars qw($VERSION);
9
10$VERSION = '0.01';
11
12# (caller(0))[3] => fully qualified subname (e.g. My::Package::function)
13
14sub parse {
15    my ($self, $source) = @_;
16    if (my $type = ref $source) {
17        if ($type eq 'SCALAR') {
18            $self->parse_text($$source);
19        } elsif ($type eq 'ARRAY') {
20            $self->parse_array(@$source);
21        } else {
22            croak '[' . (caller(0))[3] . "] Unknown ref type $type passed as source";
23        }
24    } else {
25        $self->parse_file($source);
26    }
27}
28
29sub parse_array {
30    my ($self, @lines) = @_;
31    # so it can be called as a class method
32    $self = $self->new unless ref $self;   
33    $self->parse_text(join("\n", @lines));   
34    return $self;
35}
36
37sub parse_file {
38    my ($self, $filename) = @_;
39   
40    # so it can be called as a class method
41    $self = $self->new unless ref $self;
42   
43    local $/ = undef;
44    open SRC, "< $filename" or croak '[' . (caller(0))[3] . "] Can't open $filename: $!";
45    my $src = <SRC>;
46    close SRC;
47   
48    return $self->parse_text($src);
49}
50
51sub parse_handle {
52    my ($self, $fh) = @_;
53   
54    # so it can be called as a class method
55    $self = $self->new unless ref $self;
56   
57    my $src;
58    local $/ = undef;
59    $src = readline($fh);
60    close $fh;
61    return $self->parse_text($src);
62}
63
64sub parse_text {
65    my ($self, $src) = @_;
66   
67    # so it can be called as a class method
68    $self = $self->new unless ref $self;
69   
70    croak '[' . (caller(0))[3] . '] No parser defined for this class (perhaps you need to override init?)'
71        unless defined $self->{parser};
72   
73    # optionally ensure that the source text ends in a newline
74    $src =~ /\n$/ or $src .= "\n" if $self->{ensure_newline};
75   
76    # get the name of the start rule
77    my $start_rule = $self->{start_rule};
78    croak '[' . (caller(0))[3] . '] No start rule given for the parser' unless defined $start_rule;
79   
80    # set the trace in RecDescent if we have the debug flag
81    $::RD_TRACE = $self->{debug} ? 1 : undef;
82   
83    $self->{$start_rule} = $self->{parser}->$start_rule($src);
84   
85    # mark structures as not built (newly parsed text)
86    $self->{built} = 0;
87   
88    return $self;
89}
90
91
92# module return
931;
94
95=head1 NAME
96
97Class::ParseText::Base - Base class for modules using Parse::RecDescent parsers
98
99=head1 SYNOPSIS
100
101    package My::Parser;
102    use strict;
103   
104    use base qw(Class::ParseText::Base);
105   
106    # you need to provide an init method, to set the parser and start rule
107    sub init {
108        my $self = shift;
109       
110        # set the parser and start rule that should be used
111        $self->{parser} = Parse::RecDescent->new($grammar);
112        $self->{start_rule} = 'foo';
113        $self->{ensure_newline} = 1;
114       
115        return $self;
116    }
117   
118    package main;
119   
120    my $p = My::Parser->new;
121   
122    $p->parse_text($source_text);
123    $p->parse(\$source_text);
124   
125    $p->parse_array(@source_lines);
126    $p->parse(\@source_lines);
127   
128    $p->parse_file($filename);
129    $p->parse($filename);
130
131=head1 REQUIRES
132
133This base class is in turn based on L<Class::Base>.
134
135=head1 DESCRIPTION
136
137All of the parse rules set C<< $self->{built} >> to false, to indicate that
138a fresh source has been read, and (probably) needs to be analyzed.
139
140=head2 new
141
142    my $p = My::Parser->new;
143
144Creates a new parser object. In general, calling C<new> explicitly is not
145necessary, since all of the C<parse> methods will invoke the constructor
146for you if they are called as a class method.
147
148    # as a class method
149    my $p = My::Parser->parse_file('some_source.txt');
150
151=head2 parse_file
152
153    $p->parse_file($filename);
154
155Parses the contents of of the file C<$filename>. Returns the parser object.
156
157=head2 parse_handle
158
159    $p->parse_handle($fh);
160
161Slurps the remainder of the file handle C<$fh> and parses the contents.
162Returns the parser object.
163
164=head2 parse_array
165
166    $p->parse_array(@lines);
167
168Joins C<@lines> with newlines and parses. Returns the parser object.
169
170=head2 parse_text
171
172    $p->parse_text($source);
173
174Parse the literal C<$source>. Returns the parser object.
175
176=head2 parse
177
178    $p->parse($src);
179
180Automagic method that tries to pick the correct C<parse_*> method to use.
181
182    ref $src            method
183    ========            ==================
184    ARRAY               parse_array(@$src)
185    SCALAR              parse_text($$src)
186    undef               parse_file($src)
187
188Passing other ref types in C<$src> (e.g. C<HASH>) will cause C<parse> to die.
189
190=head1 SUBCLASSING
191
192This class is definitely intended to be subclassed. The only method you should
193need to override is the C<init> method, to set the parser object that will do the
194actual work.
195
196=head2 init
197
198The following properties of the object should be set:
199
200=over
201
202=item C<parser>
203
204The Parse::RecDescent derived parser object to use.
205
206=item C<start_rule>
207
208The name of the initial rule to start parsing with. The results of
209the parse are stored in the object with this same name as their key.
210
211=item C<ensure_newline>
212
213Set to true to ensure that the text to be parsed ends in a newline.
214
215=back
216
217I<Be sure that you explicitly return the object!> This is a bug that
218has bitten me a number of times.
219
220=head1 TODO
221
222C<parse_handle> method
223
224Expand to use other sorts of parsing modules (e.g. Parse::Yapp)
225
226=head1 AUTHOR
227
228Peter Eichman, C<< <peichman@cpan.org> >>
229
230=head1 COPYRIGHT AND LICENSE
231
232Copyright E<copy>2005 by Peter Eichman.
233
234This program is free software; you can redistribute it and/or
235modify it under the same terms as Perl itself.
236
237=cut
Note: See TracBrowser for help on using the repository browser.