Embperl - building dynamic websites with Perl


Subroutines in EmbperlObject
[ << Prev: Modular File Inheritance ] [ Content ] [ Next: Conclusions >> ]

There are two kinds of inheritance in EmbperlObject. The first is the one which we described in the previous section, i.e. inheritance of modular files via the directory hierarchy. The other kind, closely related, is the inheritance of subroutines (both pure Perl and Embperl). In this context, subroutines are really object methods, as we'll see below. As you are probably already aware, there are two kinds of subroutine in Embperl, for example:

[! sub perl_sub { # Some perl code } !]

[$ sub embperl_sub $] Some HTML [$ endsub $]

In EmbperlObject, subroutines become object methods; the difference is that you always call an object method through an object reference. For example, instead of a straight subroutine call like this:

foo();

We have instead a call through some object:

$obj->foo();

EmbperlObject allows you to inherit object methods in much the same way as files. Because of the way that Perl implements objects and methods, there is just a little extra consideration needed. (Note: This is not really a good place to introduce Perl's object functionality. If you're not comfortable with inheritance, @ISA and object methods, then I suggest you take a look at the book "Programming Perl" (O'Reilly) or "Object Oriented Perl" by Damien Conway (Manning).)

A simple use of methods can be demonstrated using the following example:

/base.epl

[! sub title {'Joe's Website'} !] [- $req = shift -] <HTML> <HEAD> <TITLE>[+ $req->title() +]</TITLE> </HEAD> </HTML>

/contact/index.html

[! sub title {'Contacting Joe'} !] [- $req = shift -] <HTML> A contact form goes here </HTML>

This is an alternative way of implementing the previous "contact" example, which still uses inheritance - but instead of placing the <TITLE> tag in a separate file (head.epl), we use a method (title()). You can see that we define this method in /base.epl, so any page which is requested from the root directory will get the title "Joe's Website". This is a pretty good default title. Then, in /foo/index.html we redefine the title() method to return "Contacting Joe". Inheritance insures that when the call to title() occurs in /base.epl, the correct version of the method will be executed. Since /foo/index.html has its own version of that method, it will automatically be called instead of the base version. This allows every file to potentially redefine methods which were defined in /base.epl, and it works well. But, as your websites get bigger, you will probably want to split off some routines into their own files.

EmbperlObject also allows us to create special files which just contain inheritable object methods. EmbperlObject can set up @ISA for us, so that the Perl object methods will work as expected. To do this, we need to access our methods through a specially created object rather than directly through the Request object (usually called $r or $req). This is best illustrated by the following example, which demonstrates the code that needs to be added to base.epl and also shows how we implement inheritance via a subdirectory. Once again, assume that missing files such as constants.epl are the same as previously (Note that the 'object' parameter to Execute only works in 1.3.1 and above).

/base.epl

   	<HTML>
	[- $subs = Execute ({object => 'subs.epl'}); -]
	[- Execute ('constants.epl') -]
	[- Execute ('init.epl') -]
   	<HEAD>
	[- Execute ('head.epl') -]
	</HEAD>
	<BODY>
	[- Execute ('*', $subs) -]
	</BODY>
	[- Execute ('cleanup.epl') -]
	</HTML>

/subs.epl

[! sub hello { my ($self, $name) = @_; print OUT "Hello, $name"; } !]

/insult/index.html

[- $subs = $param[0]; $subs->hello ("Joe"); -]

/insult/subs.epl

[! Execute ({isa => '../subs.epl'}) !]

[! sub hello { my ($self, $name) = @_; $self->SUPER::hello ($name); print OUT ", you schmuck"; } !]

If we requested the file /insult/index.html then we would see something like

Hello, Joe, you schmuck

So what is happening here? First of all, note that we create a $subs object in base.epl, using a special call to Execute(). We then pass this object to files which will need it, via an Execute() parameter. This can be seen with the '*' file.

Next, we have two versions of subs.epl. The first, /subs.epl, is pretty straightforward. All we need to do is remember that all of these subroutines are now object methods, and so take the extra parameter ($self). The basic hello() method simply says Hello to the name of the person passed in.

Then we have a subdirectory, called /insult/. Here we have another instance of subs.epl, and we redefine hello(). We call the parent version of the function, and then add the insult ("you schmuck"). You don't have to call the parent version of methods you define, of course, but it's a useful demonstration of the possibilities.

The file /insult/subs.epl has to have a call to Execute() which sets up @ISA. This is the first line. You might ask why EmbperlObject doesn't do this automatically; it is mainly for reasons of efficiency. Not every file is going to contain methods which need to inherit from the parent file, and so simply requiring this one line seemed to be a good compromise. It also allows for a bit more flexibility, as you can if you want include other arbitrary files into the @ISA tree.


[ << Prev: Modular File Inheritance ] [ Content ] [ Next: Conclusions >> ]


© 1997-2023 Gerald Richter / actevy