Files
pkl/docs/modules/language-tutorial/pages/01_basic_config.adoc
Daniel Chao cf889246fd Add release notes for 0.28 (#978)
Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2025-02-26 07:52:21 -08:00

319 lines
8.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
= 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"]
}
----