Calling functions on require()d modules in Lua gives me "attempt to index local 'x' (a boolean value)" - module

I've read PIL and the ModulesTutorial on creating modules but I'm having trouble require()ing them correctly.
Here is my setup:
-- File ./lib/3rdparty/set.lua
local ipairs = ipairs
module( "set" )
function newSet (t)
local set = {}
for _, l in ipairs(t) do set[l] = true end
return set
end
And:
-- File ./snowplow.lua
local set = require( "lib.3rdparty.set" )
module( "snowplow" )
local SUPPORTED_PLATFORMS = set.newSet { "pc", "tv", "mob", "con", "iot" }
Then if I run snowplow.lua:
lua: snowplow.lua:4: attempt to index local 'set' (a boolean value)
stack traceback:
snowplow.lua:4: in main chunk
[C]: ?
What am I doing wrong in my module definition - what is the boolean exactly? Also, if I append a return _M; at the bottom of my set.lua, then everything starts working - why?

true is usually returned by require if module function is not used inside module and module code doesn't return a value.
But anyway it seems strange.
-- file m0.lua
module'm0'
--file dir1\m1.lua
module'm1'
--file test.lua
print(require'm0')
print(m0)
print(require'dir1.m1')
print(m1)
for k,v in pairs(package.loaded) do
if k:match'm%d' then print(k, v) end
end
--output
table: 0036C8C8
table: 0036C8C8
true
table: 0036B6B0
m0 table: 0036C8C8
m1 table: 0036B6B0
dir1.m1 true
So, you can simply use global variable set instead of local set assigned a value returned by require.
UPD :
It is recommended to avoid using module function and always return your table at the end of your module. In that case the whole picture is just fine:
-- file m0.lua
return 'string0'
--file dir1\m1.lua
return 'string1'
--file test.lua
print(require'm0')
print(m0)
print(require'dir1.m1')
print(m1)
for k,v in pairs(package.loaded) do
if k:match'm%d' then print(k, v) end
end
--output
string0
nil
string1
nil
m0 string0
dir1.m1 string1
UPD2 :
Problem disappears if you replace module( "set" ) with module('lib.3rdparty.set').
So, each module must remember its relative path.
Now you could access it either by calling require'lib.3rdparty.set' or by reading global variable lib.3rdparty.set - the result would be the same.

require("lib.moduleName")
local moduleName = moduleName
I'm not sure why Lua returns a boolean when you require a module on a different directory, but it seems the module is correctly set on the the global variable. So I simply used that and put it on a local variable with the same name.

Related

lua variable type nil even though i just assigned it

I have a part of a lua script here:
local cmp = require("component")
local r = cmp.br_reactor
local e = require("event")
local unicode = require ("unicode")
local exit = false
local buffersize = 10000000
local last_tick_percent = 1
print(type(last_tick_percent))
function stored_energy()
local rf_stored = r.getEnergyStored()
local rf_percent = (rf_stored/buffersize)*100
print(type(rf_precent))
print(type(last_tick_percent))
local delta_percent = rf_percent - last_tick_percent
last_tick_percent = re_percent
return rf_percent.."% ["..rf_stored.."] | "..unicode.char(916)..": "..delta_percent.."%"
end
The first print is not even executed for some reason. Inside the function, the first print returns Number while the second print returns nil.
Now I am getting the error attempt to perform arithmetic on upvalue "last_tick_percent" ( a nil value), obviously because last_tick_percent is nil which the print(type(..)) showed.
But i just assigned it literally 5 lines above.
So the questions are:
Why is last_tick_percent nil and how can i fix that?
why is the first print not executed?
you are assigning re_percent which is not declared in your script to last_tick_percent inside stored_energy. i am assuming you meant to assign rf_percent.

Define a variable and set it to a default value if something goes wrong during definition

I have the following code in my build.gradle
Contents in version.properties are:
buildVersion=1.2.3
Value of $v variable during the Gradle build is coming as: 1.2.3
Value of $artifactoryVersion variable in JENKINS build is coming as: 1.2.3.1, 1.2.3.2, 1.2.3.x ... and so on where the 4th digit is Jenkins BUILD_NUMBER available to gradle build script during Jenkins build.
BUT, when I'm running this build.gradle on my desktop where I dont have BUILD_NUMBER variable available or set in my ENVIRONMENT variables, I get an error saying trim() can't work on null. (as there's no BUILD_NUMBER for Desktop/local build).
I'm trying to find a way i.e.
What should I code in my script so that if BUILD_NUMBER is not available, then instead of gradle build processing failing for an error, it'd set jenkinsBuild = "0" (hard coded) otherwise, pick what it gets during Jenkins build.
For ex: in Bash, we set a variable var1=${BUILD_NUMBER:-"0"} which will set var1 to a valid Jenkins BUILD number if it's available and set to a value, otherwise if it's NULL, then var1 = "0".
I DON'T want to have each developer/user set this BUILD_NUMBER in some property file. All I want is, if this variable doesn't exist, then the code should put "0" in jenkinsBuilds variable and doesn't error out during desktop builds. I know during Jenkins build, it's working fine.
// Build Script
def fname = new File( 'version.properties' )
Properties props = new Properties()
props.load( new FileInputStream( fname ) )
def v = props.get( 'buildVersion' )
def env = System.getenv()
def jenkinsBuild = env['BUILD_NUMBER'].trim()
if( jenkinsBuild.length() > 0 ) {
artifactoryVersion = "$v.$jenkinsBuild"
}
All you need is some regular Java/Groovy code:
def jenkinsBuild = System.getenv("BUILD_NUMBER") ?: "0"
The code above uses Groovy's "elvis" operator, and is a shorthand for the following code, which uses Java's ternary operator:
def buildNumber = System.getenv("BUILD_NUMBER")
def jenkinsBuild = buildNumber != null ? buildNumber : "0"
Here's the answer to using a Java plain object (JDK8):
public class Sample {
private String region;
private String fruit;
public Sample() {
region = System.getenv().getOrDefault("REGION", null);
fruit = System.getenv().getOrDefault("FRUIT", "apple");
}
}
With the Env-Inject plugin you can get and set build parameters.
For example, under "Inject environment variables to the build process", add a Groovy script such as:
def paramsMap = [:]
def build = Thread.currentThread().executable
def my_var = build.getEnvVars()["MY_PARAM"]
if (!my_var) paramsMap.put("MY_PARAM", "default value")
// Return parameters map
out.println("Injecting parameters:\n" + paramsMap)
return paramsMap

Corona sdk pass value from main.lua to external module

Here is a demo I modified to remove the module(..., package.seeall) statement. It works great, and I want to use the same idea in a Corona sdk project. I want to pass a value to an existing variable that I created in the demo. Thanks for any advice.
main.lua--------------------------------------------------
-- Load external library (should be in the same folder as main.lua)
local testlib = require("testlib")
testlib.testvar = 100 -- Trying to change the testvar value in external module
-- cache same function, if you call more than once
local hello = testlib.hello
-- now all future invocations are "fast"
hello()
-- This all works fine, but I need to change the value of testvar.
testlib.lua -----------------------------------------------------
local M = {}
local testvar = 0 -- I need to change the value of this variable as well as others later.
print("testvar=",testvar)
local function hello()
print ("Hello, module")
end
M.hello = hello
return M
In this case Your local testvar is private variable for Your module (testlib.lua).
You need to provide some setters/getters for that private variable.
Basic example would be adding this to Your testlib.lua:
function setter(new_val)
test_var = new_val
end
function getter()
return test_var
end
M.set = setter
M.get = getter
Now, You can use testlib.set("some new value..") and print(testlib.get()) in Your main.lua to operate the value of testvar variable.

Lua module invocation with require returns boolean

i have wrote the next lua module:
--mod.lua
local M = {}
function M.bar()
print "bar"
end
return M
And i'm trying to use it on another lua script as:
--main.lua
function Main(context)
local mod = require 'mod'
mod.bar()
end
But i am getting the error : "attempt to index ? (a boolean value)" on the line "mod.bar()"
The same result is obtained if i use module(..., package.seeall) on the header of mod.lua.
Could anybody help me?
Thanks to W.B. my 'mod.lua' was in another path. Sorry for wasting your time.

Check if a file exists with Lua

How can I check if a file exists using Lua?
Try
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
but note that this code only tests whether the file can be opened for reading.
Using plain Lua, the best you can do is see if a file can be opened for read, as per LHF. This is almost always good enough. But if you want more, load the Lua POSIX library and check if posix.stat(path) returns non-nil.
Lua 5.1:
function file_exists(name)
local f = io.open(name, "r")
return f ~= nil and io.close(f)
end
I will quote myself from here
I use these (but I actually check for the error):
require("lfs")
-- no function checks for errors.
-- you should check for them
function isFile(name)
if type(name)~="string" then return false end
if not isDir(name) then
return os.rename(name,name) and true or false
-- note that the short evaluation is to
-- return false instead of a possible nil
end
return false
end
function isFileOrDir(name)
if type(name)~="string" then return false end
return os.rename(name, name) and true or false
end
function isDir(name)
if type(name)~="string" then return false end
local cd = lfs.currentdir()
local is = lfs.chdir(name) and true or false
lfs.chdir(cd)
return is
end
os.rename(name1, name2) will rename name1 to name2. Use the same name and nothing should change (except there is a badass error). If everything worked out good it returns true, else it returns nil and the errormessage. If you dont want to use lfs you cant differentiate between files and directories without trying to open the file (which is a bit slow but ok).
So without LuaFileSystem
-- no require("lfs")
function exists(name)
if type(name)~="string" then return false end
return os.rename(name,name) and true or false
end
function isFile(name)
if type(name)~="string" then return false end
if not exists(name) then return false end
local f = io.open(name)
if f then
f:close()
return true
end
return false
end
function isDir(name)
return (exists(name) and not isFile(name))
end
It looks shorter, but takes longer...
Also open a file is a it risky
Have fun coding!
If you're using Premake and LUA version 5.3.4:
if os.isfile(path) then
...
end
For sake of completeness: You may also just try your luck with path.exists(filename). I'm not sure which Lua distributions actually have this path namespace (update: Penlight), but at least it is included in Torch:
$ th
______ __ | Torch7
/_ __/__ ________/ / | Scientific computing for Lua.
/ / / _ \/ __/ __/ _ \ | Type ? for help
/_/ \___/_/ \__/_//_/ | https://github.com/torch
| http://torch.ch
th> path.exists(".gitignore")
.gitignore
th> path.exists("non-existing")
false
debug.getinfo(path.exists) tells me that its source is in torch/install/share/lua/5.1/pl/path.lua and it is implemented as follows:
--- does a path exist?.
-- #string P A file path
-- #return the file path if it exists, nil otherwise
function path.exists(P)
assert_string(1,P)
return attrib(P,'mode') ~= nil and P
end
If you are willing to use lfs, you can use lfs.attributes. It will return nil in case of error:
require "lfs"
if lfs.attributes("non-existing-file") then
print("File exists")
else
print("Could not get attributes")
end
Although it can return nil for other errors other than a non-existing file, if it doesn't return nil, the file certainly exists.
An answer which is windows only checks for files and folders, and also requires no additional packages. It returns true or false.
io.popen("if exist "..PathToFileOrFolder.." (echo 1)"):read'*l'=='1'
io.popen(...):read'*l' - executes a command in the command prompt and reads the result from the CMD stdout
if exist - CMD command to check if an object exists
(echo 1) - prints 1 to stdout of the command prompt
An answer which is windows only checks for files and folders, and also requires no additional packages. It returns true or false.
You can also use the 'paths' package. Here's the link to the package
Then in Lua do:
require 'paths'
if paths.filep('your_desired_file_path') then
print 'it exists'
else
print 'it does not exist'
end
Not necessarily the most ideal as I do not know your specific purpose for this or if you have a desired implementation in mind, but you can simply open the file to check for its existence.
local function file_exists(filename)
local file = io.open(filename, "r")
if (file) then
-- Obviously close the file if it did successfully open.
file:close()
return true
end
return false
end
io.open returns nil if it fails to open the file. As a side note, this is why it is often used with assert to produce a helpful error message if it is unable to open the given file. For instance:
local file = assert(io.open("hello.txt"))
If the file hello.txt does not exist, you should get an error similar to stdin:1: hello.txt: No such file or directory.
For library solution, you can use either paths or path.
From the official document of paths:
paths.filep(path)
Return a boolean indicating whether path refers to an existing file.
paths.dirp(path)
Return a boolean indicating whether path refers to an existing directory.
Although the names are a little bit strange, you can certainly use paths.filep() to check whether a path exists and it is a file. Use paths.dirp() to check whether it exists and it is a directory. Very convenient.
If you prefer path rather than paths, you can use path.exists() with assert() to check the existence of a path, getting its value at the same time. Useful when you are building up path from pieces.
prefix = 'some dir'
filename = assert(path.exist(path.join(prefix, 'data.csv')), 'data.csv does not exist!')
If you just want to check the boolean result, use path.isdir() and path.isfile(). Their purposes are well-understood from their names.
If you use LOVE, you can use the function love.filesystem.exists('NameOfFile'), replacing NameOfFile with the file name.
This returns a Boolean value.
How about doing something like this?
function exist(file)
local isExist = io.popen(
'[[ -e '.. tostring(file) ..' ]] && { echo "true"; }')
local isIt = isExist:read("*a")
isExist:close()
isIt = string.gsub(isIt, '^%s*(.-)%s*$', '%1')
if isIt == "true" then
return true
end
return false
end
if exist("myfile") then
print("hi, file exists")
else
print("bye, file does not exist")
end
if you are like me exclusively on Linux, BSD any UNIX type you can use this:
function isDir(name)
if type(name)~="string" then return false end
return os.execute('if [ -d "'..name..'" ]; then exit 0; else exit 1; fi')
end
function isFile(name)
if type(name)~="string" then return false end
return os.execute('if [ -f "'..name..'" ]; then exit 0; else exit 1; fi')
end
Actually this looks even better:
function isDir(name)
if type(name)~="string" then return false end
return os.execute('test -d '..name)
end
function isFile(name)
if type(name)~="string" then return false end
return os.execute('test -f '..name)
end
function exists(name)
if type(name)~="string" then return false end
return os.execute('test -e '..name)
end
IsFile = function(path)
print(io.open(path or '','r')~=nil and 'File exists' or 'No file exists on this path: '..(path=='' and 'empty path entered!' or (path or 'arg "path" wasn\'t define to function call!')))
end
IsFile()
IsFile('')
IsFIle('C:/Users/testuser/testfile.txt')
Looks good for testing your way. :)