IntroE...Object(3pm)

πŸ“¦
version 2.5.0 Β· 2 versions
, in ubuntu jammy

πŸ’– IntroE...Object(3pm) πŸ’–

okay bestie, so this is the user-contributed Perl documentation for Embperl::IntroEmbperlObject β€” like, the actual Perl doc page, and it's part 1 of a 3-part saga so don't go anywhere 🫢


✨ NAME ✨

Embperl::IntroEmbperlObject β€” Introduction to EmbperlObject

πŸ“š Contents πŸ“š

  • Introduction
  • Getting Started
  • Hello World
  • Website-Global Variables
  • Modular Files
  • Modular File Inheritance
  • Subroutines in EmbperlObject
  • Conclusions

🌸 Introduction 🌸

Okay so real talk: this tutorial is a complement to the Embperl documentation, not a glow-up replacement for it. We're assuming you already have basic familiarity with Apache, mod_perl, Perl, and the Embperl docs. What we're not assuming is literally any prior experience with EmbperlObject β€” you can walk in knowing zero, it's giving very beginner-friendly πŸ’…

The actual purpose here is to give you a clearer idea of how EmbperlObject can help you build large websites. We've got example code that could totally serve as a starting template for your own projects, plus hints about best practices that came out of real experience using the toolkit. And as always: there is more than one way to do it! 😌

Since EmbperlObject is an evolving tool, it's likely these design patterns will evolve over time too, and it's recommended that you check back on the Embperl website for new versions from time to time. πŸ‘‘

πŸ’­ Motivation: Constructing Modular Websites

So Embperl is a tool that lets you embed Perl code in your HTML documents. Which means, like, technically it could by itself handle just about everything you need to do with your website. So bestie… what is even the point of EmbperlObject? What does it give us that basic Embperl doesn't already?

And honestly, as is so often the case with Perl, the answer has to do with laziness. ✨ We would all like building websites to be as simple as possible. Anyone who's had to build a non-trivial site using pure HTML has quickly experienced the irritation of copy-and-pasting common code between documents β€” stuff like navigation bars and table formats. We have probably all wished for an "include" HTML tag. And EmbperlObject goes a long way toward solving this problem, without making the developer resort to a bunch of customized Perl code. No cap.

In a nutshell: EmbperlObject extends Embperl by enabling the construction of websites in a modular, or object-oriented, fashion. And I'm using the term "object-oriented" (OO) loosely here β€” in the context of inheritance and overloading β€” but you don't actually need to know anything about the OO paradigm to benefit from EmbperlObject. As you'll see in this short tutorial, it's possible to benefit from using EmbperlObject with even a minimal knowledge of Perl. With just a little instruction, pure HTML coders could use it to improve their website architecture. That said, though, EmbperlObject also provides for more advanced OO functionality, as we'll see later. πŸ‘€

πŸš€ Getting Started πŸš€

We're assuming here that you've successfully installed the latest Apache, mod_perl and Embperl on your system. That should all be relatively painless β€” problems normally occur when mixing older versions of one tool with later versions of another. So if you can, try to download the latest versions of everything. fr fr.

Having done all that, you might want to get going with configuring a website. The first thing you need to do is set up the Apache config file, usually called httpd.conf.

βš™οΈ Configuring httpd.conf βš™οΈ

The following is an example configuration for a single virtual host to use EmbperlObject. There are, as usual, different ways to do this; but if you're starting from scratch then it may be useful as a template. It works with the later versions of Apache (1.3.6 and up). Obviously, substitute your own IP address and domain name. πŸŽ€

NameVirtualHost 10.1.1.3:80

<VirtualHost 10.1.1.3:80>
        ServerName www.mydomain.com
        ServerAdmin webmaster@mydomain.com
        DocumentRoot /www/mydomain/com/htdocs
        DirectoryIndex index.html
        ErrorLog /www/mydomain/com/logs/error_log
        TransferLog /www/mydomain/com/logs/access_log
        PerlSetEnv EMBPERL_ESCMODE 0
        PerlSetEnv EMBPERL_OPTIONS 16
        PerlSetEnv EMBPERL_MAILHOST mail.mydomain.com
        PerlSetEnv EMBPERL_OBJECT_BASE base.epl
        PerlSetEnv EMBPERL_OBJECT_FALLBACK notfound.html
        PerlSetEnv EMBPERL_DEBUG 0
</VirtualHost>

# Set EmbPerl handler for main directory
<Directory "/www/mydomain/com/htdocs/">
        <FilesMatch ".*\.html$">
                SetHandler  perl-script
                PerlHandler HTML::EmbperlObject
                Options     ExecCGI
        </FilesMatch>
        <FilesMatch ".*\.epl$">
                Order allow,deny
                Deny From all
        </FilesMatch>
</Directory>

Note that you could change the .html file extension in the FilesMatch directive β€” that's a personal preference issue. Personally, I use .html for the main document files simply because I can edit files using my favorite editor (emacs) and it will automatically load html mode. Plus, and this may be a minor thing, but using .html rather than a special extension such as .epl adds a small amount of security to your site since it provides no clue that the website is using Embperl. If you're careful about the handling of error messages, then there never be any indication of this. These days, the less the script kiddies can deduce about you, the better… πŸ’€

Also, note that we've added a second FilesMatch directive, which denies direct access to files with .epl extensions (again, you could change this extension to another if you like, for example .obj). This can be helpful for cases where you have Embperl files which contain fragments of code or HTML; you want those files to be in the Apache document tree, but you don't want people to be able to request them directly β€” these files should only be included directly into other documents from within Embperl, using Execute(). This is really a security issue. πŸ”

In the examples that follow, we name files which are not intended to be requested directly with the .epl extension. Files which are intended to be directly requested are named with the standard .html extension. This can also be helpful when scanning a directory, to see which are the main document files and which are the modules. Finally, note that using the Apache FilesMatch directive to restrict access does not prevent us from accessing these files (via Execute) in Embperl.

So how does all this translate into a real website? Let's have a look at the classic first example, Hello World. 🌍

πŸ‘‹ Hello World πŸ‘‹

The file specified by the EMBPERL_OBJECT_BASE apache directive (usually called base.epl) is the lynchpin of how EmbperlObject operates. Whenever a request comes in for any page on this website, Emperl will look for base.epl β€” first in the same directory as the request, and if not found there then working up the directory tree to the root dir of the website. So for example, if a request comes in for http://www.yoursite.com/foo/bar/file.html, then Embperl first looks for /foo/bar/base.epl. If it doesn't find base.epl there, then it looks in /foo/base.epl. If no luck, then finally /base.epl. (These paths are all relative to the document root for the website). What is the point of all this? πŸ€”

In a nutshell, base.epl is a template for giving a common look-and-feel to your web pages. This file is what is actually used to build the response to any request, regardless of the actual filename which was asked for. So even if file.html was requested, base.epl is what is actually executed. base.epl is a normal file containing valid HTML mixed with Perl code, but with a couple of small differences. Here's a simple 'Hello World' example of this approach: ✨

/base.epl

<HTML>
<HEAD>
        <TITLE>Some title</TITLE>
</HEAD>
<BODY>
Joe's Website
<P>
[- Execute ('*') -]
</BODY>
</HTML>

/hello.html

Hello world!

Now, if the file http://www.yoursite.com/hello.html is requested, then base.epl is what will actually get executed initially. So where does the file hello.html get into the picture? Well, the key is the '*' parameter in the call to Execute(). '*' is a special filename, only used in base.epl. It means, literally, "the filename which was actually requested". 🫢

What you will see if you try this example is something like this:

Joe's Website

Hello world!

As you can see here, the text "Joe's Website" is from base.epl and the "Hello world!" is from hello.html. iconic behavior tbh.

This architecture also means that only base.epl has to have the boilerplate code which every HTML file normally needs to contain β€” namely the <HTML>, <BODY>, </HTML> and so on. Since the '*' file is simply inserted into the code, all it needs to contain is the actual content which is specific to that file. Nothing else is necessary, because base.epl has all the standard HTML trappings. Of course, you'll probably have more interesting content, but you get the point. πŸ’…

🌐 Website-Global Variables 🌐

okay so now we're leveling up to a slightly more interesting example. When you create Perl variables in Embperl, usually their scope is the current file, so they're effectively local to that file. But when you start splitting your website up into modules, it becomes super obvious that having variables that are global to the website β€” like, shared between multiple files β€” is extremely useful. πŸ’–

To make that happen, EmbperlObject has a special object that gets automatically passed to every page as it's executed. People usually call this the Request object, because we get one of these objects created for every document request that the web server receives. It's passed in on the stack, so you can grab it with the Perl shift statement. It also gets automatically destroyed after the request, so the Request object cannot be used to store data between requests. The whole idea is that you can store variables that are local to the current request and shared between all documents on the current website; plus, as we'll see later, we can also use it to call object methods. For example, let's say you set up some variables in base.epl, and then use them in file.html:

/base.epl

<HTML>
<HEAD>
        <TITLE>Some title</TITLE>
</HEAD>
[-
        $req = shift;
        $req->{webmaster} = 'John Smith'
-]
<BODY>
[- Execute ('*') -]
</BODY>
</HTML>

/file.html

[- $req = shift -]
Please send all suggestions to [+ $req->{webmaster} +].

See how EmbperlObject lets us set up global variables in one place and share them all over the website? If you put base.epl in the root document directory, you can have any number of other files in this directory and subdirectories, and they'll all get these variables whenever they're executed. No matter which file is requested, /base.epl is executed first, and then the requested file. ✨

You don't even have to include the requested '*' file, but the usual case is that you do β€” because it would be a little odd to completely ignore the requested file, bestie! πŸ’€


🧩 Modular Files 🧩

The previous example is cute, and it shows the basic ability to have website-wide variables set up in base.epl and then automatically shared by all other files. Going on from there, we probably want to split our files up for maintainability and readability. Like, a non-trivial website will probably define some website-wide constants, maybe some global variables, and maybe also have some kind of initialization code that has to run for every page (e.g. setting up a database connection). We could put all of this in base.epl, but that file would quickly start looking really messy. It'd be nice to split this stuff out into other files. For example:

/base.epl

<HTML>
[- Execute ('constants.epl')-]
[- Execute ('init.epl')-]
<HEAD>
        <TITLE>Some title</TITLE>
</HEAD>
<BODY>
[- Execute ('*') -]
</BODY>
[- Execute ('cleanup.epl') -]
</HTML>

/constants.epl

[-
        $req = shift;
        $req->{bgcolor} = "white";
        $req->{webmaster} = "John Smith";
        $req->{website_database} = "mydatabase";
-]

/init.epl

[-
        $req = shift;
        # Set up database connection
        use DBI;
        use CGI qw(:standard);
        $dsn = "DBI:mysql:$req->{website_database}";
        $req->{dbh} = DBI->connect ($dsn);
-]

/cleanup.epl

[-
        $req = shift;
        # Close down database connection
        $req->{dbh}->disconnect();
-]

You can see how useful this is: every page on your site now has a database connection available in $req->{dbh}. Also notice we have a cleanup.epl file that's always executed at the end β€” that's super useful for cleaning up, shutting down connections, and so on. 🫢


🧬 Modular File Inheritance 🧬

To recap: we've seen how we can break our site into modules that are common across multiple files, because they're automatically included by base.epl. Inheritance is a way we can make our websites even more modular. 🌈

Even though inheritance comes from the object-oriented paradigm, you really don't need to be an OO guru to get it. We'll demonstrate with a simple example, leading on from the previous one.

Say you wanted different parts of your website to have different <TITLE> tags. You could set the title in each page manually, but if you had a bunch of different pages in each section, that would get tiresome fast. Now, we could split off the <HEAD> section into its own file, just like constants.epl and init.epl, right? But so far it looks like we're stuck with a single head.epl file for the entire website, which doesn't really help much.

The answer is subdirectories. This is the key to unlocking inheritance, and one of the most powerful features of EmbperlObject. You might already use subdirectories in your website design, maybe for organization and maintenance. But here, subdirectories actually let you override files from upper directories. Best demonstrated by example (simplified to make this specific point clearer β€” assume constants.epl, init.epl, and cleanup.epl are the same as in the previous example):

/base.epl

<HTML>
[- Execute ('constants.epl')-]
[- Execute ('init.epl')-]
<HEAD>
[- Execute ('head.epl')-]
</HEAD>
<BODY>
[- Execute ('*') -]
</BODY>
[- Execute ('cleanup.epl') -]
</HTML>

/head.epl

<TITLE>Joe's Website</TITLE>

/contact/head.epl

<TITLE>Contacting Joe</TITLE>

Assume here that we have an index.html file in each directory that does something useful. The main thing to focus on is head.epl. You can see we have one instance of this file in the root directory, and one in a subdirectory, namely /contact/head.epl. Here's the neat part: when a page is requested from your website, EmbperlObject automatically searches for base.epl first in the same directory as the requested page. If it doesn't find it there, it tracks back up the directory tree until it does find the file. But then, when executing base.epl, any files that are Executed (like head.epl) are first looked for in the original directory of the requested file. Again, if the file isn't found there, EmbperlObject tracks back up the directory tree.

So what does this actually mean? Well, if we have a subdirectory, we can just have the usual index.html file and nothing else. In that case, all the files included by base.epl will be found in the root document directory. But if we redefine head.epl, like in our example, then EmbperlObject will pick up that version of the file whenever we're in the /contact/ subdirectory.

That's inheritance in action. In a nutshell, subdirectories inherit files like head.epl, constants.epl, and so on from upper, parent directories. But if we want, we can redefine any of these files in our subdirectories, specializing that functionality for that part of our website. If we had 20 .html files in /contact/, then loading any one of them would automatically get /contact/head.epl.

This is all very cool, but there's one more wrinkle. Let's say we want to redefine init.epl, because there's some initialization specific to the /contact/ subdirectory. That's fine β€” we could create /contact/init.epl, and that file would be loaded instead of /init.epl whenever a file is requested from the /contact/ subdir. But this also means the initialization code in /init.epl would never get executed, right? That's bad, because the base version of the file does a lot of useful setup. The answer is simple: for cases like this, we just make sure to call the parent version of the file at the start. For example:

/contact/init.epl

[- Execute ('../init.epl') -]

[-
        # Do some setup specific to this subdirectory
-]

You can see the very first thing we do here is Execute the parent version of the file (i.e. the one in the immediate parent directory). That way we can ensure the integrity of the basic initialization that every page should receive.

EmbperlObject is very smart about this process. Say, for example, we have several levels of subdirectory; then say we only redefine init.epl in one of the deeper levels, like /sub/sub/sub/init.epl. Now, if this file tries to Execute ../init.epl, there may not be any such file in the immediate parent directory β€” so EmbperlObject automatically tracks back up the directories until it finds the base version, /init.epl. So, for any subdirectory level in your website, you only have to redefine those files that are specific to this particular area. This results in a much cleaner website.

You can break your files up into whatever level of granularity you want, depending on your needs. For instance, instead of just head.epl, you might break it down into title.epl, metatags.epl, and so on. It's up to you. The more you split it up, the more you can specialize in each subdirectory. There's a balance, though, because splitting things up too much results in an overly fragmented site that can be harder to maintain. Moderation is the key β€” generally speaking, only split out files if they contain a substantial chunk of code, or if you know you need to redefine them in subdirectories.

πŸ¦‹ Subroutines in EmbperlObject πŸ¦‹

okay bestie so there are two whole kinds of inheritance in EmbperlObject, and we already did the first one (modular files, directory hierarchy, you know the drill πŸ’…). The second one, which is super closely related, is inheritance of subroutines β€” and that means both pure Perl ones and Embperl ones. And in this context, those subroutines are literally object methods, which we're about to see. You probs already know there are two flavors of subroutine in Embperl, like:

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

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

In EmbperlObject, subroutines become object methods, and the whole difference is that you always call an object method through an object reference. So instead of a plain old straight-up call like:

foo();

you get a call through some object instead:

$obj->foo();

EmbperlObject lets you inherit object methods pretty much the same way you inherit files. But because of how Perl does objects and methods under the hood, there's a tiny bit of extra stuff to keep in mind. (Also real talk: this is not a good place to be introducing Perl's whole object system. If inheritance, @ISA and object methods have you going "huh 😭", please go read the book Programming Perl (O'Reilly) or Object Oriented Perl by Damien Conway (Manning). iykyk.)


✨ A lil demo of methods ✨

A simple use of methods looks like this:

/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>

So this is an alternative way of doing that earlier "contact" example, and it still uses inheritance β€” except instead of putting the <TITLE> tag in a separate file (head.epl), we use a method (title()). See how we define that method in /base.epl? So literally any page requested from the root directory gets the title "Joe's Website". That's a pretty good default title, ngl. Then in /foo/index.html we redefine the title() method to return "Contacting Joe". Inheritance makes sure that when the call to title() happens in /base.epl, the correct version of the method runs. And since /foo/index.html has its own version of that method, it gets called automatically instead of the base one. πŸŽ€ This means every file can potentially redefine methods defined in /base.epl, and honestly it works great. But as your websites get bigger, you're gonna want to split some routines off into their own files.


🫢 Special files full of inheritable methods 🫢

EmbperlObject also lets us make special files that just contain inheritable object methods. It can set up @ISA for us so the Perl object methods actually work the way you expect. To pull that off, we have to access our methods through a specially created object instead of straight through the Request object (usually called $r or $req). This is best shown with the example below, which shows the code you add to base.epl and also demonstrates inheritance via a subdirectory. And once again, assume that missing files like constants.epl are the same as before. (Heads up: 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";
        }
!]

And if we requested /insult/index.html, we'd see something like:

Hello, Joe, you schmuck

πŸ’€ so what is actually happening here πŸ’€

First of all, notice that we create a $subs object in base.epl using a special call to Execute(). Then we pass that object along to the files that need it, via an Execute() parameter. You can see that in action with the '*' file. ✨

Next, we have two versions of subs.epl. The first one, /subs.epl, is pretty straightforward. All we gotta remember is that all of these subroutines are object methods now, so they take that extra ($self) parameter. The basic hello() method just says hello to whoever's name got passed in. cute, right?

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

The file /insult/subs.epl has to have a call to Execute() that sets up @ISA. That's the first line. You might be asking why EmbperlObject doesn't just do this automatically β€” it's mainly for efficiency reasons. Not every file is going to contain methods that need to inherit from the parent file, so just requiring that one line seemed like a good compromise. It also gives you a bit more flexibility, because you can β€” if you want β€” include other arbitrary files into the @ISA tree. 🧚


🌈 Conclusions 🌈

So there you have it, bestie β€” an intro to using EmbperlObject for building big, modular websites. You'll probably use it for stuff like website-wide navigation bars, table layouts, and honestly whatever else needs to be modularized. πŸ’–

This document is just an introduction, to give a broad flavor of the tool. For the actual details you should go refer to the actual documentation. fr fr.

EmbperlObject is inevitably gonna evolve as developers figure out what's useful and what isn't. We'll try to keep this document up-to-date with those changes, but also make sure to check the Embperl website regularly for the latest changes. πŸ”₯


πŸ‘‘ Author πŸ‘‘

Neil Gunton neil@nilspace.com


and that's a wrap, babes πŸŽ€ this page is from perl v5.34.0, dated 2022-02-06, and it lives in the IntroE...Object(3pm) man page family. go build something iconic πŸ’…βœ¨

πŸ“¦ where this page comes from