Update lang.md with latest REPL behaviour

This commit is contained in:
Torin Sandall
2016-06-22 15:55:09 -07:00
parent 3145751c05
commit 88f6232f13
+96 -132
View File
@@ -25,66 +25,62 @@ Rego is declarative so policy authors can focus on what queries should return ra
## The Basics
This section introduces the main aspsects of Rego.
This section introduces the main aspects of Rego.
The simplest rule is a single expression and is defined in terms of a [Scalar Value](#scalar-values):
```rego
pi = 3.14159 :- true
pi = 3.14159
```
Rules define the content of documents. We can query for the content of the "pi" document generated by the rule above:
```
> pi = x
+---------+
| X |
+---------+
| 3.14159 |
+---------+
> pi
3.14159
```
Rules can also be defined in terms of [Composite Values](#composite-values):
```rego
rect = {"width": 2, "height": 4} :- true
rect = {"width": 2, "height": 4}
```
The result:
```
> rect = x
+------------------------+
| X |
+------------------------+
| {"height":4,"width":2} |
+------------------------+
> rect
{
"height": 4,
"width": 2
}
```
Many expressions are defined in terms of [Equality](#equality). These expressions can be thought of as assertions. The simplest example of a rule containing an equality expression involves two scalar values:
```rego
v :- 42 = "the meaning of life"
v = true :- 42 = "the meaning of life"
```
If we query for the contents of "v" we see the expression has been evaluated:
We can evaluate "v" to check if it is equal to true:
```
> v = true
false
```
The order of operands in an equality expression does not matter. The result is the same:
```
> true = v
false
```
If we evaluate "v" on its own, the REPL prints "undefined" because the body of the rule never evaluates to true. As a result, the document generated by the rule is undefined.
```
> v
false
```
The order of operands in an equality expression does not matter:
```rego
u :- "the meaning of life" = 42
```
The result is the same:
```
> u
false
undefined
```
We can define rules in terms of [Variables](#variables) as well:
@@ -115,10 +111,11 @@ The query result is the same:
true
```
Rego supports [References](#references) to nested documents. For example:
Rego [References](#references) help you refer to nested documents. For example:
```rego
sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] :- true
sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}]
r :- sites[i].name = "prod"
```
@@ -134,7 +131,6 @@ true
We can generalize the example above with a rule that defines a set document instead of a boolean document:
```rego
sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] :- true
q[name] :- sites[i].name = name
```
@@ -143,7 +139,7 @@ When we query for "q" we obtain a set of names:
```repl
> q[x]
+----------+
| X |
| x |
+----------+
| "prod" |
| "smoke1" |
@@ -168,7 +164,7 @@ Rules which have arguments can be queried with input values:
```
> q["smoke2"]
false
undefined
> q["dev"]
true
```
@@ -195,36 +191,16 @@ sentinel = null
These documents can be queried like any other:
```
> greeting = x
+---------+
| X |
+---------+
| "Hello" |
+---------+
> max_height = x
+----+
| X |
+----+
| 42 |
+----+
> pi = x
+---------+
| X |
+---------+
| 3.14159 |
+---------+
> allowed = x
+------+
| X |
+------+
| true |
+------+
> sentinel = x
+------+
| X |
+------+
| null |
+------+
> greeting
"Hello"
> max_height
42
> pi
3.14159
> allowed
true
> sentinel
null
```
## <a name="composite-values"></a> Composite Values
@@ -239,16 +215,11 @@ cube = {"width": 3, "height": 4, "depth": 5}
The result:
```
> cube.width = x
+---+
| X |
+---+
| 3 |
+---+
> cube.width
3
```
Composite values can also be defined in terms of [Variables](#variables) or
[References](#references). For example:
Composite values can also be defined in terms of [Variables](#variables) or [References](#references). For example:
```
> a = 42, b = false, c = null, d = {"a": a, "x": [b, c]}
@@ -273,6 +244,7 @@ For example:
```rego
sites = [{"name": "prod"}, {"name": "smoke1"}, {"name": "dev"}] :- true
q[name] :- sites[i].name = name
```
@@ -281,7 +253,7 @@ In this case, we evaluate "q" with a variable "x" (which is not bound to a value
```
> q[x]
+----------+
| X |
| x |
+----------+
| "prod" |
| "smoke1" |
@@ -293,7 +265,7 @@ On the other hand, if we evaluate "q" with an input value for "name" we can dete
```
> q["smoke2"]
false
undefined
> q["dev"]
true
```
@@ -315,23 +287,15 @@ reference returns the hostname of the second server in the first site document
from our example data:
```
> sites[0].servers[1].hostname = hostname
+----------+
| HOSTNAME |
+----------+
| "helium" |
+----------+
> sites[0].servers[1].hostname
"helium"
```
References are typically written using the "dot-access" style. The canonical form does away with "." and closely resembles dictionary lookup in a language such as Python:
```
> sites[0]["servers"][1]["hostname"] = hostname
+----------+
| HOSTNAME |
+----------+
| "helium" |
+----------+
> sites[0]["servers"][1]["hostname"]
"helium"
```
Both forms are valid, however, the "dot-access" style is typically more readable. Note, there are two cases where brackets need to be used:
@@ -356,19 +320,19 @@ The following reference will select the hostnames of all the servers in our
example data:
```
> sites[i].servers[j].hostname = hostname
+------------+---+---+
| HOSTNAME | I | J |
+------------+---+---+
| "hydrogen" | 0 | 0 |
| "helium" | 0 | 1 |
| "lithium" | 0 | 2 |
| "berylium" | 1 | 0 |
| "boron" | 1 | 1 |
| "carbon" | 1 | 2 |
| "nitrogen" | 2 | 0 |
| "oxygen" | 2 | 1 |
+------------+---+---+
> sites[i].servers[j].hostname
+---+---+------------------------------+
| i | j | sites[i].servers[j].hostname |
+---+---+------------------------------+
| 0 | 0 | "hydrogen" |
| 0 | 1 | "helium" |
| 0 | 2 | "lithium" |
| 1 | 0 | "berylium" |
| 1 | 1 | "boron" |
| 1 | 2 | "carbon" |
| 2 | 0 | "nitrogen" |
| 2 | 1 | "oxygen" |
+---+---+------------------------------+
```
Conceptually, this is the same as the following imperative code (Python):
@@ -385,19 +349,19 @@ def hostnames(sites):
In the reference above, we effectively used variables named "i" and "j" to iterate the collections. If the variables are unused outside the reference, we prefer to replace them with an underscore ("_") character. The reference above can be rewritten as:
```
> sites[_].servers[_].hostname = hostname
+------------+
| HOSTNAME |
+------------+
| "hydrogen" |
| "helium" |
| "lithium" |
| "berylium" |
| "boron" |
| "carbon" |
| "nitrogen" |
| "oxygen" |
+------------+
> sites[_].servers[_].hostname
+------------------------------+
| sites[_].servers[_].hostname |
+------------------------------+
| "hydrogen" |
| "helium" |
| "lithium" |
| "berylium" |
| "boron" |
| "carbon" |
| "nitrogen" |
| "oxygen" |
+------------------------------+
```
The underscore is special because it cannot be referred to by other parts of the rule, e.g., the other side of the expression, another expression, etc. The underscore can be thought of as a special iterator. Each time an underscore is specified, a new iterator is instantiated.
@@ -422,7 +386,7 @@ The result:
```
> apps_and_hostnames[x]
+----------------------+
| X |
| x |
+----------------------+
| ["web","hydrogen"] |
| ["web","helium"] |
@@ -461,7 +425,7 @@ The result:
```
> same_site[x]
+-------+
| X |
| x |
+-------+
| "web" |
| "web" |
@@ -481,7 +445,7 @@ The body of a comprehension is able to refer to variables defined in the outer b
```
> region = "west", names = [name | sites[i].region = region, sites[i].name = name]
+-----------------+--------+
| NAMES | REGION |
| names | region |
+-----------------+--------+
| ["smoke","dev"] | "west" |
+-----------------+--------+
@@ -525,7 +489,7 @@ The result:
```
> app_to_hostnames[app] = hostnames
+-----------+-----------------------------------------------------+
| APP | HOSTNAMES |
| app | hostnames |
+-----------+-----------------------------------------------------+
| "web" | ["hydrogen","helium","berylium","boron","nitrogen"] |
| "mysql" | ["lithium","carbon"] |
@@ -557,7 +521,7 @@ When we query for the content of "hostnames" we see the same data as we would if
```
> hostnames[name]
+------------+
| NAME |
| name |
+------------+
| "hydrogen" |
| "helium" |
@@ -609,7 +573,7 @@ The result:
```
> apps_by_hostname["helium"] = app
+-------+
| APP |
| app |
+-------+
| "web" |
+-------+
@@ -643,7 +607,7 @@ The result:
```
> instances[x]
+-----------------------------------------------+
| X |
| x |
+-----------------------------------------------+
| {"address":"hydrogen","name":"web-0"} |
| {"address":"helium","name":"web-1"} |
@@ -689,20 +653,20 @@ For example, we can write a rule that defines a document containing names of
apps not deployed on the "prod" site:
```rego
apps_not_in_prod[name] :-
apps[_].name = name,
not apps_in_prod[name]
apps_in_prod[name] :-
apps[_] = app,
app.servers[_] = server,
app.name = name
prod_servers[server],
prod_servers[name] :-
sites[_] = site,
site.name = "prod",
site.servers[_].name = name
apps_in_prod[name] :-
apps[_] = app,
app.servers[_] = server,
app.name = name,
prod_servers[server]
apps_not_in_prod[name] :-
apps[_].name = name,
not apps_in_prod[name]
```
The result:
@@ -710,7 +674,7 @@ The result:
```
> apps_not_in_prod[name]
+-----------+
| NAME |
| name |
+-----------+
| "mongodb" |
+-----------+