By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,919 Members | 1,096 Online
Bytes IT Community
Submit an Article
Got Smarts?
Share your bits of IT knowledge by writing an article on Bytes.

Creating custom Modules

Kelicula
Expert 100+
P: 176
This is NOT a complete OO perl tutorial

However I thought it could be beneficial to explain some of the basic concepts, and allow some users to simplify the software design process.

I have found it to be extremely useful and beneficial to create my own "custom" modules. It (among many other things) allows you to type less. Or to make your keystrokes matter more, however you look at it. (If you do even look at it.)

Things the reader should be familiar with before reading this:
  • References
  • writing and using subroutines
  • The main three data "types" in perl

First of all you will hear alot of new terms, in dealing with OO perl. (That's object oriented) But don't be discouraged that's only the third virtue of a perl programmer "Hubris". We LOVE to have fancy names for things that noone else understands, and get paid more by our boss because of it.


Object- An object is simply a data type. It is much like a hash (if you want it to be) or an array, or a subroutine. An object is a reference to information stored in the computer memory. It is a scalar version of a multidimensional entity. But basically an object just provides you with "properties", and "methods". If you had a "girlfriend" object, it (she hopefully) would have properties: hair color, eye color, height, sex appeal (crossing my fingers here). She also would have methods, which are simply "actions" that she can perform. Or "subroutines" associated with her. She may have a "hold my hand" method, when invoked would cause her to seek you out in a crowd of strangers, and ....(drum roll) hold your hand.
The advantage of having an object is that you now know what types of things it can do, and you have access to all its properties.
Right there in one tidy place.


Class- A class is simply a "package", or a definition of what an object will be, and what kind of things it can do. If it ever it comes into existence.
Objects belong to classes. A girlfriend object would not come from the same class as a "sister" object. (unless you've from WV heheheee.. j/k)

Package- A package is a file. It is a perl script that defines a class. You write your packages, and put them in the Perl/lib directory. Then you can use them in your other scripts with the "use" keyword.

Let's see an example

Many of you will be familiar with the CGI module so let's look at a simple script and pick it apart.
Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl 
  2.  
  3. use strict;
  4. use CGI;
  5.  
  6. my $q = CGI->new();
  7.  
  8. print $q->redirect( -url =>'somewhere', -cookie => 'chocolatechip');
  9.  
  10.  
  11.  
Now what is happening here is:
We are associating our new script with the CGI package, or script, or file, or "Class". So now we have access to it's constructor method. A constructor method is simply the subroutine that makes an object "come to life". That is done with perls "bless" function. More on that later...

Then, (this is important) we create a CGI object called "$q". You see we didn't have a CGI object before this point, we just had a "blueprint" for an object of the CGI class.

Next we invoke the "redirect" method of our object. Which (as methods do) preforms the task of changing our location.

Expand|Select|Wrap|Line Numbers
  1.  
  2. print $q->redirect( -url =>'somewhere', -cookie => 'chocolatechip');
  3.  
  4.  

OK, so let's get dirty

Let's create a package.
This is done with the package keyword. You must first carefully consider what to name your package, because this will also be the name of your class, and the name of your file. Packages have the .pm extension. So create a text file (in your favorite text editor, but NOT Word, or any program that adds rich character formatting. We want plain ASCII text) and name it Girlfriend.pm
Always use a first letter capitol to name your package, perl reserves lower case packages for pragmas, like "strict".

Then type this in your new file:
Expand|Select|Wrap|Line Numbers
  1. package Girlfriend;
  2.  
  3.  
  4. 1;
  5.  
Save this file in the perl "lib" directory. On windows it's C:/Perl/lib.

THAT'S IT!!
You are now ready to "use" your new package.
Notice that we didn't need to list the path to Perl. We also don't need to CHMOD 755 the Girlfriend.pm file either. However you DO need to include the "1;" at the end so that another script can "use" this file. The last statement MUST be a true value. This is the easiest way to achieve that.

You can now create another script and type;
Expand|Select|Wrap|Line Numbers
  1.  
  2. #!/usr/bin/perl
  3.  
  4. use strict;
  5. use Girlfriend;
  6.  
  7.  
At the top of it.

"Well this package is useless", you say.
That's right, we haven't given the Girlfriend object any properties, or methods. (sounds familiar)

Let's fix that.

Start by defining a "constructor" method. Go back to the Girlfriend.pm file and add.

Expand|Select|Wrap|Line Numbers
  1.  
  2.  
  3. sub new {
  4.  
  5. my $class = @_;
  6.  
  7. my $self  = {};
  8. $self->{hairColor} = undef;
  9. $self->{height} = undef;
  10. $self->{friends} = [];
  11.  
  12. return bless($self, $class);
  13. }
  14.  
  15.  
Ah Ha!! There is the magic.
return bless($self, $class);

This reads, associate these properties with any object of the Girlfriend class.

Now in the other script add.
Expand|Select|Wrap|Line Numbers
  1.  
  2. my $jane = Girlfriend->new();
  3.  
Now we have an object.

We can populate it's properties easily.
Expand|Select|Wrap|Line Numbers
  1.  
  2. $jane->{hairColor} = "brown";
  3. $jane->{friends} = ["Sally", "Jim", "Angie"];
  4.  
  5.  
We could also write a method of girlfriend.
After the "new" sub add:
Expand|Select|Wrap|Line Numbers
  1.  
  2. sub smile {
  3.  
  4. print ":-)";
  5. }
  6.  
  7.  
Then to use it in the other script.

Expand|Select|Wrap|Line Numbers
  1. $jane->smile;
  2.  
  3.  
This would print ":-)" to STDOUT.

Notice that when we added values for the properties, they were added to the $jane object of the Girlfriend "class". NOT to the class itself.
We can create other Girlfriend objects too. (although it's not advisable hehheee)

Expand|Select|Wrap|Line Numbers
  1.  my $sara = Girlfriend->new();
  2. $sara->{height} = "TooTall";
  3.  
  4. etc...
  5.  
Then we can have two objects, with different properties, that share to same "structure" or class. However methods may act differently on them depending on what their properties are. Alter the smile sub like this.

Expand|Select|Wrap|Line Numbers
  1.  
  2. sub smile {
  3. my $this = @_;
  4.  
  5. if ($this->{height} =~ /TooTall/){
  6.   print ":-(";
  7. }
  8. else{
  9. print ":-)";
  10.   }
  11. }
  12.  
Now in our other script if we call on the smile method, and "TooTall" is NOT the value of height, we get a smile otherwise a frown.

We would now get a smile from this:
Expand|Select|Wrap|Line Numbers
  1.  
  2. $jane->smile;
  3.  
But a frown from this:
Expand|Select|Wrap|Line Numbers
  1.  
  2. $sara->smile;
  3.  
That's called Polymorphism.

Did you notice the $this variable?
You see when you call on a "class method" the first argument sent to the sub is the object you're working on.

So the argument list would be: $jane.
If you add something else like:
Expand|Select|Wrap|Line Numbers
  1.  
  2. $jane->smile('Hello');
  3.  
  4.  
The argument list would be:
"$jane", "Hello".

Remember that $jane is a reference to an object so we can access it's properties in the sub eg:
Expand|Select|Wrap|Line Numbers
  1. $this->{height};
  2.  
  3.  
You can access a class method directly via:
Expand|Select|Wrap|Line Numbers
  1.  
  2. Girlfriend::smile();
  3.  
  4.  
But it's NOT recommended.





OK well that's enough of OO perl talk.
There are a lot of good tutorials out there to teach you the in's and out's already.

Some of which are located at the bottom of this article.

Let me give you an example of using this to reduce typing, and simplify coding/debugging.

Let's say you have a repetitive task that always needs accomplished.
Use a subroutine you say!!

Yes, but what if this task occurs in every script. You would still have to write that "sub" in every script.

Let's say you want to know if a user is logged in or not, and if they are you want to know certain things about them, all of which is stored in a database.

You could create a "User" module.

Expand|Select|Wrap|Line Numbers
  1. package User;
  2.  
  3. use strict;
  4. use DBI;
  5.  
  6. my $database = "the database";
  7. my $handle = "yourHandle";
  8. my $pass = "yourPassword";
  9.  
  10. my $dbh = DBI->connect("DBI:mysql:$database:localhost", $handle, $password) || die "Error: $DBI::errstr";
  11.  
  12.  
  13. sub new {
  14.  
  15. my ($class, $id) = @_;
  16.  
  17. my $sth = $dbh->prepare(qq~ SELECT * FROM users WHERE id = ? ~);
  18. $sth->execute($id);
  19.  
  20. my $user = $sth->fetchrow_hashref;
  21. $sth->finish;
  22.  
  23. return bless($user, $class);
  24.  
  25. }
  26.  
  27. $dbh->disconnect;
  28.  
  29. 1;
  30.  
Now in your scripts you can easily check if their logged in, and if they are, have access to all the columns in the "users" table record, that is associated with their "id" like this. (Assuming you are storing their id number in a cookie.)

Expand|Select|Wrap|Line Numbers
  1.  
  2. #!/usr/bin/perl
  3.  
  4. use strict;
  5. use CGI;
  6. use User;
  7.  
  8. my $q = CGI->new();
  9.  
  10. if(my $v = $q->cookie('name'){
  11.    my $user = User->new($v);
  12. }
  13.  
  14.  
  15. # Asumming they were loggin in....
  16.  
  17. print "Hello, $user->{username}, I see you have been a member since: $user->{joined}, would you like to update your email address? We have: $user->{email}";
  18.  
  19.  
That's if you were using a mysql database, and had the columns "username", "joined", and "email" in your users table.

Go ahead try it yourself!!

I didn't even get into writing a method for the User module.

Be sure to check out these links below:

Tom's OO tutorial

Excellent pdf!!
Perl training Aussie style
Feb 4 '08 #1
Share this Article
Share on Google+
3 Comments


Kelicula
Expert 100+
P: 176
Please expound!!

I left A LOT out.But I just wanted to get the ball rollin, so to speak...
Feb 4 '08 #2

KevinADC
Expert 2.5K+
P: 4,059
I just skipped through fast, but I noticed the last code snippet has one or two errors in it. Missing a ')' after cookie('name') and $user is scoped to the enclosing block and will not be available to the rest of the script.

Should be:

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2. use strict;
  3. use CGI;
  4. use User;
  5. my $q = CGI->new();
  6. my $user;
  7. if (my $v = $q->cookie('name')) {
  8.    $user = User->new($v);
  9. }
  10. # Asumming they were loggin in....
  11. print "Hello, $user->{username}, I see you have been a member since: $user->{joined}, would you like to update your email address? We have: $user->{email}";
The HTTP header is also missing, but maybe I'm being too nit-picky mentioning that.

Regards,
Kevin(ADC)
Feb 4 '08 #3

Kelicula
Expert 100+
P: 176
I just skipped through fast, but I noticed the last code snippet has one or two errors in it. Missing a ')' after cookie('name') and $user is scoped to the enclosing block and will not be available to the rest of the script.

Should be:

Expand|Select|Wrap|Line Numbers
  1. #!/usr/bin/perl
  2. use strict;
  3. use CGI;
  4. use User;
  5. my $q = CGI->new();
  6. my $user;
  7. if (my $v = $q->cookie('name')) {
  8.    $user = User->new($v);
  9. }
  10. # Asumming they were loggin in....
  11. print "Hello, $user->{username}, I see you have been a member since: $user->{joined}, would you like to update your email address? We have: $user->{email}";
The HTTP header is also missing, but maybe I'm being too nit-picky mentioning that.

Regards,
Kevin(ADC)

That's what I get for staying up late. :(

I guess I should point out, that this tutorial is NOT the kind where you can copy, and paste the code, but, more about the concepts.

I just kinda made the code up, as I was writing it, it's not been debugged, or executed.

I also, left out, "inheritance", "package variables", and exporting into name spaces, weak vs. strong references, destructor methods, using "@ISA", and "our" the __PACKAGE__ variable, interface vs. inheritance polymorphism etc...

But I did try to focus more on reusing code, instead of creating full blown packages.
Hopefully it's enough to get someones feet wet and then maybe decide to learn more...(Please see the excellent links at the bottom!!)

Thanks Kevin!
Feb 4 '08 #4