【问题标题】:lua module is not loading librarieslua 模块没有加载库
【发布时间】:2014-07-21 20:38:48
【问题描述】:

背景资料:

我刚接触 lua,我正在尝试了解模块的工作原理。但我正在尝试将预先存在的模块加载到新脚本中并从命令行运行此脚本。

代码:

我有一个名为 main.lua 模块的文件,看起来像这样:

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.

我现在正在尝试为此模块创建一个测试脚本。我在一个单独的 lua 文件中有以下逻辑:

package.path = '/usr/share/myapp/main.lua;'
local my_object = require("main")

print my_object.update_widget

问题:

当我尝试运行我的测试脚本时遇到以下错误:

attempt to call field 'postgres' (a table value)

它失败的那一行是在我尝试创建环境变量的 connect_to_db() 方法中:

env = assert (luasql.postgres())

到目前为止我已经尝试过什么:

  1. 我已经修改了我的测试脚本中的package.path 以匹配 main.lua 使用的内容。我通过以“常规”方式执行 main.lua(由 Web 应用程序驱动)并将package.path 的内容转储到日志文件中来做到这一点。 我已经从日志文件中复制了路径,并将其用作我的测试脚本中的package.path 值......当然,我必须通过添加一个额外的条目来修改它 - 一个通向 main.lua 的路径。
    但除此之外,包路径是相同的。

  2. 我在 main.lua 中添加了 print 语句,以证明它正在进入 update_widget 方法...并且它只是尝试创建 postgres 失败。

  3. 我已经在测试脚本中添加了 luasql.postgres 库,看看是否有帮助...就像这样:

    package.path = '/var/x/appname/main.lua;'
    
    local pgdb = require("luasql.posgres")
    
    print(pgdb)
    myenv = assert(lua.postgres()) -- fails
    

测试脚本也在试图创建这个对象时死掉了……我会继续四处寻找。这一定是路径的问题......但我看不出由网络应用程序加载时创建的路径与我在测试脚本中所拥有的路径之间的区别。 我现在将使用 DIFF 工具进行比较。

任何建议将不胜感激。

谢谢。

编辑 1

我绝对认为这是路径,尽管我现在还看不出这里有什么问题。 我创建了另一个测试脚本(我们称之为 test3)。但是这一次,我没有通过将值分配给 package.path 来明确设置路径。 我只是尝试包含 luasql.postgres pacakge 并按照原始测试脚本的方式使用它......它可以工作! 所以这是有效的代码:

luasql = require "luasql.postgres"
local myenv = assert (luasql.postgres())
print(myenv)

但这失败了:

package.path = package.path .. ';/usr/share/myapp/main.lua'

luasql = require "luasql.postgres"
myenv = assert (luasql.postgres())
print(myenv)

另外,greatwolf 的观点是,我在 lua 中尝试了交互模式......并且我的代码工作得很好。

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

所以...这是交互模式下的 package.path 变量:

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

这是我原来的测试脚本失败的路径。

/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/分享/lua/5.1/?/init.lua

【问题讨论】:

  • 你能通过一个 lua 解释器或 repl 来测试一下,看看 luasql.postgres 返回了什么?根据github repopostgres本身应该是一个函数。
  • greatwolf,请看我的编辑 1

标签: module lua


【解决方案1】:

路径有问题。我仍然不确定到底出了什么问题,但我在测试脚本中更改了我的逻辑:

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

'

package.path = package.path .. '/usr/share/myapp/main.lua' -- append to default path.

现在它找到了 lua postgres 包并让我也调用函数

【讨论】:

  • 出于好奇,如果您尝试像这样package.path = '/usr/share/myapp/main.lua;' .. package.path 前置会怎样?
  • 经过一些测试,正在发生的事情变得越来越清楚。 require 按从左到右的顺序考虑 package.path。对于每个给定的路径,它会检查文件是否存在,如果存在则使用该文件,并且该模块不考虑其余路径。
  • 对于/usr/share/myapp/main.lua;,因为它没有?,只要你require 一个模块,lua 就会逐字搜索该文件。换句话说,像这样指定main.lua 的路径充当“包罗万象”的默认值。由于它首先出现在所有其他路径之前,因此最终会在模块加载期间使用。
【解决方案2】:

当 Lua 执行 require "luasql.postgres" 时,它会尝试在 luasql 文件夹中的 luasql 文件夹中的任何位置找到 postgres.lua,加载并执行它,从而将出现在模块级别的任何非局部变量(包括函数)放入全局命名空间中的postgres.lua。您展示的main.lua 需要一个模块,然后将其用作函数:luasql.postgres()。这仅在使用某些技巧时才有效。例如,如果加载的模块返回一个函数,你可以使用

fn = require 'luasql.postgres'
fn()

执行返回的函数。

此外,与 python 不同,您可以从模块中导入项目,而在 Lua 中则不能。所以它不像 postgres 可以是一个函数或可调用表。

如果您将main.lua 替换为以下内容,

require 'luasql.postgres'
luasql.postgres()

然后运行你的测试脚本,或者直接运行main.lua,你应该得到一个错误。如果你不这样做,该模块肯定会做一些特别的事情来支持这种使用。

如果你像上面那样更改了main.lua,但它不起作用,那么你也不能这样做

env = assert (luasql.postgres())

但是你可以做任何这些,这取决于postgres.lua 做了什么:

env = assert (luasql.postgres)
env = assert (someFunctionDefinedInPostgresModule)
env = assert (someFunctionDefinedInPostgresModule())
env = assert (luasql.postgres.someFunction)
env = assert (luasql.postgres.someFunction())

【讨论】:

  • 投反对票的人至少可以发表评论说明原因吗?我很困惑这怎么会不是答案,我很想知道我错过了什么。
  • Schollii,我投了反对票,因为你不能调用 luasql.postgres() 的评论。这是一个合法的函数调用。如果我误解了您的评论,请告诉我!我很乐意撤消我的反对票!
  • 另外,我知道模块只是表......但我对您关于没有“__call”的评论很感兴趣。您能否进一步解释一下或将我指向一篇文章以了解更多信息?谢谢。
  • @dot 我不明白它是如何合法的,除非 postgres.lua 正在做一些特别的事情。我已经更新了我的答案,如果你能尝试一下,那将不胜感激。
  • @dot 我刚刚查看了您的编辑,并且有效的代码与您在顶部的代码不同:在您的编辑中,您有 luasql=require 'luasql.postgres',在这种情况下当然是可以工作,这甚至是我在回答中解释的事情之一。所以我觉得在这里投反对票是不合适的。
猜你喜欢
  • 2011-08-19
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 2017-02-07
  • 2015-08-15
  • 2015-09-11
  • 2016-08-04
  • 2016-01-10
相关资源
最近更新 更多