Showing posts with label advanced perl. Show all posts
Showing posts with label advanced perl. Show all posts

Jul 10, 2013

Perl Config File

We can make use of Config::Simple module for this.
This library supports parsing, updating and creating configuration files.

Main Features of Config::Simple are as mentioned below:
1) It allows to read config file in different formats/styles like INI-FILE format and HTML format.
2) It allows to read config file in the form of objects and access the variables from the object.
3) It allows to fetch all the variables at into a hash/hashref using "vars" method.

Let's discuss how can we read/modify/write config files easily in perl as mentioned below :
Reading config file in INI-FILE (ini) style
Reading config file in HTTP-LIKE style
Creating config file in INI style

1) Reading/Updating config file in INI-FILE (ini) style

If the configuration file has different blocks, then this style is very useful
Let's explain with the below mentioned example

db_ini.cfg

[mysql]
host=DBI:mysql:host
login=mysql_user
password=mysql_pass
db_name=test
RaiseError=1
PrintError=1

[oracle]
host=DBI:oracle:host
login=oracle_user
password=oracle_pass
db_name=oracle_db
RaiseError=1
PrintError=1
  

Script
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Config::Simple;

my $cfg = new Config::Simple('db_ini.cfg');

#Get Values from Config File
print "\n MySql DB Name     : " . $cfg->param("mysql.db_name");
print "\n MySql DB Password : " . $cfg->param("mysql.password");

print "\n\n Oracle DB Name     : " . $cfg->param("oracle.db_name");
print "\n Oracle DB Password : " . $cfg->param("oracle.password");
 
#Set/Update Values Config File
$cfg->param("mysql.db_name", "new_mysql_db_name");
$cfg->param("mysql.password", "new_mysql_password");

print "\n\n MySql DB Name     : " . $cfg->param("mysql.db_name");
print "\n MySql DB Password : " . $cfg->param("mysql.password");

$cfg->param("oracle.db_name", "new_orcl_db_name");
$cfg->param("oracle.password", "new_orcl_password");

print "\n\n Oracle DB Name     : " . $cfg->param("oracle.db_name");
print "\n Oracle DB Password : " . $cfg->param("oracle.password");

#Adding a new Variable to Config File
$cfg->param("mysql.new_var", "mysql_adding_variable");

print "\n\n MySql New Var     : " . $cfg->param("mysql.new_var");

$cfg->param("oracle.new_var", "oracle_adding_variable");

print "\n\n Oracle New Var     : " . $cfg->param("oracle.new_var");

print "\n\n Deleting Mysql New Var 'new_var' ... ";
$cfg->delete('mysql.new_var'); # deletes 'new_var' from [mysql] block

print "\n\n Deleting Oracle New Var 'new_var' ... ";
$cfg->delete('oracle.new_var'); # deletes 'new_var' from [oracle] block

#Config Vars
#Config::Simple also supports vars() method, which, depending on the context used, returns all the values either as hash or hashref
my %Config = $cfg->vars();
print "\n\n Config Hash Obj : " . Dumper(\%Config);

my $config_ref = $cfg->vars();
print "\n\n Config Hash Ref : " . Dumper($config_ref);
  

db_ini.cfg Output
 MySql DB Name     : test
 MySql DB Password : mysql_pass

 Oracle DB Name     : oracle_db
 Oracle DB Password : oracle_pass

 MySql DB Name     : new_mysql_db_name
 MySql DB Password : new_mysql_password

 Oracle DB Name     : new_orcl_db_name
 Oracle DB Password : new_orcl_password

 MySql New Var     : mysql_adding_variable

 Oracle New Var     : oracle_adding_variable

 Deleting Mysql New Var 'new_var' ... 
 
 Deleting Oracle New Var 'new_var' ... 
 
 Config Hash Obj : $VAR1 = {
          'mysql.PrintError' => '1',
          'mysql.db_name' => 'new_mysql_db_name',
          'oracle.password' => 'new_orcl_password',
          'oracle.host' => 'DBI:oracle:host',
          'mysql.host' => 'DBI:mysql:host',
          'mysql.password' => 'new_mysql_password',
          'oracle.PrintError' => '1',
          'oracle.login' => 'oracle_user',
          'mysql.RaiseError' => '1',
          'oracle.db_name' => 'new_orcl_db_name',
          'oracle.RaiseError' => '1',
          'mysql.login' => 'mysql_user'
        };


 Config Hash Ref : $VAR1 = {
          'mysql.PrintError' => '1',
          'oracle.password' => 'new_orcl_password',
          'mysql.db_name' => 'new_mysql_db_name',
          'oracle.host' => 'DBI:oracle:host',
          'mysql.host' => 'DBI:mysql:host',
          'oracle.PrintError' => '1',
          'mysql.password' => 'new_mysql_password',
          'oracle.login' => 'oracle_user',
          'mysql.RaiseError' => '1',
          'oracle.db_name' => 'new_orcl_db_name',
          'oracle.RaiseError' => '1',
          'mysql.login' => 'mysql_user'
        };
  


2) Reading/Updating config file in HTTP-LIKE style

When we just key and value pairs, this simple HTTP-Like style works.
Let's explain with the below mentioned example

db_http.cfg
host:'DBI:mysql:host'
login:user
password:secret
db_name:test
RaiseError:1
PrintError:1
  

Script
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Config::Simple;

my $cfg = new Config::Simple('db_http.cfg');

#Get Values from Config File
print "\n DB Name     : " . $cfg->param("db_name");
print "\n DB Password : " . $cfg->param("password");
 
#Set/Update Values Config File
$cfg->param("db_name", "new_db_name");
$cfg->param("password", "new_password");

print "\n\n DB Name     : " . $cfg->param("db_name");
print "\n DB Password : " . $cfg->param("password");

#Adding a new Variable to Config File
$cfg->param("new_var", "adding_variable");

print "\n\n New Var     : " . $cfg->param("new_var");

print "\n\n Deleting New Var 'new_var' ... ";
$cfg->delete('new_var'); # deletes 'new_var'

#Config Vars
#Config::Simple also supports vars() method, which, depending on the context used, returns all the values either as hash or hashref
my %Config = $cfg->vars();
print "\n\n Config Hash Obj : " . Dumper(\%Config);

my $config_ref = $cfg->vars();
print "\n\n Config Hash Ref : " . Dumper($config_ref);


db_http.cfg Output
 DB Name     : test
 DB Password : secret

 DB Name     : new_db_name
 DB Password : new_password

 New Var     : adding_variable

 Deleting New Var 'new_var' ... 
 
 Config Hash Obj : $VAR1 = {
          'db_name' => 'new_db_name',
          'password' => 'new_password',
          'RaiseError' => '1',
          'PrintError' => '1',
          'login' => 'user',
          'host' => 'DBI:mysql:host'
        };

 Config Hash Ref : $VAR1 = {
          'db_name' => 'new_db_name',
          'password' => 'new_password',
          'RaiseError' => '1',
          'host' => 'DBI:mysql:host',
          'login' => 'user',
          'PrintError' => '1'
        };
  


3) Creating config file in INI style

Creating a config file is explained as mentioned below.

$cfg = new Config::Simple(syntax=>'ini');
$cfg->write("test.cfg");

Supported "syntax" keywords are "ini", "simple" or "http"

write()
Alternatively, you can pass a name to either write() or save() to indicate the name of the file to create instead of modifying existing configuration file

Since we are trying to create a new config file, we need to pass the file name.

Script

$cfg = new Config::Simple(syntax=>'ini');

$cfg->param("mysql.dsn", "DBI:mysql:db;host=localhost.com");
$cfg->param("mysql.user", "username");
$cfg->param("mysql.pass", 'secret');
$cfg->write("test.cfg");
  

test.cfg Output
[mysql]
dsn:mysql:db;host=localhost.com
user:username
pass:secret
  


Jul 8, 2013

Unit Testing in Perl

We can write test scripts in Perl using Test::Simple and Test::More in easy way.

Test::More is an yet another framework for writing test scripts

Lets explain Test::More module with examples.

ok() vs is() 

1) Similar to ok(), is() and isnt() compare their two arguments with eq and ne respectively and use the result of that to determine if the test succeeded or failed. 

is($hsh{a}, 200, 'Test 200');
isnt($hsh{a}, 200, 'Test 200');

are similar to these:

ok($hsh{a} eq 200, 'Test 200');
ok($hsh{a} ne 200, 'Test 200');

2) They produce better diagnostics on failure. 
ok() cannot know what you are testing for (beyond the name)
but 
is() and isnt() know what the test was and why it failed. 

In case of test fail, ok() shows fail like below :
ok($hsh{a} == 200, 'Test 200');
# not ok 5 - Fail
#   Failed test 'Fail'
#   at main.pl line 21.

In case of test fail, is() or isnt() shows fail like below :
is($hsh{a}, 200, 'Test 200');
# not ok 5 - Fail
#   Failed test 'Fail'
#   at main.pl line 20.
#          got: '100'
#     expected: '200'

like()
like() allows to use regular exporessions in writing test cases
The following example, we are trying to check $str contains string 'freedom' or not

like($str, qr/freedom/i, 'String contains Freedom - ignore case');
ok($str =~ /freedom/i, 'String contains Freedom - ignore case');


cmp_ok()
cmp_ok() also useful in those cases where you are giving explicit conditions like >=, <=, ==, != etc.,

cmp_ok($scalar, "<=", 200, '10 is less than or equal to 200 - pass');
cmp_ok($scalar, "==", 10, '10 is equal to 10 - pass');

can_ok()

Syntax:
can_ok($module, @methods);
can_ok($object, @methods);

can_ok checks if a mthod exists in an object, here $obj is the object of "support" class
can_ok also checks if a method exists in an class, here "support" is the class
can_ok is good at taking mutiples methods to test at one shot

E.g.,
can_ok($obj, "add");
can_ok("support", "multiply");
can_ok("support", qw(test add multiply));

Lets explain the above methods with an example :
In the following example, we use support.pm for testing object, class and methods

support.pm
#!/usr/bin/perl

package support;

use strict;
use warnings;
use Data::Dumper;

sub new {
    my($class) = shift;
        
    my($self) = {};

    return(bless($self, $class));
}


sub multiply {
  my $a = shift;
  my $b = shift;
 
  return ($a*$b);
}  

sub add {
  my $a = shift;
  my $b = shift;
 
  return ($a+$b);
}  

sub test {
    print "\n test mehthod inside support package"; 
}  

1;  

main.pl
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Test::More tests=>20;
use support;

my $obj = new support;

#You usually want to test if the module you're testing loads ok, rather than just vomiting if its load fails. It's recommended that you run use_ok() inside a BEGIN block so its functions are exported at compile-time and prototypes are properly honored.
BEGIN { use_ok("CGI"); }

#print "\n Obj : " . Dumper($obj);


#Testing Packages and Objects -----------------------------------------------
#Testing an object belongs to a class or not
ok (defined($obj) && ref $obj eq 'support', 'support obj new worked');

#can_ok checks if a mthod exists in an object, here $obj is the object of "support" class
#can_ok also checks if a method exists in an class, here "support" is the class
#can_ok is good at taking mutiples methods to test at one shot
can_ok($obj, "add");
can_ok("support", "multiply");
can_ok("support", qw(test add multiply));


#isa_ok checks if an object belongs to a class or not
isa_ok($obj, 'support');


#Testing Values -----------------------------------------------
my $scalar = 10;
my %hsh    = (a=>100, b=>200, c=>300);
my $str    = 'Freedom lies in being bold';


#is() vs ok()
#is() is recommended over ok()
#ok() function doesn't provide good diagnostic output.
#ok() cannot know what you are testing for (beyond the name), but is() and isnt() know what the test was and why it failed.

ok($scalar == 10, 'Pass');
is($scalar, 10, 'Pass');

is($hsh{a}, 100, 'Pass');
ok($hsh{a} == 100, 'Pass');

#is($hsh{a}, 200, 'Fail');
# not ok 5 - Fail
#   Failed test 'Fail'
#   at main.pl line 20.
#          got: '100'
#     expected: '200'

#ok($hsh{a} == 200, 'Fail');
# not ok 5 - Fail
#   Failed test 'Fail'
#   at main.pl line 21.

isnt($scalar, 20, 'Pass');

#like() allows to use regular exporessions in writing test cases
like($str, qr/freedom/i, 'String contains Freedom - ignore case');
ok($str =~ /freedom/i, 'String contains Freedom - ignore case');

#It's also useful in those cases where you are comparing numbers and applying conditions
cmp_ok($scalar, "<=", 200, '10 is less than or equal to 200 - pass');
cmp_ok($scalar, "==", 10, '10 is equal to 10 - pass');


Output:

1..20
ok 1 - use CGI;
ok 2 - support obj new worked
ok 3 - support->can('add')
ok 4 - support->can('multiply')
ok 5 - support->can(...)
ok 6 - The object isa support
ok 7 - Pass
ok 8 - Pass
ok 9 - Pass
ok 10 - Pass
ok 11 - Pass
ok 12 - String contains Freedom - ignore case
ok 13 - String contains Freedom - ignore case
ok 14 - 10 is less than or equal to 200 - pass
ok 15 - 10 is equal to 10 - pass
# Looks like you planned 20 tests but ran 15.
  


Apr 27, 2013

Loop through Directory and read the files in Perl

Now, we discuss about how to loop through a directory and read all the files in Perl
I have a directory with name "humanists" which has different files as mentioned below :

humanists :
abraham_lincon.txt
alfred_nobel.txt
mahatma_gandhi.txt
mother_teresa.txt
winston_churchill.txt

All the files has details in the following format
Name: <>
Born: <>
Died: <>

Now we have to loop thorugh all the files in the directory and get the information from these files and create a hash object.

Lets dive into this example. Please drop me a comment if you have any doubts on the same.


read_humanists.pl
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $dir_path = "/home/prabhath/prabhath_test/test/humanists";

my %humanists_list;

opendir(IN_DIR, $dir_path) or die $!; 
open (LOG_FILE, "> read_humanists.log") or die $!; 

unless ( -d $dir_path) {
   print "\n Path not present: " . $dir_path;
} else {
   print "\n Path is present: " . $dir_path;
}


while (my $file = readdir(IN_DIR)) {
    next if $file =~ /^\./;
    
    unless (-f "$dir_path/$file") {
        print "\n -W- Not a File, Ignoring : " . "$dir_path/$file" . "\n";
        next;
    }   

    open(IN_FILE, "< $dir_path/$file")
                    ||  die "\n Cant open file for reading: " . "$dir_path/$file";

    my @lines = ;
    close(IN_FILE);

    my @newlines;
    foreach my $each_line (@lines) {
        if ($each_line =~ /^Name:/) {
           my ($name) = $each_line =~ /Name:\s(.*)$/;
           $humanists_list{$file}{"name"} = $name;
        }

        if ($each_line =~ /^Born:/) {
           my ($dob) = $each_line =~ /Born:\s(.*)$/;
           $humanists_list{$file}{"date_of_birth"} = $dob;
        }

        if ($each_line =~ /^Died:/) {
           my ($dod) = $each_line =~ /Died:\s(.*)$/;
           $humanists_list{$file}{"died"} = $dod;
        }
    }   
} 

Output:
          'abraham_lincon.txt' => {
                                    'died' => 'April 15, 1865',
                                    'date_of_birth' => 'February 12, 1809',
                                    'name' => 'Abraham Lincon'
                                  },
          'winston_churchill.txt' => {
                                       'died' => 'January 24, 1965',
                                       'date_of_birth' => 'November 30, 1874',
                                       'name' => 'Winston Churchill'
                                     },
          'alfred_nobel.txt' => {
                                  'died' => 'December 10, 1896',
                                  'date_of_birth' => 'October 21, 1833',
                                  'name' => 'Alfred Nobel'
                                },
          'mother_teresa.txt' => {
                                   'died' => 'September 5, 1997',
                                   'date_of_birth' => 'August 26, 1910',
                                   'name' => 'Mother Teresa'
                                 },
          'mahatma_gandhi.txt' => {
                                    'died' => 'January 30, 1948',
                                    'date_of_birth' => 'October 2, 1869',
                                    'name' => 'Mahatma Gandhi'
                                  }
  


Please refer to other topics on Unix like :
Unix Delete Duplicated Lines in a File
Unix Unique Lines in a File
Unix Grep Examples
Unix Cut Command Examples
Search a Directory in Unix
Unix For Loop
pushd & popd in Unix
Find Size of Directory
Word Count


Please refer to other topics on AWK like :
Awk Examples
Print First Two Columns of File
Print Last Two Columns of File


Please refer to other topics on Dict like :
Dict in Python
Dict keys and values in Python


Please refer to other topics on List like :
List in Python
Append to list in Python
Delete the last name from the list in Python
Remove an element from List in Python
Check an element exists in an list in Python
Python Filter Vs Map Vs List Comprehension


Please refer to other topics on File Concepts like :
Print File Content in Python
Print File in Reverse Order in Python


Please refer to Regular Expressions Concepts :
Brief on Regular Expressions
Greedy Operators in Regular Expressions in Perl
Modifiers in Regular Expressions in Perl
Capturing concept in Regular Expressions in Perl
Capture Pre Match ,Post Match, Exact match in Regular Expressions in Perl
Non Capturing Paranthesis in Regular Expressions in Perl
Substitute nth occurance in Regular Expressions in Perl
All Topics in Regular Expressions in Perl


You might also wish to read other topics like :
Python Class and Object Example
Inheritance in Python
Packages in Python
Exceptions in Python
How to remove duplicate lines from a file in Perl
How to remove duplicate lines from a file in Pyhton


How to create excel report in Perl


We can generate Microsoft Excel (XLS) report using Perl

Note:
Please install module Spreadsheet::WriteExcel before running the program

We can create worksheets
We can set styles like color/font/size etc for the cells


#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Spreadsheet::WriteExcel;


my ($xls_label, $workbook, $worksheet, $format_header, $format_row);

$xls_label = "test.xls";

$workbook = Spreadsheet::WriteExcel->new($xls_label);

$worksheet = $workbook->add_worksheet();

$format_header = $workbook->add_format(); # Add a format
$format_header->set_bold();
$format_header->set_color('purple');
$format_header->set_align('center');
$format_header->set_size(12);

$format_row = $workbook->add_format(); # Add a format
$format_header->set_bold();
$format_row->set_align('center');

my $row = 0;
my $column = 0;

$worksheet->write($row, 0, 'S.No', $format_header);
$worksheet->write($row, 1, 'Humanists', $format_header);

my @humanists_arr = ("Mother Teresa", "Mahatma Gandhi", "Abraham Lincoln", "Winston Churchil", "Alfred Nobel");

foreach my $each_humanist (@humanists_arr) {
   $row++;
   $worksheet->write($row, 0, $row, $format_row);
   $worksheet->write($row, 1, $each_humanist, $format_row);
}

1;


Output :
S.No Humanists
1 Mother Teresa
2 Mahatma Gandhi
3 Abraham Lincoln
4 Winston Churchil
5 Alfred Nobel  


Please refer to other topics on Unix like :
Unix Delete Duplicated Lines in a File
Unix Unique Lines in a File
Unix Grep Examples
Unix Cut Command Examples
Search a Directory in Unix
Unix For Loop
pushd & popd in Unix
Find Size of Directory
Word Count


Please refer to other topics on AWK like :
Awk Examples
Print First Two Columns of File
Print Last Two Columns of File


Please refer to other topics on Dict like :
Dict in Python
Dict keys and values in Python


Please refer to other topics on List like :
List in Python
Append to list in Python
Delete the last name from the list in Python
Remove an element from List in Python
Check an element exists in an list in Python
Python Filter Vs Map Vs List Comprehension


Please refer to other topics on File Concepts like :
Print File Content in Python
Print File in Reverse Order in Python


Please refer to Regular Expressions Concepts :
Brief on Regular Expressions
Greedy Operators in Regular Expressions in Perl
Modifiers in Regular Expressions in Perl
Capturing concept in Regular Expressions in Perl
Capture Pre Match ,Post Match, Exact match in Regular Expressions in Perl
Non Capturing Paranthesis in Regular Expressions in Perl
Substitute nth occurance in Regular Expressions in Perl
All Topics in Regular Expressions in Perl


You might also wish to read other topics like :
Python Class and Object Example
Inheritance in Python
Packages in Python
Exceptions in Python
How to remove duplicate lines from a file in Perl
How to remove duplicate lines from a file in Pyhton


Jun 22, 2008

Closure in Perl

What is closure?

- Anonymous subroutines (subroutines without name) act as closures with respect to my() variables ie., lexical variables.

- Closure says if you define an anonymous function in a particular lexical
context, it pretends to run in that context even when it's called outside of
the context.

Example:
########

#!F:\Perl\bin\perl -w
use strict;

sub newprint {
   my $x = shift; # 'x' is a lexical variable
   return sub { my $y = shift; print "$x, $y!\n"; }; #Anonymous subroutine, observe $x
}
my $h = newprint("Howdy");
my $g = newprint("Greetings");

&$h("world"); # Howdy world
&$g("earthlings"); # Greetings earthlings


Note particularly that $x continues to refer to the value passed into
newprint() despite the fact that the my $x has seemingly gone out of
scope by the time the anonymous subroutine runs. That's what closure is all
about.

This applies only to lexical variables, by the way. Dynamic variables
continue to work as they have always worked. Closure is not something that
most Perl programmers need trouble themselves about to begin with.


One More Example on Closure:
##########################

- The important thing about closures is that you can use them to hide different lexicals into seperate
references to the same subroutine.

- I think that the important thing about closures is being able to call the same code but have it use different
variables (without passing them in as arguments).


use strict;
sub make_hello_printer {
  my $message = "Hello, world!";
  return sub { print $message; }
}

my $print_hello = make_hello_printer();
$print_hello->()



As you'd expect, that prints out the Hello, world! message. Nothing special going on here, is there? Well,

actually, there is. This is a closure. Did you notice?

What's special is that the subroutine reference we created refers to a lexical variable called $message. The

lexical is defined in make_hello_printer, so by rights, it shouldn't be visible outside of make_hello_printer,

right? We call make_hello_printer, $message gets created, we return the subroutine reference, and then

$message goes away, out of scope.

Except it doesn't. When we call our subroutine reference, outside of make_hello_printer, it can still see and

receive the correct value of $message. The subroutine reference forms a closure, ``enclosing'' the lexical

variables it refers to.


One More Example on Closure:
##########################

#!F:\Perl\bin\perl -w
use strict;

sub make_counter {
my $start = shift;
return sub { $start++ }
}

my $from_ten = make_counter(10);
my $from_three = make_counter(3);
print $\ = "\n"; # Prints new line each and every print
print $from_ten->(); # 10
print $from_ten->(); # 11
print $from_three->(); # 3
print $from_ten->(); # 12
print $from_three->(); # 4