I'm just new to lua and I'm trying to understand how modules work. But I'm trying to load a pre-existing module into a new script and run this script from the command line.
I have a file called main.lua module that looks something like this:
module (..., package.seeall)
-- Load libraries
require("luasql.postgres")
require("luasql.sqlite3")
local connect_to_db = function()
if not global_con then
env = assert (luasql.postgres())
global_con = assert (env:connect(databasename, databaseUser, databasepassword, databaseserver))
return true
else
return false
end
end
update_widget = function (parm1, parm2, parm3)
local connected = connect_to_db()
if connected then
-- do something else
return true
end
end -- end function.
I'm now trying to create a test script for this module. I have the following logic in a separate lua file:
package.path = '/usr/share/myapp/main.lua;'
local my_object = require("main")
print my_object.update_widget
I'm getting the following error when I try to run my test script:
attempt to call field 'postgres' (a table value)
The line it's failing on is in the connect_to_db() method where I try to create an environment variable:
env = assert (luasql.postgres())
I've modified the package.path
in my test script to match what is being used by main.lua. I did so by executing main.lua the "regular" way - driven by a web app - and dumping out the contents of package.path
to a log file.
I've copied the path from the log file and used it as the package.path
value in my test script... of course, I had to modify it by adding an additional entry - a path leading to main.lua.
But other than that, the package paths are the same.
I've added print statements inside main.lua to prove that it is getting into the update_widget method... and that it's just failing trying to create the postgres.
I've added the luasql.postgres library in the test script to see if that would help... like so:
package.path = '/var/x/appname/main.lua;'
local pgdb = require("luasql.posgres")
print(pgdb)
myenv = assert(lua.postgres()) -- fails
The test script also dies trying to create this object... I'm going to keep hunting around. It must be a problem with the paths... but I can't see the difference between the path thats created when loaded by the web app, vs. what I have in the test script. I'm going to use a DIFF tool to compare for now.
Any suggestions would be appreciated.
Thanks.
EDIT 1
I definitely think it's the path, although I can't see just yet what's wrong with here. I created yet another test script (let's call it test3).. but this time, I didn't explicitly set the path by assigning values to package.path. I just tried to include the luasql.postgres pacakge and use it the way the original test script does... and it works! So here's code that works:
luasql = require "luasql.postgres"
local myenv = assert (luasql.postgres())
print(myenv)
But this fails:
package.path = package.path .. ';/usr/share/myapp/main.lua'
luasql = require "luasql.postgres"
myenv = assert (luasql.postgres())
print(myenv)
Also to greatwolf's point, I tried from interactive mode in lua... and my code works just fine.
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> pgdb = require("luasql.postgres")
> print(pgdb)
table: 0x176cb228
> myenv=assert(luasql.postgres())
> print(myenv)
PostgreSQL environment (0x176c9d5c)
>
So... here's the package.path variable from interactive mode:
> print(package.path)
./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua
>
And here's the path from my original test script where it fails.
/usr/share/myapp/main.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua
It was a problem with the path. I'm still not sure exactly what was wrong, but I changed my logic in the test script from:
package.path = '/usr/share/myapp/main.lua;' -- resetting package path manually
package.path=package.path ..'./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua
'
to
package.path = package.path .. '/usr/share/myapp/main.lua' -- append to default path.
Now it finds the lua postgres package and lets me call the functions too
When Lua executes require "luasql.postgres"
it tries to find postgres.lua in luasql
folder anywhere in its LUA_PATH
, loads it, and executes it, thereby putting any non-local variables (including functions) appearing at module level of postgres.lua
in the global namespace. The main.lua
you show is requiring a module then using it as a function: luasql.postgres()
. This will only work if some trick is used. For instance, if the loaded module returns a function, you could use
fn = require 'luasql.postgres'
fn()
to execute the function returned.
Also, unlike python where you can import items from within a module, in Lua you can't. So it's not like postgres could be a function or callable table.
If you replace main.lua
with the following,
require 'luasql.postgres'
luasql.postgres()
and run your test script, or run main.lua
directly, you should get an error. If you don't, the module is definitely doing something special to support this use.
If you change your main.lua
as above and it doesn't work, then neither can you do
env = assert (luasql.postgres())
but you could do any of these, depending on what postgres.lua
does:
env = assert (luasql.postgres)
env = assert (someFunctionDefinedInPostgresModule)
env = assert (someFunctionDefinedInPostgresModule())
env = assert (luasql.postgres.someFunction)
env = assert (luasql.postgres.someFunction())
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