Machsupport Forum

Mach Discussion => Mach4 General Discussion => Topic started by: rrc1962 on May 29, 2016, 03:56:04 PM

Title: Using Modules
Post by: rrc1962 on May 29, 2016, 03:56:04 PM
Can't seem to find any documentation covering the basics.  Lets say I have a module "Module1.lua" and it has a function in it called "theFunction()".  Heres what I have so far.  This is the module...

Code: [Select]
local Module1 = {}

function theFunction()
wx.wxMessageBox('Module Test')
end

return Module1

This is the code in a button event that I want to call "theFuntion()"

Code: [Select]
sw = require('Module1')
inst = mc.mcGetInstance()
sw.theFunction()

I suspect the reason it's not working is because the module is not in the right directory...or one or both files need a path specified...or the module needs to be loaded on screen load.  Maybe a combination of these.

Thanks
Title: Re: Using Modules
Post by: DazTheGas on May 29, 2016, 04:24:43 PM
You need to rename your function so it is tied to the Module1 table

Code: [Select]
local Module1 = {}

function Module1.theFunction()
wx.wxMessageBox('Module Test')
end

return Module1

As a norm the modules should be placed in the Mach4Hobby/Modules directory

DazTheGas
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 06:08:50 PM
When I run it in debug I get this...

Code: [Select]
[string "C:\Users\Richard\AppData\Local\Temp\le53EB.mc..."]:2: module 'Module1' not found:
no field package.preload['Module1']
no file 'C:\Mach4Hobby\lua\Module1.lua'
no file 'C:\Mach4Hobby\lua\Module1\init.lua'
no file 'C:\Mach4Hobby\Module1.lua'
no file 'C:\Mach4Hobby\Module1\init.lua'
no file '.\Module1.lua'
no file 'C:\Mach4Hobby\Module1.dll'
no file 'C:\Mach4Hobby\loadall.dll'
no file '.\Module1.dll'
stack traceback:
[C]: in function 'require'
[string "C:\Users\Richard\AppData\Local\Temp\le53EB.mc..."]:2: in main chunk

Do I need to be loading the module in the screen load script or providing a path to it somewhere?

If I put Module1.lua in C:\Mach4Hobby\, it opens a file dialog when I debug, then seems to run OK.  When I try to run it outside the editor, it doesn't do anything.
Title: Re: Using Modules
Post by: dude1 on May 29, 2016, 06:24:46 PM
have a look back to the last page on the M4 post have a look at what popperbear did
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 06:41:21 PM
last page on the M4 post

Not sure what that means.
Title: Re: Using Modules
Post by: DazTheGas on May 29, 2016, 06:41:38 PM
Out of curiosity insert this before you do sw = require('Module1') and have your module in the Mach4Hobby\Modules directory, the debug info means it cant find the file, this is already in the startup script but just incase whatever your doing cant see it??

Code: [Select]
   local profile = mc.mcProfileGetName(inst)
    local path = mc.mcCntlGetMachDir(inst)
    package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"

DazTheGas
Title: Re: Using Modules
Post by: DazTheGas on May 29, 2016, 06:43:11 PM
Oh and the extension needs to be .lua
Title: Re: Using Modules
Post by: dude1 on May 29, 2016, 06:55:43 PM
http://www.machsupport.com/forum/index.php/topic,27572.0.html
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 07:47:51 PM
So just to recap, here is the module...It is called Module1.lua

Code: [Select]
local Module1 = {}

function Module1.theFunction()
wx.wxMessageBox('Module Test')
end

return Module1

This is the button code calling the function in the module...I've tried this...

Code: [Select]
inst = mc.mcGetInstance()
M.theFunction()

And this...

Code: [Select]
inst = mc.mcGetInstance()
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"
local M = require "Module1"
M.theFunction()

Also tried adding this to the screen load script...

Code: [Select]
package.path = "./?.lua;c:/Mach4Hobby/Modules/?.mcc;"  
M = require "Module1"

As well as this....

Code: [Select]
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"
M = require "Module1"

Still nothing....I also tried putting a copy of Module1.lua in C:\Mach4Hobby, C:\Mach4Hobby\Modules and C:\Mach4Hobby\Profiles\Mach4Mill\Modules
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 08:15:53 PM
Maybe a step in the right direction.  When I run the code below in the editor...

Code: [Select]
inst = mc.mcGetInstance()
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"
local M = require "Module1"
local rc = theFunction()

It opens a file dialog with Module1.lua already entered.  I click open and the module opens up allowing me to step through it.  When it gets to the bottom of the module, it returns to the calling script.  The next line in the script is the call to theFunction(), which generates this error.

Code: [Select]
mcLua ERROR: Lua: Error while running chunk
[string "C:\Users\Richard\AppData\Local\Temp\le4431.mc..."]:6: attempt to call global 'theFunction' (a nil value)
Title: Re: Using Modules
Post by: dude1 on May 29, 2016, 08:17:41 PM
have a look at what popperbear did in his modules they work
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 08:27:49 PM
What he did contradicts what Daz said.  Poppabear is using an.mcc file.  Daz said to use a .lua file, which jives with basic lua documentation. I'm surprised there are not enough people using modules to warrant a blurb in the scripting manual on how to use them.  They talk about modules and how useful they are, but nothing on how to use them. 
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 08:38:20 PM
Poppabear has this in the screen load script...

Code: [Select]
package.path = "./?.lua;c:/Mach4Hobby/Modules/?.mcc;" --where the module file is.   
M = require "Module1"

Daz has this

Code: [Select]
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"
M = require "Module1"

Poppabear is referencing .mcc files where Daz references .lua files.  Everything I'm digging up tells me that the module should be a .lua file.
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 08:59:14 PM
Found a problem in the button script.  I had theFunction(), not M.theFunction().

I can now cycle through the code in the editor and when it hits the line M.theFunction(), it goes to the function and does nothing.  I should be displaying a message box.  Running it outside the editor doesn't do anything either.  Am I trying to do something here that can't be done in a function?  Is it a scope issue?

Correction...It works in the editor.  The message box was displaying in the background.  Does not work outside the editor though.
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 09:31:02 PM
OK...It's working....And here's why it wasn't.  The button script was never executing.  This has happened many times.  When I press a button nothing happens.  You assume the script has an error and commence to chase it down the rabbit hole, just to find that the script is not running.

I started out this morning with the button script on the Left Up Script.  Remembering all the trouble I've had with broken buttons, I moved the script to Left Down early this afternoon.  Never had two broken button events, but third time is a charm.  I moved it to Clicked and it all works.
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 10:25:05 PM
Arrrg...So now I'm just trying to call a function from another function within the module and I get this...

Code: [Select]
C:\Mach4Hobby\Profiles\Mach4Mill\Modules\ShapeWizard.lua:45: attempt to call global 'getHeader' (a nil value)
stack traceback:
C:\Mach4Hobby\Profiles\Mach4Mill\Modules\ShapeWizard.lua:45: in function 'Circle1'
[string "C:\Users\Richard\AppData\Local\Temp\le221E.mc..."]:9: in main chunk

This is the line that generates the error...

Code: [Select]
    wx.wxMessageBox(getHeader() .. getStart('0', '50') .. getStop('0') .. getEnd())
This is getHeader()

Code: [Select]
function getheader()
    gcode1 = 'G20\n'
    gcode1 = gcode1 .. 'G90\n'
    gcode1 = gcode1 .. 'G91.1\n'
    gcode1 = gcode1 .. 'M1102\n'
    gcode1 = gcode1 .. 'M1000\n'
    return gcode1
end
Title: Re: Using Modules
Post by: rrc1962 on May 29, 2016, 11:16:30 PM
When I load the module, I call sw = require(MduleName).  I think when I call getHeader(), I need to call sw.getHeader().  Sounds like a good start tomorrow.
Title: Re: Using Modules
Post by: DazTheGas on May 30, 2016, 06:10:09 AM
Let me try and clear this one up about modules before you awake........

Modules in Lua - wxLua are like other languages classes, now these classes hold functions (class of functions). Now when declaring these Modules wx or lua need to know where to look, this is where the package.path comes in.

Like all other languages you declare the path which is "global" so no need to keep declaring all over the place.

Code: [Select]
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;"

So lets break this down to what wxlua  sees when we require a module called newClass, first lets look in  "Mach4Hobby\Profiles\"current profile name"\Modules and look for newClass.lua  and if not found then lets look in Mach4Hobby\Modules for newClass.lua - so does it have to be .lua extension?? - nope it can be anything you want

Code: [Select]
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.mcs;"

The above will look in the same directories but also look in the last directory for newClass.mcs  - so now we can find modules lets look at the module


Code: [Select]
local myClass = {}

function myClass.test()
    wx.wxMessageBox("Nothing to see here")
end

function test()
    wx.wxMessageBox("Still Nothing to see here")
end

return myClass

The above will create a class called myClass and declare myClass.test() as available to public to use, however the function test() is private and can only be used by the class.

Now lets load the class from mach4, first make an instance of the class and call it what you like

message = require "newClass" - wxlua will now search our path from earlier for the newClass file and make a new instance of the class called myClass contained in the file, now to use a function in the class we need to call it with the instance of the class we created "message", so to run the test function we would use message.test() - this will now run and in this case show a messagebox.

If wanted you can use many instances of the same class
message = require "newClass"
message2 = require "newClass"

each one of the buttons or dro`s etc in the editor create an instance of a class for example.

DazTheGas

Time for coffee and biccy now
Title: Re: Using Modules
Post by: rrc1962 on May 30, 2016, 02:38:42 PM
Lets say I create the same class with a slight twist...If I say message = require "myClass" and call message.test() it should return a message box saying 'Nothing to see here'.  We pass 'Nothing' to test2(), it then takes that argument and concatenates ' to see here', then returns the result back to the message box.  Shouldn't this work?

The problem isn't accessing test() from outside.  Problem is accessing test2() from within test().  They are defined within the same module, yet lua doesn't seem to think that test2() exists.

Code: [Select]
local myClass = {}

function myClass.test()
    wx.wxMessageBox(test2('Nothing'))
end

function test2(str)
    str = str .. ' to see here'
    return str
end

return myClass
Title: Re: Using Modules
Post by: DazTheGas on May 30, 2016, 03:44:46 PM
I have just copied your myClass and made new module exactly the same in my modules directory and run this code

Code: [Select]
local inst = mc.mcGetInstance()
local profile = mc.mcProfileGetName(inst)
local path = mc.mcCntlGetMachDir(inst)
package.path = path .. "\\Profiles\\" .. profile .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.lua;" .. path .. "\\Modules\\?.mcs;"

message = require "newClass"

message.test()

which as expected displayed a messagebox with "Nothing to see here"

If i try to access message.test2() then it gives an error

So this is working correctly as it should.

DazTheGas
Title: Re: Using Modules
Post by: rrc1962 on May 30, 2016, 04:42:23 PM
First, thanks so much for your help.  It's all working now, but I'm not sure why.  I ended up re-writing the module in question from scratch and it worked.  I couldn't find a typo in the one that didn't or any other reason for it to fail.  Maybe a hidden character?  Also figured out that you have to restart M4 for any changes to a module to take effect.