Modules with standalone main program

classic Classic list List threaded Threaded
60 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Modules with standalone main program

Dirk Laurie-2
This has come up before, but I can't remember or find the answer.

Is there a test that allows the following logic?

----
if test then -- module was invoked by 'require'
  return module
end
-- continue with main program
----

The best I can come up with is to insist on 'lua -i' for the
standalone, and use os.exit if I don't want to fall back to Lua.

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Paul K-2
> Is there a test that allows the following logic?

Maybe this one: `if pcall(debug.getlocal, 4, 1) then return module end`?

Paul

On Sat, Feb 24, 2018 at 12:25 AM, Dirk Laurie <[hidden email]> wrote:

> This has come up before, but I can't remember or find the answer.
>
> Is there a test that allows the following logic?
>
> ----
> if test then -- module was invoked by 'require'
>   return module
> end
> -- continue with main program
> ----
>
> The best I can come up with is to insist on 'lua -i' for the
> standalone, and use os.exit if I don't want to fall back to Lua.
>

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Sean Conner
In reply to this post by Dirk Laurie-2
It was thus said that the Great Dirk Laurie once stated:

> This has come up before, but I can't remember or find the answer.
>
> Is there a test that allows the following logic?
>
> ----
> if test then -- module was invoked by 'require'
>   return module
> end
> -- continue with main program
> ----
>
> The best I can come up with is to insist on 'lua -i' for the
> standalone, and use os.exit if I don't want to fall back to Lua.

  You mean like this?

        [spc]lucy:/tmp>lua mod.lua
        I was executed as a program
        [spc]lucy:/tmp>lua
        Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
        > m = require "mod"
        I was included as a module
        >

Here's my "module":

        if ... then
          print("I was included as a module")
          return {}
        end
       
        print("I was executed as a program")

It also works for Lua 5.1 and 5.2.

  -spc


Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Luiz Henrique de Figueiredo
>         if ... then
>           print("I was included as a module")
>           return {}
>         end
>         print("I was executed as a program")

Try lua mod.lua 1 2 3 .

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan
On Feb 24, 2018, at 6:30 AM, Luiz Henrique de Figueiredo <[hidden email]> wrote:

>>        if ... then
>>          print("I was included as a module")
>>          return {}
>>        end
>>        print("I was executed as a program")
>
> Try lua mod.lua 1 2 3 .
>

As long as the command is NOT mod.lua mod 1 2 3,
I can test for required with select(1, ...) == 'mod', or simply (...) = "mod"

see http://lua-users.org/wiki/FloatSumFast
Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Dirk Laurie-2
2018-02-24 13:37 GMT+02:00 albertmcchan <[hidden email]>:

> On Feb 24, 2018, at 6:30 AM, Luiz Henrique de Figueiredo <[hidden email]> wrote:
>
>>>        if ... then
>>>          print("I was included as a module")
>>>          return {}
>>>        end
>>>        print("I was executed as a program")
>>
>> Try lua mod.lua 1 2 3 .
>>
>
> As long as the command is NOT mod.lua mod 1 2 3,
> I can test for required with select(1, ...) == 'mod', or simply (...) = "mod"
>
> see http://lua-users.org/wiki/FloatSumFast

Actually, the manual documents what 'require' does, in particular:

"Once a loader is found, require calls the loader with two arguments:
modname and an extra value dependent on how it got the loader. (If the
loader came from a file, this extra value is the file name.)"

And dofile does not do that.

Thanks.

-- Dirk

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan


On Feb 24, 2018, at 7:46 AM, Dirk Laurie <[hidden email]> wrote:

> Actually, the manual documents what 'require' does, in particular:
>
> "Once a loader is found, require calls the loader with two arguments:
> modname and an extra value dependent on how it got the loader. (If the
> loader came from a file, this extra value is the file name.)"
>
> And dofile does not do that.
>
> Thanks.
>
> -- Dirk
>

does require cache the result, and set package.loaded.mod ?

If mod were "required", BEFORE mod.lua return results to set
package.loaded.mod, require function set it to something not nil

AFTER the require call, package.loaded.mod is set to whatever
mod.lua returns (or true if mod return nothing)

--> with require(), package.loaded.mod always tested not nil

if package.loaded.mod then
  -- loaded from require
else
  -- run as a program
end

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Soni "They/Them" L.


On 2018-02-24 10:28 AM, albertmcchan wrote:

>
> On Feb 24, 2018, at 7:46 AM, Dirk Laurie <[hidden email]> wrote:
>
>> Actually, the manual documents what 'require' does, in particular:
>>
>> "Once a loader is found, require calls the loader with two arguments:
>> modname and an extra value dependent on how it got the loader. (If the
>> loader came from a file, this extra value is the file name.)"
>>
>> And dofile does not do that.
>>
>> Thanks.
>>
>> -- Dirk
>>
> does require cache the result, and set package.loaded.mod ?
>
> If mod were "required", BEFORE mod.lua return results to set
> package.loaded.mod, require function set it to something not nil
>
> AFTER the require call, package.loaded.mod is set to whatever
> mod.lua returns (or true if mod return nothing)
>
> --> with require(), package.loaded.mod always tested not nil
>
> if package.loaded.mod then
>    -- loaded from require
> else
>    -- run as a program
> end
>

Why does nobody support renaming modules, it's 2018 :(

local function compareargs(...)
     local vargs = table.pack(...)
     for i=1,vargs.n do
         if arg[i] ~= vargs[i] then return false end
     end
     return true
end
if package.loaded[...] and not compareargs(...) then -- be nice to ppl
     -- (probably? with about a 99.999% chance) loaded from require
else
     -- do whatever you want just don't screw with the [...] above >.>
end

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan


On Feb 24, 2018, at 9:05 AM, "Soni \"They/Them\" L." <[hidden email]> wrote:

> Why does nobody support renaming modules, it's 2018 :(
>
> local function compareargs(...)
>     local vargs = table.pack(...)
>     for i=1,vargs.n do
>         if arg[i] ~= vargs[i] then return false end
>     end
>     return true
> end
> if package.loaded[...] and not compareargs(...) then -- be nice to ppl
>     -- (probably? with about a 99.999% chance) loaded from require
> else
>     -- do whatever you want just don't screw with the [...] above >.>
> end
>
> --
> Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.
>

I got an idea to take care of remaining 0.001% case.

have require set package.loaded.mod to false before it were fully loaded.
(it were currently set to some userdata anyway)

if package.loaded.mod == false then
  -- loading from require, but not yet finish ...
else
  -- standalone program
end

so, even if lua had mod.lua "require" by default, above
can test for mod.lua running as stand-alone program



Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Dirk Laurie-2
In reply to this post by Albert Chan
2018-02-24 15:28 GMT+02:00 albertmcchan <[hidden email]>:

>
>
> On Feb 24, 2018, at 7:46 AM, Dirk Laurie <[hidden email]> wrote:
>
>> Actually, the manual documents what 'require' does, in particular:
>>
>> "Once a loader is found, require calls the loader with two arguments:
>> modname and an extra value dependent on how it got the loader. (If the
>> loader came from a file, this extra value is the file name.)"
>>
>> And dofile does not do that.
>>
>> Thanks.
>>
>> -- Dirk
>>
>
> does require cache the result, and set package.loaded.mod ?
> If mod were "required", BEFORE mod.lua return results to set
> package.loaded.mod, require function set it to something not nil

On entry to mod.lua, package.loaded.mod must be nil if the package is
being required. The file would not be loaded otherwise.

> AFTER the require call, package.loaded.mod is set to whatever
> mod.lua returns (or true if mod return nothing)
>
> --> with require(), package.loaded.mod always tested not nil
>
> if package.loaded.mod then
>   -- loaded from require
> else
>   -- run as a program
> end

I have settled on the following version as conforming to the docs, i.e. safest:

local modname, filename = ...
if filename and filename:match(modname .."%.lua$") then return end

This code can be cut-and-pasted since it does not depend on the module
name. It even works for submodules, e.g.
    require "mod.submod"

The only caveat is that the module name must not contain a magic
character except "."; in particular (I burnt my fingers on this one)
not a hyphen.

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan

> On Feb 24, 2018, at 10:31 AM, Dirk Laurie <[hidden email]> wrote:
>
> On entry to mod.lua, package.loaded.mod must be nil if the package is
> being required. The file would not be loaded otherwise.

That is true. However, once require "activated", it set
package.loaded.mod to something that is not nil.
--> it is marked loaded even if it is not completely loaded

You can try add print(package.loaded.mod) inside mod.lua
If you run it as mod = require "mod",  it print out "userdata"

After the require call, package.loaded.mod is replace by mod.lua
returns.  Even if mod.lua returning nothing, package.loaded.mod
will be set to true (to signal require not to loaded it again)

That is why below code work:

if not package.loaded.mod then
  --  not required, run it standalone
end



Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan
In reply to this post by Dirk Laurie-2

> On Feb 24, 2018, at 10:31 AM, Dirk Laurie <[hidden email]> wrote:
>
> I have settled on the following version as conforming to the docs, i.e. safest:
>
> local modname, filename = ...
> if filename and filename:match(modname .."%.lua$") then return end
>
> This code can be cut-and-pasted since it does not depend on the module
> name. It even works for submodules, e.g.
>    require "mod.submod"
>
> The only caveat is that the module name must not contain a magic
> character except "."; in particular (I burnt my fingers on this one)
> not a hyphen.
>

There is a problem with circular reasoning.

The goal is to test if mod.lua were required, BUT
the test ASSUMED that the call were from require, even
study documentation of lua require, then test if it is being required.

If it is called like lua mod.lua arg1 arg2, your first line is already wrong.
You can always adjust arg1 arg2 to make above code pass (or fail)

For the same reason, package.loaded.mod should NOT
be replaced by package.loaded[ ... ]

(It only work if ... were REALLY from require(...))






Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Tony Papadimitriou
In reply to this post by Sean Conner
This method will fail if there are command line parameters.

Unfortunately, the conclusion was that there seems to be no fail-proof
method.

This is a very important feature but there is zero interest from the Lua
team to provide a reliable method.

> You mean like this?
>...
>Here's my "module":
>
>if ... then
>  print("I was included as a module")
>  return {}
>end
>
>print("I was executed as a program")


Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Paul K-2
> Unfortunately, the conclusion was that there seems to be no fail-proof method.

I already suggested a method earlier that works with Lua 5.1+ and
handles command line parameters as well as require/dofile calls:

if pcall(debug.getlocal, 4, 1) then
  print("package")
else
  print("main script")
end

Paul.

On Sat, Feb 24, 2018 at 11:36 AM, Tony Papadimitriou <[hidden email]> wrote:

> This method will fail if there are command line parameters.
>
> Unfortunately, the conclusion was that there seems to be no fail-proof
> method.
>
> This is a very important feature but there is zero interest from the Lua
> team to provide a reliable method.
>
>> You mean like this?
>> ...
>> Here's my "module":
>>
>> if ... then
>>  print("I was included as a module")
>>  return {}
>> end
>>
>> print("I was executed as a program")
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan
In reply to this post by Dirk Laurie-2
I now know why require "mod" set package.loaded.mod to some userdata
the userdata "sentinel" is used to check for errors during require,
and provide a default true if mod.lua does not return anything.

we can use sentinel to test mod.lua currently being required:

patch: in loadlib.c luaopen_package()

< lua_pushlightuserdata(L, sentinel);
< lua_setfield(L, -2, "loading");

with above 2 lines patch, we can now do this:

if package.loaded.mod == package.loading then
    return mod_func
end

-- code below for running stand-alone

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Albert Chan
In reply to this post by Paul K-2

On Feb 24, 2018, at 2:46 PM, Paul K <[hidden email]> wrote:

>> Unfortunately, the conclusion was that there seems to be no fail-proof method.
>
> I already suggested a method earlier that works with Lua 5.1+ and
> handles command line parameters as well as require/dofile calls:
>
> if pcall(debug.getlocal, 4, 1) then
>  print("package")
> else
>  print("main script")
> end
>
> Paul.
>

can you elaborate what 4 and 1 mean ?

how does it know we are testing mod.lua being required (or not) ?
and not testing for something else ?

 ("mod" is never mentioned in above test)

the stand-alone program might also require some other modules, which
also might require others ... does above work all the time ?
Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Andrew Gierth
In reply to this post by Albert Chan
>>>>> "albertmcchan" == albertmcchan  <[hidden email]> writes:

 albertmcchan> I now know why require "mod" set package.loaded.mod to
 albertmcchan> some userdata

5.1 does this, but 5.2+ do not.

--
Andrew.

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Dirk Laurie-2
In reply to this post by Paul K-2
2018-02-24 21:46 GMT+02:00 Paul K <[hidden email]>:
>> Unfortunately, the conclusion was that there seems to be no fail-proof method.

I don't need a fail-proof method. I need a method that works for a
one-file module of which I know the name by which it will be required.

> I already suggested a method earlier that works with Lua 5.1+ and
> handles command line parameters as well as require/dofile calls:
>
> if pcall(debug.getlocal, 4, 1) then
>   print("package")
> else
>   print("main script")
> end

It does not do what I want.

$ lua
Lua 5.3.4  Copyright (C) 1994-2017 Lua.org, PUC-Rio
> dofile"lmodules/mod.lua"
package

I.e. "doflile" is treated just like "require'.

I want "require" to return and all other ways of running the file to continue.

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Dirk Laurie-2
In reply to this post by Andrew Gierth
2018-02-24 22:30 GMT+02:00 Andrew Gierth <[hidden email]>:
>>>>>> "albertmcchan" == albertmcchan  <[hidden email]> writes:
>
>  albertmcchan> I now know why require "mod" set package.loaded.mod to
>  albertmcchan> some userdata
>
> 5.1 does this, but 5.2+ do not.

In the API, you have the option.

Reply | Threaded
Open this post in threaded view
|

Re: Modules with standalone main program

Andrew Gierth
>>>>> "Dirk" == Dirk Laurie <[hidden email]> writes:

 albertmcchan> I now know why require "mod" set package.loaded.mod to
 albertmcchan> some userdata

 >> 5.1 does this, but 5.2+ do not.

 Dirk> In the API, you have the option.

Where?

--
Andrew.

123