Modules

Module allows you to build reusable scripts. Each module is usually packaged as a separate JAR file, which should be added to CLASSPATH or located in the directory ${PNUTS_HOME}/modules/.

This section explains how to write a module. For the concept of modules, please refer to "The Pnuts Language".

Steps to make a module

Modules can be written by either Pnuts, Java, or both. This section explains how to write a module in Pnuts. For information on module in Java, see "Implementing a Module in Java".

  1. Name the corresponding package. e.g. "org.acme.util"
    The module will be identified by this name.
  2. Edit the initialization script. "org/acme/util/init.pnut" in this case. When this script is executed, the current package is set to "org.acme.util". Once this script is loaded, the functions in the module should be available.
  3. If the module depends on other module, register the module with use() after resetting the module list in org/acme/util/init.pnut file. For instance, if org.acme.util depends on pnuts.lib module, it would be like:
    use(null)
    use("pnuts.lib")
    
    package("org.acme.util")
    
    function hello(){
      println("hello")
    }
    
  4. Archives the script files into a JAR file when you distribute the module.

Autoloading

When the module defines a lot of functions, autoload() can be used to separate the scripts into smaller script files and defer the script loading until a symbol in a script is first used.

autoload("play", "org/acme/util/cdplayer")
org/acme/util/init.pnut
> use("org.acme.util")
...
> play("something")
...

Autoloaded scripts are executed with the module list that was in use when autoload() was called.

Exporting Symbols

By default, symbols that references a function of the name are automatically exported. To export arbitrary objects which would not be exported by default, or to prevent symbols that would exported from being exported, Package.export() method call is needed to define exported symbols.

pkg = package()
pkg.export("play")

Note that exported symbols must be defined or autoloaded when Package.export() is called.

When implementing a module in Java, pnuts.ext.ModuleBase class provides a simpler way. Symbols can be initialized and exported at the same time as follows.

EXPORTS.play = <object>

Module Initialization in Java

Since it is possible to implement loadable class in Java, module initialization can also be done in Java.

See "Implementing Loadable Class in Java" and "Implementing a Module in Java".

Module Version Information

Module Version Information identifies a particular specification and a particular build number of a module. The version information can be used for defining module dependency. Also, bug reports would be more helpful with the information.

To add a module version information, define 'Package Version ID in the JAR file.

For instance, prepare the following manifest file. Specification-Version and Implementation-Version defines the specification and the implementation version of the module, respectively.

Manifest-version: 1.0
Name: org.acme.util
Specification-Title: Acme Library Functions
Specification-Version: 1.0
Specification-Vendor: Foo Bar, Inc.
Implementation-Title: org.acme.util
Implementation-Version: 20020704000000
Implementation-Vendor: Foo Bar, Inc.

To add the manifest file to the JAR file, specify the file with the m option of jar command.

% jar cfm module.jar manifest.mf *

To retrieve the version information of a module, use versionInfo() or manifest().

Dynamic Modules

Normal modules that we have been discussing above must be implemented before execution and identified by their names. Dynamic module is different in that it is defined on-the-fly without executing an initialization script and does not have to be identified by the name.

Here are the steps to create a dynamic module:

  1. Create a pnuts.lang.Package object using createPackage(), etc.
  2. Define names in the Package
  3. Call use() specifying the Package object
  4. Call Package.export() method for each name to be exported

p = createPackage()
p.add = function (x, y) x + y
use(p)
p.export("add")

add(2, 3) ==> 5