I am implementing a plugin system with Lua scripts for an application. Basically it will allow the users to extend the functionality by defining one or more functions in Lua. The plugin function will be called in response to an application event.
Are there some good open source plugin frameworks in Lua that can serve as a model?
In particular I wonder what is the best way to pass parameters to the plugin and receive the returned values, in a way that is both flexible and easy to use for the plugin writers.
Just to clarify, I am interested in the design of the API from the point of view of the script programming in Lua, not from the point of view of the hosting application.
Any other advice or best practices related to the design of a plugin system in Lua will be appreciated.
Lua's first-class functions make this kind of thing so simple that I think you won't find much in the way of frameworks. Remember that Lua's mantra is to provide minimal mechanism and let individual programmers work out policy for themselves.
Your question is very general, but here's what I recommend for your API:
A single plugin should be represented by a single Lua table (just as a Lua module is represented by a single table).
The fields of the table should contain operations or callbacks of the table.
Shared state should not be stored in the table; it should be stored in local variables of the code that creates the table, e.g.,
local initialized = false
return {
init = function(self, t) ... ; initialized = true end,
something_else = function (self, t)
if not initialized then error(...) end
...
end,
...
}
You'll also see that I recommend all plugin operations use the same interface:
The reason for passing and returning a single table instead of positional results is that it will help you keep code compatible as interfaces evolve.
In summary, use tables and first-class functions aggressively, and protect your plugin's private state.
The plugin function will be called in response to an application event.
That suggests the observer pattern. For example, if your app has two events, 'foo' and 'bar', you could write something like:
HostApp.listeners = {
foo = {},
bar = {},
}
function HostApp:addListener(event, listener)
table.insert(self.listeners[event], listener)
end
function HostApp:notifyListeners(event, ...)
for _,listener in pairs(self.listeners[event]) do
listener(...)
end
end
Then when the foo
event happens:
self:notifyListeners('foo', 'apple', 'donut')
A client (e.g. a plugin) interested in the foo
event would just register a listener for it:
HostApp:addListener('foo', function(...)
print('foo happened!', ...)
end)
Extend to suit your needs.
In particular I wonder what is the best way to pass parameters to the plugin and receive the returned values
The plugin just supples you a function to call. You can pass any parameters you want to it, and process it's return values however you wish.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With