xonsh: Is there a way to call a function as a command that takes optional arguments? - xonsh

I have a function in Xonsh that I'm trying to use like a command (ie: without parens). The function should optionally take arguments, however whenever I call the function without arguments, I just get the function address. How do you call a function with optional parameters?
Here's the example:
def _up(args, stdin=None):
# go up any number of directories
if not args or len(args) < 1:
args[0] = 1
balloons = ('../' * int(args[0]))
# echo #(balloons)
cd #(balloons)
aliases['up'] = _up
When I call up with no parameters, I get <function __main__.up>. When I call it like this, it works: up 2.
I could do a function like this that works, but then I can't call it without using parentheses (ie: as a command) which is what I'd prefer:
def up(dirs=1):
# go up any number of directories
balloons = ('../' * dirs)
# echo #(balloons)
cd #(balloons)
Calling up() and up(2) both work this way, but is more cumbersome than just calling up or up 2. What's the right way to accomplish what I'm trying to do in Xonsh?

I'm not certain why you're getting the function repr when you aren't passing in an argument, but a tweaked version of your function works:
def _up(args): # don't need stdin
# go up any number of directories
if not args or len(args) < 1:
args = [1] # if args is None you can't index to it
balloons = ('../' * int(args[0]))
# echo #(balloons)
cd #(balloons)
aliases['up'] = _up
on current-ish main of xonsh # c2f862df this works to go up one level with just an up or you can specify many levels with up 3, etc.

Related

Rspec: Checking the content of a system call

I have a Rake task in my Rails project which executes openssl through a system call.
The code looks like this:
system('bash', '-c', 'openssl cms -verify...')
I need to run the command in bash rather than dash (which is default on Ubuntu) to use process substitution in the command.
I need to create a test with rspec which checks that, in this case, the argument verify was passed as expected.
I have tried the following:
expect(Kernel).to receive(:system) do |args|
expect(args[2]).to match(/verify/)
end
However, this only gives me the third letter in the first string sent to system - i.e. the letter s from bash - rather than the third argument sent in the system call.
What am I doing wrong here? Any suggestions would be much appreciated.
Args are being passed to the block as sequential arguments, so if you want to treat them as an array, you need a splat operator in do |*args|:
expect(Kernel).to receive(:system) do |*args|
expect(args[2]).to match(/verify/)
end
Just to take a step back, it's important to understand how block arguments work, since they are different from methods. For example:
def my_fn(*args)
yield(*args)
end
my_fn(1,2,3) { |args| print args }
# => 1
my_fn(1,2,3) { |a, b, c| print [a,b,c] }
# => [1,2,3]
my_fn(1,2,3) { |*args| print args }
# => [1,2,3]
So if you did do |args| (without the splat), you are assigning the args variable to the first argument passed to the block ("bash") and ignoring the other arguments.

Lua (require) invoke an not intended print of required file name

When require is called in testt.lua which is one of two files the return is movee and movee.lua.
movee are for the most part a class to be required, but should be able to accept to be called direct with parameter.
movee.lua
local lib = {} --this is class array
function lib.moveAround( ... )
for i,direction in ipairs(arg) do
print(direction)
end
end
function lib.hello()
print("Hello water jump")
end
lib.moveAround(...)
return lib
testt.la
local move = require("movee")
Expected result is not to call lib.moveAround or print of file name when require is called.
Your expectations are incorrect. Lua, and most scripting languages for that matter, does not recognize much of a distinction between including a module and executing the Lua file which provides that module. Every function statement is a statement whose execution creates a function object. Until those statements are executed, those functions don't exist. Same goes for your local lib = {}. And so on.
Now, if you want to make a distinction between when a user tries to require your script as a module and when a user tries to execute your script on the command line (or via just loadfile or similar), then I would suggest doing the following.
Check the number of arguments the script was given. If no arguments were given, then your script was probably required, so don't do the stuff you don't want to do when the user requires your script:
local nargs = select("#", ...)
if(nargs > 0) then
lib.moveAround(...)
end
Solved by replacing
lib.moveAround(...)
with
local argument = {...}
if argument[1] ~= "movee" and argument[2] ~= "movee" then
lib.moveAround(...)
end
require("movee")
will execute the code within movee.lua
lib.moveAround(...)
is part of that code. Hence if you require "movee" you call lib.moveAround
If the expected result is not to call it, remove that line from your code or don't require that file.

LuaJ does not supply command line arguments correctly

I tried the utility method provided by luaj to call a lua file with command line args (this one http://lua-users.org/wiki/SourceCodeFormatter)
Globals globals = JsePlatform.standardGlobals();
String script ="src/codeformatter.lua";
File f = new File(script);
LuaValue chunk = globals.loadfile(f.getCanonicalPath());
List<String> argList = Arrays.asList("--file","test.lua");
JsePlatform.luaMain(chunk, argList.toArray(new String[argList.size()]));
However i always get attempt to call nil where the code tries to access the arg table ( while i < table.getn(arg) do) - i tried other examples and they all result in the same error - luaj does not seem to set the "arg" table correctly - even a simply print arg[1] will not work.
LuaJ does not support table.getn anymore because it got removed in lua 5.1 - replace every occurances of table.getn with #varname - and init the args array with ocal args={...} at the top made it work.
Still, the code formatter does not really do what i expected it todo
There are two issues:
calls to table.getn(arg) should be replaced with #arg
the chunk's environment is not set up properly by luaj 3.0.1 so arg isn't set
However, as a workaround, you can capture the inputs using the varargs "..." syntax by adding a line at the top of codeformatter.lua such as
arg = {...}
Here is a code snippet to illustrate:
Globals globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.load(
"arg = {...};" +
"print(#arg, arg[1], arg[2])");
JsePlatform.luaMain(chunk, new String[] {"--file","test.lua"});
Produces output:
2 --file test.lua

Env not modify when loading module in modulefile

I would like to load a module into a modulefile (to resolve dependencies).
MyModule:
#%Module########################################
##
## Modulefile
#
proc ModulesHelp { } {
puts stderr "Env for MyProg"
}
proc addPath {var val} {
prepend-path $var $val
}
module load MyOtherModule
addPath PATH /opt/MyModule/bin
MyOtherModule:
#%Module########################################
##
## Modulefile
#
proc ModulesHelp { } {
puts stderr "Env for MyOtherProg"
}
proc addPath {var val} {
prepend-path $var $val
}
addPath PATH /opt/MyOtherModule/bin
When I run module load MyModule, both modules seem to be loaded but environment is not right :
$module list
Currently Loaded Modulefiles:
1) MyModule 2) MyOtherModule
$echo $PATH
/opt/MyModule/bin:/usr/bin:/bin
If I add the line foreach p [array names env] { set tmp $env($p) } or at least set tmp $env(PATH) in the MyModule after the module load MyOtherModule line, the environment is correctly modified. It also work fine if I don't use my function addPath but I use the prepend-path command directly, which is a bit annoying because I would like to do more things in the addPath function of course.
Anyone as an idea on what is going on and what I am missing ?
The prepend-path is probably doing some “clever” stuff to manage a variable; what exactly it is is something I don't know and don't need to know, because we can solve it all using generic Tcl. To make your wrapping of it work, use uplevel to evaluate the code in the proper scope, though you need to consider whether to use the global scope (name #0) or the caller's scope (1, which is the default); they're the same when your procedure addPath is called from the global level, but otherwise can be quite different, and I don't know what other oddness is going on with the modules system processing.
To demonstrate, try this addPath:
proc addPath {var val} {
puts stderr "BEFORE..."
uplevel 1 [list prepend-path $var $val]
puts stderr "AFTER..."
}
We use list to construct the thing to evaluate in the caller's scope, as it is guaranteed to generate substitution-free single-command scripts. (And valid lists too.) This is the whole secret to doing code generation in Tcl: keep it simple, use list to do any quoting required, call a helper procedure (with suitable arguments) when things get complicated, and use uplevel to control evaluation scope.
(NB: upvar can also be useful — it binds local variables to variables in another scope — but isn't what you're recommended to use here. I mention it because it's likely to be useful if you do anything more complex…)

How to get the output of python script executed from a ruby method

I am trying to run a python script from ruby method. I am running this method as a rake task within a Rails app. I am using the solution mentioned here:
def create
path = File.expand_path('../../../../GetOrders', __FILE__)
output = `"python2 " + path + "/parse.py"`
print output
str = JSON.parse(output)
print str
end
EDIT: This works:
output = `python2 #{path}/parse.py`
EDIT2:
Using the python script i am trying to pass a list of dictionaries to the ruby function. The python script looks something like:
import xml.etree.ElementTree as ET
import json
def parse():
tree = ET.parse('response.xml')
root = tree.getroot()
namespaces = {'resp': 'urn:ebay:apis:eBLBaseComponents'}
order_array = root.find("resp:OrderArray", namespaces=namespaces)
detailsList = []
for condition:
details["key1"] = value1
details["key2"] = value2
detailsList.append(details)
output = json.dumps(detailsList)
return output
print parse()
Could someone explain what i am doing wrong and how can I fix this. Thanks
When you do this:
output = `python2 #{path}/parse.py`
output will be assigned the standard output of the python script, but that script isn't writing anything to standard output; the json data that's the return value of the parse() call is simply discarded. You seem to be expecting the execution of the script to have a "return value" that's the return value of the script's last expression, but that's not how processes work.
You probably want to replace the parse() call at the end of the script with print parse().
You are calling this exact line on the shell:
"python2 -path- /parse.py"
which the shell interprets as a single command: python2 (with a space at the end).
Try using string interpolation, which works with the backtick operator:
output = `python2 #{path}/parse.py`
Imagine typing this exact string:
"python2 " + path + "/parse.py"
into your shell (e.g. bash). It would look for a program named "python2 " and give it four arguments
+
path
+
/parse.y
You can't put arbitrary Ruby code inside a backtick string the same way you can't put arbitrary code in normals strings. You must use string interpolation.

Resources