loading values from `require(file)` into local variables - module

Sorry if this is an FAQ but if some lib.lua returns a table of local functions e.g.
return {readCsv=readCsv, sumList=sumList, printHelp=printHelp}
and file2.lua imports it using
local lib=require("lib")
is there some programmatic way to automate the loading of the lib values into the local space? So i DON'T have to keep doing e.g.
local readCsv,sumList,printHelp=lib.readCsv,lib.sumList,lib.printHelp
I know its standard practice in LUA and it properly does not annoy many people. But it happens so often that I was wondering if there was a standard shortcut.
(Note: Just to be clear, I know how to make them globals by loading them into _ENV but that is exactly what I do not want.)

In Lua, local variables are statically declared constructs. They're known at compile-time and cannot (generally) be allocated at runtime. Even the number of locals that an individual function holds is known at compile-time, even if the values held in them are not known until the function object is created.
As such, there is no dynamic mechanism to dump the contents of a table into a runtime-defined number of local variables.
The closest you could do is to parse the Lua script text manually to find all of the require statements, do those require yourself, and parse the tables to generate a sequence of local declarations that you will insert into the appropriate place in your Lua script text. You would then compile that script and use it.
But this is a huge amount of work just to get rid of lib.. It's just not worth it.

Since, it's just a regular table that is being returned by require, you can "unpack" that table to turn it into a list of values:
-- return values as both array and hash
return {readCsv, sumList, printHelp,
readCsv=readCsv, sumList=sumList, printHelp=printHelp}
-- then do
local readCsv,sumList,printHelp = (table.unpack or unpack)(require "lib")
The order of returned/assigned values will obviously matter.
If somebody still wants to use a "regular" syntax with local lib = require "lib", it will continue to work.

Based on the above, I came up with a function that simplifies importing. Now I sort of agree with #NicolBolas that is all a little "cancer of the semi-colon" but heh, its short and optional (only a few lines of code, does not mess with usual LUA module conventions)
get"file" requires the file and unpacks results in alphabetical order. Kind of analogous to the Python command
from file import *
get"file thing1 thing2.." requires the file and unpacks only thing1 thing2. Kind of analogous to the Python command
from file import thing1,thing2
e.g. heres a file that returns some code:
-- file = cc.lua
function fun1() print(1) end
function fun2() print(2) end
function fun3() print(3) end
function fun4() print(4) end
function fun5() print(5) end
return {fun3=fun3, fun1=fun1, fun2=fun2, funs5=fun5, fun4=fun4}
Here's one example of usage (unpack all). Note that the sub-module (cc.lua) can return its things in any order at all and this code will unpack them in alpha order:
-- file = gettest1.lua
local get=require"get"
local fun1,fun2,fun3,fun4,fun5=get"cc"
fun5()
And here's the other usage where we can unpack somethings, in any order we want:
-- file = gettest2.lua
local get=require"get"
local fun3,fun1=get"cc fun3 fun1"
fun1()
And here's the code for the get.lua file that holds the get function
-- file = get.lua
local function get(spec)
local gets, keys,out={},{},{}
for get in string.gmatch(spec, "([^ ]+)") do gets[#gets+1]= get end
local results = require(table.remove(gets,1))
if #gets>0
then keys= gets
else for key,_ in pairs(results) do keys[#keys+1] = key end
table.sort(keys)
end
for _,key in ipairs(keys) do out[#out+1] = results[key] end
return table.unpack(out)
end
return get
Improvements? Suggestions? Comments?

Related

Extracting information from a file variable in d3 pick basic

I have a file variable in d3 pick basic and I am trying to figure out what file it corresponds to.
I tried the obvious thing which was to say:
print f *suppose the file variable's name is f in this case
but that didn't work, because:
SELECTION: 58[B34] in program "FILEPRINTER", Line 7: File variable used
where string expression expected.
I also tried things like:
list f *didn't compile
execute list dict f *same error
execute list f *same error
but those also did not work.
In case any one is wondering, the reason I am trying to do this in the first place is that there is a global variable that is passed up and down in the code base I am working with, but I can't find where the global variable gets its value from.
That file pointer variable is called a "file descriptor". You can't get any information from it.
You can use the file-of-files to log Write events, and after a Write is performed by the code, check to see what file was updated. The details for doing this would be a bit cumbersome. You really should rely on the Value-Add Reseller or contract with competent assistance for this.
If this is not a live end-user system, you can also modify an item getting written with some very unique text like "WHAT!FILE!IS!THIS?". Then you can do a Search-System command to search the entire account (or system) to find that text. See docs for proper use of that command.
This is probably the best option... Inject the following:
IF #USER = "CRISZ" THEN ; * substitute your user ID
READU FOO FROM F,"BLAH" ELSE
DEBUG
RELEASE F,"BLAH"
END
END
That code will stop only for one person - for everyone else it will flow as normal. When it does stop, use the LIST-LOCKS command to see which file has a read lock for item "BLAH". That's your file! Don't forget to remove and recompile the code. Note that recompiling code while users are actively using it results in aborts. It's best to do this kind of thing after hours or on a test system.
If you can't modify the code like that, diagnostics like this can be difficult. If the above suggestions don't help, I think this challenge might be beyond your personal level of experience yet and recommend you get some help.
If suggestion here Does help, please flag this as the answer. :)

Dynamically set input and output paths in pig using UDFs

I would like to create a no-arg pig script that dynamically creates input and output paths.
The script itself should determine a input file glob based on current date and similarly determine an output file path based on current date. While I know that one can easily pass in parameters I was hoping to have a no-arg script and use a couple of simple jython UDFs to compute these paths.
How do I do that? I can't seem to set variables by calling a UDF. For instance,
%default OUTPUTPATH myfn();
or
path = myfn();
don't seem to work.
Any ideas?
(Why no-args? Because I would like to have a single static amazon data pipeline config that runs the same script each day but under the hood would run the last day's or last week's worth of log files each time.)
Sadly, to my knowledge, there is no way to do this in pure pig. However, you can define these changing variables in a python wrapper. In your case, you'll just define the dict of args like:
d = {
'OUTPATH': myfn(),
}
And then pass that dict like:
P = Pig.compile(path_to_my_script)
Q = P.bind(d)
results = Q.run()
Of course there is a little more to add to the wrapper, but it should be pretty clear from the docs.

calling script_execute with a variable

I'm using GameMaker:Studio Pro and trying to execute a script stored in a variable as below:
script = close_dialog;
script_execute(script);
It doesn't work. It's obviously looking for a script named "script". Anyone know how I can accomplish this?
This question's quite old now, but in case anyone else ends up here via google (as I did), here's something I found that worked quite well and avoids the need for any extra data structures as reference:
scriptToCall = asset_get_index(scr_scriptName);
script_execute(scriptToCall);
The first line here creates the variable scriptToCall and then assigns to it Game Maker's internal ID number for the script you want to call. This allows script_execute to correctly find the script from the ID, which doesn't work if you try to pass it a string containing the script name.
I'm using this to define which scripts should be called in a particular situation from an included txt file, hence the need to convert a string into an addressable script ID!
You seem to have some confusion over how Game Maker works, so I will try to address this before I get around to the actual question.
GML is a rather simple-minded beast, it only knows two data types: strings and numbers. Everything else (objects, sprites, scripts, data structures, instances and so on) is represented with a number in your GML code.
For example, you might have an object called "Player" which has all kinds of fancy events, but to the code Player is just a constant number which you can (e.g.) print out with show_message(string(Player));
Now, the function script_execute(script) takes as argument the ID of the script that should be executed. That ID is just a normal number. script_execute will find the script with that ID in some internal table and then run the script.
In other words, instead of calling script_execute(close_dialog) you could just as well call script_execute(14) if you happened to know that the ID of close_dialog is 14 (although that is bad practice, since it make the code difficult to understand and brittle against ID changes).
Now it should be obvious that assigning the numeric value of close_dialog to a variable first and then calling script_execute on that variable is perfectly OK. In the end, script_execute only cares about the number that is passed, not about the name of the variable that this number comes from.
If you are thinking ahead a bit, you might wonder whether you need script_execute at all then, or if you could instead just do this:
script = close_dialog;
script();
In my opinion, it would be perfectly fine to allow this in the language, but it does not work - the function call operator actually does care about the name of the thing you try to call.
Now with that background out of the way, on to your actual question. If close_dialog is actually a script, your suggested code will work fine. If it is an extension function (or a built-in function -- I don't own Studio so what do I know) then it does not actually have an ID, and you can't call it with script_execute. In fact, you can't even assign close_dialog to a variable then because it does not have any value in GML -- all you can do with it then is call it. To work around this though, you could create a script (say, close_dialog_script which only calls close_dialog, which you can then use just as above.
Edit: Since it does not seem to work anyway, check whether you have a different resource by the name of close_dialog (perhaps a button sprite). This kind of conflict could mean that close_dialog gives you the ID of the sprite, not of the script, while calling the script directly would still work.
After much discussion on the forums, I ended up going with this method.
I wrote a script called script_id()
var sid;
sid = 6; //6 = scriptnotfound script :)
switch (argument0) {
case "load_room":
sid = 0;
break;
case "show_dialog":
sid = 1;
break;
case "close_dialog":
sid = 3;
break;
case "scrExample":
sid = 4;
break;
}
return sid;
So now I can call script_execute(script_id("close_dialog"));
I hate it, but it's better than keeping a spreadsheet... in my opinion.
There's also another way, with execute_string();
Should look like this:
execute_string(string(scriptName) + "();");

How to comment on MATLAB variables

When I´m using MATLAB, sometimes I feel the need to make comments on some variables. I would like to save these comments inside these variables. So when I have to work with many variables in the workspace, and I forget the context of some of these variables I could read the comments I put in every one of them. So I would like to comment variables and keep the comments inside of them.
While I'm of the opinion that the best (and easiest) approach would be to make your variables self-documenting by giving them descriptive names, there is actually a way for you to do what you want using the object-oriented aspects of MATLAB. Specifically, you can create a new class which subclasses a built-in class so that it has an additional property describing the variable.
In fact, there is an example in the documentation that does exactly what you want. It creates a new class ExtendDouble that behaves just like a double except that it has a DataString property attached to it which describes the data in the variable. Using this subclass, you can do things like the following:
N = ExtendDouble(10,'The number of data points')
N =
The number of data points
10
and N could be used in expressions just as any double value would. Using this example subclass as a template, you could create "commented" versions of other built-in numeric classes, with the exception of those you are not allowed to subclass (char, cell, struct, and function_handle).
Of course, it should be noted that instead of using the ExtendDouble class like I did in the above example, I could instead define my variable like so:
nDataPoints = 10;
which makes the variable self-documenting, albeit with a little more typing needed. ;)
How about declaring another variable for your comments?
example:
\>> num = 5;
\>> numc = 'This is a number that contains 5';
\>> whos
...
This is my first post in StackOverflow. Thanks.
A convenient way to solve this is to have a function that does the storing and displaying of comments for you, i.e. something like the function below that will pop open a dialog box if you call it with comments('myVar') to allow you to enter new (or read/update previous) comments to variable (or function, or co-worker) labeled myVar.
Note that the comments will not be available in your next Matlab session. To make this happen, you have to add save/load functionality to comments (i.e. every time you change anything, you write to a file, and any time you start the function and database is empty, you load the file if possible).
function comments(name)
%COMMENTS stores comments for a matlab session
%
% comments(name) adds or updates a comment stored with the label "name"
%
% comments prints all the current comments
%# database is a n-by-2 cell array with {label, comment}
persistent database
%# check input and decide what to do
if nargin < 1 || isempty(name)
printDatabase;
else
updateDatabase;
end
function printDatabase
%# prints the database
if isempty(database)
fprintf('no comments stored yet\n')
else
for i=1:size(database,1)
fprintf('%20s : %s\n',database{i,1},database{i,2});
end
end
end
function updateDatabase
%# updates the database
%# check whether there is already a comment
if size(database,1) > 0 && any(strcmp(name,database(:,1)))
idx = strcmp(name,database(:,1));
comment = database(idx,2);
else
idx = size(database,1)+1;
comment = {''};
end
%# ask for new/updated comment
comment = inputdlg(sprintf('please enter comment for %s',name),'add comment',...
5,comment);
if ~isempty(comment)
database{idx,1} = name;
database(idx,2) = comment;
end
end
end
Always always always keep the Matlab editor open with a script documenting what you do. That is, variable assignments and calculations.
Only exceptions are very short sessions where you want to experiment. Once you have something -- add it to the file (It's also easier to cut and paste when you can see your entire history).
This way you can always start over. Just clear all and rerun the script. You never have random temporaries floating around in your workspace.
Eventually, when you are finished, you will also have something that is close to 'deliverable'.
Have you thought of using structures (or cells, although structures would require extra memory use)?
'>> dataset1.numerical=5;
'>> dataset1.comment='This is the dataset that contains 5';
dataset1 =
numerical: 5
comment: 'This is the dataset that contains 5'

SSIS save string variable to text file

It seems like it should be simple but as of yet I havent found a way to save the value stored in an SSIS string variable to a text file. I've looked at using the flat file destination inside of a data flow but that requires a data flow source.
Any ideas on how to do this?
Use a script task.
I just tried this. I created a File connection manager, with the connection string pointing to the file I wanted to write to. I then created a string variable containing the text to write.
I added a Script Task, specified my string variable in the Read Only Variables list, then clicked Edit Script. The script was as follows:
public void Main()
{
ConnectionManager cm = Dts.Connections["File.tmp"];
var path = cm.ConnectionString;
var textToWrite = (string)Dts.Variables["User::StringVariable"].Value;
System.IO.File.WriteAllText(path, textToWrite);
Dts.TaskResult = (int)ScriptResults.Success;
}
This worked with no problems.
Here's a little sample of some code that worked in a SQL CLR in C#. You'll need to use VB if you're on 2005 I believe. The script task also needs the read variable property set to MyVariable to make the value of your variable available to it.
// create a writer and open the file
TextWriter tw = new StreamWriter("\\\\server\\share$\\myfile.txt");
// write a line of text to the file
tw.WriteLine(Dts.Variables["MyVariable"].Value);
// close the stream
tw.Close();
All it takes is one line of code in a simple Script task. No other dependencies, such as a connection manager, are needed.
Here's what it would look like in C#:
public void Main()
{
string variableValue = Dts.Variables["TheVariable"].Value.ToString();
string outputFile = Dts.Variables["Path"].Value.ToString();
System.IO.File.WriteAllText(outputFile, variableValue);
Dts.TaskResult = (int)ScriptResults.Success;
}
Obviously the most important line here is the one containing the WriteAllText function call.
The Path variable should contain a full path + filename for the output file.
Ok, I have an answer that doesn't involve use of script task. Pick some oledb sql source you have that's simple and you have a lot of control over. Make a query that returns only one row. Then put this query in a string variable:
"select vara, ' var =: " + #[User:varIWantToSee] + "' as myvar from tablea where vara = 1"
Then in OLEDB source pick "SQL command from a variable"
For varIWantToSee make sure you initialize it with a lot characters or ssis makes a very small length for that column that it doesn't let you override. At run time varIWantToSee will get set and you can see it. Pump this all into a flat file destination and you are in business. Why do some people have to do this? Because some people need to know the value of the variables in the runtime environment, their laptop development doesn't show the variable values they need. In my case I was running this on an Azure environment that had the database accesses I needed to test. If I were microsoft I would create a task that shows the runtime variable value at that stage of the job by writing it to the ssis log file created when the package runs. If someone knows how to do that, please enlighten us.
It's possible to use a Derived Column transformation to write the value of a variable into a column. The problem is that it needs a source to drive it, and there's no stock data source you can use that just spits out a null row onto the pipeline.
So, either you repurpose a single-row source to drive the derived column transformation, or you do what another answer suggests, and do it with a Script source.
I did it the way you described. I already had a oledb connection manager defined so I used an OLE DB Source and used the SQL Command data access mode. I used a simple query:
select getdate() as dt
...just to get it out of the way. Now I know the date of my variable pull. Then I used a Derived Column Transform to make my package variables available and wrote it out to a flat file.
Elegant? No, but it gets the job done.
Lets say you don't want to mess with Script tasks and you don't have a database you can connect to just to issue a data source command like:
SELECT 'Some arbitrary text'
There are still several ways to use a Process task for something as simple as writing a line of text to a file. For example you can use PowerShell with an input variable built using the following expression:
"'"+REPLACE(#[User::Text],"'","''")+"' > '"+REPLACE(#[User::Filename],"'","''")+"'"
Notice I escaped the filename because single quotes are legal there. Also note I used '>' for redirecting which overwrites the file if it exists. If I wanted to append I'd use '>>'.
Initially I had trouble with this method when User::Text contained multiple lines. It turns out you need some extra EOL characters after your filename when a command spans lines. Like this:
"'"+REPLACE(#[User::Text],"'","''")+"' > '"+REPLACE(#[User::Filename],"'","''")+"'\r\n\r\n"
Using cmd.exe with echo is a bit more precarious but can also work in certain circumstances and has much less overhead.
P.S. I've noticed with some versions of PowerShell that StandardInputVariable content is ignored without this:
-Command -
in the Arguments box. A lone minus sign as a Command argument is 'magic' and documented at https://learn.microsoft.com/en-us/powershell/scripting/powershell.exe-command-line-help. I believe all versions of PowerShell accept this param so even if it's not required for your version you may want to include it since it shouldn't break anything and may keep your code from breaking if PowerShell is updated to a version that requires it.