Syndication::ESF - Create and update ESF files


Syndication-ESF documentation Contained in the Syndication-ESF distribution.

Index


Code Index:

NAME

Top

Syndication::ESF - Create and update ESF files

SYNOPSIS

Top

    use Syndication::ESF;

    my $esf = Syndication::ESF->new;

    $esf->parsefile( 'my.esf' );

    $esf->channel( title => 'My channel' );

    $esf->add_item(
        date  => time,
        title => 'new item',
        link  => 'http://example.org/#foo'
    );

    print "Channel: ", $esf->channel( 'title' ), "\n";
    print "Items  : ", scalar @{ $esf->{ items } }, "\n";

    my $output = $esf->as_string;

    $esf->save( 'my.esf' );

DESCRIPTION

Top

This module is the basic framework for creating and maintaing Epistula Syndication Format (ESF) files. More information on the format can be found at the Aquarionics web site: http://www.aquarionics.com/article/name/esf

This module tries to copy the XML::RSS module's interface. All applicable methods have been copied and should respond in the same manner.

Like in XML::RSS, channel data is accessed through the channel() sub, and item data is accessed straight out of the items array.

INSTALLATION

Top

    perl Makefile.PL
    make
    make test
    make install

METHODS

Top

new()

Creates a new Syndication::ESF object. It currently does not accept any parameters.

channel(title => $title, contact => $contact, link => $link)

Supplying no parameters will give you a reference to the channel data. Specifying a field name returns the value of the field. Giving it a hash will update the channel data with the supplied values.

contact_name()

shortcut to get the contact name

contact_email()

shortcut to get the contact email

add_item(date => $date, title => $title, link => $link, mode => $mode)

By default, this will append the new item to the end of the list. Specifying 'insert' for the mode parameter adds it to the front of the list.

parse($string)

Parse the supplied raw ESF data.

parsefile($filename)

Same as parse(), but takes a filename as input.

as_string()

Returns the current data stored in the object as a string.

save($filename)

Saves the value of as_string() to the supplied filename.

AUTHOR

Top

Brian Cassidy <bricas@cpan.org>

COPYRIGHT AND LICENSE

Top

SEE ALSO

Top

* XML::RSS

Syndication-ESF documentation Contained in the Syndication-ESF distribution.
package Syndication::ESF;

use strict;
use warnings;
use Carp;

our $VERSION = '0.13';

# Defines the set of valid fields for a channel and its items
my @channel_fields = qw( title contact link );
my @item_fields    = qw( date title link );

sub new {
    my $class = shift;
    my $self  = {
        channel => {},
        items   => []
    };

    bless $self, $class;

    return $self;
}

sub channel {
    my $self = shift;

    # accessor; if there's only one arg
    if ( @_ == 1 ) {
        return $self->{ channel }->{ $_[ 0 ] };
    }

    # mutator; if there's more than one arg
    elsif ( @_ > 1 ) {
        my %options = @_;

        for ( keys %options ) {
            $self->{ channel }->{ $_ } = $options{ $_ };

            # extract email and name from contact info
            if ( $_ eq 'contact' ) {
                my @contact = split( / /, $options{ $_ }, 2 );
                $contact[ 1 ] =~ s/[\(\)]//g;
                $self->channel(
                    'contact_name'  => $contact[ 1 ],
                    'contact_email' => $contact[ 0 ]
                );
            }
        }
    }

    return $self->{ channel };
}

sub contact_name {
    my $self = shift;
    return $self->channel( 'contact_name' );
}

sub contact_email {
    my $self = shift;
    return $self->channel( 'contact_email' );
}

sub add_item {
    my $self    = shift;
    my $options = { @_ };
    my $mode    = $options->{ mode };

    # depending on the mode, add the item to the
    # start or end of the feed
    if ( $mode and $mode eq 'insert' ) {
        unshift( @{ $self->{ items } }, $options );
    }
    else {
        push( @{ $self->{ items } }, $options );
    }

    return $self->{ items };
}

sub parse {
    my $self = shift;
    my $data = shift;

    # boolean to indicate if we're parsing the meta data or the items.
    my $metamode = 1;

    foreach my $line ( split /(?:\015\012|\012|\015)/, $data ) {

        # skip to the next line if it's a comment
        next if $line =~ /^#/;

        chomp( $line );

        # if it's a blank line, get out of meta-mode.
        if ( $line eq '' ) {
            $metamode = 0;
            next;
        }

        my @data = split /\t/, $line;

        # depending on what mode we're in, insert the channel, or item data.
        if ( $metamode ) {
            $self->channel( $data[ 0 ] => $data[ 1 ] );
        }
        else {
            push @{ $self->{ items } },
                { map { $item_fields[ $_ ] => $data[ $_ ] }
                    0 .. $#item_fields };
        }
    }
}

sub parsefile {
    my $self = shift;
    my $file = shift;

    open( my $esf, $file ) or croak "File open error ($file): $!";

    my $data = do { local $/; <$esf>; };

    close( $esf ) or carp( "File close error ($file): $!" );

    $self->parse( $data );
}

sub as_string {
    my $self = shift;

    my $data;

    # append channel data
    $data .= "$_\t" . $self->channel( $_ ) . "\n" for @channel_fields;
    $data .= "\n";

    # append item data
    foreach my $item ( @{ $self->{ items } } ) {
        $data .= $item->{ $_ } . "\t" for @item_fields;
        $data =~ s/\t$/\n/;
    }

    return $data;
}

sub save {
    my $self = shift;
    my $file = shift;

    open( my $esf, ">$file" ) or croak "File open error ($file): $!";

    print { $esf } $self->as_string;

    close( $esf ) or carp( "File close error ($file): $!" );
}

1;