Config::INI::Reader - a subclassable .ini-file parser


Config-INI documentation Contained in the Config-INI distribution.

Index


Code Index:

NAME

Top

Config::INI::Reader - a subclassable .ini-file parser

VERSION

Top

version 0.018

SYNOPSIS

Top

If family.ini contains:

  admin = rjbs

  [rjbs]
  awesome = yes
  height = 5' 10"

  [mj]
  awesome = totally
  height = 23"

Then when your program contains:

  my $hash = Config::INI::Reader->read_file('family.ini');

$hash will contain:

  {
    '_'  => { admin => 'rjbs' },
    rjbs => {
      awesome => 'yes',
      height  => q{5' 10"},
    },
    mj   => {
      awesome => 'totally',
      height  => '23"',
    },
  }

DESCRIPTION

Top

Config::INI::Reader is yet another config module implementing yet another slightly different take on the undeniably easy to read ".ini" file format. Its default behavior is quite similar to that of Config::Tiny, on which it is based.

The chief difference is that Config::INI::Reader is designed to be subclassed to allow for side-effects and self-reconfiguration to occur during the course of reading its input.

METHODS FOR READING CONFIG

Top

These methods are all that most users will need: they read configuration from a source of input, then they return the data extracted from that input. There are three reader methods, read_string, read_file, and read_handle. The first two are implemented in terms of the third. It iterates over lines in a file, calling methods on the reader when events occur. Those events are detailed below in the METHODS FOR SUBCLASSING section.

All of the reader methods return an unblessed reference to a hash.

All throw an exception when they encounter an error.

read_file

  my $hash_ref = Config::INI::Reader->read_file($filename);

Given a filename, this method returns a hashref of the contents of that file.

read_string

  my $hash_ref = Config::INI::Reader->read_string($string);

Given a string, this method returns a hashref of the contents of that string.

read_handle

  my $hash_ref = Config::INI::Reader->read_handle($io_handle);

Given an IO::Handle, this method returns a hashref of the contents of that handle.

METHODS FOR SUBCLASSING

Top

These are the methods you need to understand and possibly change when subclassing Config::INI::Reader to handle a different format of input.

current_section

  my $section_name = $reader->current_section;

This method returns the name of the current section. If no section has yet been set, it returns the result of calling the starting_section method.

parse_section_header

  my $name = $reader->parse_section_header($line);

Given a line of input, this method decides whether the line is a section-change declaration. If it is, it returns the name of the section to which to change. If the line is not a section-change, the method returns false.

change_section

  $reader->change_section($section_name);

This method is called whenever a section change occurs in the file.

The default implementation is to change the current section into which data is being read and to initialize that section to an empty hashref.

parse_value_assignment

  my ($name, $value) = $reader->parse_value_assignment($line);

Given a line of input, this method decides whether the line is a property value assignment. If it is, it returns the name of the property and the value being assigned to it. If the line is not a property assignment, the method returns false.

set_value

  $reader->set_value($name, $value);

This method is called whenever an assignment occurs in the file. The default behavior is to change the value of the named property to the given value.

starting_section

  my $section = Config::INI::Reader->starting_section;

This method returns the name of the starting section. The default is: _

can_ignore

  do_nothing if $reader->can_ignore($line)

This method returns true if the given line of input is safe to ignore. The default implementation ignores lines that contain only whitespace or comments.

preprocess_line

  $reader->preprocess_line(\$line);

This method is called to preprocess each line after it's read but before it's parsed. The default implementation just strips inline comments. Alterations to the line are made in place.

finalize

  $reader->finalize;

This method is called when the reader has finished reading in every line of the file.

new

  my $reader = Config::INI::Reader->new;

This method returns a new reader. This generally does not need to be called by anything but the various read_* methods, which create a reader object only ephemerally.

ORIGIN

Top

Originaly derived from Config::Tiny, by Adam Kennedy.

AUTHOR

Top

Ricardo Signes <rjbs@cpan.org>

COPYRIGHT AND LICENSE

Top


Config-INI documentation Contained in the Config-INI distribution.

use strict;
use warnings;
package Config::INI::Reader;
BEGIN {
  $Config::INI::Reader::VERSION = '0.018';
}
use Mixin::Linewise::Readers;
# ABSTRACT: a subclassable .ini-file parser


use Carp ();
use IO::File 1.14;
use IO::String;

our @CARP_NOT = qw(Mixin::Linewise::Readers);


sub read_handle {
  my ($invocant, $handle) = @_;

  my $self = ref $invocant ? $invocant : $invocant->new;

  # parse the file
  LINE: while (my $line = $handle->getline) {
    next LINE if $self->can_ignore($line);

    $self->preprocess_line(\$line);

    # Handle section headers
    if (defined (my $name = $self->parse_section_header($line))) {
      # Create the sub-hash if it doesn't exist.
      # Without this sections without keys will not
      # appear at all in the completed struct.
      $self->change_section($name);
      next LINE;
    }

    if (my ($name, $value) = $self->parse_value_assignment($line)) {
      $self->set_value($name, $value);
      next;
    }

    my $lineno = $handle->input_line_number;
    Carp::croak "Syntax error at line $lineno: '$line'";
  }

  $self->finalize;

  return $self->{data};
}


sub current_section {
  defined $_[0]->{section} ? $_[0]->{section} : $_[0]->starting_section;
}


sub parse_section_header {
  return $1 if $_[1] =~ /^\s*\[\s*(.+?)\s*\]\s*$/;
  return;
}


sub change_section {
  my ($self, $section) = @_;

  $self->{section} = $section;

  if (!exists $self->{data}{$section}) {
    $self->{data}{$section} = {};
  }
}


sub parse_value_assignment {
  return ($1, $2) if $_[1] =~ /^\s*([^=\s][^=]*?)\s*=\s*(.*?)\s*$/;
  return;
}


sub set_value {
  my ($self, $name, $value) = @_;

  $self->{data}{ $self->current_section }{$name} = $value;
}


sub starting_section { q{_} }


sub can_ignore {
  my ($self, $line) = @_;

  # Skip comments and empty lines
  return $line =~ /\A\s*(?:;|$)/ ? 1 : 0;
}


sub preprocess_line {
  my ($self, $line) = @_;

  # Remove inline comments
  ${$line} =~ s/\s+;.*$//g;
}


sub finalize { }


sub new {
  my ($class) = @_;

  my $self = { data => {}, };

  bless $self => $class;
}


1;

__END__