Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lua module is not loading libraries

Tags:

module

lua

Background Information:

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.

Code:

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

Problem:

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())

What I've Tried so far:

  1. 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.

  2. 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.

  3. 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

like image 881
dot Avatar asked Dec 17 '13 21:12

dot


2 Answers

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

like image 164
dot Avatar answered Oct 21 '22 10:10

dot


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())
like image 26
Oliver Avatar answered Oct 21 '22 09:10

Oliver