AutoHotkey String concatenation with Object Properties - properties

How does one concatenate strings in a Send command where one of the strings is in an objects property?
What I've tried:
obj = {prop: "hi"}
Send, Test %obj.prop% ; syntax error
Send, % "Test" % obj.prop ; syntax error
Send, Test %obj%.prop ; sends Test .prop

obj := {prop: "hi"}
Send, % "Test " obj.prop
Send, % "Test " obj["prop"]
Steer away from using = as your assign operator, while it can be used to assign string or numeric value, it's better to develop habit of using := (Var := expression) when it comes to autohotkey.

Related

Using a default value for a function parameter which depends of other parameter

I'd like to create an script which takes an input file and optionally an output file. When you don't pass an output file, the script uses the same filename as the input but with the extension changed. I don't know how to write a default parameter which changes the extension.
#!/usr/bin/env raku
unit sub MAIN(
Str $input where *.IO.f, #= input file
Str $output = $input.IO.extension("txt"), #= output file
Bool :$copy, #= copy file
Bool :$move, #= move file
);
Unfortunately that doesn't work:
No such method 'IO' for invocant of type 'VMNull'
in block <unit> at ./copy.raku line 5
How can I do something like that?
error message is less than awesome but program not working is expected because you have in the signature
Str $output = $input.IO.extension("txt")
but the right hand side returns an IO::Path object with that extension but $output is typed to be a String. That is an error:
>>> my Str $s := "file.csv".IO.extension("txt")
Type check failed in binding; expected Str but got IO::Path (IO::Path.new("file.t...)
in block <unit> at <unknown file> line 1
>>> sub fun(Str $inp, Str $out = $inp.IO.extension("txt")) { }
&fun
>>> fun "file.csv"
Type check failed in binding to parameter '$out'; expected Str but got IO::Path (IO::Path.new("file.t...)
in sub fun at <unknown file> line 1
in block <unit> at <unknown file> line 1
Sometimes compiler detects incompatible default values:
>>> sub yes(Str $s = 3) { }
===SORRY!=== Error while compiling:
Default value '3' will never bind to a parameter of type Str
------> sub yes(Str $s = 3⏏) { }
expecting any of:
constraint
but what you have is far from a literal, so runtime detection.
To fix it, you can either
change to Str() $output = $inp.IO.extension("txt") where Str() means "accept Any object and then cast it to Str". So $output will end up being a string like "file.txt" available in MAIN.
similar alternative: Str $output = $inp.IO.extension("txt").Str but it's repetitive in Str.
change to IO::Path() $output = $inp.IO.extension("txt"). Similarly, this casts to whatever recieved to an IO::Path object, so, e.g., you'll have "file.txt".IO available in $output. If you do this, you might want to do the same for $input as well for consistency. Since IO::Path objects are idempotent to .IO (in eqv sense), no other part of the code needs changing.

Make win+m followed by win+p execute code

What shoud I do to execute some code (ie: MsgBox "Hello") by:
Pressing win+m
Unpressing m whithout unpressing win
Pressing p
Seems like there's a good answer already, I just wanted to input what I could think of, so here's a version of the earlier answer, but without Sends.
I'd say a solution without them is always desirable, though, of course, in something as small as this, you'll struggle to find any difference in practice.
;runs after m is released on a LWin+m press
<#m up::
Hotkey, <#p, WinMP_Callback, On ;Enable LWin+p hotkey
KeyWait, LWin ;wait for LWin to be released
if (A_PriorKey = "m")
WinMinimizeAll ;keep win+m functional
Hotkey, <#p, , Off ;disable LWin+p hotkey
return
WinMP_Callback()
{
;do stuff
;add this at the end if you dont want
;to be able to keep running this function
;on subsequent presses of p before LWin is released
;Hotkey, <#p, , Off
}
So pretty much what the difference here is toggling the LWin+p hotkey on and off and just using WinMinimizeAll instead of sending LWin+m, since they're the same thing.
Try this:
<#m:: ; "<#" means "LWin"
LWin_m := true ; assign the Boolean value "true" or "1" to this variable
KeyWait, LWin, L ; wait for LWin to be released
LWin_m := false
return
<#p::
If (LWin_m) ; If this variable has the value "true"
msgbox "Hello"
; else
; do sth else
return
EDIT:
For not losing normal win+m and win+p try this:
<#m:: ; "<#" means "LWin"
LWin_m := true ; assign the Boolean value "true" or "1" to this variable
KeyWait, LWin, L ; wait for LWin to be released
If (A_PriorKey = "m")
Send #m
LWin_m := false
return
<#p::
If (LWin_m) ; If this variable has the value "true"
msgbox "Hello"
else
Send #p
return

Temporary variable in AMPL

Is there a way in AMPL to declare and use temporary variables? What I mean by that is the "regular" variables used in programming (instead of model variables), especially in the .run file, such as saving a string for repeated use in the .run file:
some_file = sprintf(foo%u.txt, 3); # Temporary variable
print "Hello World" > some_file;
print "Hello again" > some_file;
If it's not variable within the optimisation that you're going to solve, then it's a parameter. You can change the parameter value with let, like so:
reset;
param blah symbolic;
let blah := "hello world";
print blah;
let blah := "this parameter has changed";
print blah;
Parameters in AMPL are number by default; string params need to be explicitly declared as symbolic.
Note that I've declared the param in a separate statement from the first assignment. If I were to assign a value in the declaration, like param blah symbolic := "hello world";, then it would fail when I try to change the value.

Can you loop a Perl 6 block that's in a variable?

I keep wanting to do something like this:
my $block := {
state $n = 0;
say $n++;
last if $n > 3;
};
loop $block;
Or even:
$block.loop;
I'm not expecting that this is possible but it would sure be cool if it was.
How would I find out where a particular routine comes from?
$ perl6
To exit type 'exit' or '^D'
> &loop.^name
===SORRY!=== Error while compiling:
Undeclared routine:
loop used at line 1
Making $block.loop work, is rather easy and could live in module land:
use MONKEY;
augment class Block {
method loop($self:) {
Nil while $self()
}
}
my $a = { print "a" };
$a.loop # aaaaaaaaaaaaaaaaaaa (with apologies to Knorkator)
Making loop $block work would be rather more involved, as this would involve changes to the action handling of the Perl 6 grammar.
Using what is already in Perl 6, you can use Seq.from-loop in sink context.
(Note that the REPL doesn't put the last statement on a line into sink context)
my $block := {
state $n = 0;
say $n++;
last if $n > 3;
}
Seq.from-loop: $block;
Seq.from-loop: {say $++}, {$++ <= 3};

Get input and pass variable from an if statement with Haskell

Here is a simplified version of the code I'm working on.
main :: IO ()
main = do
args <- getArgs
if null args
then putStr "> " ; userInput <- getLine
else userInput <- readFile $ head args
let conclusion = userInput
This won't work without do notation, the variable won't pass to conclusion below when I do use it, and the putStr, which I'm trying to use to create a kind of prompt, just makes it mad.
Is there something that I'm forgetting to add somewhere?
There are a few problems here. First, you need to include do after then and else:
if null args
then do putStr "> " ; userInput <- getLine
else do userInput <- readFile $ head args
if in do notation is the same as if everywhere else; you have to put an expression after then and else, not statements, and you need do to turn a bunch of statements into an expression. This still isn't quite valid, though; the last statement in a do block must be an expression, but you have a bind here. After all, every statement has to have a result value, but a bind has none.
The second problem is, as you've observed, that this introduces a new scope, and so you can't access variables you bind from outside. This makes sense if you think about it; after all, you could bind the variable on one side and not the other. The solution is to simply move the bind outside the if:
main :: IO ()
main = do
args <- getArgs
userInput <- if null args
then do putStr "> " ; getLine
else readFile $ head args
let conclusion = userInput
So, the action whose result we bind to userInput is still computed depending on the result of null args, but we bind the variable outside the conditional.
Note that I didn't add a do to the else branch this time; it's not required, since there's only a single expression there. (It's still valid, but it's unidiomatic to use do when it's not necessary.)
This code still won't work unless you put something after the let conclusion = userInput line (since, like I said, do blocks must end with an expression), but presumably you already have code there.
As an additional note, you should avoid using functions like head and tail; head is a partial function (not defined for every argument — head [] will produce an error), and those are generally considered unidiomatic. You should use pattern-matching instead, like this:
userInput <- case args of
[] -> do putStr "> " ; getLine
fileName:_ -> readFile fileName
This is just like the pattern-matching used when defining a function, but for a single value rather than any number of arguments.
Any variable bindings you do in the then and else blocks won't be visible in the outer scope, so you need to bind the result from the if clause itself.
main :: IO ()
main = do
args <- getArgs
userInput <- if null args
then do
putStr "> "
getLine
else readFile $ head args