Module /fusion/io
Basic input/output features. At present these are generally Ion-oriented.
Reading Ion Data
The current Ion input port is an internal parameter that is the default
source for reading Ion data. If it is not parameterized
via one of the with_ion_from_* procedures, it is initialized from stdin
when it's first needed.
The recommended way to consume a stream of Ion data is to use the
in_port series in conjuction with a
for comprehension. For example, to consume all
remaining data on the current Ion input port into a list of top-level values,
you can write:
(for_list [(v (in_port))]
v)
Or, more directly:
(series_to_list (in_port))
The general comprehension pattern is valuable when you need to transform the
data, since you can do it on-the-fly. For example, to extract the
address fields from a document of structs:
(for_list [(v (in_port))]
(. v "address"))
At a lower level than in_port, the read procedure
produces one datum from the current port at a time, then a dedicated
end-of-file marker. For example, to write (as Ion lines) those addresses to
the current output port:
(let loop [(value (read))]
(unless (is_eof value)
(writeln (. value "address"))
(loop (read))))
As you can see, read can be awkward when handling more than one datum, so
it's usually better to use one of the series-orient approachs above.
In this case, since we evoke side effects (printing) and don't need a
result container, we can use for:
(for [(v (in_port))]
(writeln (. value "address"))
The input port consumed by read and in_port can be "redirected" via
procedures like with_ion_from_file,
with_ion_from_lob, and
with_ion_from_string, which
parameterize the current input port for the duration of their invocation.
For example, this procedure reads a file into a list of top-level values:
(define ion_file_to_list (path)
(with_ion_from_file path
(lambda ()
(series_to_list (in_port)))))
Output
There are three "styles" of output:
ionizeis for strict generation of Ion data. If ionization encounters a value that is not within the Ion type system, an exception is thrown.writeis lax generation of Ion data. It works likeionizeexcept that it outputs non-Ion values in a manner that is generally unreadable by an Ion parser.displayis for human-readable content. It works likewriteexcept for character data types (strings and symbols), which are output as-is without escapes.
These procedures render to the current output port, an internal parameter that's currently not accessible from this library, but that is configurable upon launch of the Fusion runtime. See FusionRuntimeBuilder for details.
Exported Bindings
(current_directory)
Returns the absolute path of the current working directory.
This is a parameter, so the value is thread-local and
dynamically scoped via parameterize.
(display value ...)
Outputs a text representation of the values to the current output port, in a
form meant for human consumption.
When a value is an unannotated string or symbol, its character data is written
as-is, unquoted and unescaped.
All other values are rendered as by write.
No characters are written between the values.
In general, the result will be unreadable by the Fusion and Ion readers.
(display_to_string value ...)
Returns a string with a human-oriented text representation of the values.
The output format is as defined by display.
(displayln value ...)
Displays the values, then a newline.
A unique value that denotes an end-of-file condition.
(ionize value)
Outputs an Ion text representation of value to the current output port,
throwing an exception if the value contains any non-Ionizable data like closures.
See write for an alternative that doesn't fail an
non-Ionizable inputs.
(ionize_to_blob value)
Encodes an Ion binary representation of value, throwing an exception if the
value contains any non-Ionizable data like closures. The result is a blob
containing an Ion binary document.
(ionize_to_string value)
Encodes an Ion text representation of value, throwing an exception if the
value contains any non-Ionizable data like closures. The result is a string
containing an Ion text document.
(is_eof value)
Determines whether a value is the Fusion end-of-file value. This value is
bound to the name eof.
(jsonize_to_string value)
Encodes an JSON text representation of value, throwing an exception if the
value contains any non-Ionizable data like closures. The result is a string
containing a JSON text document.
Compared to ionize_to_string, this method applies these conversions:
- All annotations are suppressed.
- Nulls of any type are printed as JSON
null. - Blobs are printed as strings, containing Base64.
- Clobs are printed as strings, containing only Unicode code points U+00 through U+FF.
- Sexps are printed as lists.
- Symbols are printed as strings.
- Timestamps are printed as strings, using Ion timestamp format.
(read)
Reads an Ion value from the current Ion input port.
Returns eof when there's no more data.
Here's one way to print to stdout the address fields of the
structs on stdin:
(let loop [(value (read))]
(unless (is_eof value)
(writeln (. value "address"))
(loop (read))))
In general, read is more low-level than necessary;
see /fusion/io for more options.
(with_ion_from_file path thunk)
Opens the file at path and uses it as the current Ion input port while
applying the thunk. The file is closed when the thunk returns (normally or
abnormally).
The path must be a non-empty string denoting the file to read. If the path
is relative, it is resolved against
current_directory.
The thunk must be a procedure that accepts zero arguments.
A common use of this procedure is to read the top-level Ion values from a file into a list:
(with_ion_from_file "path/to/file.ion"
(|| (series_to_list (in_port))))
For other idioms, see /fusion/io.
(with_ion_from_lob lob thunk)
Uses the content of lob (a blob or clob) as the current Ion input port
while applying the thunk.
The lob must be non-null and may contain Ion text or binary data.
The thunk must be a procedure that accepts zero arguments.
A common use of this procedure is to read a single Ion value from the data:
(with_ion_from_lob {{"[only_me]"}} read) --> [only_me]
A common use of this procedure is to read the top-level Ion values from a lob into a list:
(with_ion_from_lob {{"[first] 2"}} // Reading from a clob
(|| (series_to_list (in_port))))
=>
[[first], 2]
For other idioms, see /fusion/io.
(with_ion_from_string string thunk)
Uses the content of string as the current Ion input port
while applying the thunk.
The string must be non-null and must contain Ion text data.
The thunk must be a procedure that accepts zero arguments.
A common use of this procedure is to read a single Ion value from the data:
(with_ion_from_string "123" read) --> 123
This leverages the fact that read accepts zero arguments and consumes the
current Ion input port. Note that this is likely to be more lenient than you
wish, since the input is treated as a full Ion document:
(with_ion_from_string "$ion_1_0 123 /* ignored */" read) --> 123
If more than one value is expected, you can read them all into a list:
(with_ion_from_string "1 k {a:false}"
(|| (series_to_list (in_port))))
=>
[1, k, {a:false}]
For other idioms, see /fusion/io.
(write value)
Outputs a text representation of value to the current output port, following
Ion syntax where possible.
The result will be unreadable (by the Fusion and Ion readers) if the value
contains any non-Ionizable data like closures.
Contrast this with ionize, which throws an exception
in such cases.
(writeln value)
Writes the value, then a newline.