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

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

separated basic parser using code out into a separate Class::ParseText::Base base class; updated docs, manifest, and changelog

File size: 5.2 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
51#TODO: get this working
52sub parse_handle {
53    my ($self, $fh) = @_;
54   
55    # so it can be called as a class method
56    $self = $self->new unless ref $self;
57   
58    my $src;
59    while ($_ = readline($fh)) { $src .= $_ }
60    warn $src;
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    $self->{$start_rule} = $self->{parser}->$start_rule($src);
80   
81    # mark structures as not built (newly parsed text)
82    $self->{built} = 0;
83   
84    return $self;
85}
86
87
88# module return
891;
90
91=head1 NAME
92
93Class::ParseText::Base - Base class for modules using Parse::RecDescent parsers
94
95=head1 SYNOPSIS
96
97    package My::Parser;
98    use strict;
99   
100    use base qw(Class::ParseText::Base);
101   
102    # you need to provide an init method, to set the parser and start rule
103    sub init {
104        my $self = shift;
105       
106        # set the parser and start rule that should be used
107        $self->{parser} = Parse::RecDescent->new($grammar);
108        $self->{start_rule} = 'foo';
109        $self->{ensure_newline} = 1;
110       
111        return $self;
112    }
113   
114    package main;
115   
116    my $p = My::Parser->new;
117   
118    $p->parse_text($source_text);
119    $p->parse(\$source_text);
120   
121    $p->parse_array(@source_lines);
122    $p->parse(\@source_lines);
123   
124    $p->parse_file($filename);
125    $p->parse($filename);
126
127=head1 REQUIRES
128
129This base class is in turn based on L<Class::Base>.
130
131=head1 DESCRIPTION
132
133All of the parse rules set C<< $self->{built} >> to false, to indicate that
134a fresh source has been read, and (probably) needs to be analyzed.
135
136=head2 new
137
138    my $p = My::Parser->new;
139
140Creates a new parser object. In general, calling C<new> explicitly is not
141necessary, since all of the C<parse> methods will invoke the constructor
142for you if they are called as a class method.
143
144    # as a class method
145    my $p = My::Parser->parse_file('some_source.txt');
146
147=head2 parse_file
148
149    $p->parse_file($filename);
150
151Parses the contents of of the file C<$filename>. Returns the parser object.
152
153=head2 parse_array
154
155    $p->parse_array(@lines);
156
157Joins C<@lines> with newlines and parses. Returns the parser object.
158
159=head2 parse_text
160
161    $p->parse_text($source);
162
163Parse the literal C<$source>. Returns the parser object.
164
165=head2 parse
166
167    $p->parse($src);
168
169Automagic method that tries to pick the correct C<parse_*> method to use.
170
171    ref $src            method
172    ========            ==================
173    ARRAY               parse_array(@$src)
174    SCALAR              parse_text($$src)
175    undef               parse_file($src)
176
177Passing other ref types in C<$src> (e.g. C<HASH>) will cause C<parse> to die.
178
179=head1 SUBCLASSING
180
181This class is definitely intended to be subclassed. The only method you should
182need to override is the C<init> method, to set the parser object that will do the
183actual work.
184
185=head2 init
186
187The following properties of the object should be set:
188
189=over
190
191=item C<parser>
192
193The Parse::RecDescent derived parser object to use.
194
195=item C<start_rule>
196
197The name of the initial rule to start parsing with. The results of
198the parse are stored in the object with this same name as their key.
199
200=item C<ensure_newline>
201
202Set to true to ensure that the text to be parsed ends in a newline.
203
204=back
205
206=head1 TODO
207
208C<parse_handle> method
209
210Expand to use other sorts of parsing modules (e.g. Parse::Yapp)
211
212=head1 AUTHOR
213
214Peter Eichman, C<< <peichman@cpan.org> >>
215
216=head1 COPYRIGHT AND LICENSE
217
218Copyright E<copy>2005 by Peter Eichman.
219
220This program is free software; you can redistribute it and/or
221modify it under the same terms as Perl itself.
222
223=cut
Note: See TracBrowser for help on using the repository browser.