How can I prettify Perl code generated by Perl? - perl

I have a test generator written in Perl. It generates tests that connect to a simulator. These tests are themselves written in Perl and connect to the simulator via its API. I would like the generated code to be human-readable, which means I'd like it to be properly indented and formatted. Is there a good way to do it?
Details follow, or you can skip to the actual question below.
This is an example:
my $basic = ABC
TRIGGER => DELAY(
NUM => 500,
),
)
BASIC
my $additional = STATE_IS(
STATE => DEF,
INDEX => 0,
),
ADDITIONAL
I'd like the command ABC to be executed with a delay of 500 (units aren't relevant just now) after I call &event, and the state of index 0 is DEF. Sometimes I'll also want to wait for indeces 1, 2, 3 etc...
For only one index I'd like to see this in my test:
&event(
CMD => ABC
TRIGGER => DELAY(
NUM => 500,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
),
),
)
For two indeces I'd like to see:
&event(
CMD => ABC
TRIGGER => DELAY(
NUM => 500,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 1,
),
),
),
)
So basically I'm adding a block of:
TRIGGER => STATE_IS(
STATE => DEF,
INDEX => 0,
),
for each index, and the index number changes.
Here's how I'm doing it:
for $i (0..$num_indeces) {
# update the index number
$additional =~ s/(INDEX\s*=>\s*)\d+,/$1 $i,/;
$basic =~ s/(
(\),\s*) # capture sequences of ),
+ # as many as possible
\)\s* # end with ) without a ,
} )/$additional $1/sx; # replace with the additional data
Here's the actual question
The problem here is that the code comes out poorly indented. I'd like to run the resulting $basic through a prettifier like this:
&prettify($basic, "perl");
Which would format it nicely according to Perl's best practices. Is there any good way to do this?

PerlTidy makes your code not only tidy, but really beautiful. You can easily tweak it according to your local coding standards.

I have used this:
use Perl::Tidy;
sub Format {
my $source = shift;
my $result;
Perl::Tidy::perltidy(
source => \$source,
destination => \$result,
argv => [qw(-pbp -nst)]
);
return $result;
}

Related

Perl RRD::Simple no display data

I am new in Perl and also RRDs.
I have tried to implement a simple example, and although it seems that is operating correctly the output is not displayed. The pictures are produced normally but there is no data in the graphs.
I have been following the CPAN documentation for implementation RRD::Simple and theoretically I am doing something wrong. I tried to debug the code and it seems fine, but when it comes to print the graphs there is no data.
#!/usr/bin/perl
use strict;
use warnings;
use RRD::Simple ();
use Data::Dumper;
$| = 1; # Flush the output
my ($rrd, $unixtime, $file);
$file = "perl.txt";
my $path = '/home/os/Desktop/Test_Perl/';
my $period = '3years';
my $rrdfile = 'myfile.rrd';
while (sleep 15) {
open(FH, ">>", $file) || die "Unable to open $file: $!\n";
my $range = 50;
my $minimum = 100;
my $random_number_in = int(rand($range)) + $minimum;
my $random_number_out = int(rand($range)) + $minimum;
my $random_number_sec = int(rand($range)) + $minimum;
# Create an interface object
$rrd = RRD::Simple->new(
file => $rrdfile,
cf => [qw( AVERAGE MIN MAX LAST )],
#default_dstype => "DERIVE",
);
unless (-e $rrdfile) {
# Create a new RRD file with 3 data sources called
# bytesIn, bytesOut and faultsPerSec.
$rrd->create(
$period,
step => 5, # 5 sec interval
bytesIn => "GAUGE",
bytesOut => "GAUGE",
faultsPerSec => "GAUGE"
);
}
# Put some arbitary data values in the RRD file for the same
# 3 data sources called bytesIn, bytesOut and faultsPerSec.
$rrd->update(
bytesIn => $random_number_in,
bytesOut => $random_number_out,
faultsPerSec => $random_number_sec
);
print FH "This is the bytes_in: $random_number_in\n";
print FH "This is the bytes_out: $random_number_out\n";
print FH "This is the bytes_sec: $random_number_sec\n";
# Generate graphs:
# /home/os/Desktop/Test_Perl/myfile-hourly.png, /home/os/Desktop/Test_Perl/myfile-daily.png
# /home/os/Desktop/Test_Perl/myfile-weekly.png, /home/os/Desktop/Test_Perl/myfile-monthly.png
my %rtn = $rrd->graph(
$rrdfile,
destination => $path,
basename => "my_graph",
timestamp => "both", # graph, rrd, both or none
periods => [qw(hour day week month)], # omit to generate all graphs
sources => [qw(bytesIn bytesOut faultsPerSec)],
source_colors => [qw(ff0000 aa3333 000000)],
source_labels => [("Bytes In", "Bytes Out", "Faults Per Second")],
source_drawtypes => [qw(LINE1 AREA LINE)],
line_thickness => 2,
extended_legend => 1,
title => "Network Interface eth0",
vertical_label => "Bytes/Faults",
width => 800,
height => 500,
interlaced => "", # If images are interlaced they become visible to browsers more quickly
);
printf("Created %s\n", join(", ", map { $rtn{$_}->[0] } keys %rtn));
# Return information about an RRD file
my $info = $rrd->info($rrdfile); # This method will return a complex data structure containing details about the RRD file, including RRA and data source information.
print Data::Dumper::Dumper($info);
my #sources = $rrd->sources($rrdfile);
my $seconds = $rrd->retention_period($rrdfile); # This method will return the maximum period of time (in seconds) that the RRD file will store data for.
# Get unixtime of when RRD file was last updated
$unixtime = $rrd->last($rrdfile);
print FH "myfile.rrd was last updated at " . scalar(localtime($unixtime)) . "\n";
# Get list of data source names from an RRD file
my #dsnames = $rrd->sources;
print "Available data sources: " . join(", ", #dsnames) . "\n";
my $heartbeat_In = $rrd->heartbeat($rrdfile, "bytesIn");
my $heartbeat_Out = $rrd->heartbeat($rrdfile, "bytesOut");
my $heartbeat_sec = $rrd->heartbeat($rrdfile, "faultsPerSec"); # This method will return the current heartbeat of a data source.
printf "This is the heartbeat_in: %s\n", $heartbeat_In;
my #rtn_In = $rrd->heartbeat($rrdfile, "bytesIn", 10);
my #rtn_Out = $rrd->heartbeat($rrdfile, "bytesOut", 10);
my #rtn_sec = $rrd->heartbeat($rrdfile, "faultsPerSec", 10); # This method will set a new heartbeat of a data source.
close(FH);
}
Part of the output:
'myfilerrd' => {
'last_ds' => 'U',
'value' => undef,
'min' => '0',
'max' => undef,
'minimal_heartbeat' => 120,
'index' => 3,
'type' => 'DERIVE',
'unknown_sec' => 15
}
I do not understand why the value is undefined?
After 3-4 days of testing and searching over the Internet for more information I just found the answer to my problem. RRD is a very simple to use tool but very very powerful. I would recommend anybody to use it through Perl especially with RRD::Simple module is very easy.
Answer:
I was adjusting the heart beat of my RRD to 10 sec, while my step (data collection time) is 300 by default. If the user do not specify the step "sampling frequency" by default the system will use 300. In result the graph takes 0 values so there is not output. More information and very nice analysis can be found here HeartBeat
Based on my experimentation, I found that since I am using a while loop inside the create function I have to first give the command:
my $rrd = RRD::Simple->new( file => "myfile.rrd" );
and as a second step I had to kill the process and set the step by entering the command:
my $rrd = RRD::Simple->new(
file => "myfile.rrd",
step => 50 );
Based on my experimentation I found that I had to remove this block of code below had to be added to the file as a second step. First had to make the creation and then add it on my loop. This is because initially the "myfile.rrd" has to be created with all the settings, before the user start modifying them.
unless (-f "myfile.rrd") {
$rrd->create(
step => 50,
bytesIn => "GAUGE",
bytesOut => "GAUGE",
faultsPerSec => "COUNTER"
);
}
Another point that worth mentioning here is that by default RRD Data Source (DS) is set to GAUGE. More information can be found here RRDtool
The Perl module can be found easily CPAN RRD::Simple which provides analysis and extra "features" that you can add to your code.
In conclusion RRD::Simple is very simple, it can be executed by copy-paste into your program. Any further modifications (e.g sample rates, Average/Max/Min values etc.) need a bit of reading upon but definitely worth the effort. Unfortunately there is not much of examples online so some testing need it to be done in order to understand what I need to modify in my code to make it work. By writing this short analysis and providing some links to read upon I hope to save someone else from spending a few days to come up with the answer to his problem.
Again I encourage anyone to try implementing RRD's is a very powerful tool to graphically view your results and store the data up to 3 years.
Another update that I think is useful to some people maybe. Instead of following all this process by adding and removing code in order to make the rrd file working.
After modifications and experimentation I found another solution.
use strict;
use RRD::Simple;
use RRDs;
my $rrd = RRD::Simple->new(
file => "myfile.rrd",
rrdtool => "/usr/local/rrdtool-1.2.11/bin/rrdtool", #optional
tmpdir => "/var/tmp", #optional
cf => [ qw(AVERAGE MAX) ], #optional
default_dstype => "COUNTER", #optional
on_missing_ds => "add", #optional
RRDs::tune("myfile.rrd", "-i", "Source_Name:0") #optional -i or --minimum
RRDs::tune("myfile.rrd", "-a", "Source_Name:200") #optional -a or --maximum
);
There are several optional values that someone can use, but I recommend to use all of them so you can take full control of the program.
I am using:
default_dstype => "COUNTER", #optional
Because by default RRD's will set GAUGE as Data Source (DS). By setting the DS to COUNTER the user can set the minimum and maximum values. Short examples can be found here also RRD::Simple::Examples.

Perl/Curses event handling and I/O

So, I just started trying to use the perl curses module for a project I'm working on. The documentation seems to be extremely lacking, what little I can find on cpan seems to be half-finished and assumes previous curses library experience, which I don't have. I have two issues I am trying to solve, my code so far:
#!/usr/bin/perl
use strict;
use Curses::UI;
use Term::ReadKey;
my ($cols, $rows, $wp, $hp) = GetTerminalSize();
my $cui = new Curses::UI( -color_support => 1);
sub eDialog {
my $return = $cui->dialog(
-message => "Are you sure?",
-title => "Really quit?",
-buttons => ['yes', 'no']
);
exit(0) if $return;
}
sub entryUpdate {
my $mainentry = shift;
if($mainEntry->get() =~ m/.*\n$/)
{
print STDERR $mainEntry->get();
}
}
$cui->set_binding( \&eDialog , "\cQ");
my $mainWin = $cui->add(
'viewWin', 'Window',
-border => 1,
-height => ($rows - 3),
-bfg => 'green'
);
my $mainView = $mainWin->add(
"viewWid", "TextViewer",
-wrapping => 1
);
my $entryWin = $cui->add(
'entryWin', 'Window',
-border => 1,
-y => ($rows - 3),
-height => 1,
-bfg => 1
);
my $mainEntry = $entryWin->add(
"entryWid", "TextEntry",
-onchange => \&entryUpdate()
);
$mainEntry->focus();
$cui->mainloop();
I managed to get the UI set up how I want it, but actually making it work is proving problematic.
1). I want to be able to, when text is typed into the $mainEntry widget, detect when enter/return is pressed, and execute a subroutine to do stuff with the text typed into the widget, then clear it out. (I tried accomplishing this with the entryUpdate subroutine, but that isn't working at all, no matter how I've tried to do it.)
2). I want to be able to periodically (Say, every 1 second or 500ms), execute another subroutine, and have the string it returns added to the $mainView widget.
Getting either or both of these to work has proven to be a huge issue thus far, I just dont know enough about how curses works and I haven't been able to find the information I need anywhere. Any help would be much appreciated.
1) You can simply bind the return key to a subrouting using set_binding:
use Curses qw(KEY_ENTER);
$mainEntry->set_binding(sub {
$mainView->text($mainView->text . $mainEntry->get . "\n");
$mainView->draw;
$mainEntry->text("");
}, KEY_ENTER);
2) It seems that there are timer methods (found them by grepping the Curses-UI source code), but they are not documented, which is probably an issue. Here's how it's used:
$cui->set_timer('timer_name', sub {
$mainView->text($mainView->text . scalar(localtime)."\n");
$mainView->draw;
}, 1);

HTML::TableExtract with a table inside of a table

I have a small script that I am using to manipulate the code from a remote URL (code is separate). The manual page for HTML::TableExtract has the following code section relating to doing a table-in-a-table extract, ie
$te = new HTML::TableExtract
(
headers => [qw(Summary Region)],
chain => [
{ depth => 0, count => 2 },
{ headers => [qw(Part Qty Cost)] }
],
);
My code contains this, ie:
use HTML::TableExtract;
use strict;
use warnings;
my $te = new HTML::TableExtract
(
headers => [qw(Incident Date Time Location Description)],
chain => [
{ depth => 0, count => 2 },
{ headers => [qw(Unit DIS ENR ONS LEF ARR BUS REM COM)] }
],
);
$te->parse_file('data.html');
However, running it gives me this:
Can't locate object method "chain" via package "HTML::TableExtract" at /usr/lib/perl5/HTML/Parser.pm line 80.
Is there something I'm missing? (If anyone has a better way to extract a table from within a table (while printing information from both I'm all ears)
I didn't see any document about chain method in the doc of HTML::TableExtract. Maybe you're using an expired version?
But according to the doc, you could do this using the depth and count attributes:
$te = HTML::TableExtract->new(
headers => [qw(Unit DIS ENR ONS LEF ARR BUS REM COM)],
depth => 1,
count => 1
);
$te->parse($html_string);
depth: Specify how embedded in other tables your tables of interest
should be. Top-level tables in the HTML document have a depth of 0,
tables within top-level tables have a depth of 1, and so on.
count: Specify which table within each depth you are interested in,
beginning with 0.
In your case depth and count should be both 1.

represent allowed status transitions graph in Perl

There is something like status changes check logic in our app.
Currently checking is being handled by ugly if statement
I want to replace it by transition matrix:
my %allowed_status_changes = (
1 => (2,5),
2 => (1,2,3,4,5),
3 => (4,2),
4 => (3,2),
5 => (),
);
my $is_allowed_transition =
$submitted_status ~~ $allowed_status_changes {$original_status};
if ($prerequestsites && !$is_allowed_transition) {
return;
}
certain transitions can be allowed only on additional condition, therefore I will need something like
2 => (
(target => 1)
(target => 2, condition => $some_condition)
(target => (3,4), condition => $other_condition),
(target => 5)
),
(in my opinion it is too long)
What structure would you use in this situation if you should focus on readability and maintainability?
How you will parse it to check if transition is allowed?
If the conditions are very prevalent (e.g. almost every allowed transition has them) then your latter structure is perfectly fine, other than your syntax error of representing a hashref with "()" instead of "{}".
If the conditions are rare, I'd suggest going with #1, augmented by optional constructs similar to your #2.
Please note that readability of checking code is IMHO very clear though voluminous and not very idiomatic.
OTOH, maintainability of the matrix is high - you have terse yet readable syntax from #1 where no conditions are needed and a clear though longer syntax for conditions which is flexible enough for many conditions per many settings like your #2.
my %allowed_status_changes = (
1 => [2,5],
2 => [1,5,{targets=>[2], conditions=>[$some_condition]}
,{targets=>[3,4], conditions=>[$other_condition, $more_cond]}]
3 => [4,2],
4 => [3,2],
5 => [],
);
sub is_allowed_transition {
my ($submitted_status, $original_status ) = #_;
foreach my $alowed_status (#$allowed_status_changes{$original_status}) {
return 1 if !ref $alowed_status && $alowed_status == $submitted_status;
if (ref $alowed_status) {
foreach my $target (#$alowed_status{targets}) {
foreach my $condition (#$alowed_status{conditions}) {
return 1 if check_condition($submitted_status
, $original_status, $condition);
}
}
}
}
return 0;
}
if ($prerequestsites
&& !$is_allowed_transition($submitted_status, $original_status )) {
return;
}
Although I agree with DVK for the most part, I have to say, once you start delving into arrays of arrays of hashes, you're reaching a code complexity level that is hard to maintain without much spinning of heads and bugs.
At this point, I'd probably reach for an object and a class, for a bit of syntactic sugar.
my $transitions = TransitionGraph->new();
$transition->add( 1, { targets => [ 2, 5 ] });
$transition->add( 2, { targets => [ 1, 5 ] });
$transition->add( 2, { targets => [ 2 ], conditions => [ $some_condition ] });
$transition->add( 2, { targets => [ 3, 4 ], conditions => [ $other_condition, $more_cond ]});
$transition->add( 3, { targets => [4,2] } );
$transition->add( 4, { targets => [3,2] } );
$transition->add( 5, { targets => [] } );
if( $transition->allowed( 1 , 3 )){
}
Class implementation is up to the user, but I'd use Moose.
The primary benefits of this is you're encapsulating how the state graph works so you can Just Use it and worry about how the graph works seperate from where its used.
nb. in the above proposed API, add() creates a new record if one does not exist, and updates that record if it does exist. This turned out to be simpler than having "upgrade" methods or "get this item and then modify it" techniques.
Internally, it could do this, or something like it:
sub add {
my ( $self , $input_state, $rules ) = #_;
my $state;
if ( $self->has_state( $input_state ) ) {
$state = $self->get_state( $input_state );
} else {
$state = TransitionGraphState->new( source_id => $input_state );
$self->add_state( $input_state, $state );
}
my $targets = delete $rules{targets};
for my $target ( #$targets ) {
$state->add_target( $target, $rules );
}
return $self;
}
sub allowed {
my ( $self, $from, $to ) = #_;
if ( not $self->has_state( $from ) ){
croak "NO source state $from in transition graph";
}
my $state = $self->get_state( $from );
return $state->allowed_to( $to );
}
This also has the cool perk of not requiring one particular code set to work on the sub-nodes, you can create seperate instances with their own behaviour just in case you want one source state to be treated differently.
$transition->add_state( 2, $some_other_class_wich_works_like_transitiongraphstate );
Hope this is helpful =).
There is nothing wrong with the second form. You are not going to be able to get around the fact that you must encode the state machine somewhere. In fact, I think having the entire machine encoded in one place like that is far easier to understand that something with too many layers of abstraction where you need to look in n different places to understand the flow of the machine.

How can I use Perl and RRD to plot ping times?

I'm trying to do my first rrd graph through Perl.
I have tried RRD::Simple and rrds and just can't get either one to work.
Here's what I have so far:
use strict;
use RRD::Simple ();
# Create an interface object
my $rrd = RRD::Simple->new( file => "server.rrd" );
# Put some arbitary data values in the RRD file for the same
# 3 data sources called bytesIn, bytesOut and faultsPerSec.
$rrd->create(
EqSearch => "DERIVE",
MfSearch => "DERIVE",
EQCostBasis => "DERIVE",
MFCostBasis => "DERIVE"
);
$rrd->update(
EqSearch => 2,
MfSearch => 3,
EQCostBasis => 10,
MFCostBasis => 15
);
# Generate graphs:
# /var/tmp/myfile-daily.png, /var/tmp/myfile-weekly.png
# /var/tmp/myfile-monthly.png, /var/tmp/myfile-annual.png
my %rtn = $rrd->graph(
destination => "/Users/cmuench/Documents/Code/perl",
title => "Server A",
vertical_label => "",
interlaced => "",
periods => [qw(hour)]
);
The output is:
graph http://www.mediafire.com/imgbnc.php/a39e2bd662adefa823dca66351db637c5g.jpg
From your above script, the main issue is that you don't have enough data to show in graphs. you can see the data in your rrd using 'rrdtool fetch`.
If you can use bash instead of perl. Look at this "Round Trip and Packet Loss stats with rrdtool"
If you still want to use perl module RRD::Simple, please look at the examples provided with this module i.e. RRD::Simple::Examples Or provide more details about the problem you are facing.