work-in-progress
Rye uses URI-style file paths prefixed with %. These support various path operations:
; Get file extension (including the dot)
File-ext? %data/file.txt ; returns ".txt"
File-ext? %data/file.temp.png ; returns ".png"
; Get filename with extension
Filename? %path/to/document.pdf ; returns "document.pdf"
; Get filename without extension (stem)
Stem? %path/to/document.pdf ; returns "document"
; Get directory path
Dir? %path/to/document.pdf ; returns "path/to"
; Split path into components
Split %path/to/document.pdf ; returns { "path" "to" "document.pdf" }
; Check if path is absolute
Is-absolute %/home/user/file.txt ; returns true
Is-absolute %relative/path.txt ; returns false
; Check if file exists
Does-exist %data/file.txt ; returns true or false
; Read entire file as string
Read %test.txt
; returns string with full content
; Read file as block of lines
Read\lines %test.txt
; returns block with one string per line
; Read file as bytes
Read\bytes %binary.dat
; returns native bytes object
; Write string to file (creates or overwrites)
Write %output.txt "Hello, World!\n"
; returns the content that was written
For more control, you can work with file objects directly:
; Create a new file and write to it
file: Create %output.txt
file .Write "Hello, World!\n"
file .Write "Second line\n"
file .Close
; Open existing file for reading
file: Open %data.txt
content: Read-all file
file .Close
print content
; Get file information
file: Open %data.txt
info: Stat file
print "File size:" + to-string Size? info
file .Close
Rye uses a reader/writer pattern for streaming data. This allows processing large files without loading everything into memory.
; Reader from file path
reader: Reader %data.txt
; Reader from file object
file: Open %data.txt
reader: Reader file
; Reader from string (for testing/processing)
reader: reader "some string content"
; Standard input
reader: stdin
; Writer from file object
file: Create %output.txt
writer: Writer file
; Standard output/error
writer: stdout
writer: stderr
; Read all content as string
reader: Reader %data.txt
content: reader .Read\string
reader .Close
print content
; Copy without loading into memory
Open %source.txt |Copy Create %destination.txt
; Or using reader explicitly
reader: Reader %source.txt
writer: Writer Create %dest.txt
reader .Copy writer
; Open file for appending
file: Open\append %log.txt
file .Write "New log entry\n"
file .Close
The tail-file builtin monitors files for new content - useful for log file monitoring:
; Tail a file, following new content
tailer: tail-file %app.log true true
; Arguments: path, follow (true), reopen on rotation (true)
; Read lines as they are added
forever {
line: tailer .Read-line
print "New line:" ++ line
}
; Close when done
tailer .Close
; Prompt user for input
name: input "Enter your name: "
print "Hello, " ++ name
; HTTPS GET - returns response body as string
Get https://api.example.com/data |print
; HTTP GET
Get http://api.example.com/data |print
; POST with JSON content type
Post https://api.example.com/users "{\"name\":\"test\"}" 'json |print
; POST with text content type
Post https://api.example.com/submit "plain text data" 'text |print
; POST with URL-encoded form data
Post https://api.example.com/form "name=test&value=123" 'urlencoded |print
For more control over requests (custom headers, authentication), use the Request pattern:
; Create a request with custom method
req: Request https://api.example.com/resource 'POST "{\"data\":\"value\"}"
; Add headers
req .Header! 'Content-Type "application/json"
req .Header! 'Authorization "Bearer token123"
; Or use Basic Authentication
req .Basic-auth! "username" "password"
; Execute the request
response: req .Call
; Read response body
body: response .Read-body
print body
Download large files without loading into memory:
; Stream HTTPS download directly to file
Open https://example.com/large-file.zip
|Copy Create %download.zip
; With progress (using reader)
reader: Open https://example.com/file.zip
writer: Writer Create %file.zip
reader .Copy writer
; Load credentials from a file
info: context { do Load %.ftpinfo }
; Connect, login, and retrieve a file
Open ftp://download.example.com:21
|Login info/user info/pwd
|Retrieve "path/to/file.zip"
|Copy Create %local.zip
The cmd builtin creates command objects for running external programs:
; Simple command execution
cmd { echo -n Hello World } |Output
; returns "Hello World"
; Command with shell pipes
cmd { echo -n Hello World |tr A-Z a-z |sed "s/hello/goodbye/" } |Output
; returns "goodbye world"
; Embed Rye values into commands
cmd { echo -n "1 + 1 =" { 1 + 1 } } |Output
; returns "1 + 1 = 2"
; Pass list as arguments
args: list { "two" "arguments" }
cmd { printf "'%s' " ?args } |Output
; returns "'two' 'arguments' "
; Change working directory
cmd { pwd } |Dir! %/ |Output |trim
; returns "/"
; Pipe commands together
cmd { echo -n Hello World } |Pipe cmd { tr a-z A-Z } |Output
; returns "HELLO WORLD"
; Run and check success
cmd { true } |Run ; succeeds
cmd { false } |Run ; fails with error
; Get exit status
cmd { true } |Status ; returns 0
cmd { false } |Status ; returns 1
cmd { false |true } |Status ; returns list [ 1 0 ]
; Open SQLite database
db: Open sqlite://mydata.db
; Execute statements (CREATE, INSERT, UPDATE, DELETE)
db .Exec "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
db .Exec { INSERT INTO users ( name , age ) VALUES ( "Alice" , 30 ) }
; Use Rye variables in SQL (note spacing in SQL dialect)
name: "Bob"
db .Exec { INSERT INTO users ( name , age ) VALUES ( ?name , 42 ) }
; Query data
db .Query { SELECT * FROM users WHERE age > 25 } |print
; Debug SQL generation
db .Show-SQL { SELECT * FROM users WHERE name = ?name }
; returns the SQL string with parameters
; Open PostgreSQL connection
db: Open postgres://user:pass@localhost:5432/dbname
; Execute and query work the same as SQLite
db .Exec { INSERT INTO users ( name , age ) VALUES ( "Alice" , 30 ) }
result: db .Query "SELECT * FROM users"
; Open MySQL connection
db: Open mysql://user:pass@tcp(localhost:3306)/dbname
; Or with separate password
db: Open\pwd mysql://user@tcp(localhost:3306)/dbname "password"
; Execute and query
db .Exec { INSERT INTO test VALUES ( 1 , "test" ) }
id: 101
db .Query { SELECT * FROM test WHERE id = ?id }
; Read file as bytes
bytes1: Read\bytes %file1.bin
; Append two byte arrays
combined: append\bytes bytes1 bytes2
; Write bytes to file
write\bytes combined "output.bin"