Using Namespaces To Load Lasso Tags Into Memory

This article describes different ways to load custom tags into memory in Lasso, and presents an alternative method of managing tag libraries.

LassoStartup and LassoLibraries

Lasso provides a number of different ways to make custom tags (and types) available for use in your scripts. Tag definitions can be pasted directly into scripts, or included from external files. Alternatively, tag files can be placed in one of two special folders within the Lasso application folder, LassoStartup and LassoLibraries, for automatic loading.

Placing tags within these special folders provides two distinct advantages. First, Lasso handles the loading of the tags for you, so it’s not necessary to manually include any extra files or code in your scripts; the tags are simply always available for use. If placed in LassoStartup, they’re loaded as part of the initialization process when the Lasso Service starts. If placed in LassoLibraries (and arranged in a certain way), they’re loaded on-demand, the first time they are used in a script.

Secondly, once loaded, tags placed in these special folders remain resident in memory until the Lasso Service is restarted. This eliminates the overhead of reading a file from disk, parsing the tag definition, constructing an internal prototype, and adding it to the tag registry, a process that must otherwise be repeated for each tag every time a script which uses that tag runs. For a single tag, all of those actions happen in a few milliseconds, but with larger libraries, those milliseconds can add up to noticeable delays.

Despite the advantages, it’s not always convenient or even possible to place tags in these special folders. For instance, if your project is hosted in a shared hosting environment, you may not have access to the Lasso application folder. If you use a version control system such as Subversion, you’d have to maintain separate working copies in order to keep two directories in different locations in sync. Although LassoLibraries provides a mechanism for unloading tags programmatically, reloading custom tags defined in LassoStartup requires a restart of the Lasso Site and/or the entire Lasso Service. Generally speaking, it’s just more convenient to be able to keep all the files related to a single project within a single folder.

Pushing Tags Into The Global Namespace

The ideal setup, then, is one where the developer can both specify the location of tag libraries, and have them loaded into memory. Fortunately, the same mechanism that allows files in LassoLibraries to be loaded into memory on-demand can be used on other paths as well.

You may have noticed that Lasso’s tag names use a categorization system to organize sets of tags into groups. For example, the tags which deal with string manipulation are all prefixed by string_. These groups are called namespaces (namespaces in general | namespaces in Lasso) and they have a number of interesting uses. What’s important to understand in this context, however, is that Lasso’s namespaces are hierarchical, and all descend from a top-level namespace known as the global namespace. Tags defined within the global namespace remain resident in memory, and thanks to the [namespace_using] tag, we can push tag definitions into the global namespace programmatically.

For example, once the following code snippet runs, the [foo] tag will be available for use on any page until Lasso is restarted. Without the namespace tags, [foo] will only exist on the page in which it was defined.

[
	namespace_using(namespace_global);
		define_tag('foo');
			return('bar');
		/define_tag;
	/namespace_using;
]

A Flexible Loader For Managing Tag Libraries

The [tags_load] custom tag uses this technique to “watch” the given folder and make sure all the tags within it are loaded into memory. Basic usage is simply:

[tags_load('/path/to/mytags/')]

Optionally, you can specify what type of files to load by extension (the default is .inc), and a condition for whether or not to refresh all tags:

[
	tags_load(
		'/path/to/mytags/',
		-ext='.lasso',
		-refresh=(var_defined('reloadmytags') && $reloadmytags === true)
	);
]

When the tag loader is called, it will list every file in the given path which matches the given extension. It does not currently recurse into subdirectories, and will ignore files that begin with a period.

It will then iterate through that list, checking to see if a tag by that name already exists. For instance, if the file is “foo_bar.inc”, it will check for a tag called [foo_bar]. If none is found (or the refresh condition has been met), it will include the file using the [library] tag within a [protect] block. Any errors that occur when loading an individual file will be trapped and logged to Lasso’s built-in error database, and the tag loader will move on to the next file. Log entries made by the tag loader are prefixed with “[Tagloader]” like so:

[Tagloader] Error loading [foo_bar]: No permission.

The total number of successfully loaded tags for each path is stored in a global variable. On subsequent calls for that path, if the number of files to load matches the number of tags already loaded (and the refresh condition is not met), the rest of the routine is skipped. Thus, even if the tag loader is called on every page load, it’s usually only doing work if a new tag is added to the path, or a refresh is requested. When it’s finished, the results are logged to the error database:

[Tagloader] 113 of 115 tags loaded successfully.

In its current incarnation, it’s important that each file loaded with the tag loader contain a tag with the same name as the file. Otherwise, that file will be reloaded every time, regardless of whether it’s necessary. So, for instance, if you have all of the tags in the foo_ namespace in a single file called foo_library.inc, you’ll want to include a placeholder tag to register the library with the tag loader. I typically just define a simple tag which returns “Loaded” and place it at the end of the file (so that it only loads if there are no other errors):

[
	define_tag('foo_bar');
		...
	/define_tag;

	...

	define_tag('foo_library');
		return('Loaded');
	/define_tag;
]

The tag loader could be extended with more options for greater flexibility, but the current feature set has met my needs well for quite some time. Some ideas include:

  • Optionally accepting an array instead of a string for the path, so that multiple locations can be loaded via a single tag call.
  • Recursing subdirectories so that tags can be broken down into nested folders.
  • Replacing the -ext param with -match and/or -deny params which would accept arrays of conditions to match against filenames.
  • An additional -usenamespace param which could override or append to the default global namespace.

Hopefully a future version of Lasso will support custom paths to LassoLibraries and/or other methods of moving things in and out of memory. The namespace library which ships with Lasso is, itself, written in LassoScript, and could easily be modified to support custom paths. However, that would require maintaining a custom-compiled version of Startup.LassoApp everywhere you want to deploy your code — not a very portable solution. In the meantime, I think this is a satisfactory workaround.

[tags_load] can be downloaded at tagSwap.net


Spread the Love:
These icons link to social bookmarking sites where readers can share and discover new web pages.

  • DZone
  • Technorati
  • del.icio.us
  • StumbleUpon
  • TwitThis
  • Furl
  • Reddit
  • Digg
  • Slashdot
  • TailRank
  • Pownce
  • Ma.gnolia
  • Fark
  • BlinkList

1 comment:

  1. Marc Pope, 15. April 2008, 10:27

    Very interesting Jason. Thanks!

     

Write a comment: