What's new in Scout (command-line) 4.0.0?
This page deals with the scout command-line tool. To find out what's new in the Swift package, please refer to this page.
New command-line features list
- XML attributes can now be read. In Swift, new options offer to keep the attributes, and to specify a strategy to handle single child elements when exporting a XML explorer.
- Import a CSV file to one of the available formats with a precisely shaped structure.
- It's possible to export a single dimension array to a Zsh array, and to export a single dimension dictionary to a Zsh associative array.
Breaking changes
- Adding a value to a path with non-existing keys and indexes will not work anymore. Only when an element of the path is the last will it be valid to add a new key. The solution is now to create empty dictionaries or arrays and fill them after.
- It’s now required to indicate the data format of the input. For instance
bash scout read -i People.json -f json
. The previous implementation was checking all possible data formats to see if one was a good fit. This takes more time, and can lead to unwanted behaviours with the new usage ofCodable
since the YAML coder can also code JSON. - The force type specifications for int and boolean have been removed. They did not really make sense since they can always be correctly automatically inferred.
Set/Add group values
It’s now possible to set or add a group value to a path. An array is a list of values separated by commas and enclosed by square brackets. A dictionary is a list of (key, value) parts separated by double points. Those values are separated by commas and enclosed by squared brackets.
Some examples
Set Tom colors to an array made of strings (automatically inferred).
scout add -i People.json -f json "Tom.colors=[Blue, White, Yellow]"
Set Robert weekdays to a dictionary of integers (automatically inferred).
scout add -i People.json -f json "Robert.weekdays=[monday: 5, thirsday: 3]"
It’s possible to nest values in each other. Although it’s not recommenced to nest too much, this can be useful when the value is built programmatically.
Set Robert weekdays to a dictionary of arrays
scout add -i People.json -f json \
"Robert.weekdays=[monday: [1, 2], thirsday: [3, 4]]"
Do note that type inferring still work. This is why it’s not needed in the examples to clearly specify the type. It’s still possible also to force a type, like a string rather than an integer. For instance
scout add -i People.json -f json "Robert.scores=['123', '456']"
To force a string is done by enclosing with ”/” or ”’” like /23/
or '89'
. Forcing a real (Plist only) is done by enclosing with tildes ”~” like ~23~
.
Empty group values
As adding a value to a path will no more create dictionaries or arrays on the fly, the new method is to add empty arrays or dictionaries. To do so, specify []
for an empty array and {}
for an empty dictionary.
For instance, to add a new empty array to Robert scores.
scout add -i People.json -f json "Robert.scores=[]"
And to add a new dictionary for Robert weekdays.
scout add -i People.json -f json "Robert.weekdays={}"
Add new values
I believe this will provide a clearer and more robust interface to add new value. If it’s possible to specify arrays and dictionaries directly with the new syntax, it might be safer or easier to do it programmatically (in a loop for example).
colors=(Red White Blue)
scout add -m $file -f $format "Tom.colors=[]"
for color in $colors; do
scout add -m $file -f $format "Tom.colors[#]=$color"
done
Work with Zsh arrays
Add arrays
It’s possible set or add an array from Zsh directly by enclosing it with square brackets.
colors=(Red White Blue)
scout add -i People.json -f json "Tom.colors=[$colorsArray]"
Set associative arrays
The same is true for associatives arrays which are a counterpart of dictionaries. To specify a dictionary to Scout, it’s possible to provide a Zsh associative array as a list of key values
enclosed with curl brackets.
declare -A ducks=(Riri 10 Fifi 20 Loulou 30)
dict=${(@kv)ducks}
scout add -i $file -f $format "Tom.ducks={$dict}"
Get an array or dictionary in Zsh
Zsh integration goes in the other way with two new export functions. To get a 1-dimension array from the data, the option —export|-e
can be used with the array
option and by enclosing the result with brackets.
hobbies=("${(@f)$(scout read -i People.json -f json "Robert.hobbies" -e array)}")
echo $hobbies[1] # video games
The same goes for dictionaries to associative arrays with the dictionary
option.
declare -A movie=("${(@f)$(scout read -i People.json -f json "Suzanne.movies[0]" -e dictionary)}")
echo $movie[title] # Tomorrow is so far
XML attributes
When working with XML and the read features, Scout will allow to read an attribute with a key element.
For instance with the following XML.
<Tom score="20">
<height>175</height>
<age>68</age>
</Tom>
It’s now possible to read the score value.
scout read -i File.json -f json "Tom.score"
<Tom score="20">
<height>175</height>
<age>68</age>
</Tom>
The following will output 20
scout read -i File.json -f json "Tom.score"
When the following will output 68.
scout read -i File.json -f json "Tom.[1]"
CSV import
A new CSV import feature is available to convert a CSV input as JSON, Plist, YAML or XML. A cool feature when working with named headers is that they will be treated as paths. This can shape very precisely the structure of the converted data. For instance, the following CSV
name.first;name.last;hobbies[0];hobbies[1]
Robert;Roni;acting;driving
Suzanne;Calvin;singing;play
Tom;Cattle;surfing;watching movies
will be converted to the following Json structure.
[
{
"hobbies" : [
"acting",
"driving"
],
"name" : {
"first" : "Robert",
"last" : "Roni"
}
},
{
"hobbies" : [
"singing",
"play"
],
"name" : {
"first" : "Suzanne",
"last" : "Calvin"
}
},
{
"name" : {
"first" : "Tom",
"last" : "Cattle"
},
"hobbies" : [
"surfing",
"watching movies"
]
}
]
When there are no headers, the input will be treated as a one or two dimension(s) array.
scout csv -i people.csv -s ";" -f json --headers
The headers|--no-headers
flag is needed to specify whether the CSV string begins with named headers. It’s also possible to use the standard input to provide the CSV data.