Class::ParseText::Base - Base class for modules using Parse::RecDescent parsers


Text-FormBuilder documentation Contained in the Text-FormBuilder distribution.

Index


Code Index:

NAME

Top

Class::ParseText::Base - Base class for modules using Parse::RecDescent parsers

SYNOPSIS

Top

    package My::Parser;
    use strict;

    use base qw(Class::ParseText::Base);

    # you need to provide an init method, to set the parser and start rule
    sub init {
        my $self = shift;

        # set the parser and start rule that should be used
        $self->{parser} = Parse::RecDescent->new($grammar);
        $self->{start_rule} = 'foo';
        $self->{ensure_newline} = 1;

        return $self;
    }

    package main;

    my $p = My::Parser->new;

    $p->parse_text($source_text);
    $p->parse(\$source_text);

    $p->parse_array(@source_lines);
    $p->parse(\@source_lines);

    $p->parse_file($filename);
    $p->parse($filename);

REQUIRES

Top

This base class is in turn based on Class::Base.

DESCRIPTION

Top

All of the parse rules set $self->{built} to false, to indicate that a fresh source has been read, and (probably) needs to be analyzed.

new

    my $p = My::Parser->new;

Creates a new parser object. In general, calling new explicitly is not necessary, since all of the parse methods will invoke the constructor for you if they are called as a class method.

    # as a class method
    my $p = My::Parser->parse_file('some_source.txt');

parse_file

    $p->parse_file($filename);

Parses the contents of of the file $filename. Returns the parser object.

parse_handle

    $p->parse_handle($fh);

Slurps the remainder of the file handle $fh and parses the contents. Returns the parser object.

parse_array

    $p->parse_array(@lines);

Joins @lines with newlines and parses. Returns the parser object.

parse_text

    $p->parse_text($source);

Parse the literal $source. Returns the parser object.

parse

    $p->parse($src);

Automagic method that tries to pick the correct parse_* method to use.

    ref $src            method
    ========            ==================
    ARRAY               parse_array(@$src)
    SCALAR              parse_text($$src)
    undef               parse_file($src)

Passing other ref types in $src (e.g. HASH) will cause parse to die.

SUBCLASSING

Top

This class is definitely intended to be subclassed. The only method you should need to override is the init method, to set the parser object that will do the actual work.

init

The following properties of the object should be set:

parser

The Parse::RecDescent derived parser object to use.

start_rule

The name of the initial rule to start parsing with. The results of the parse are stored in the object with this same name as their key.

ensure_newline

Set to true to ensure that the text to be parsed ends in a newline.

Be sure that you explicitly return the object! This is a bug that has bitten me a number of times.

TODO

Top

parse_handle method

Expand to use other sorts of parsing modules (e.g. Parse::Yapp)

AUTHOR

Top

Peter Eichman, <peichman@cpan.org>

COPYRIGHT AND LICENSE

Top


Text-FormBuilder documentation Contained in the Text-FormBuilder distribution.

package Class::ParseText::Base;

use strict;
use warnings;
use Carp;

use base qw(Class::Base);
use vars qw($VERSION);

$VERSION = '0.01';

# (caller(0))[3] => fully qualified subname (e.g. My::Package::function)

sub parse {
    my ($self, $source) = @_;
    if (my $type = ref $source) {
        if ($type eq 'SCALAR') {
            $self->parse_text($$source);
        } elsif ($type eq 'ARRAY') {
            $self->parse_array(@$source);
        } else {
            croak '[' . (caller(0))[3] . "] Unknown ref type $type passed as source";
        }
    } else {
        $self->parse_file($source);
    }
}

sub parse_array {
    my ($self, @lines) = @_;
    # so it can be called as a class method
    $self = $self->new unless ref $self;    
    $self->parse_text(join("\n", @lines));    
    return $self;
}

sub parse_file {
    my ($self, $filename) = @_;
    
    # so it can be called as a class method
    $self = $self->new unless ref $self;
    
    local $/ = undef;
    open SRC, "< $filename" or croak '[' . (caller(0))[3] . "] Can't open $filename: $!";
    my $src = <SRC>;
    close SRC;
    
    return $self->parse_text($src);
}

sub parse_handle {
    my ($self, $fh) = @_;
    
    # so it can be called as a class method
    $self = $self->new unless ref $self;
    
    my $src;
    local $/ = undef;
    $src = readline($fh);
    close $fh;
    return $self->parse_text($src);
}

sub parse_text {
    my ($self, $src) = @_;
    
    # so it can be called as a class method
    $self = $self->new unless ref $self;
    
    croak '[' . (caller(0))[3] . '] No parser defined for this class (perhaps you need to override init?)'
        unless defined $self->{parser};
    
    # optionally ensure that the source text ends in a newline
    $src =~ /\n$/ or $src .= "\n" if $self->{ensure_newline};
    
    # get the name of the start rule
    my $start_rule = $self->{start_rule};
    croak '[' . (caller(0))[3] . '] No start rule given for the parser' unless defined $start_rule;
    
    # set the trace in RecDescent if we have the debug flag
    $::RD_TRACE = $self->{debug} ? 1 : undef;
    
    $self->{$start_rule} = $self->{parser}->$start_rule($src);
    
    # mark structures as not built (newly parsed text)
    $self->{built} = 0;
    
    return $self;
}


# module return
1;