Discussion:
Is there a similar way to do if __name__ == '__main__' as in python ?
gary ng
2007-02-08 04:35:43 UTC
Permalink
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".

In python, this is usually done through

if __name__ = "__main__":

How should I do it in lua ?

regards,

gary



____________________________________________________________________________________
Sucker-punch spam with award-winning protection.
Try the free Yahoo! Mail Beta.
http://advision.webevents.yahoo.com/mailbeta/features_spam.html
Rici Lake
2007-02-08 05:04:06 UTC
Permalink
Post by gary ng
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".
In python, this is usually done through
How should I do it in lua ?
I don't know if this is how you *should* do it, but it is
how you *can* do it (with thanks to lhf and a discussion
on the #lua irc channel):

During the execution of require, the packages.loaded table
entry for the module is set to a sentinel, in order to
detect circular dependencies. The sentinal is a userdata
object. So, if your module does not return a userdata,
you could establish that you're not running inside a
require by checking:

if type(package.loaded.<modulename>) ~= "userdata" then
-- run self test
end

or type(package.loaded["<modulename>"]) if the modulename has dots in
it.

However, that means that you need to know the name of the module.
Fortunately, if the module is being loaded with require, you'll
receive that as the first parameter.

Putting that together:

----- Module selftest.lua -----

local myname = ...

-- My personal style is not to pollute the global
-- namespace with modules, so this is not quite
-- according to PiL, but it works fine.

local Module = {}
function Module.hello(who)
print("Hello, "..(who or "whoever you are").."!")
end

-- Since I'm not creating a global, I have to return the
-- Module table.

if type(package.loaded[myname]) == "userdata" then
return Module
else
print "Testing the selftest module"
print "The next line should be familiar:"
Module.hello"world"
end
Glenn Maynard
2007-02-08 05:23:04 UTC
Permalink
Post by gary ng
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".
In python, this is usually done through
How should I do it in lua ?
I'm not sure (Rici probably answered that), but for this particular
task, I'd probably do it a little differently:

lua -e 'RunTests = true;' YourScript.lua

and then check RunTests.
--
Glenn Maynard
Rici Lake
2007-02-08 05:52:12 UTC
Permalink
Post by Glenn Maynard
Post by gary ng
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".
In python, this is usually done through
How should I do it in lua ?
I'm not sure (Rici probably answered that), but for this particular
lua -e 'RunTests = true;' YourScript.lua
and then check RunTests.
Well, in casting about for a way to simulate the Pythonic
behaviour, I did consider that, but the problem is that if
all of your modules use that system, and the target module
require()s another module, then both modules will self-test,
which may not be what you wanted (particularly if the
self-tests take a long time and/or there are a lot of
dependencies.)

So you could modify that slightly by setting
RunTests = "modulename"
instead of just to true. However, that means hard-coding
the name of the module into the module-file, which I
wanted to avoid.

So what I was looking for was a way for a module to tell
fairly definitively whether it had been require()'d or
dofile()'d; checking the package.loaded table for a
magic undocumented sentinel may not be the most pleasant
solution, but it works. Your mileage and aesthetic sensibilities
may vary. :)
gary ng
2007-02-08 06:16:10 UTC
Permalink
Post by Rici Lake
So you could modify that slightly by setting
RunTests = "modulename"
instead of just to true. However, that means
hard-coding
the name of the module into the module-file, which I
wanted to avoid.
Thanks for the suggestion from both.

I am not quite understand the above though.

I took your approach and do it like this :

local __name__
if type(package.loaded["my_module"]) ~= "userdata"
then
__name__ = "__main__"
module("my_module")
...things I write

then at the end, the pythonic way:

if __name__ == "__main__" then <self test> end

Won't this also hardcode the module name in the module
file, right there in the module() call ?




____________________________________________________________________________________
Sucker-punch spam with award-winning protection.
Try the free Yahoo! Mail Beta.
http://advision.webevents.yahoo.com/mailbeta/features_spam.html
Rici Lake
2007-02-08 06:24:44 UTC
Permalink
Post by gary ng
Post by Rici Lake
So you could modify that slightly by setting
RunTests = "modulename"
instead of just to true. However, that means
hard-coding
the name of the module into the module-file, which I
wanted to avoid.
Thanks for the suggestion from both.
I am not quite understand the above though.
local __name__
if type(package.loaded["my_module"]) ~= "userdata"
then
__name__ = "__main__"
module("my_module")
...things I write
if __name__ == "__main__" then <self test> end
Won't this also hardcode the module name in the module
file, right there in the module() call ?
Yes, that's one of the reasons I don't use module().

The actual code in my original message avoids hard-coding
the module name with the line:

local myname = ...

at the beginning. That picks up the first argument supplied
when the module chunk is called; if it is called by require(),
that will be the module name. If it is called by the stand-alone
interpreter, that will be the first command-line argument, if
there is one, but that won't hurt the package.loaded test
(in particular, t[nil] is nil for any table that doesn't have
an __index metamethod which checks for that condition.)

In other words, if the module is not being require()d, then
myname might be set to anything, but it's highly unlikely to
be set to the name of a module which is currently being
require()d at the point at which the file is being executed,
since at that point no require() is in progress.
gary ng
2007-02-08 06:38:37 UTC
Permalink
Post by Rici Lake
Yes, that's one of the reasons I don't use module().
The actual code in my original message avoids
hard-coding
local myname = ...
at the beginning. That picks up the first argument
supplied
when the module chunk is called; if it is called by
require(),
Ah, I thought module() is now the recommended way.

But anyway, out of curiosity, what would be the usage
scenario for not hardcode the module name ? As my
limited usage of require() is just to load another
file which is hardcoded in the file system anyway ?





____________________________________________________________________________________
Now that's room service! Choose from over 150,000 hotels
in 45,000 destinations on Yahoo! Travel to find your fit.
http://farechase.yahoo.com/promo-generic-14795097
Rici Lake
2007-02-08 06:52:00 UTC
Permalink
Post by gary ng
Post by Rici Lake
Yes, that's one of the reasons I don't use module().
The actual code in my original message avoids
hard-coding
local myname = ...
at the beginning. That picks up the first argument
supplied
when the module chunk is called; if it is called by
require(),
Ah, I thought module() is now the recommended way.
It is, so take anything I say with a grain of salt.
Post by gary ng
But anyway, out of curiosity, what would be the usage
scenario for not hardcode the module name ? As my
limited usage of require() is just to load another
file which is hardcoded in the file system anyway ?
Well, for example, I might want to have two different
versions of a module, say mymodule_v4 and mymodule_v5
both kicking around at the same time.

I can do that by saying:

local mymodule = require"mymodule_v4"

in any code which wants to use mymodule_v4; there's no global
pollution and the contents of the file mymodule_v4.lua don't
need to know that I've renamed the file.

Of course, most of my code will have:

local mymodule = require"mymodule"

in it, so I have to make that work, too. I can't use a symlink
because the module system identifies modules names in the package
cache with the filename; however, I can create a file mymodule.lua
with the single line:

return require"mymodule_v5"

and everything will work nicely.

I could also use a catchall loader which tried to figure
that out for me, perhaps by doing a file listing.
Bret Victor
2007-02-08 06:56:27 UTC
Permalink
Post by gary ng
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".
Lua is a lot more mutable than most languages. If you
need "require" to do something fancy, it may be simplest
to simply redefine "require":

local oldRequire = require
function require (...)
local wasInsideRequire = isInsideRequire
isInsideRequire = true
oldRequire(...)
isInsideRequire = wasInsideRequire
end

If you like, you can put this bit of code into its own little
module and require it before you require anything else.

Thereafter, anything that wants to know whether it's been
required just has to check the "isInsideRequire" global variable:

if not isInsideRequire then runUnitTest() end
Bret Victor
2007-02-08 07:14:29 UTC
Permalink
My apologies; I forgot that we're all supposed to pay attention to
the return value of "require" these days. Here's a replacement for
my replacement:

local oldRequire = require
function require (...)
local wasInsideRequire = isInsideRequire
isInsideRequire = true
local t = oldRequire(...)
isInsideRequire = wasInsideRequire
return t
end
Niklas Frykholm
2007-02-08 08:14:08 UTC
Permalink
Post by gary ng
I want to write lua modules and put some self testing
code at the end of the script which got executed only
if it is run as its own and not through "require".
In python, this is usually done through
How should I do it in lua ?
A dead simple but not very robust solution is

if arg[0] == 'menu.lua' then

Slightly more robust:

if arg[0]:match("[.%w]*$") == 'menu.lua' then

Replace "menu.lua" with the name of your file. Still not 100 % robust
(you could have files named menu.lua in different directories), but
maybe enough to cover your needs.

// Niklas

Continue reading on narkive:
Loading...