lua icon indicating copy to clipboard operation
lua copied to clipboard

Add support to hook into require

Open Papipo opened this issue 1 year ago • 11 comments

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!

Papipo avatar Aug 07 '24 13:08 Papipo

Alternatively, creating a separate function (ie. import) that works like require but allows to return modules, that's also fine.

Papipo avatar Aug 08 '24 16:08 Papipo

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.

Papipo avatar Aug 09 '24 10:08 Papipo

Hello @Papipo, I'm still thinking about ways to do this. I'll get back to you

davydog187 avatar Aug 23 '24 16:08 davydog187

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.

iggi42 avatar Jun 12 '25 16:06 iggi42

I will look into this, thanks!

davydog187 avatar Jun 13 '25 19:06 davydog187

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

iggi42 avatar Jun 22 '25 06:06 iggi42

https://hexdocs.pm/lua/Lua.html#load_api/3 already exists for that purpose. I believe the ask is a bit different

davydog187 avatar Jun 22 '25 18:06 davydog187

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.

Papipo avatar Jun 23 '25 06:06 Papipo

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.

iggi42 avatar Jun 23 '25 15:06 iggi42

@davydog187 if what iggi says is true then this can be closed.

Papipo avatar Jul 03 '25 08:07 Papipo

There's quite a bit of documentation I'd like to add on this topic. So ill close when that is done @Papipo

davydog187 avatar Jul 03 '25 10:07 davydog187