What is a Plug-In Architecture Application Framework? According to this C++ article on Code Guru about Plug-in Architecture Framework for Beginners:
Simply speaking, it is a framework that will allow a program to “look for” add-in functionality at startup, and then allow that plug-in to cooperate with itself.
Famous examples are Eclipse, Netbeans, Visual Studio, Microsoft Office VSTO, … which can be extended by addins crafted by external developers. This kind of Architecture allows to build an Ecosystem from Third Parties. This Extensibility capability is a Key for Software Business Success. Rebol 3 will finally also take this path.
So how can we implement such kind of architecture in general and then in Rebol ? The general steps are:
1. Program starts up and will look up for the plugins in a given directory.
2. Program calls some predefined methods on each proper plugin found.
3. Program then store the name of each Plugin and keeps a reference to it so that the functions in this plug-in can be called later.
4. During the course of running the program, the user selects one of the menu items, and one of a set of clearly defined standard methods are invoked.
Let’s take an example given in this Dr Dobbs Article for C#:

The example application contains two plug-ins: CustomerPlug and EmployeePlug.
For the Program or Host Application to be able to display the menu “Customers” and “Employees”, it must be able to read some property attached to each Plugin. Of course the name of the property must be known at design time by the Host whereas the value of the property (”Employees” or “Customers”) could only be known at runtime. In the article above, the design choice was to implement them as C# custom attributes so that the module would be self-describing:
[PlugDisplayName("Employees")]
[PlugDescription("This plug is for managing employee data")]
In Rebol, such design values or meta-datas can be set in script header like this:
Rebol[
PlugDisplayName: "Employees"
PlugDescription: "This plug is for managing employee data"
]
It’s much easier than in .NET (which requires to create a class derived from System.Attribute) but the trick part is to get the values at runtime. So add Employee.Context object or context (as told you - you’d better read previous lesson on “How to build a Simple Knowledge Management System with the Rebol Help System” - Context is a shortcut for Make Object! and the “.” part in Employee.Context is not mandatory, just a personal convention):
Rebol[
PlugDisplayName: "Employees"
PlugDescription: "This plug is for managing employee data"
]
Employee.Context: Context [
getPlugDisplayName: func[][
system/script/header/PlugDisplayName
]
getPlugDescription: func[][
system/script/header/PlugDescription
]
]
save the file above (employee.r) for example in rebol install subdirectory “test”. Do it manually in your file Explorer or copy the code above into clipboard then type this in Rebol Console:
make-dir %test
write %test/employee.r read clipboard://
You can now run the script:
do %test/employee.r
and guess getting the property values the Employee Plugin Object should be as easy as:
Employee.Context/getPlugDisplayName
Employee.Context/getPlugDescription
Bad guess, this returns a bunch of insanities!
>> Employee.Context/getPlugDisplayName
** Script Error: Cannot use path on none! value
** Where: getPlugDisplayName
** Near: system/script/header/PlugDisplayName
>> Employee.Context/getPlugDescription
** Script Error: Cannot use path on none! value
** Where: getPlugDescription
** Near: system/script/header/PlugDescription
To see why, modify your script by adding these 4 lines below Rebol header (Rebol []):
print ["system/script/header/PlugDisplayName: " system/script/header/PlugDisplayName]
print ["system/script/header/PlugDescription: " system/script/header/PlugDescription]
print ["system/script/path: " system/script/path]
input
to get this:
Rebol[
PlugDisplayName: "Employees"
PlugDescription: "This plug is for managing employee data"
]
print ["system/script/header/PlugDisplayName: " system/script/header/PlugDisplayName]
print ["system/script/header/PlugDescription: " system/script/header/PlugDescription]
print ["system/script/path: " system/script/path]
input
Employee.Context: Context [
getPlugDisplayName: func[][
system/script/header/PlugDisplayName
]
getPlugDescription: func[][
system/script/header/PlugDescription
]
]
When executing %test/employee.r with do again, the result should be:
>> do %test/employee.r
Script: "Untitled" (none)
system/script/header/PlugDisplayName: Employees
system/script/header/PlugDescription: This plug is for managing employee data
system/script/path: /C/Rebol/test/

Note this line:
Script: "Untitled" (none)
Rebol uses these attributes in header to display them:
Title: "Employee Plugin Module"
Date: 1-Nov-2009
So you can optionally add these two lines. It would also be usefull that we store the File name (for example for tracing the source of a bug in the plugin once the application has been deployed) so let’s add in header (% is Rebol’s decorator for File’s type):
File: %employee.r
Rebol’s Woe: it’s a pity that Rebol doesn’t provide any system variable which gives the current script executing but only the current path of the script (system/script/path). system/options/script does only give the full script name and path of the first script passed on dos command line to Rebol executable NOT if it is executed in console and NOT the full path for subsequent scripts called by the very first one.
Our full header now becomes:
Rebol[
Title: "Employee Plugin"
Date: 1-Nov-2009
File: %employee.r
PlugDisplayName: "Employees"
PlugDescription: "This plug is for managing employee data"
]
So let’s come back to our question: why can’t Rebol’s Console display Plugin’s header informations ? Well AFTER the execution of employee.r, type this in Console:
print ["system/script/path: " system/script/path]
Then compare the result AFTER script execution :
>> print ["system/script/path: " system/script/path]
system/script/path: /C/Rebol/
to what the result DURING script execution which was (copied from above):
system/script/path: /C/Rebol/test/
As you can see the script path is different once we get out of the script execution context. The question is then how can we persist this volatile context ? By using some kind of static variable. Indeed, we can profit from the fact that during Object creation, Rebol assigns values to its properties for their initialization so let’s add these two lines to Employee.Context:
_PlugDisplayName: system/script/header/PlugDisplayName
_PlugDescription: system/script/header/PlugDescription
And then modify the method accessors like this:
getPlugDisplayName: func[][
_PlugDisplayName
]
getPlugDescription: func[][
_PlugDescription
]
You can also use a shortcut for func when there is no argument passing and rewrite the code like this:
getPlugDisplayName: does[ _PlugDisplayName]
getPlugDescription: does[_PlugDescription]
or for simple accessors
PlugDisplayName: get '_PlugDisplayName
PlugDescription: get '_PlugDescription
and ultimately simpler (since we are inside the Object context) just
PlugDisplayName: _PlugDisplayName
PlugDescription: _PlugDescription
Save the whole script below to %test/employee.r once again:
Rebol[
Title: "Employee Plugin"
Date: 1-Nov-2009
File: %employee.r
PlugDisplayName: "Employees"
PlugDescription: "This plug is for managing employee data"
]
Employee.Context: Context [
_PlugDisplayName: system/script/header/PlugDisplayName
_PlugDescription: system/script/header/PlugDescription
PlugDisplayName: _PlugDisplayName
PlugDescription: _PlugDescription
]
We can now get the Plugin Infos from outside of its execution context:
>> do %test/employee.r
Script: "Employee Plugin" (1-Nov-2009)
>> employee.context/PlugDisplayName
== "Employees"
>> employee.context/PlugDescription
== "This plug is for managing employee data"
To be continued in Part II soon…
















No comments yet.