Starting with 4.2, Alfons provides an API to embed Alfons functionality in your programs.
- Alfons API
You need to install the development rock instead of the upstream one. For that, follow these steps:
# Clone project
$ git clone https://github.com/daelvn/alfons.git
# Install dependencies
$ luarocks install moonscript
$ luarocks install rockbuild
$ luarocks install amalg
# Create the runnable file
$ alfons produce
# Build the rockspec locally
$ rockbuild -f rock-dev.yml -m --delete 4.4 # or change the version if you want
If there is enough demand, I'll upload the dev rockspec to LuaRocks with every release in form of an alfons-extra
package or similar.
The rock also installs optional dependencies for Alfons like http
or linotify
. If you do not wish to install them, feel free to edit the development rockframe.
alfons.env
provides the default environment table (ENVIRONMENT
), which does not include the functions in alfons.provide
, and a function called loadEnv
which takes a string of Lua code and a table, and will load the Lua code with the table as its environment. This function uses different mechanisms on different versions, due to loadstring
being deprecated.
Contains a generic function readFile
that reads a file content and loads it, an alias readLua
, and then readMoon
which compiles MoonScript content from a file before returning the Lua value, and readTeal
for a Teal equivalent.
Contains a single function, getopt
, which takes a list of arguments, and returns a table of parsed options.
See arguments.md
alfons.look
introduces a require
-style module lookup function that instead of running them and returning its results, it returns the contents of the file. It returns a table with a function makeLook
, which takes a package path (defaults to package.path
) and returns a lookup function. This function takes a module name and returns the contents of the file found, or nil
and an error otherwise.
provide
includes all the helper functions used in Taskfiles.
See Functions.
Returns a function (not a table). The function is simply a reimplementation of setfenv for Lua 5.2+
Returns a table with a field VERSION
which contains the current Alfons version.
Contains functions to generate help messages, including a column formatter.
Contains the comment parser for documenting Taskfiles.
Provides the main functions required to run a Taskfile.
initEnv
takes a run
function (see below), a base environment (defaults to alfons.env
's ENVIRONMENT
), a private global environment table (referred to as genv
), and a module name (defaults to main
). It returns an environment ready to use in Taskfiles. This function is internal and should not really be used, so I will not explain it.
runString
takes:
- either a string of Lua code or a module to perform lookup on (using
alfons.look
) as its first argument. - Then it takes a base environment (defaults to
alfons.env
'sENVIRONMENT
) - A boolean flag
runAlways
which determines whether thealways
task should be run or not. - A numeric
child
argument (actually unused) that determines how deep into the loaded Taskfiles you are (defaults to0
for the main file and increments for children taskfiles whenload
is called). - A
genv
, where the tasks for all modules are neatly stored. Although you can set a starting value for this table (defaults to an empty one), you will not be able to access it again (unless you create the table before passing it and store the reference). - A reverse queue
rqueue
that determines the order in which thedefault
,teardown
andfinalize
tasks should be run. This queue should be reversed before running each task in it. - A boolean value that determines whether to pretty-print errors or not.
It loads the contents of the Taskfile without executing it.
It returns either the environment table (for accessing tasks and store
) if it was already loaded or a function for running the Taskfile with arguments. These arguments will be processed by alfons.getopt
.
The function returned adds the args
function to the environment, local to each taskfile. It also adds the function uses
, for checking the argument list for commands.
It runs the Alfons file and loads all tasks to env.tasks
, where env
represents the environment table. It wraps all tasks in a run
function, which essentially pre-passes the name of the task (@name
), and the task itself (@task
).
It also adds the load
function to load taskfiles inside taskfiles.
It runs the always
task if the runAlways
argument is enabled (defaults to true
).
Then it adds a trigger to run the default
and finalize
tasks.
Finally, it returns the environment of the taskfile. It looks something like this, irrelevant parts skipped for convenience. These are the only things you will need to know.
env = {
tasks = {}, -- table to access all tasks
store = {}, -- global storage
finalize = function() end -- calls the `default` and `finalize` tasks.
}
In the last section we mentioned genv
and how you could initially set its value but not access it later. Lets look at its structure.
genv = {
["main"] = {} -- this is main's environment
["fetch"] = {} -- environment for a subtaskfile
}
<metatable> = {
store = {} -- global storage is here
}
Task lookup in the env.tasks
table happens by looking at all the loaded taskfiles in genv
. By adding more fields to genv
initially, you can pre-load taskfiles without really loading them.
The global storage is in genv
's metatable, which you can also preload values at.
bin/alfons.moon
is written in just a few lines of code, let's write a simplified version of it:
First, lets get the list of tasks that we should run:
import getopt from require "alfons.getopt"
args = getopt {...}
The official program supports custom taskfile locations, but for the sake of simplicity, we'll skip that and only allow loading Alfons.lua
.
import readLua from require "alfons.file"
content, contentErr = readLua "Alfons.lua"
unless content then error contentErr
This is a straightforward step to get the environment.
import runString from require "alfons.init"
alfons, alfonsErr = runString content
unless alfons then error alfonsErr
env = alfons ...
Now we need to run the tasks we have been asked for, with their respective arguments, and run teardown
after each of them.
for command in *args.commands
env.tasks[command] args[command] if env.tasks[command]
(rawget env.tasks, "teardown") if rawget env.tasks, "teardown"
Finally, simply call the trigger to run default
tasks if no other task in each taskfile has been run, and finalize
tasks.
env.finalize!
And just like that, we have implemented Alfons! It is a pretty simple tool, despite the looks of it, really.