Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.roc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
app [main] {
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.13.0/nW9yMRtZuCYf1Oa9vbE5XoirMwzLbtoSgv7NGhUlqYA.tar.br",
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.14.0/dC5ceT962N_4jmoyoffVdphJ_4GlW3YMhAPyGPr-nU0.tar.br",
}

import cli.Task exposing [Task]
Expand Down
4 changes: 2 additions & 2 deletions examples/command.roc
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ respond : Request, Model -> Task Response [ServerErr Str]_
respond = \req, _ ->
# Log request date, method and url using echo program
datetime = Utc.now! |> Utc.toIso8601Str
result <-
result =
Command.new "echo"
|> Command.arg "$(datetime) $(Http.methodToStr req.method) $(req.url)"
|> Command.status
|> Task.attempt
|> Task.result!

when result is
Ok {} -> okHttp "Command succeeded."
Expand Down
36 changes: 15 additions & 21 deletions examples/dir.roc
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,24 @@ server = { init: Task.ok {}, respond }
respond : Request, Model -> Task Response [ServerErr Str]_
respond = \_, _ ->
# Get current working directory
{} <-
Env.cwd
|> Task.await \cwd -> Stdout.line "The current working directory is $(Path.display cwd)"
|> Task.onErr \CwdUnavailable -> Stderr.line "Unable to read current working directory"
|> Task.await
Env.cwd
|> Task.await \cwd -> Stdout.line "The current working directory is $(Path.display cwd)"
|> Task.onErr! \CwdUnavailable -> Stderr.line "Unable to read current working directory"

# Try to set cwd to examples
{} <-
Env.setCwd (Path.fromStr "examples")
|> Task.await \{} -> Stdout.line "Set cwd to examples/"
|> Task.onErr \InvalidCwd -> Stderr.line "Unable to set cwd to examples/"
|> Task.await
Env.setCwd (Path.fromStr "examples")
|> Task.await \{} -> Stdout.line "Set cwd to examples/"
|> Task.onErr! \InvalidCwd -> Stderr.line "Unable to set cwd to examples/"

# List contents of examples directory
{} <-
Dir.list (Path.fromStr "./")
|> Task.await \paths ->
paths
|> List.map Path.display
|> Str.joinWith ","
|> \pathsStr -> "The paths are;\n$(pathsStr)"
|> Stdout.line
|> Task.onErr \DirReadErr path err ->
Stderr.line "Error reading directory $(Path.display path):\n\t$(err)"
|> Task.await
Dir.list (Path.fromStr "./")
|> Task.await \paths ->
paths
|> List.map Path.display
|> Str.joinWith ","
|> \pathsStr -> "The paths are;\n$(pathsStr)"
|> Stdout.line
|> Task.onErr! \DirReadErr path err ->
Stderr.line "Error reading directory $(Path.display path):\n\t$(err)"

Task.ok { status: 200, headers: [], body: Str.toUtf8 "Logged request" }
2 changes: 1 addition & 1 deletion examples/error-handling.roc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ handleErr = \appErr ->
HttpErr err -> "Http error fetching content:\n\t$(Inspect.toStr err)"
# Log error to stderr
Stderr.line! "Internal Server Error:\n\t$(errMsg)"
_ <- Stderr.flush |> Task.attempt
Stderr.flush!

# Respond with Http 500 Error
Task.ok {
Expand Down
10 changes: 6 additions & 4 deletions examples/sqlite3.roc
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ server = { init: Task.ok {}, respond }
respond : Request, Model -> Task Response [ServerErr Str]_
respond = \_, _ ->
# Read DB_PATH environment variable
maybeDbPath <- Env.var "DB_PATH" |> Task.attempt
maybeDbPath =
Env.var "DB_PATH"
|> Task.result
|> Task.mapErr! \_ -> ServerErr "DB_PATH not set on environment"

# Query todos table
rows <-
rows =
SQLite3.execute {
path: maybeDbPath |> Result.withDefault "<DB_PATH> not set on environment",
query: "SELECT id, task FROM todos WHERE status = :status;",
Expand All @@ -28,10 +31,9 @@ respond = \_, _ ->
when cols is
[Integer id, String task] -> "row $(Num.toStr id), task: $(task)"
_ -> crash "unexpected values returned, expected Integer and String got $(Inspect.toStr cols)"
|> Task.onErr \err ->
|> Task.onErr! \err ->
# Crash on any errors for now
crash "$(SQLite3.errToStr err)"
|> Task.await

body = rows |> Str.joinWith "\n"
# Print out the results
Expand Down
Binary file modified examples/todos.db
Binary file not shown.
12 changes: 5 additions & 7 deletions examples/todos.roc
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,26 @@ routeTodos = \dbPath, req ->

listTodos : Str -> Task Response *
listTodos = \dbPath ->
output <-
output =
Command.new "sqlite3"
|> Command.arg dbPath
|> Command.arg ".mode json"
|> Command.arg "SELECT id, task, status FROM todos;"
|> Command.output
|> Task.await
|> Command.output!

when output.status is
Ok {} -> jsonResponse output.stdout
Err _ -> byteResponse 500 output.stderr

createTodo : Str, { task : Str, status : Str } -> Task Response *
createTodo = \dbPath, { task, status } ->
output <-
output =
Command.new "sqlite3"
|> Command.arg dbPath
|> Command.arg ".mode json"
|> Command.arg "INSERT INTO todos (task, status) VALUES ('$(task)', '$(status)');"
|> Command.arg "SELECT id, task, status FROM todos WHERE id = last_insert_rowid();"
|> Command.output
|> Task.await
|> Command.output!

when output.status is
Ok {} -> jsonResponse output.stdout
Expand Down Expand Up @@ -166,7 +164,7 @@ handleErr = \appErr ->

# Log error to stderr
Stderr.line! "Internal Server Error:\n\t$(errMsg)"
_ <- Stderr.flush |> Task.attempt
Stderr.flush!

# Respond with Http 500 Error
Task.ok {
Expand Down
11 changes: 5 additions & 6 deletions platform/Command.roc
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,12 @@ clearEnvs = \@Command cmd ->
## > Stdin is not inherited from the parent and any attempt by the child process
## > to read from the stdin stream will result in the stream immediately closing.
## ```
## output <-
## output =
## Command.new "sqlite3"
## |> Command.arg dbPath
## |> Command.arg ".mode json"
## |> Command.arg "SELECT id, task, status FROM todos;"
## |> Command.output
## |> Task.await
## |> Command.output!
##
## when output.status is
## Ok {} -> jsonResponse output.stdout
Expand All @@ -160,12 +159,12 @@ output = \@Command cmd ->
## Execute command and inheriting stdin, stdout and stderr from parent
## ```
## # Log request date, method and url using echo program
## date <- Utc.now |> Task.map Utc.toIso8601Str |> Task.await
## result <-
## date = Utc.now |> Task.map! Utc.toIso8601Str
## result =
## Command.new "echo"
## |> Command.arg "$(date) $(Http.methodToStr req.method) $(req.url)"
## |> Command.status
## |> Task.attempt
## |> Task.result!
##
## when result is
## Ok {} -> respond "Command succeeded"
Expand Down
19 changes: 8 additions & 11 deletions platform/Http.roc
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,9 @@ errorToString = \err ->
##
## ```
## # Prints out the HTML of the Roc-lang website.
## response <-
## response =
## { Http.defaultRequest & url: "https://www.roc-lang.org" }
## |> Http.send
## |> Task.await
## |> Http.send!
##
## response.body
## |> Str.fromUtf8
Expand Down Expand Up @@ -217,17 +216,15 @@ parseFormUrlEncoded = \bytes ->
[] if List.isEmpty chomped -> dict |> Ok
[] ->
# chomped last value
keyStr <- key |> chainUtf8
valueStr <- chomped |> chainUtf8

Dict.insert dict keyStr valueStr |> Ok
key |> chainUtf8 \keyStr ->
chomped |> chainUtf8 \valueStr ->
Dict.insert dict keyStr valueStr |> Ok

['=', ..] -> parse tail ParsingValue chomped [] dict # put chomped into key
['&', ..] ->
keyStr <- key |> chainUtf8
valueStr <- chomped |> chainUtf8

parse tail ParsingKey [] [] (Dict.insert dict keyStr valueStr)
key |> chainUtf8 \keyStr ->
chomped |> chainUtf8 \valueStr ->
parse tail ParsingKey [] [] (Dict.insert dict keyStr valueStr)

['%', secondByte, thirdByte, ..] ->
hex = Num.toU8 (hexBytesToU32 [secondByte, thirdByte])
Expand Down
8 changes: 4 additions & 4 deletions platform/InternalHttp.roc
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ ErrorBody := List U8 implements [

errorBodyToInspector : ErrorBody -> _
errorBodyToInspector = \@ErrorBody val ->
fmt <- Inspect.custom
when val |> List.takeFirst 50 |> Str.fromUtf8 is
Ok str -> Inspect.apply (Inspect.str str) fmt
Err _ -> Inspect.apply (Inspect.str "Invalid UTF-8 data") fmt
Inspect.custom \fmt ->
when val |> List.takeFirst 50 |> Str.fromUtf8 is
Ok str -> Inspect.apply (Inspect.str str) fmt
Err _ -> Inspect.apply (Inspect.str "Invalid UTF-8 data") fmt

errorBodyToUtf8 : ErrorBody -> List U8
errorBodyToUtf8 = \@ErrorBody body -> body
Expand Down
5 changes: 2 additions & 3 deletions platform/SQLite3.roc
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ execute :
}
-> Task (List (List InternalSQL.SQLiteValue)) Error
execute = \{ path, query, bindings } ->
result <-
result =
Effect.sqliteExecute path query bindings
|> InternalTask.fromEffect
|> Task.attempt
|> Task.result!

when result is
Ok rows -> Task.ok rows
Expand Down Expand Up @@ -139,4 +139,3 @@ errToStr = \err ->
DONE -> "DONE: sqlite3_step() has finished executing"

"$(msg1) - $(msg2)"

20 changes: 8 additions & 12 deletions platform/Task.roc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module [
fromResult,
batch,
result,
sequence,
sequence,
forEach,
]

Expand Down Expand Up @@ -88,8 +88,7 @@ err = \a -> InternalTask.err a
## We can use [attempt] to handle the failure cases using the following;
##
## ```
## result <- canFail |> Task.attempt
## when result is
## when canFail |> Task.result! is
## Ok Success -> Stdout.line "Success!"
## Err Failure -> Stdout.line "Oops, failed!"
## Err AnotherFail -> Stdout.line "Ooooops, another failure!"
Expand Down Expand Up @@ -117,8 +116,8 @@ attempt = \task, transform ->
##
## ```
## # Prints "Hello World!\n" to standard output.
## {} <- Stdout.write "Hello "|> Task.await
## {} <- Stdout.write "World!\n"|> Task.await
## Stdout.write! "Hello "
## Stdout.write! "World!\n"
##
## Task.ok {}
## ```
Expand Down Expand Up @@ -218,9 +217,7 @@ awaitResult = \res, transform ->
## ```
batch : Task a c -> (Task (a -> b) c -> Task b c)
batch = \current -> \next ->
f <- next |> await

map current f
next |> await \f -> map current f

## Transform a task that can either succeed with `ok`, or fail with `err`, into
## a task that succeeds with `Result ok err`.
Expand Down Expand Up @@ -249,7 +246,7 @@ result = \task ->


## Apply each task in a list sequentially, and return a [Task] with the list of the resulting values.
## Each task will be awaited (see [Task.await]) before beginning the next task,
## Each task will be awaited (see [Task.await]) before beginning the next task,
## execution will stop if an error occurs.
##
## ```
Expand All @@ -262,9 +259,8 @@ result = \task ->
sequence : List (Task ok err) -> Task (List ok) err
sequence = \tasks ->
List.walk tasks (InternalTask.ok []) \state, task ->
value <- task |> await

state |> map \values -> List.append values value
task |> await \value ->
state |> map \values -> List.append values value

## Apply a function that returns `Task {} _` for each item in a list.
## Each task will be awaited (see [Task.await]) before beginning the next task,
Expand Down
21 changes: 9 additions & 12 deletions platform/Tcp.roc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ StreamErr : InternalTcp.StreamErr
##
## ```
## # Connect to localhost:8080 and send "Hi from Roc!"
## stream <- Tcp.withConnect "localhost" 8080
## stream = Tcp.withConnect! "localhost" 8080
## Tcp.writeUtf8 "Hi from Roc!" stream
## ```
##
Expand All @@ -44,18 +44,16 @@ StreamErr : InternalTcp.StreamErr
##
withConnect : Str, U16, (Stream -> Task a err) -> Task a [TcpConnectErr ConnectErr, TcpPerformErr err]
withConnect = \hostname, port, callback ->
stream <- connect hostname port
|> Task.mapErr TcpConnectErr
|> Task.await
stream = connect hostname port
|> Task.mapErr! TcpConnectErr

result <- callback stream
result = callback stream
|> Task.mapErr TcpPerformErr
|> Task.onErr
|> Task.onErr!
(\err ->
_ <- close stream |> Task.await
close! stream
Task.err err
)
|> Task.await

close stream
|> Task.map \_ -> result
Expand All @@ -76,7 +74,7 @@ close = \stream ->
##
## ```
## # Read up to 64 bytes from the stream and convert to a Str
## received <- File.readUpTo 64 stream |> Task.await
## received = File.readUpTo! 64 stream
## Str.fromUtf8 received
## ```
##
Expand Down Expand Up @@ -135,15 +133,15 @@ readUntil = \byte, stream ->
##
## ```
## # Read a line and then print it to `stdout`
## lineStr <- File.readLine stream |> Task.await
## lineStr = File.readLine! stream
## Stdout.line lineStr
## ```
##
## If found, the newline is included as the last character in the [Str].
##
readLine : Stream -> Task Str [TcpReadErr StreamErr, TcpReadBadUtf8 _]
readLine = \stream ->
bytes <- readUntil '\n' stream |> Task.await
bytes = readUntil! '\n' stream

Str.fromUtf8 bytes
|> Result.mapErr TcpReadBadUtf8
Expand Down Expand Up @@ -223,4 +221,3 @@ streamErrToStr = \err ->
Unrecognized code message ->
codeStr = Num.toStr code
"Unrecognized Error: $(codeStr) - $(message)"