NAME
Text::NumericData::App - tools for applications using Text::NumericData
SYNOPSYS
# usage of the application
my
$app
= SomeApp->new();
# arguments optional, defaults shown
exit
$app
->run(\
@ARGV
, \
*STDIN
, \
*STDOUT
);
# The application itself.
package
SomeApp;
use
Text::NumericData;
our
@ISA
= (
'Text::NumericData::App'
);
sub
new
{
my
$class
=
shift
;
# All settings optional.
%setup
=
(
parconf
=>{
info
=>
'a program that sets the second column to a given value'
}
,
pardef
=>[
'value'
,42,
''
,
'value to set second column to'
]
# Optionally bar some parameters of Text::NumericData from command line.
,
exclude_pars
=>[
'strict'
]
);
return
$class
->SUPER::new(\
%setup
);
}
sub
main
{
my
$self
=
shift
;
# Conveniently use common parameter hash.
# Could use something custom, though.
my
$txd
= Text::NumericData->new(
$self
->{param});
my
$data
= 0;
while
(
my
$line
= <
$self
->{in}>)
{
unless
(
$data
)
{
# Separate header and data.
if
(
$txd
->line_check(
$line
)){
$data
= 1; }
else
{
{
$self
->{out}}
$line
; }
}
if
(
$data
)
{
my
$d
=
$txd
->line_data(
$_
);
$d
->[1] =
$self
->{param}{value};
{
$self
->{out}} ${
$txd
->data_line(
$d
)};
}
}
return
0;
}
Pipe processing mode
package
SomeApp;
use
Text::NumericData;
our
@ISA
= (
'Text::NumericData::App'
);
sub
new
{
my
$class
=
shift
;
# All settings optional.
%setup
=
(
parconf
=>{
info
=>
'a program that sets the second column to a given value'
}
,
pardef
=>[
'value'
,42,
''
,
'value to set second column to'
]
# Activate pipe mode via Text::ASCIIPipe.
# See documentation about meaning of handler functions.
,
pipemode
=>1
# Handlers optional, but when you specify none,
# nothing happens.
# $self handle is implicit --- please hand in methods!
,
pipe_init
=> \
&init
# once before real action
# another option: work on raw line before parsing
# might return true value to skip further processing
#,pipe_preparse => \&check_line
,
pipe_begin
=> \
&begin
# new file
,
pipe_header
=> \
&process_header
,
pipe_first_data
=> \
&process_first_data
,
pipe_data
=> \
&process_data
# override generic handler that would call the three above
#,pipe_line => \&process_line
,
pipe_end
=> \
&end
# file end
,
pipe_allend
=> \
&allend
# total end
);
return
$class
->SUPER::new(\
%setup
);
}
# This shall return non-zero on error.
# Other handlers are doomed to be successful.
sub
init
{
my
$self
=
shift
;
$self
->{some_state} = 17;
return
0;
}
sub
begin
{
my
$self
=
shift
;
# Create fresh Text::NumericData handle.
$self
->new_txd();
# This would happen by default, too.
}
sub
process_header
{
my
$self
=
shift
;
# Do something with $self->{txd} or $_[0] ...
}
sub
process_first_data
{
my
$s
=
"# This will be inserted before first data line.\n"
;
return
\
$s
;
}
sub
process_data
{
my
$self
=
shift
;
my
$d
=
$txd
->line_data(
$_
[0]);
$d
->[1] =
$self
->{param}{value};
$_
[0] = ${
$txd
->data_line(
$d
)};
}
sub
end
{
# nothing of interest, could give some report
}
sub
allend
{
# see above
}
File-based pipe processing
package
SomeApp;
use
Text::NumericData;
our
@ISA
= (
'Text::NumericData::App'
);
sub
new
{
my
$class
=
shift
;
# All settings optional.
%setup
=
(
parconf
=>{
info
=>
'a program that sets the second column to a given value'
}
,
pardef
=>[
'value'
,42,
''
,
'value to set second column to'
]
# operate on whole file at a time
,
filemode
=>1
# Note that pipe mode does not add that much functionality,
# the piped reading is built into the Text::NumericData::File class
# already. There's only a basic loop checking special return values.
,
pipemode
=>1
,
pipe_init
=> \
&init
,
pipe_file
=> \
&process_file
,
pipe_allend
=> \
&allend
);
return
$class
->SUPER::new(\
%setup
);
}
# This shall return non-zero on error.
# Other handlers are doomed to be successful.
sub
init
{
my
$self
=
shift
;
$self
->{some_state} = 17;
return
0;
}
# This is supposed to return nozero error if program should abort.
sub
process_file
{
my
$self
=
shift
;
# Do something with $self->{txd}, which has the current file read in.
return
0;
# all fine
}
sub
allend
{
# Whatever you see fit to do here.
}
DESCRIPTION
This is wholly intended for building the standard txd* tools, but might be useful for you, too. It glues together Text::NumericData and Config::Param to quickly deploy a command line program that offers a standard parameter set. The setting of pipemode triggers the Text::ASCIIPipe processing pattern.
It merges your parameter definitions with the ones from Text::NumericData, parses command line using Config::Param, and also ensures binary mode for input/output (as Text::NumericData tries to treat line ends explicitly).
Line-based mode
This creates an instance of Text::NumericData as $self->{txd} and is intended to process files line-by-line.
File-based mode
This creates an instance of Text::NumericData::File as $self->{txd} and is intended to read files into $self->{txd} before processing as a whole.
MEMBERS
This base class defines some members that you should know about
- run
-
This is the method that actually runs the program which is fleshed out in a subclass from Text::NumericData::App. It takes 3 optional arguments: ref to command line argument array (defaults to \@ARGV), ref to input (defaults to \*STDIN), ref to output (defaults to \*STDOUT). Those are stored in $self->{argv}, $self->{in} and $self->{out}, respectively.
- param
-
Paramater hash from Config::Param, defining the parameter space for your program including Text::NumericData.
- txd
-
An instance of either Text::NumericData or Text::NumericData::Lines (depending on filemode setting). The default pipemode file-begin handler refreshes this one.
- new_txd
-
The refresh method: Replace $self->{txd} by a new instance. The default pipe_begin callback calls this to give you something to work with. It's also called before running main() when not in pipemode.
- argv, in, out
-
The places where run method stores the currently active argument array and input/output handles.
- setup
-
Well, actually, you defined that: This is the configuration hash handed to the constructor, extended a bit by this (additional setup of Config::Param, for example).
- state
-
A general-purpose hash with some state information. Of interest might be $self->{state}{data}, which indicates if we hit the data section of the file. But if you need to handle that explicitly, you'll manage your own state.
- default_line_hook
-
Method that runs when you do not override pipe_line.
- error
-
Simple wrapper to print out a message and return a given value or -1 per default. This is to cut down such code in main or init methods:
if
(
$some_bad_thing
)
{
print
STDERR
"Some error occured!\n"
;
return
$bad_return_value
;
}
to
return
$self
->error(
"Some error occured"
,
$bad_return_value
)
if
$some_bad_thing
;
So it doesn't do much yet. It might carry an error count and do something with it.