WebLord

WebLord

The Site Construction Power Tool

WebLord Tutorials

The following tutorials are meant to demonstrate some of the more complex concepts of WebLord. If you are not clear with WebLord's basic concepts you may not understand what these tutorials are trying to convey.

Tutorial #1     The "If / then / else" conditionals property
Demonstrates the construction of an 'if-then-else...' construct to return an operating system specific command to execute, depending on the operating system on which you are running WebLord.

Tutorial #2     The use of unique-id
A 16-character unique identifier can be used for unique filenames, unique anchor names, etc.

Tutorial #3     Values supplied by external software
Use an external program to supply a value such as a current date and time to an object.

Tutorial #4     Misconceptions & Pitfalls
Misconceptions that can cause hair loss

Tutorial #5     Referencing External Files
How to load the contents of an external file.

The "If / then / else" conditionals property

Imagine that you maintain your site description files on an MS-DOS readable floppy disk that contains binaries (executable program versions) of WebLord for MS-DOS, a Unix platform, and your Amiga. You carry this disk with you to make instant changes wherever you go and use the local network to upload the new version directly to your provider (hey, you're a cool kind of person, you do this kind of thing all the time!)

The problem you face is that each platform uses a different program to upload the pages and you don't want to be changing the site description file again and again, so you'd like to implement something like the following logic:

	if OS = "AMIGA"
		upload file by copying it to the FTP: device
	else
	if OS = "Windows"
		upload file by copying it to the web server's directory
	else
	if OS = "Unix"
		upload file by copying it to your public web directory
	else
		admit to the user that we haven't got support for her O/S

Yes, this is possible! Although WebLord has no scripting language, it is still possible (and not overly difficult) to implement such a multiple-decision construct. Consider this:

	text = upload-output
	{
		if=_OS "=" "AMIGA";
			then =	"echo "Uploading (Amiga) '" output "'..."\\n"
				"copy quiet " output " ftp:walrus@wam.umd.edu/www/\\n"
				"copy quiet " output " apache:htdocs";
			else =	upload-output-2;
	}
	text = upload-output-2
	{
		if=_OS "=" "WIN32";
			then =	"echo off\\n"
				"echo Uploading (32bit Windows) '" output "'...\\n"
				"copy " output " c:\\\\sambar\\\\htdocs\\\\walrus >null:\\n";
			else =	upload-output-3;
	}
	text = upload-output-3
	{
		if=_OS "=" "UNIX";
			then =	"echo "Uploading (Unix) '" output "'..."\\n"
				"/bin/cp " output " ~/" output;
			else =	"echo "Operating system '" _OS "' is not supported!";
	}

Note that the 'if' property causes a decision to be made: the object's value becomes either the result of the 'then' or the 'else' property. The presence of an 'if' property will override and entirely hide a 'value' property. By setting a page's 'post-exec' property to reference the above 'upload-output' object you obtain the command string that applies to the operating system for which WebLord is compiled.

How does it work? Simple!

'Upload-output' performs a comparison (using the 'if' property) to determine if the operating system ( _OS ) is an Amiga. If this expression evaluates true, the object returns the result of its 'then' property. If the expression evaluates false, the object returns to result of its 'else' property, instead.

The 'else' property of the 'upload-output' object, however, references another object (upload-output-2), so that object has to be evaluated: it performs a similar 'if' operation; if that object's expression also evaluates false, then it, in turn, references the 'upload-output-3' object.

The final result is returned to the calling objects and becomes the result of the 'upload-output' object and may then be assigned to the 'post-exec' property of a page, thereby providing the command to upload the current page using the methods appropriate to the current operating system.

Here is another such 'if-then-else' statement that use useful for deleting a file in an operating system independent manner. The 'delete-file' object expects to inherit a 'file-to-delete' property from the caller:

	text = delete-file	{
		if=_OS "=" "AMIGA";
			then=	"c:delete quiet " file-to-delete;
			else=	delete-file-2;
	}
	text = delete-file-2	{
		if=_OS "=" "WIN32";
			then= "del " file-to-delete " >nul:";
			else=delete-file-3;
	}
	text = delete-file-3	{
		if=_OS "=" "UNIX";
			then= "/bin/rm -f " file-to-delete " >/dev/null";
	}

The use of unique-id

The following implements a more or less operating system independent unique filename, including the ability to choose either a new one before or after the reference (to C/C++/Java programmers, the '++' suffix will have meaning, although WebLord's '++' has no matching '--').

	text = unique-file-name
	{
		value = unique-file-path unique-id ".tmp";
	}
	text = unique-file-name++
	{
		value = unique-file-path-1 unique-id++ ".tmp";
	}
	text = ++unique-file-name
	{
		value = unique-file-path-1 ++unique-id ".tmp";
	}


	text = unique-file-path
	{
		if=_OS "=" "AMIGA";
			then="t:";
			else=unique-file-path-2;
	}
	text = unique-file-path-2
	{
		if=_OS "=" "WIN32";
			then="./";
			else=unique-file-path-3;
	}
	text = unique-file-path-3
	{
		if=_OS "=" "UNIX";
			then="/var/tmp/";
	}

Whenever you need a unique filename, you could simply reference the 'unique-file-name' object and you will get one. This is especially useful with objects that use an 'exec' method combined with a 'value-in-file' property to execute an external command, then load the output of that command to make that the value of the object. Most frequently, the 'exec-cleanup' would reference something like the 'unique-file-name++' (although it is not necessary to increment (change) the unique file.

The key ingredient in the above is the built-in 'unique-id' (with matching '++unique-id' and 'unique-id++'); notice that '++ unique-id' (with a space between the '++' and the 'unique-id') is not the same thing! In fact, it would be two different objects, one named '++' (usually undefined, therefore no value) and 'unique-id' which is not incremented as might be expected.

When would you use the incrementing feature? If you are debugging and wish to skip the cleanup process ('exec-cleanup') and therefore leave the temporary file(s) on disk for inspection. How to tell which file is which? Change the 'unique-file-name' (and related) objects to add some other extension to the value, or more characters to the 'unique-id'.


Values supplied by external software

Let's say that before a certain date you wish to have one text in your page, and after that date you wish to have another. If you use WebLord to construct the page dynamically (on demand), you could get a guaranteed switch-over from one response to another without having to lift a finger! Let's try this:

	text = month-day
	{
		value-in-file	= "1";
		exec		= "now ".%m%d" >" value;
		value		= scratch-file;
		exec-cleanup	= "rm " value;
		value-is-static	= "1";
		trim-newline	= "1";
		scratch-file	= "scratch.tmp";
}

Notice that it would be perfectly fine to supply a unique-file-name instead of a 'scratch-file' and thereby avoid fixed and specific filenames. There is no law, of course, that says that you must use unique filenames to implement exec functionality. You are free to choose your implementation.

Another important point needs to be made: When the object is evaluated, the 'value' property (in combination with the the 'exec' and 'value-in-file') produces a complex value for the object. The value is, therefore, not merely "scratch.tmp" but the contents of the file named "scratch.tmp" as constructed through the call described by the 'exec' property.

The 'exec' property (and exec-cleanup) seem to reference the object value again which may appear to you as a recursive (and bogus) reference. This is not so: when referenced as a property, 'value' is merely that: a property like any other, and in this case evaluates to "scratch.tmp". This permits you to define the name of that file ("scratch.tmp") only once.

Instead of referencing 'value' in the 'exec' and 'exec-cleanup' directories, we could have chosen to reference the 'scratch-file' property directly, but that wouldn't have made for a very effective demonstration of this important principle! :-)

Also note the use of the 'trim-newline' property; this is useful here because we use I/O redirection and AmigaDOS adds a newline at the end of the output which the 'trim-newline' removes. It doesn't hurt specifying trim-newline (perhaps even globally in the SITE object) because it does nothing if a newline is not present at the end of the retrieved file.

Now it's time to use the 'month-day' object:

	text = Greeting
	{
		if = month-day "=" "0903";
			then = "Today is Udo's birthday!";
			else = "Hello world.";
	}

The 'month-day' object being referenced in the comparison returns the output of the external file. So when you reference the object 'greeting', you will get "Today is Udo's birthday!" if it is the September 3 (0903) and "Hello world." on every other day of the year.


Misconceptions & Pitfalls

Some properties are defined for all objects and are therefore inheritable only up to the SITE object. If a new object is instantiated, the 'name' property, for example, of the original object is no longer accessible. The section on inheritance rules discusses this process. Consider now this example:

	page = Test
	{
		# note that every object has an automatic property 'name' (and 'type');
		# for this object 'name' is 'Test' and 'type' is 'page';
		...
		page-name = "Test";
		post-exec = upload-page;
		...
	}

	site = main
	{
		...
		output = "htdocs/" name ".html";
		upload = "copy " output " t:";
	}

	text = upload-page
	{
		# the 'name' property in this object is 'upload-page'; if this object
		# forms an inherited value for another object, then the parent object's
		# 'name' property is replaced by THIS object's 'name' property.
		value = "copy " output " t:";
	}
This is what happens:
  1. The 'Test' page references upload-page; neither the 'Test' page nor the SITE object define this property, so the 'upload-page' object is instantiated.
  2. The 'upload-page' object references output which is not defined by 'upload-page' but IS defined by the SITE object.
  3. Here is where the problem starts: the currently active object ('upload-page') now supplies the 'name' portion for the output property, and NOT THE 'TEST' OBJECT!! In other words, 'name' will be resolved to the name of the 'upload-page' object (i.e. 'upload-page').
  4. The result? A recursive definition that will "blow" up.¹

How to get around this? Don't use the built-in 'name' property!

Instead, define something like 'page-name' (as was already done above) and in the SITE object, reference 'page-name' instead of 'name': all will be fine!

Why does the 'name' property exist? It is a convenient shortcut that works in many cases through the inheritance chain, but stops working once it gets to a newly instantiated object. The difference is that objects act slightly different in that case than mere properties. It's a trade-off for the power that objects supply.


¹ A future version of WebLord will immediately detect recursive references and produce meaningful diagnostics to help you quickly resolve such problems.

Referencing external files

The following (simple!) object returns the value of a file:

	text = startup-sequence
	{
		value-in-file =	"1";
		value =		"s:startup-sequence";
	}

The following returns a listing of your SYS: directory:

	text = sys-dir-listing
	{
		value-in-file =	"1";
		exec =		"list sys: >" value;
		value =		"t:scratch.file";
		exec-cleanup =	"c:delete " value;
	}

WebLord is Copyright © 1997 Udo K Schuermann. The latest versions of the software and (this) documentation can be obtained from the WebLord Home Page (the link will only function if you are connected to the internet.) This page has last been updated on Tuesday August 05, 1997.