Add support to hook into require
Hi!
I have this app in which users can provide their lua scripts. I don't have those in the filesystem so I need to intercept require calls somehow (I will be returning them from the database or as chunks from ETS).
An option is to override require itself, but I think that adding a searcher after the preload one is more lua-esque.
In case it's better to just override require, how would yo approach returning preloaded modules?
Basically I don't know if luerl provides a mechanism to hook into require and if we can wrap it in this lib.
Thanks!
Alternatively, creating a separate function (ie. import) that works like require but allows to return modules, that's also fine.
This works, I can return anything from the imported script:
defmodule ErluaTest do
use ExUnit.Case
doctest Erlua
import Lua
defmodule Custom do
@imports %{
"custom" => ~LUA"""
return {
greet = function(name)
print("Printed hello, " .. name)
end,
template = function(name)
return "Templating hello, " .. name
end
}
"""
}
def import([], [path], state) do
{:ok, ret, state} = Luerl.New.do(state, @imports[path])
{ret, state}
end
end
test "Loading lua scripts dynamically" do
entrypoint = ~LUA"""
print("I am the entrypoint")
local imported = import("custom")
imported.greet("world")
print("gonna print a rendered template: " .. imported.template("world"))
"""
result =
Lua.new()
|> Lua.set!([:import], {Custom, :import, []})
|> Lua.eval!(entrypoint)
end
end
But as you can see I had to use Luerl do, you can't use eval! there.
Also, conceptually I don't know if the import function should reuse the state or use a blank slate. I like the latter to avoid unexpected side effects.
Hello @Papipo, I'm still thinking about ways to do this. I'll get back to you
is there still interest on this?
If you want to hook into the lua require you have to write a searcher and loader.
I did it here, feel free to copy.
There you can do stuff like require([[luerl_ext_json]]) and get a table returned by the table/2 of the registered beam module.
I will look into this, thanks!
I would be down to writing a PR for this, assuming I understand the issue correctly.
Just to be clear, you are looking for a function like setup_require(lua_vm, [ api_module ]) :: lua_vm, where an api_module is an elixir module implementing the Lua.Api behaviour, correct?
defmodule ExampleAPI do
use Lua.API, scope: "example.api"
deflua square(name), _state do
square * square
end
end
soo it can be used in lua
local example = require("example.api")
return example.square(2) -- return 4
https://hexdocs.pm/lua/Lua.html#load_api/3 already exists for that purpose. I believe the ask is a bit different
Imagine an app in which users can define their own lua modules. Those are parsed and stored as chunks somewhere (in the db as binary, on ETS, doesn't matter).
When require is called, we can hook into it and try to find what they want to load and return that. Perhaps if we don't find it, then we can fallback to regular require (which would hit the filesystem). But there aren't Elixir modules involved here.
yeah, you can already do that, there is no need to change this project for that, imo.
See package.searchers in lua for how to.
@davydog187 if what iggi says is true then this can be closed.
There's quite a bit of documentation I'd like to add on this topic. So ill close when that is done @Papipo