The Introduction to luajr
vignette shows you how to get started with calling Lua code from R. This
vignette shows you how to integrate Lua code into your R package, either
for internal use within the package or for direct use by your package’s
users.
Generally when you want to include Lua code in your package, it means that you want to include one or more functions written in Lua either internally in your package or as an outward-facing function for your users.
In Lua, the standard way to write a “module” – Lua’s equivalent of
R’s packages – is to put together a Lua script that returns a table,
where the table contains all the functions (or variables) that the
module should export. The script can also contain local functions or
variables that are accessible only within the module itself, and the
module is then loaded with Lua’s require
function. For
example, you may have a script mymodule.lua
containing this
Lua code:
local mymodule = {}
local fave_name = "Nick"
function mymodule.greet(name)
print("Hello, " .. name .. "!")
if name == fave_name then
print("Incidentally, that's a great name. Nice one.")
end
end
return mymodule
This returns a Lua table containing the function greet
,
which in turn makes use of the “private” (local) variable
fave_name
. In Lua, to use this module, you would write
something like:
Here, Lua’s require
looks for a script called
mymodule.lua
in a few places, including the current working
directory. For more information on Lua modules, see the Lua wiki and the Lua
manual.
You can use a similar technique to load functions from a Lua module
into R as follows. The recommendation is that you put
mymodule.lua
in your package directory under the
subdirectory inst/Lua
; then when your package is installed,
you can get the path to this module file using
system.file("Lua", "mymodule.lua", package = "myPackage")
,
where "myPackage"
is the name of your R package. Then
create a new R script in the R
subdirectory of your
package, called e.g. lua_exports.R
, with the following
code:
# Package Lua state
pkgL <- NULL
#' Greet the user
#'
#' This function prints a greeting to someone.
#'
#' @usage greet(name)
#' @param name The name of the person to be greeted.
#' @return Nothing.
#' @export
greet <- NULL
.onLoad <- function(libname, pkgname)
{
# Obtain the package namespace
ns <- asNamespace(pkgname)
# Create a Lua state for this package
assign("pkgL", luajr::lua_open(), envir = ns)
# Load the module in our package state
mymod <- luajr::lua(filename = system.file("Lua", "mymodule.lua",
package = "luajrtest"), L = pkgL)
# Add functions to the package namespace
assign("greet", luajr::lua_func(mymod$greet, "1", L = pkgL), envir = ns)
invisible()
}
There are three sections here. First, we create the variable
pkgL
which will hold the Lua state used by the functions in
our package.
Second, we create the variable greet
which is a
placeholder for the function greet
within the Lua module.
We document this object as though it was a function, with parameters
defined. Note that we provide an explicit @usage
tag
because roxygen can’t guess the parameters just by inspecting the
object’s declaration (which is NULL
at this point). We also
mark it for @export
.
Finally, we write the .onLoad
function which is
automatically called whenever our package is loaded. (See the R
documentation ?.onLoad
for details.) Within this function,
we create the Lua state in pkgL
, load the module as a list
mymod
, and then assign to the variable greet
using lua_func()
.
Note that mymod
is a list containing the member
greet
, which is an external pointer to the Lua function.
This pointer cannot be used directly as a function, but has to be passed
through lua_func()
so that we can specify the
argcode
argument which determines the function’s parameter
passing behaviour.
For each new function you want to import from your Lua module, you
will have to add a new “placeholder” (like greet
above),
(optionally) document the placeholder with details of how to call the
function, mark the function for @export
(if you want it to
be available to end users of the package), and use assign
to actually load the corresponding function into place.