Case expression in Erlang escript - linux

I am testing my erlang escript, the content of escriptis this:
#!/usr/bin/env escript
main([Action]) ->
case Action of
start -> start();
stop -> stop()
end;
main(_) ->
usage().
usage() ->
io:format("usage: factorial integer\n"),
halt(1).
start() -> io:format("Start.~n").
stop() -> io:format("Stop.~n").
But when I try to run the escript, I got this problem:
./escript start
escript: exception error: no case clause matching "start"
What caused this problem? Is the format of argument wrong?

Command line arguments are passed as strings to main/1, not atoms, so you need to match "start" and "stop", not start and stop:
...
main([Action]) ->
case Action of
"start" -> start();
"stop" -> stop()
end;
...
Unless your actual code is more complicated/different, you can also match ["start"] and ["stop"] in the function clause directly:
main(["start"]) -> start();
main(["stop"]) -> stop();
main(_) ->
usage().
This will call usage() for ./escript foo as well while your original script would crash, which may or may not be what you want.

Related

Mapping errors from Command::new("/bin/bash") arguments

I am executing a bash command, for which I would like to catch an error when the move argument fails. Since there is one more command after move, my goal is to capture specifically whether the move operation got successfully executed to a status code and to break out of the entire Rust program.
Is there a way to accomplish this? I have provided below the source code.
let path : String = "/home/directory/".to_string();
let command = Command::new("bin/bash")
.arg("-c")
.arg("mv somefile1.txt /home/")
.arg("cp ~/somefile2.txt .")
.stdout(Stdio::piped())
.output();
bash -c doesn't accept two commands like that. You could try splitting it into two separate Commands:
Command::new("bash")
.arg("-c")
.arg("mv somefile1.txt /home/")
.status()?
.success() // bool
.then(|| ()) // convert bool to Option
.ok_or("mv failed")?; // convert Option to Result
Command::new("bash")
.arg("-c")
.arg("cp ~/somefile2.txt .")
.status()?
.success() // bool
.then(|| ()) // convert bool to Option
.ok_or("cp failed")?; // convert Option to Result
Or joining them into a single command with &&:
Command::new("bash")
.arg("-c")
.arg("mv somefile1.txt /home/ && cp ~/somefile2.txt .")
.status()?
.success() # bool
.then(|| ()) # convert bool to Option
.ok_or("failed")?; # convert Option to Result
Better yet, use native Rust functions:
mv → std::fs::rename
cp → std::fs::copy
~ → home::home_dir
This avoids the overhead of calling out to bash and is portable to non-Unix operating systems.
use std::fs;
use dirs::home_dir;
if let Some(home) = home_dir() {
fs::rename("somefile1.txt", home.join("somefile1.txt"))?;
fs::copy(home.join("somefile2.txt"), ".")?;
}

Where does a thread return after being woken up by a semaphore?

My understanding of Semaphore principle
I am currently trying to understand how Semaphores work.
I have understood that when calling P(sem), if sem=0 the thread will get blocked, otherwise the value of the semaphore will be reduced and the thread let into the critical section.
When calling V(sem), the semaphore value will be increased, if sem=0 and a thread is waiting, that thread is woken up.
Now consider this problem:
Two threads are running, thread1 runs function1, thread2 runs function2. There are two semaphores s=0 and m=1 which are shared between both threads.
function1 {
while(true) {
P(s)
P(s)
P(m)
print("a")
V(m)
}}
function2 {
while(true) {
P(m)
print("b")
V(m)
V(s)
}}
What I expected would happen
I have expected the output string to be print b's and a's in some random order.
The threads start. Let's say thread1 enters function1 first:
Step1: P(s)-> s=0 so block the thread
thread2 enters function2
P(m) -> m=1 -> set m=m-1=0
print b
V(m) -> m=m+1=1
V(s) -> s=0 and thread is wating -> set s=s+1=1 and wake up thread
Step2: Thread2 returns to the second P-statement
thread1 continues in function1
P(s) -> s=1 -> set s=s-1=0
P(m) -> m=1 -> set m=m-1=0
print a
V(m) -> m=0 but noone waiting -> set m=m+1=1
Step2: Thread1 runs function1 again
P(s) -> s=0 -> block
Thread2 runs function 2
P(m) -> m=1 -> set m=m-1=0
print b
V(m) -> m=m+1=1
V(s) -> s=0 and thread waiting -> wake up thread 2
Step3: Thread1 returns to function1 second P-statement
P(s) -> s=1 -> set s=s-1=0
P(m) -> m=1 -> set m=m-1=0
print a
V(m) -> set m=1
Step4 Thread2 runs function 2
P(m) -> m=1 -> set m=0
print b
V(m) -> set m=1
V(s) -> s=0 -> set s=1, no thread waiting
Step5 Thread 2 runs function 2 again
print b
... and so on
The Problem/The Questions
I am very unsure, if it is correct, that thread1 returns to the second P-statement after it is woken up when thread2 runs function2.
It seems wrong to me, because if I consider how a semaphore would usually be implemented:
P(s)
* do something *
V(s)
If it where to return after the P-statement, the value of the semaphore does not get decreased, and the V-statement would increase the semaphore to a wrong value of 2.
But if it repeats the first P-statement in the example, that would mean the output string is only b's.
Can someone tell me if my understanding is correct or if not, correct my mistake?

How to mark non-pure function as pure in Nim

Is there a way to mark non-pure function p as pure? Maybe with some pragma?
I'm using p for debug, and it can't be used inside pure func procs.
playground
proc p(message: string): void = echo message
func purefn: void =
p "track"
purefn()
Error:
/usercode/in.nim(3, 6) Error: 'purefn' can have side effects
Well, for a start you can just use debugEcho instead of echo - it has no side effects (and it's specifically made for use-cases like that).
In other cases you can "lie" to the compiler by doing:
proc p(message: string) =
{.cast(noSideEffect).}:
echo message
func purefn =
p "track"
purefn()
as described in https://nim-lang.org/docs/manual.html#pragmas-nosideeffect-pragma, but I would advise against it.
For your case, you can use debugEcho inside of echo which fakes having no side effects.
Other than that, you can use the {.cast(noSideEffect).} pragma if you're not using echo in your real code:
proc p(message: string): void = echo message
func purefn: void =
{.cast(noSideEffect).}:
p "track"
purefn()

Testing captured IO from a spawned process

I want to test the return value and the IO output on the following method:
defmodule Speaker do
def speak do
receive do
{ :say, msg } ->
IO.puts(msg)
speak
_other ->
speak # throw away the message
end
end
end
In the ExUnit.CaptureIO docs, there is an example test that does this which looks like the following:
test "checking the return value and the IO output" do
fun = fn ->
assert Enum.each(["some", "example"], &(IO.puts &1)) == :ok
end
assert capture_io(fun) == "some\nexample\n"
end
Given that, I thought I could write the following test that performs a similar action but with a spawned process:
test ".speak with capture io" do
pid = Kernel.spawn(Speaker, :speak, [])
fun = fn ->
assert send(pid, { :say, "Hello" }) == { :say, "Hello" }
end
assert capture_io(fun) == "Hello\n"
end
However, I get the following error message telling me there was no output, even though I can see output on the terminal:
1) test .speak with capture io (SpeakerTest)
test/speaker_test.exs:25
Assertion with == failed
code: capture_io(fun) == "Hello\n"
lhs: ""
rhs: "Hello\n"
stacktrace:
test/speaker_test.exs:30: (test)
So, am I missing something perhaps with regards to testing spawned processes or methods that use the receive macro? How can I change my test to make it pass?
CaptureIO might not be suited for what you're trying to do here. It runs a function and returns the captured output when that function returns. But your function never returns, so seems like this won't work. I came up with the following workaround:
test ".speak with capture io" do
test_process = self()
pid = spawn(fn ->
Process.group_leader(self(), test_process)
Speaker.speak
end)
send(pid, {:say, "Hello"})
assert_receive {:io_request, _, _, {:put_chars, :unicode, "Hello\n"}}
# Just to cleanup pid which dies upon not receiving a correct response
# to the :io_request after a timeout
Process.exit(pid, :kill)
end
It uses Process.group_leader to set the current process as the receiver of IO messages for the tested process and then asserts that these messages arrive.
I had a similar problem, I had a registered process on my Application that would timeout every 10 seconds and write to stdio with IO.binwrite, to simulate multiple timeouts I took upon #Pawel-Obrok answer, but change it as to reply the :io_request with an :io_reply, that way the process would not hang allowing me to send multiple messages.
defp assert_io() do
send(MyProcess, :timeout)
receive do
{:io_request, _, reply_as, {:put_chars, _, msg}} ->
assert msg == "Some IO message"
send(Stats, {:io_reply, reply_as, :ok})
_ ->
flunk
end
end
test "get multiple messages" do
Process.group_leader(Process.whereis(MyProcess), self())
assert_io()
assert_io()
end
If you want to know more about the IO protocol take a look at the erlang docs about it.

no parse exception

I am trying to cach exception caused by read function:
run :: CurrentData -> IO ()
run current = do
{
x <- (getCommandFromUser) `E.catch` handler;
updated <- executeCommand x current;
run updated;
} where handler :: E.IOException -> IO Command
handler e = do putStrLn "wrong command format" >> return (DoNothing);
In this code function getCommandfrom user gets some string from user and then tries to read some data from this string using "read" function
If read fails there is exception thrown:
*** Exception : prelude.read : no parse
and program exits...
I can't catch this exception - what is type of this exception???
I tried also E.SomeException instead of E.IOException...
E is from import Control.Exception As E
"what is type of this exception?" The type is ErrorCall, also available from Control.Exception. An ErrorCall is what is thrown when the error function is called.
Just change the type of handler and it will work. A last resort to get things working is to catch E.SomeException, but that's almost always the wrong thing to do.

Resources