Page 1 of 5 123 ... LastLast
Results 1 to 10 of 42

Thread: Getting started with LUA/pas2lua

  1. #1

    Getting started with LUA/pas2lua

    Alrighty, I'm looking at starting a simple project shortly, but it isn't a game. I easily get frustrated by things like batch files and their limited functionality, and I have never messed with the windows "powershell" that now exists. And on linux my knowledge is basic. However linux has a bonus over windows, in that Cron Jobs is super easy to use if you understand it, and so can automate your tasks.

    What I am looking at writing, as a way to learn Lua, is a "luaexec" application that acts as a windows service and periodically executes various Lua scripts. For example if I wanted to clean my temp dir, and my delphi projects area of unneeded stuff I could have the script run once a week.

    However I am wondering about a few things.

    How would I execute a script, giving it information it may need as "configuration" that is dependent upon a per-script basis? For example, returning a table of named keys for the settings. IE:
    Code:
    settings = {
      extensions = {
        ".dcu",
        ".log",
      },
      whitelist = {
        "mydocs",
      },
      blacklist = {
        "user_tempdir"
      },
      mainDir = "C:\Delphi",
    }
    I am guessing it would be better to create a threaded lua script that checks the given timeframe, and then executes a script given the 'settings' variable. So I guess you could say something like this would be effective.

    Code:
    luaExec = {
      Tasks = {},
    }
    
    function luaExec:AddTask(script, settings, period)
      tables.insert(luaExec.Tasks,{ func = script, options = settings, frequency = period, });
    end
    
    function luaExec:Init()
      luaExec.AddTask();
    end
    
    function luaExec:Process()
    
    end
    
    luaExec.Init()
    CreateThreadedProcess('luaExec', 'Process')
    Starting to loose my though process in writing that... Anyhow. Bascially, is it better to have an XML configuration file with settings, scripts, and date/numerical periods to execute a script, or is there a way I could do it all in a sort of library fashion? Like put all the scripts into the library and then you just configure when you want them to run, and any settings they may need.

    I'm confusing myself here. Gah. So I'll just start with the simple question: How do I pass a lua table from Delphi to a given lua script? Where it may contain a table or multiple tables within itself.

    And, what is better in my case? Making a main lua script that handles most the gruntwork, or sort of splitting it between the two?

  2. #2

    Getting started with LUA/pas2lua

    I'll do my best to answer your questions. Though, not quite in order .

    When it comes to where to store your configuration information, that all depends on the level of customization you want to give to the user. While its true that a script offers more flexibility, it also bloats the application and makes the configuration more complex. To this, simpler is typically better. Think XML or INI as your root configuration manager. Keep a recording of scripts, times, and run instances that need to occur some place outside of the scripting environment.

    That being said, you can also have a global script instance that modifies your current run state. Make sure that this is optional, as many users arn't going to need this functionality.

    For individual task scripts, think of it this way. You will need to initialize an instance of Lua for each separate task that you want to run where anything from another script should not affect it. If your using my TLuaObject and TLua objects, then simply fire up a new instance of TLua for each script that you want to execute. Then release that instance and clean up after yourself when the execution is complete. If you want config options from your root script to affect other scripts that run in separate TLua instances then you will have to manually migrate them. That can be a bit tricky, but it can be done .

    Something to keep in mind is that Lua maintains state information until you call close. So if you run "a = 5" and then run "print(a)" you will get an output of 5, unless you called close between the two calls. Use this to your advantage.

    Looking at: SDL, Lua and FPC game engine sample should be of some use. Also join the Lua Mailing List. Finally take a look at: My version of LuaTut and Lua FPC/Delphi wrappers, that has an updated version of LuaObject and LuaWrapper. New bug fixes that arn't in production yet, and some other fun stuff that will be presented in the book when its released.

    Once you get your basic test bed working, feel free to post it up here with questions. I'll be happy to follow up and answer everything that I can.

    Oh yeah, final note, PIL and PIL 2 are your friends. Read them, and buy a copy if you can afford it.

  3. #3

    Getting started with LUA/pas2lua

    Quote Originally Posted by jdarling
    Oh yeah, final note, PIL and PIL 2 are your friends. Read them, and buy a copy if you can afford it.
    Gracious, you weren't kidding! LUA is far more efficient and powerful than I had originally thought. Hmm. I am nowhere near done reading though. I may end up buying PIL 1 & 2 for references, and so that I can also employ Lua in any of my future projects. It is certainly far more powerful than I imagined!

    I think my program, instead of being a service, will just be a tray application with a configuration that writes to an XML file. This way I can change the icon when something is running, or even change it to a textual "gauge" to show progress of a weightier script. I think it would be best that way, because I can also bind it to let the user execute any script in their library directory at any time by a direct right-click menu. I think that would work just fine. Not to mention, I have absolutely no clue how to install a service application.

    As to some more advanced date/time manipulation, I am still thinking. I don't want the memory overhead of keeping a "minute counter" per item, so the best way would be a "last run" date. Then I could just do a fast boolean check of when the "lastrun+interval <= now" evaluates true; I think I can use a sort of addition expression to the dates in Delphi, but I must do some research on that.

    When a task is called, multiple ones may be called at once, I will add the script name and operating object to a stringlist but I won't support threaded function calls. At least initially. I am uncertain at this point, still haven't read far enough, about how I would go about marking a script as free. As for task configuration the simplest way will be a key=value list, an editor/component for which already exists. This way I just create (using a certain ECXML object ) an entry into the configuration like this:
    Code:
    <luaExec>
      <!-- Generic Options -->
      <options></options>
      <tasks>
        <task option="value" ... />
      </tasks>
    </luaExec>
    So then when loading the configuration file I just pull specific options like "script" and "interval" out and dump the rest to a Lua table that could be considered a "global object" independently put into each script. For that, perhaps a record of the lua-object, script name, and configuration record would be more expedient.

    To handle the task icon I have a few components already, so I'm not concerned. However I will code some Lua functions to update the hint, progress "label" in the icon, and (in general) permit switching between the two standard icon, and dynamically modified one.

    I will of course extend Lua with recursive searching of the file system, returning a table/array of strings, and a few other simpler matters. However one thing a person will always want, is the ability to track execution and errors in your tasks ... so I think I might employ a simple RSS feed which you can "subscribe" to on your own computer, and which is updated upon each (un)successful operation. This would involve a global script, as in this way the data gathering is much more dynamic and used in a very rapid form. This way I can also permit greater flexibility in logging through this functionality, while using built in I/O functions to write the data to the file.

    Quote Originally Posted by jdarling
    Something to keep in mind is that Lua maintains state information until you call close. So if you run "a = 5" and then run "print(a)" you will get an output of 5, unless you called close between the two calls. Use this to your advantage.
    I am not entirely certain what you mean by this. From what I understand if you execute the script and the execution runs through, it consists of one "pass". Therefore of course the variable persists, but do you mean that between concurrent executions without freeing the script the variables are held? Or would this change at all in a threaded execution of a given function? Like I said, I'm scarcely into part 1, section 7.1, so I haven't read a whole heck of a lot about Lua yet.

    I have never exactly understood mailing lists, or used them, so I am not sure how I would join or post messages to it. Is it like a newsgroup? I don't know how to do more than read those, and sending messages are restricted to special servers an ISP or generic web server may have.

    Thanks for the updated version of the Lua objects; I will try and create a test bed soon, but aside from reading and planning the actual operation of this application ... I think my hands will be too full for that yet! :lol:

    Thanks for taking the time to answer all of my questions.

  4. #4

    Getting started with LUA/pas2lua

    You have some very ambitious ideas in there Robert. As I said, I would keep it simple to start with. Something that lets you select a script, schedule it, and run it. Believe me, an efficient scheduling system is not as trivial as it sounds . The threading system should be next. Then the rest of your stuff.

    You will find (as you read more) that the io library already has almost everything you need to execute a full tree walk (in Linux, Windows and MAC)!

    As for ECXML, its a very good component, but please remember that its over 10 years old (believe it or not). I haven't updated it in quite some time, as there are other things on my plate taking priority. The newer version, for FPC, is still in early beta and has a few bugs. Though, its my choice any more . Also, you will find that there are ALOT of good libraries for parsing XML in Lua (that way your config file is actually read by a script that can be customized by any user). Of course thats up to you.

    For the persistence thing, here is a quick example:
    [pascal]var Lua : TLua;
    begin
    Lua := TLua.Create;
    Lua.LoadScript('a = 0'#13#10'function Test()'#13#10'print(a.."\n")'#13#10'a=a+1'#13#10'e nd'#13#10'Test()');
    Lua.Execute;
    Lua.CallFunction('Test')
    Lua.CallFunction('Test')
    Lua.Free;
    end[/pascal]

    Output:
    Code:
    0
    1
    2
    If you called .Execute instead of .CallFunction then you would see the output as 0, 0, 0. Of course, if you did a nil test then an assignment and used .Execute you would get 0, 1, 2 as the Lua State is never closed. You will learn more about that as you read PIL.

    Personally, I bought PIL 1 and 2. More because I respect the author posting 1 for free then anything. I find reading them online a better option, but I like the feeling that I'm supporting the guy at some level .

    Some place on my hard drive I have ALOT of sample code. I'll look around and see if I can find it. If so I'll zip it up and make it available for download for you.

    On the subject of the mailing list. You can sign up at:
    http://www.lua.org/lua-l.html

    Basically, you give it a valid e-mail address and then everyone on the list gets a copy of each others messages that are sent to the list. Its the "Primary form of Support for Lua". There are some really smart people on the list, and I've yet to have a problem getting help when I need it. I'm just now starting to post answers, as I'm just getting to the point that I know enough to answer competently

  5. #5
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Getting started with LUA/pas2lua

    Hi Robert,

    I'll save you some time on the date manipulation....

    TDateTime is a float. The integer part represents the day while the decimal part represents time.

    Its your standard offset idea, so 0 equates to 12/30/1899 12:00 am.

    To offset this by 1 second, you add 1/86400 (86400 = 24 x 60 x 60 = The number of seconds in 1 day). To offset by 1 day, you add 1. Using this method, you can go forward and backwards in time quickly and easily.

    I've used this kind of manipulation quite extensively for scheduling in the past... it works a treat.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  6. #6

    Getting started with LUA/pas2lua

    Athena, thank you very much! That is indeed simple and easy to use; it will fit my intents and purposes most perfectly!

    Heh, you make me grin Jeremy. I am as stubborn as the day is long, and as determined to tackle the whole thing right at the beginning as I was before. Me, start with the easy stuff? No way! :lol: But, seriously, I won't be taking things too quickly here. I need to do some serious experimentation with Lua first to get my bearings, but it won't take long after that to write the full application. My intents aren't cross platform as of this moment because my intent is to design a tray application, which I don't know how to do in other OSes and have no interest in plumbing the depths of at this moment. That makes things easier since I can assume several things such as the existence of certain OS specific functions and methods.

    I'm now on PIL 20.1 (Part III) and looking into pattern matching. This makes the whole business of making an RSS feed child's play to me, being a web designer/developer (self taught thus far), and would let me make "inter-script" functions; I assume that there is a way to call "CallFunction" with parameters, and its existence would make things simpler. Else there are clear and simple work-arounds.

    I misunderstood the mailing-list for a newsgroup; newsgroups I dislike due to their rather restrictive nature of "You must have thus and such server to post a message" when for the most part I don't know what they're even babbling about. :?

    So at the moment the design plan is as follows:

    Step 1: Create the barebones application consisting of functions and a simple tray application. Icons are crafted at this stage too, to indicate whether a script is running or not, and if
    there has been an error. An error console is of utmost importance, as well as a tabbed options dialog; I think an auto-show the error log might be important to begin with. Been there, done that, so it's mostly just deja vu -- and ensuring future expandability.

    Step 2: Given a stable and versatile barebones app, with functions for dynamic menus and such, here is where the initial scheduling will occur. My first idea is to limit the execution to a maximum of once every two months, all the way down to once every few minutes or so. The "library" directory will be implemented as well as reading/writing of options to an application specific directory (partly for Vista support). For ease of installation of new scripts, I will enable a simple check item in the icon's menu that shows a square "drop form" at a selectable corner of the screen.

    Step 3: With that done simple testing of scheduled "alert" scripts will take place to verify my timing/scheduling system operates. As well as some performance testing of it; for instance detecting the general load of the computer, testing to see if something is fullscreen (not entirely sure how to though) to ensure a script is not executed at a time of moderately high load. For instance, in the midst of a game. Waiting until the game ends will not hurt a thing. And a menu to allow for forced execution of the scheduled scripts, updating their last-run date, will also help allow a user override. The icon switching actually begins here, not sooner.

    Step 4: With step 3 out of the way, the real bulk of the work picks up. Integrating Lua with the options, scheduling, and even per-script configuration (if really necessary). I don't think a global script does much at this stage, so that will come later, if at all. However the RSS functionality I want to write in lua at least, for instance "RSS.RegisterResult({result = 'pass', overview = 'yadda yadda yadda'})", so that on a per script basis things can be put together and then sent back to the application. If I do decide to use a global script at this time, the RSS functionality will be built in, and receive "messages" from other scripts by pass-thru functions to allow updating the feed. I will permit the user to set a limit upon the age of notifications, so they do not have too large a file to load.

    Step 5: No real plan here just yet, but I figure the optimization, tweaking, and extension of Lua begins here. I'd like to add zip support, I'll use TurboPower Abbrevia, so that scheduled backups can happen and maybe hashing to generate file lists with built in hash information.

  7. #7

    Getting started with LUA/pas2lua

    All things considered, it's fun spec'ing projects out, and it's another to actually research/architect them. At the moment, looking at this again, I'm considering that this isn't what I need; the nuance of scheduling lua scripts to run at any time I choose on my computer does not outweigh my need to get accustomed to the language. While I still like this idea, I've opted for a simpler start, since I'm not entirely sure how to pass more than 20 (the buffer length of Lua) results at once, or in a table. That's a bit overkill, but I don't want to tackle such problems when I am still super new to using the language myself.

    So, instead, I'll just make a barebones FPC console application that has a "library" directory, a main script that acts as the actual program, and some various "library" extension objects to Lua. Not to mention that with very little work indeed, I can make a console roguelike with just a simple script -- a very simple one, but functional nonetheless.

    PS: Jeremy, this is just where you'll have to let me "think myself out", as you caught me early in the brainstorm process and I was needing a bit of input.

    Quick question on the topic of Lazarus/FPC, but does the DOS unit work in finding files cross-platform? I was wondering and looking, but I couldn't tell -- the remarks in the documentation mentioned that it was revised for cross-platform compatibility, but not what did work across them. If I am going to implement a "library" directory like I intend, I must be able to enumerate the files within it, so that's the main thing stopping me right now.

  8. #8

    Getting started with LUA/pas2lua

    Can't answer the question about finding files, as I don't use the DOS unit at all in FPC .

    On the problem of returning 20 items from a function. Its a very simple fix. Return a table instead, then you can have as many items as you want. So for example:
    Code:
    function MyTest&#40;&#41;
      local i = &#123;&#125;
      for n=1,1000 do
        i&#91;n&#93;=tostring&#40;n&#41;
      end
      return i
    end
    In pascal then just call luaToVariant(L, idx) on your result type and expect to get back a variant array. It took along time to modify luaToVariant to accept variant arrays, but its been a very worth while effort

  9. #9

    Getting started with LUA/pas2lua

    Well, what do you use in FPC to find a given file? Or, do you even do that in your stuff? :?

    I mean a pascal function passing more than 20 results to lua, which I figured would be best as a table. Though, passing a table as a result is a little cryptic to me.

  10. #10

    Getting started with LUA/pas2lua

    FindFirst/FindNext (from http://www.delphibasics.co.uk/RTL.asp?Name=FindNext)[pascal] var
    searchResult : TSearchRec;

    begin
    // Try to find regular files matching Unit1.d* in the current dir
    if FindFirst('Unit1.d*', faAnyFile, searchResult) = 0 then
    begin
    repeat
    ShowMessage('File name = '+searchResult.Name);
    ShowMessage('File size = '+IntToStr(searchResult.Size));
    until FindNext(searchResult) <> 0;

    // Must free up resources used by these successful finds
    FindClose(searchResult);
    end;
    end;[/pascal]

Page 1 of 5 123 ... LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •