Lua.API behaviour (Lua v0.3.0)

View Source

Defines the Behaviour for defining a Lua API

To create a module that exports functions to the global scope

defmodule MyAPI do
  use Lua.API

  # Can be called via `print("hi")` in lua
  deflua print(msg), do: IO.puts msg
end

Optionally, you can provide a scope

defmodule SpecificAPI do
  use Lua.API, scope: "namespace.domain"

  # Can be called via `namespace.domain.foo(5)` in lua
  deflua foo(v), do: v
end

You can access Lua state

defmodule State do
  use Lua.API

  deflua bar(name), state do
    # Pull's the value of `number` out of state
    val = Lua.get!(state, [:number])

    2 * val
  end
end

Regular functions are not exported

defmodule SpecificAPI do
  use Lua.API

  # Won't be exposed
  def baz(v), do: v
end

Installing an API

A Lua.API can provide an optional install/3 callback, which can run arbitrary Lua code or change the Lua state in any way.

An install/3 callback takes a Lua.t/0 and should either return a Lua script to be evaluated, a Lua.Chunk.t/0, or return a new Lua.t/0

defmodule WithInstall do
  use Lua.API, scope: "install"

  @impl Lua.API
  def install(lua, _scope, _data) do
    Lua.set!(lua, [:foo], "bar")
  end
end

If you don't need to write Elixir, but want to execute some Lua to setup global variables, modify state, or expose some additonal APIs, you can simply return a Lua chunk directly using the c modifier on Lua.sigil_LUA/2

defmodule WithLua do
  use Lua.API, scope: "whoa"

  import Lua

  @impl Lua.API
  def install(_lua, _scope, _data) do
    ~LUA[print("Hello at install time!")]c
  end
end

Guards

When doing use Lua.API, we also import the guards documented in this API. This can be useful for having different function heads that match on encoded values. E.g.

deflua say_type(value) when is_table(value), do: "table"
deflua say_type(value) when is_userdata(value), do: "table"

Keep in mind that if you want to work with values passed to deflua functions, they still need to be decoded first.

Summary

Functions

Defines a function that can be exposed in Lua through Lua.load_api/3

Is the value a reference to an Erlang / Elixir function?

Is the value a reference to a Lua function?

Is the value a reference to an Erlang / Elixir mfa?

Is the value a reference to a Lua table?

Is the value a reference to userdata?

Raises a runtime exception inside an API function, displaying contextual information about where the exception was raised.

Types

scope_def()

@type scope_def() :: [String.t()]

Callbacks

install(t, scope_def, any)

(optional)
@callback install(Lua.t(), scope_def(), any()) :: Lua.t() | Lua.Chunk.t() | String.t()

scope()

@callback scope() :: scope_def()

Functions

deflua(fa, rest)

(macro)

See deflua/3

deflua(fa, state, rest)

(macro)

Defines a function that can be exposed in Lua through Lua.load_api/3

deflua add_two(number) when is_number(number) do
  number + 2
end

Accessing state

Sometimes, you may want to access or modify the Lua environment in a deflua. This can be done by using the following syntax

deflua get_value(key), state do
  # Access the Lua environment
  Lua.get!(lua, [key])
end

To modify and return new state, return a tuple

deflua set_value(key, value), state do
  # Return nothing but modify the state
  {[], Lua.set!(lua, [key])}
end

Using guards

Since deflua uses non-conventional syntax to receive the current state, make sure you specifiy the when clause and guards first, e.g.

deflua set_int(key, value) when is_integer(value), state do
  # Return nothing but modify the state
  {[], Lua.set!(lua, [key])}
end

Specifyiing the when cluase and guards last will result in a confusing error message.

Variadic functions

Technically, all Lua functions are variadic, which means they can receive a variable number of arguments. As a convenience, Lua applies your arguments to deflua functions so that they can be written in idiomatic Elixir.

If you need to handle variadic arguments, annotate the function with the @variadic module attribute.

@variadic true
deflua print(args) do
  IO.puts(Enum.join(args, " "))
end

@variadic behavior

When using the @variadic attribute, note that it is per-function. Lua will reset this attribute after every function definition, so there is no need to manually reset it yourself

is_erl_func(record)

(macro)

Is the value a reference to an Erlang / Elixir function?

is_lua_func(record)

(macro)

Is the value a reference to a Lua function?

is_mfa(record)

(macro)

Is the value a reference to an Erlang / Elixir mfa?

is_table(record)

(macro)

Is the value a reference to a Lua table?

is_userdata(record)

(macro)

Is the value a reference to userdata?

runtime_exception!(message)

(macro)

Raises a runtime exception inside an API function, displaying contextual information about where the exception was raised.