NAME
Config::Column - simply packages input and output of "config" / "BBS log" file whose records are separated by any delimiter.
SYNOPSIS
# Copy the datalist in a tab separated file to readable formatted text file.
use utf8;
use lib './lib';
use Config::Column;
my $order_delim = [qw(1 subject date value)];
my $order_nodelim = ['' => 1 => ': [' => subject => '] ' => date => ' : ' => value => ''];
my $delimiter = "\t";
# MAIN file instance
my $ccmain = Config::Column->new(
'mainfile.dat', # the data file path
'utf8', # character encoding of the data file (PerlIO ":encoding($layer)") or PerlIO layer (ex. ':encoding(utf8)')
$order_delim, # list of key names
$delimiter, # delimiter that separates data column
1, # first index for data list
"\0" # delimiter that separates data record ("lines")
);
# SUB file (human readable)
my $ccsub = Config::Column->new(
'', # this can be empty because data file will be opened externally and file handle is passed to this instance
'', # same reason
$order_nodelim, # list of key names and delimiters
undef, # do not define delimiter
1, # first index for data list
# delimiter that separates data record ("lines") is Default
);
# Read data from MAIN file.
my $data = $ccmain->read_data;
# Add new data.
push @$data,{subject => 'YATTA!', date => '2012/03/06T23:33:00+09:00', value => 'All tests passed!'};print $data;
# Write data to MAIN file.
$ccmain->write_data($data);
# Write header to SUB file
open my $fh,'+<:encoding(utf8)','subfile.txt';
flock $fh,2;
truncate $fh,0;
seek $fh,0,0;
print $fh 'Single line diary?',"\n";
# Add data to SUB file. Don't close and don't truncate $fh.
$ccsub->write_data($data,$fh,1,1);
print $fh 'The end of the worl^h^h^h^hfile';
close $fh;
INTRODUCTION
This module generalizes the list of keys and delimiters that is common in "config" / "BBS log" file format and packageizes data list input and output of these files.
It treats data list as simple array reference of hash references.
my $datalist = [
{}, # If the first index for data list (see below section) is 1, 0th data is empty.
{title => "hoge",value => "huga"},
{title => "hoge2",value => "huga"},
{title => "hoge3",value => "huga"},
];
It manages only IO of that data list format and leaves data list manipulating to basic Perl operation.
DESCRIPTION
Constructor
new()
my $cc = Config::Column->new(
$datafile, # the data file path
$layer, # character encoding of the data file (PerlIO ":encoding($layer)") or PerlIO layer (ex. ':encoding(utf8)')
$order, # the "order" (see below section) (ARRAY REFERENCE)
$delimiter, # delimiter that separates data column
$indexshift, # first index for data list (may be 0 or 1 || can omit, and use 0 as default) (Integer >= 0)
$linedelimiter # delimiter that separates data record ("lines")(can omit, and use Perl default (may be $/ == "\n"))
);
$indexshift
is 0 or 1 in general. For example, if $indexshift == 1
, you can get first data record by accessing to $datalist->[1]
, and $datalist->[0]
is empty.
There is two types of definition of $order
and $delimiter
for 2 following case.
- single delimiter (You must define delimiter.)
-
my $cc = Config::Column->new( './filename.dat', # the data file path 'utf8', # character encoding of the data file or PerlIO layer [qw(1 author id title date summary)], # the "order" [keys] "\t", # You MUST define delimiter. 1, # first index for data list "\n" # delimiter that separates data record );
In this case, "order" is names (hash keys) of each data column.
It is for data formats such as tab/comma separated data.
- multiple delimiters (Never define delimiter.)
-
my $cc = Config::Column->new( './filename.dat', # the data file path 'utf8', # character encoding of the data file or PerlIO layer [qw('' 1 ': ' author "\t" id "\t" title "\t" date "\t" summary)], # [delim key delim key ...] undef, # NEVER define delimiter (or omit). 1, # first index for data list "\n" # delimiter that separates data record );
In this case, "order" is names (hash keys) of each data column and delimiters.
$order
's 0,2,4...th (even) elements are delimiter, and 1,3,5...th (odd) elements are names (hash keys).It is for data formats such as ...
['', 1, ' [', subject, '] : ', date, ' : ', article]
-
1 [This is the subject] : 2012/02/07 : Article is there. HAHAHA! 2 [Easy to read] : 2012/02/07 : Tab separated data is for only computers.
['', thread_number, '.dat<>', subject, ' (', res_number, ')'] # subject.txt (bracket delimiter is errorous)
-
1325052927.dat<>Nurupo (988) 1325387590.dat<>OKOTOWARI!!!!!! Part112 [AA] (444) 1321698127.dat<>Marked For Death 18 (159)
Index column
The name "1" in $order
means the index of data records.
If the name "1" exists in $order
, integer in the index column will be used as array references' index.
$delimiter = "\t";
$order = [1,somedata1,somedata2];
# data file
1 somedata other
2 foobar 2000
3 hoge piyo
5 English isDifficult
|
| read_data()
v
$datalist = [
{}, # 0
{somedata1 => 'somedata', somedata2 => 'other'}, # 1
{somedata1 => 'foobar', somedata2 => '2000'}, # 2
{somedata1 => 'hoge', somedata2 => 'piyo'}, # 3
{}, # 4
{somedata1 => 'English', somedata2 => 'isDifficult'}, # 5
];
| ^
| write_data() | read_data()
v |
# data file
1 somedata other
2 foobar 2000
3 hoge piyo
4
5 English isDifficult
Methods
add_data_last()
This method adds data records to the data file after previous data in the file. Indexes of these data records are automatically setted by reading the data file before.
$cc->add_data_last($data,$fh,$fhflag);
my $data = {title => "hoge",value => "huga"} || [
{title => "hoge",value => "huga"},
{title => "hoge2",value => "huga"},
{title => "hoge3",value => "huga"},
]; # hash reference of single data record or array reference of hash references of multiple data records
my $fh; # file handle (can omit)
my $fhflag = 1; # if true, file handle will not be closed (can omit)
If you give a file handle to the argument, file that defined by constructor is omitted and this method uses given file handle and adds data from the place current file pointer points not from the head of file.
Return value:
Succeed > first: 1 , second: (if $fhflag
is true) file handle
Fail > first: false (return;)
add_data()
This method adds data records to the data file.
$cc->add_data($datalist,$startindex,$fh,$fhflag);
my $datalist = {title => "hoge",value => "huga"} || [
{title => "hoge",value => "huga"},
{title => "hoge2",value => "huga"},
{title => "hoge3",value => "huga"},
]; # hash reference of single data record or array reference of hash references of multiple data records
my $startindex = 12; # first index of the data record (can omit if you don't want index numbers)
my $fh; # file handle (can omit)
my $fhflag = 1; # if true, file handle will not be closed (can omit)
If you give a file handle to the argument, file that defined by constructor is omitted and this method uses given file handle and adds data from the place current file pointer points not from the head of file.
Return value:
Succeed > first: 1 , second: (if $fhflag
is true) file handle
Fail > first: false (return;)
write_data()
This method writes data records to the data file. Before writing data, the contents of the data file will be erased.
$cc->write_data($datalist,$fh,$fhflag,$noempty);
my $datalist = [
{title => "hoge",value => "huga"},
{title => "hoge2",value => "huga"},
{title => "hoge3",value => "huga"},
]; # array reference of hash references of multiple data records
my $fh; # file handle (can omit)
my $fhflag = 1; # if true, file handle will not be closed (can omit)
my $noempty = 1; # see below
If you give a file handle to the argument, file that defined by constructor is omitted and this method uses given file handle. If $noempty
is true, the contents of the data file will not be erased, and writes data from the place current file pointer points not from the head of file.
Return value:
Succeed > first: 1 , second: (if $fhflag
is true) file handle
Fail > first: false (return;)
read_data()
This method reads data records from the data file.
$cc->read_data($fh,$fhflag);
my $fh; # file handle (can omit)
my $fhflag = 1; # if true, file handle will not be closed (can omit)
If you give a file handle to the argument, file that defined by constructor is omitted and this method uses given file handle and reads data from the place current file pointer points not from the head of file.
Return value:
Succeed > first: data list (array reference of hash references) , second: (if $fhflag
is true) file handle
Fail > first: false (return;)
read_data_num()
This method reads data record's last index number from the data file.
$cc->read_data_num($fh,$fhflag);
my $fh; # file handle (can omit)
my $fhflag = 1; # if true, file handle will not be closed (can omit)
If you give a file handle to the argument, file that defined by constructor is omitted and this method uses given file handle and reads data from the place current file pointer points not from the head of file.
Return value:
Succeed > first: last index , second: (if $fhflag
is true) file handle
Fail > first: false (return;)
DEPENDENCIES
This module requires no other modules and libraries.
NOTES
This module is written in object-oriented style but treating data by naked array or file handle so you should treat data by procedural style.
For example, if you want to delete 3,6 and 8th element in data list completely, the following code will be required.
splice @$datalist,$_,1 for sort {$b <=> $a} qw(3 6 8);
So, if you want more smart OO, it will be better to use another modules that wraps naked array or file handle in OO (such as Object::Array ... etc?), or create Config::Column::OO etc. which inherits this module and can use methods pop, shift, splice, delete, etc.
TODO
Odd Engrish
AUTHOR
Narazaka (http://narazaka.net/)
COPYRIGHT AND LICENSE
Copyright 2011-2012 by Narazaka, all rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.