mirror of
https://github.com/apple/pkl.git
synced 2026-05-21 14:27:07 +02:00
cf889246fd
Co-authored-by: Islon Scherer <islonscherer@gmail.com>
319 lines
8.3 KiB
Plaintext
319 lines
8.3 KiB
Plaintext
= Basic Configuration
|
|
include::ROOT:partial$component-attributes.adoc[]
|
|
|
|
In this first part of xref:index.adoc[the Pkl tutorial], you build familiarity with Pkl syntax and basic structure.
|
|
You also learn different ways to invoke Pkl to produce different formats.
|
|
|
|
== Basic values
|
|
|
|
Consider the following example Pkl file.
|
|
|
|
[source,{pkl}]
|
|
.intro.pkl
|
|
----
|
|
name = "Pkl: Configure your Systems in New Ways"
|
|
attendants = 100
|
|
isInteractive = true
|
|
amountLearned = 13.37
|
|
----
|
|
|
|
Running Pkl on this file gives
|
|
|
|
[source,shell]
|
|
----
|
|
$ pkl eval /Users/me/tutorial/intro.pkl
|
|
name = "Pkl: Configure your Systems in New Ways"
|
|
attendants = 100
|
|
isInteractive = true
|
|
amountLearned = 13.37
|
|
----
|
|
|
|
It may seem nothing happened.
|
|
However, Pkl tells you that it _accepts the input_.
|
|
In other words, you now know that `intro.pkl` does not contain any errors.
|
|
|
|
You can ask Pkl to print this configuration in a different format, using the `-f` option.
|
|
For example, JSON:
|
|
|
|
[source,shell]
|
|
----
|
|
$ pkl eval -f json /Users/me/tutorial/intro.pkl
|
|
{
|
|
"name": "Pkl: Configure your Systems in New Ways",
|
|
"attendants": 100,
|
|
"isInteractive": true,
|
|
"amountLearned": 13.37
|
|
}
|
|
----
|
|
|
|
Or _PropertyList_ format:
|
|
|
|
[source,shell]
|
|
----
|
|
$ pkl eval -f plist /Users/me/tutorial/intro.pkl
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>name</key>
|
|
<string>Pkl: Configure your Systems in New Ways</string>
|
|
<key>attendants</key>
|
|
<integer>100</integer>
|
|
<key>isInteractive</key>
|
|
<true/>
|
|
<key>amountLearned</key>
|
|
<real>13.37</real>
|
|
</dict>
|
|
</plist>
|
|
----
|
|
|
|
Notice that Pkl generated `<string>`, `<integer>`, `<true/>` and `<real>` for the values in your configuration.
|
|
This means it has _both_ correctly derived the types of the literal values _and_ translated those types to the corresponding elements in the PropertyList.
|
|
xref:03_writing_a_template.adoc[Part III] goes into types in more detail.
|
|
|
|
|
|
== Structure: Classes, objects, modules
|
|
|
|
A configuration often requires more than just basic values.
|
|
Typically, you need some kind of (hierarchical) structure.
|
|
Pkl provides _immutable objects_ for this.
|
|
|
|
Objects have three kinds of members: properties, elements and entries.
|
|
First, look at the syntax for objects and their members.
|
|
|
|
=== Properties
|
|
|
|
[source,{pkl}]
|
|
.simpleObjectWithProperties.pkl
|
|
----
|
|
bird { // <1>
|
|
name = "Common wood pigeon" // <2>
|
|
diet = "Seeds"
|
|
taxonomy { // <3>
|
|
species = "Columba palumbus"
|
|
}
|
|
}
|
|
----
|
|
<1> This _defines_ `bird` to be an object
|
|
<2> For primitive values, Pkl has the `=` syntax (more on this later).
|
|
<3> Just like `bird {`, but to show that objects can be nested.
|
|
|
|
This defines an object called `bird` with three _named properties_: `name`, `diet`, and `taxonomy`.
|
|
The first two of these are strings, but `taxonomy` is another object.
|
|
This means properties in an object can have different types and objects can be nested.
|
|
|
|
=== Elements
|
|
|
|
Of course, you don't always have names for every individual structure in your configuration.
|
|
What if you want "just a bunch of things" without knowing how many?
|
|
Pkl offers _elements_ for this purpose.
|
|
Elements are object members, just like properties.
|
|
Where you index properties by their name, you index elements by an integer.
|
|
You can think of an object that only contains elements as _array_.
|
|
Much like arrays in many languages, you can use square brackets to access an element, for example, `myObject[42]`.
|
|
|
|
You write an element, by writing only an expression.
|
|
Pkl derives the index from the number of elements already in the object.
|
|
For example:
|
|
|
|
[source,{pkl}]
|
|
.simpleObjectsWithElements.pkl
|
|
----
|
|
exampleObjectWithJustIntElements {
|
|
100 // <1>
|
|
42
|
|
}
|
|
|
|
exampleObjectWithMixedElements {
|
|
"Bird Breeder Conference"
|
|
(2000 + 23) // <2>
|
|
exampleObjectWithJustIntElements // <3>
|
|
}
|
|
----
|
|
<1> When you write only the value (without a name), you describe an _element_.
|
|
<2> Elements don't have to be literal values; they can be arbitrary _expressions_.
|
|
<3> Elements can really be _any_ value, not just primitive values.
|
|
|
|
[[entries]]
|
|
=== Entries
|
|
|
|
Objects can have one more kind of member; _entries_.
|
|
Like a _property_, an _entry_ is "named" (technically _keyed_).
|
|
Unlike a property, the name does not need to be known at declaration time.
|
|
Of course, we need a syntax to tell entries apart from properties.
|
|
You write entry "names" by enclosing them in square brackets ("names" is quoted, because the names do not need to be strings; any value can index entries).
|
|
|
|
[source,{pkl}]
|
|
.simpleObjectsWithEntries.pkl
|
|
----
|
|
pigeonShelter {
|
|
["bird"] { // <1>
|
|
name = "Common wood pigeon"
|
|
diet = "Seeds"
|
|
taxonomy {
|
|
species = "Columba palumbus"
|
|
}
|
|
}
|
|
["address"] = "355 Bird St." // <2>
|
|
}
|
|
|
|
birdCount {
|
|
[pigeonShelter] = 42 // <3>
|
|
}
|
|
----
|
|
<1> The difference with properties is the notation of the key: `[<expression>]`.
|
|
<2> As with properties, entries can be primitive values or objects.
|
|
<3> Any object can be used as a key for an entry.
|
|
|
|
|
|
=== Mixed members
|
|
|
|
In the examples so far, you have seen objects with properties, object with elements and object with entries.
|
|
These object members can be freely mixed.
|
|
|
|
[source,{pkl}]
|
|
.mixedObject.pkl
|
|
----
|
|
mixedObject {
|
|
name = "Pigeon"
|
|
lifespan = 8
|
|
"wing"
|
|
"claw"
|
|
["wing"] = "Not related to the _element_ \"wing\""
|
|
42
|
|
extinct = false
|
|
[false] {
|
|
description = "Construed object example"
|
|
}
|
|
}
|
|
----
|
|
|
|
Notice, how properties (`name`, `lifespan` and `extinct`), elements (`"wing"`, `"claw"`, `42`) and entries (`"wing"`, `false`) are mixed together in this one object.
|
|
You don't have to order them by kind, and you don't require (other) special syntax.
|
|
|
|
=== Collections
|
|
|
|
This free-for-all mixing of object members can become confusing.
|
|
Also, target formats are often considerably more restrictive.
|
|
In the following example, you see what happens when you try to produce JSON from `mixedObject`:
|
|
|
|
[source,shell]
|
|
----
|
|
$ pkl eval -f json /Users/me/tutorial/mixedObject.pkl
|
|
–– Pkl Error ––
|
|
Cannot render object with both properties/entries and elements as JSON.
|
|
Object: "Pigeon"
|
|
|
|
89 | text = renderer.renderDocument(value)
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L90)
|
|
----
|
|
|
|
This is why Pkl has two special types of object, namely _listings_, which contain _exclusively_ elements, and _mappings_, which contain _exclusively_ entries.
|
|
Both listings and mappings _are_ "just objects," so, they don't require syntax besides that of objects:
|
|
|
|
[source,{pkl}]
|
|
.collections.pkl
|
|
----
|
|
birds { // <1>
|
|
"Pigeon"
|
|
"Parrot"
|
|
"Barn owl"
|
|
"Falcon"
|
|
}
|
|
|
|
habitats { // <2>
|
|
["Pigeon"] = "Streets"
|
|
["Parrot"] = "Parks"
|
|
["Barn owl"] = "Forests"
|
|
["Falcon"] = "Mountains"
|
|
}
|
|
----
|
|
<1> A listing containing four elements.
|
|
<2> A mapping containing four entries.
|
|
|
|
[NOTE]
|
|
====
|
|
_Technically_, the correct way to define `birds` and `habitats` is by using `new Listing {...}` and `new Mapping {...}` explicitly.
|
|
You will see what these mean in part xref:03_writing_a_template.adoc[three] of this tutorial.
|
|
====
|
|
|
|
When you render _this_ configuration as JSON, everything works:
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"birds": [
|
|
"Pigeon",
|
|
"Parrot",
|
|
"Barn owl",
|
|
"Falcon"
|
|
],
|
|
"habitats": {
|
|
"Pigeon": "Streets",
|
|
"Parrot": "Parks",
|
|
"Barn owl": "Forests",
|
|
"Falcon": "Mountains"
|
|
}
|
|
}
|
|
----
|
|
|
|
Notice particularly, that you rendered the listing as a JSON _array_.
|
|
When you index the listing with an integer, you're referring to the element inside the listing at the corresponding position (starting from `0`).
|
|
For example:
|
|
|
|
[source,{pkl}]
|
|
.indexedListing.pkl
|
|
----
|
|
birds {
|
|
"Pigeon"
|
|
"Parrot"
|
|
"Barn owl"
|
|
"Falcon"
|
|
}
|
|
|
|
relatedToSnowOwl = birds[2]
|
|
----
|
|
results in
|
|
[source,{pkl}]
|
|
----
|
|
birds {
|
|
"Pigeon"
|
|
"Parrot"
|
|
"Barn owl"
|
|
"Falcon"
|
|
}
|
|
relatedToSnowOwl = "Barn owl"
|
|
----
|
|
|
|
== Exercises
|
|
|
|
1. Given the following JSON snippet (taken from W3C examples), write the `.pkl` file that produces this JSON:
|
|
|
|
+
|
|
[source,json]
|
|
----
|
|
{
|
|
"name": "Common wood pigeon",
|
|
"lifespan": 8,
|
|
"friends": {
|
|
"bird1": "Parrot",
|
|
"bird2": "Albatross",
|
|
"bird3": "Falcon"
|
|
}
|
|
}
|
|
----
|
|
|
|
2. For some reason, we decide we no longer need the birdX names of the different birds; we just need them as an array.
|
|
Change your solution to the previous question to produce the following JSON result:
|
|
|
|
+
|
|
[source,json]
|
|
----
|
|
{
|
|
"name": "Common wood pigeon",
|
|
"lifespan": 8,
|
|
"birds": ["Parrot", "Barn owl", "Falcon"]
|
|
}
|
|
----
|