diff options
author | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-18 17:51:53 +0100 |
---|---|---|
committer | Stephen Dolan <mu@netsoc.tcd.ie> | 2012-09-18 17:51:53 +0100 |
commit | cf134909fd20021f4f7628f1eb7c1ad11c4a4e62 (patch) | |
tree | 8308212a1dbede042dc744206e84d925fcbffe1f | |
parent | a4eea165bbab6d13f89b59707e835d58b7014a66 (diff) |
Documentation. Copious.
25 files changed, 10269 insertions, 0 deletions
diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..4e01195c --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +.sass-cache +output/* + +# Autogenerated from public/css/base.scss +public/css/base.css
\ No newline at end of file diff --git a/docs/Rakefile b/docs/Rakefile new file mode 100644 index 00000000..b4e1d6d1 --- /dev/null +++ b/docs/Rakefile @@ -0,0 +1,54 @@ +require 'bonsai' +require 'liquid' +require 'maruku' +require 'json' + +module ExtraFilters + def markdownify(input) + Maruku.new(input).to_html + end + + def sanitize(input) + input.gsub(/[^a-zA-Z0-9_]/,"") + end + + def json(input) + input.to_json + end + + def unique(input) + @n = (@n || 0) + 1 + input + @n.to_s + end +end + +Liquid::Template.register_filter(ExtraFilters) + + +task :serve do + begin + Bonsai.log "Press Control+C to quit" + + require 'rack' + require 'sinatra' + require 'watch' + require 'launchy' + + Bonsai.root_dir = Dir.pwd + + server = fork { + app = Rack::Builder.app { + use Bonsai::StaticPassThrough, :root => Bonsai.root_dir + "/output", :urls => ["/"] + run Bonsai::DevelopmentServer + } + Rack::Handler.default.run(app, :Port => 5000) do + Launchy.open("http://localhost:5000/") + end + } + Watch.new("{content,templates,public}/**/*") { Bonsai::Exporter.process! } + rescue Interrupt + Process.kill("QUIT", server) + Process.wait(server) + exit + end +end diff --git a/docs/content/1.tutorial/default.yml b/docs/content/1.tutorial/default.yml new file mode 100644 index 00000000..5ba2df15 --- /dev/null +++ b/docs/content/1.tutorial/default.yml @@ -0,0 +1,239 @@ +headline: Tutorial +body: + - text: | + + Twitter have a JSON API, so let's play with that. This URL gets + us the last 5 tweets about JSON: + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true'" + result: | + {"completed_in":0.108,"max_id":247677287108067328,"max_id_str":"247677287108067328","next_page":"?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1","page":1,"query":"json","refresh_url":"?since_id=247677287108067328&q=json&include_entities=1","results":[{"created_at":"Mon, 17 Sep 2012 12:44:01 +0000","entities":{"hashtags":[],"urls":[{"url":"http:\/\/t.co\/XRvh1ZVw","expanded_url":"http:\/\/jase.im\/Ri7I0M","display_url":"jase.im\/Ri7I0M","indices":[112,132]}],"user_mentions":[{"screen_name":"imagemechanics","name":"Jason Cotterell","id":57271393,"id_str":"57271393","indices":[3,18]}]},"from_user":"_AaronNg","from_user_id":79771704,"from_user_id_str":"79771704","from_user_name":"NgChenChong","geo":null,"id":247677287108067328,"id_str":"247677287108067328","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2523558403\/ek8mo4j4beq84iw28gjl_normal.jpeg","source":"<a href="http:\/\/twitter.com\/">web<\/a>","text":"RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp:\/\/t.co\/XRvh1ZVw","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}, ... + + - text: | + + There's lots of info and no whitespace, so to make it a bit more + legible we pipe it through jq, telling jq to just spit the input + back at us using the expression `.`: + + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.'" + result: | + + { + "since_id_str": "0", + "since_id": 0, + "results_per_page": 5, + "completed_in": 0.108, + "max_id": 247677287108067330, + "max_id_str": "247677287108067328", + "next_page": "?page=2&max_id=247677287108067328&q=json&rpp=5&include_entities=1", + "page": 1, + "query": "json", + "refresh_url": "?since_id=247677287108067328&q=json&include_entities=1", + "results": [ + { + "from_user_name": "NgChenChong", + "from_user_id_str": "79771704", + "from_user_id": 79771704, + "from_user": "_AaronNg", + "iso_language_code": "en", + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "to_user": null + /* lots more fields... */ + }, + /* lots more results... */ + ] + } + + + - text: | + + Let's pull out the first tweet: + + + - command: "curl 'http://search.twitter.com/search.json?q=json&rpp=5&include_entities=true' | jq '.results[0]'" + result: | + { + "from_user_name": "NgChenChong", + "from_user_id_str": "79771704", + "from_user_id": 79771704, + "from_user": "_AaronNg", + "iso_language_code": "en", + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "to_user": null + /* lots more fields... */ + }, + + - text: | + + For the rest of the examples, I'll leave out the `curl` command - it's not going to change. + + + There's still a lot of info we don't care about there, so we'll + restrict it down to the most interesting fields. + + + - command: "jq '.results[0] | {from_user, text}'" + result: | + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + + - text: | + + The `|` operator in jq feeds the output of one filter + (`.results[0]` which gets the first element of the results + array) into the input of another (`{from_user, text}` which + builds an object of those two fields). + + Now let's get the rest of the tweets: + + + + - command: "jq '.results[] | {from_user, text}'" + result: | + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + { + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + } + { + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + } + { + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + } + { + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + + + - text: | + + `.results[]` returns each element of the results array, one at a + time, which are all fed into `{from_user, text}`. + + + Data in jq is represented as streams of JSON values - every jq + expression runs for each value in its input stream, and can + produce any number of values to its output stream. + + Streams are serialised by just separating JSON values with + whitespace. This is a `cat`-friendly format - you can just join + two JSON streams together and get a valid JSON stream. + + If you want to get the output as a single array, you can tell jq to + "collect" all of the answers by wrapping the filter in square + brackets: + + - command: "jq '[.results[] | {from_user, text}]'" + result: | + [ + { + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + }, + { + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + }, + { + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + }, + { + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + }, + { + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + ] + + + - text: | + + - - - + + Next, let's try getting the URLs out of those API results as + well. In each tweet, the Twitter API includes a field called + "entities" which looks like this: + + { + "user_mentions": [], + "urls": [{ + "indices": [83, 103], + "display_url": "bit.ly/StniqT", + "expanded_url": "http://bit.ly/StniqT", + "url": "http://t.co/28Jesbio" + }], + "hashtags": [ + {"indices": [108, 114], "text": "Apple" }, + {"indices": [121, 129], "text": "Awesome"} + ] + } + + We want to pull out all of the "url" fields inside that array of url + objects, and make a simple list of strings to go along with the + "from_user" and "text" fields we already have. + + + + - command: "jq '.results[] | {from_user, text, urls: [.entities.urls[].url]}'" + result: | + { + "urls": [ + "http://t.co/XRvh1ZVw" + ], + "text": "RT @imagemechanics: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas>.\nhttp://t.co/XRvh1ZVw", + "from_user": "_AaronNg" + } + { + "urls": [ + "http://t.co/Lhp92IqD" + ], + "text": "RT @_kud: iPhone 5 website teardown: How Apple compresses video using JPEG, JSON, and <canvas> -- http://t.co/Lhp92IqD", + "from_user": "blouerat" + } + { + "urls": [ + "http://t.co/7KALdWaX" + ], + "text": "Dynamic Forms Mobile App by pmadiset: Few Forms details are hosted on our server in the form of JSON. This JSON ... http://t.co/7KALdWaX", + "from_user": "cebu_iphone" + } + { + "urls": [ + "http://t.co/28Jesbio" + ], + "text": "iPhone 5 website insanity - Video compressing using JPEG, JSON, and <canvas> http://t.co/28Jesbio (Oh #Apple, U So #Awesome...)", + "from_user": "dieswaytoofast" + } + { + "urls": [ + "http://t.co/M70snaIf" + ], + "text": "RT @umutm: A very nice web-based JSON editor - http://t.co/M70snaIf", + "from_user": "Leolik" + } + + + - text: | + + Here we're making an object as before, but this time the urls + field is being set to `[.entities.urls[].url]`, which collects + all of the URLs defined in the entities object. + + - text: | + + - - - + + asdf
\ No newline at end of file diff --git a/docs/content/2.download/default.yml b/docs/content/2.download/default.yml new file mode 100644 index 00000000..03c9cb7f --- /dev/null +++ b/docs/content/2.download/default.yml @@ -0,0 +1,52 @@ +headline: Download jq +body: + + - text: | + + jq is written in C and has no runtime dependencies, so it should be + possible to build it for nearly any platform. Prebuilt binaries are + available for Linux (64-bit x86) and OS X. + + * [Download binary for 64-bit Linux](/download/linux/x68_64/jq) + * [Download binary for OS X](/download/osx/64/jq) + * [Download source](/download/source/jq.tgz) + + jq is licensed under the MIT license. For all of the gory + details, read the file `COPYING` in the source distribution. + + Hacking on jq + ============= + + If you want to work on jq, grab the source from + [https://github.com/stedolan/jq](https://github.com/stedolan/jq). + + + To build it from a git clone, you'll need to install a few + packages first: + + * [Flex](http://www.gnu.org/software/flex/) + * [Bison](http://www.gnu.org/software/bison/) + * [Python](http://www.python.org) + * [GCC](http://gcc.gnu.org) + * [Make](http://www.gnu.org/software/make) + + Most of these aren't necessary if you're just trying to compile + jq from the released tarball - that version has the + non-platform-specific build steps already done, so you'll only + need a C compiler and `make` to finish it off. + + For Linux systems, these will all be in your system's package + manager, and if you do development on the machine they're most + likely already installed. I have no idea how to get these + installed on OS X, you're on your own there. + + `flex` and `bison` are used to generate the lexer and parser for + jq, and some python scripts generate the UTF8 encoding tables + needed for JSON parsing. + + Building the documentation + -- + + jq's documentation is compiled into static HTML using + [Bonsai](http://www.tinytree.info). To view the documentation + locally, run `rake serve` from the docs/ subdirectory.
\ No newline at end of file diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml new file mode 100644 index 00000000..20793976 --- /dev/null +++ b/docs/content/3.manual/manual.yml @@ -0,0 +1,688 @@ +headline: jq Manual +sections: + - title: Basics + body: "{ some *intro* text \n\n\n}\n" + entries: + - title: "`.`" + body: | + + The absolute simplest (and least interesting) jq expression + is `.`. This is a jq expression that takes its input and + produces it unchanged as output. + + Since jq by default pretty-prints all output, this trivial + program can be a useful way of formatting JSON output from, + say, `curl`. + + examples: + - program: '.' + input: '"Hello, world!"' + output: ['"Hello, world!"'] + + - title: "`.foo`" + body: | + + The simplest *useful* jq expression is .foo. When given a + JSON object (aka dictionary or hash) as input, it produces + the value at the key "foo", or null if there\'s none present. + + examples: + - program: '.foo' + input: '{"foo": 42, "bar": "less interesting data"}' + output: [42] + - program: '.foo' + input: '{"notfoo": true, "alsonotfoo": false}' + output: ['null'] + + - title: "`.[foo]`" + body: | + + You can also look up fields of an object using syntax like + `.["foo"]` (.foo above is a shorthand version of this). This + one works for arrays as well, if the key is an + integer. Arrays are zero-based (like javascript), so .[2] + returns the third element of the array. + + examples: + - program: '.[0]' + input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['{"name":"JSON", "good":true}'] + + - program: '.[2]' + input: '[{"name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['null'] + + - title: "`.[]`" + body: | + + If you use the `.[foo]` syntax, but omit the index + entirely, it will return *all* of the elements of an + array. Running `.[]` with the input `[1,2,3]` will produce the + numbers as three seperate results, rather than as a single + array. + + examples: + - program: '.[]' + input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: + - '{"name":"JSON", "good":true}' + - '{"name":"XML", "good":false}' + + - program: '.[]' + input: '[]' + output: [] + + - title: "`,`" + body: | + + If two jq expressions are separated by a comma, then the + input will be fed into both and there will be multiple + outputs: first, all of the outputs produced by the left + expression, and then all of the outputs produced by the + right. For instance, jq expression `.foo, .bar`, produces + both the "foo" fields and "bar" fields as separate outputs. + + examples: + - program: '.foo, .bar' + input: '{"foo": 42, "bar": "something else", "baz": true}' + output: ['42', '"something else"'] + + - program: "[.user, .projects[]]" + input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' + output: ['"stedolan"', '"jq"', '"wikiflow"'] + + - program: '.[4,2]' + input: '["a","b","c","d","e"]' + output: ['"d"', '"c"'] + + - title: "`|`" + body: | + The | operator combines two jq expressions by feeding the output(s) of + the one on the left into the input of the one on the right. It\'s + pretty much the same as the Unix shell\'s pipe, if you\'re used to + that. + + If the one on the left produces multiple results, the one on + the right will be run for each of those results. So, the + expression `.[] | .foo` retrieves the "foo" field of each + element of the input array. + + examples: + - program: '.[] | .name' + input: '[{name":"JSON", "good":true}, {"name":"XML", "good":false}]' + output: ['"JSON"', '"XML"'] + + - title: Types and Values + body: | + + jq supports the same set of datatypes as JSON - numbers, + strings, booleans, arrays, objects (which in JSON-speak are + hashes with only string keys), and "null". + + Booleans, null, strings and numbers are written the same way as + in javascript. Just like everything else in jq, these simple + values take an input and produce an output - `42` is a valid jq + expression that takes an input, ignores it, and returns 42 + instead. + + entries: + - title: Array construction - `[]` + body: | + + As in JSON, `[]` is used to construct arrays, as in + `[1,2,3]`. The elements of the arrays can be any jq + expression. All of the results produced by all of the + expressions are collected into one big array. You can use it + to construct an array out of a known quantity of values (as + in `[.foo, .bar, .baz]`) or to "collect" all the results of a + jq expression into an array (as in `[.items[].name]`) + + Once you understand the "," operator, you can look at jq\'s array + syntax in a different light: the expression [1,2,3] is not using a + built-in syntax for comma-separated arrays, but is instead applying + the `[]` operator (collect results) to the expression 1,2,3 (which + produces three different results). + + If you have a jq expression `X` that produces four results, + then the expression `[X]` will produce a single result, an + array of four elements. + + examples: + - program: "[.user, .projects[]]" + input: '{"user":"stedolan", "projects": ["jq", "wikiflow"]}' + output: ['["stedolan", "jq", "wikiflow"]'] + - title: Objects - `{}` + body: | + + Like JSON, `{}` is for constructing objects (aka + dictionaries or hashes), as in: `{"a": 42, "b": 17}`. + + If the keys are "sensible" (all alphabetic characters), then + the quotes can be left off. The value can be any expression + (although you may need to wrap it in parentheses if it\'s a + complicated one), which gets applied to the {} expression\'s + input (remember, all jq expressions have an input and an + output). + + {foo: .bar} + + will produce the JSON object `{"foo": 42}` if given the JSON + object `{"bar":42, "baz":43}`. You can use this to select + particular fields of an object: if the input is an object + with "user", "title", "id", and "content" fields and you + just want "user" and "title", you can write + + {user: .user, title: .title} + + Because that\'s so common, there\'s a shortcut syntax: `{user, title}`. + + If one of the expressions produces multiple results, + multiple dictionaries will be produced. If the input\'s + + {"user":"stedolan","titles":["JQ Primer", "More JQ"]} + + then the expression + + {user, title: .titles[]} + + will produce two outputs: + + {"user":"stedolan", "title": "JQ Primer"} + {"user":"stedolan", "title": "More JQ"} + + Putting parentheses around the key means it will be evaluated as an + expression. With the same input as above, + + {(.user): .titles} + + produces + + {"stedolan": ["JQ Primer", "More JQ"]} + + examples: + - program: '{user, title: .titles[]}' + input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' + output: + - '{"user":"stedolan", "title": "JQ Primer"}' + - '{"user":"stedolan", "title": "More JQ"}' + - program: '{(.user): .titles}' + input: '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' + output: ['{"stedolan": ["JQ Primer", "More JQ"]}'] + + - title: Builtin operators and functions + body: | + + Some jq operator (for instance, `+`) do different things + depending on the type of their arguments (arrays, numbers, + etc.). However, jq never does implicit type conversions. If you + try to add a string to an object you'll get an error message and + no result. + + entries: + - title: Addition - `+` + body: | + + The operator `+` takes two jq expressions, applies them both + to the same input, and adds the results together. What + "adding" means depends on the types involved: + + - **Numbers** are added by normal arithmetic. + + - **Arrays** are added by being concatenated into a larger array. + + - **Strings** are added by being joined into a larger string. + + - **Objects** are added by merging, that is, inserting all + the key-value pairs from both objects into a single + combined object. If both objects contain a value for the + same key, the object on the right of the `+` wins. + + examples: + - program: '.a + 1' + input: '{"a": 7}' + output: '{"a": 8}' + - program: '.a + .b' + input: '{"a": [1,2], "b": [3,4]}' + output: ['[1,2,3,4]'] + - program: '{a: 1} + {b: 2} + {c: 3} + {a: 42}' + input: 'null' + output: ['{"a": 42, "b": 2, "c": 3}'] + + - title: Subtraction - `-` + body: | + + As well as normal arithmetic subtraction on numbers, the `-` + operator can be used on arrays to remove all occurences of + the second array's elements from the first array. + + examples: + - program: '4 - .a' + input: '{"a":3}' + output: ['1'] + - program: . - ["xml", "yaml"] + input: '["xml", "yaml", "json"]' + output: ['["json"]'] + + - title: Multiplication, division - `*` and `/` + body: | + + These operators only work on numbers, and do the expected. + + examples: + - program: '10 / . * 3' + input: 5 + output: [6] + + - title: `length` + body: | + + The builtin function `length` gets the length of various + different types of value: + + - The length of a **string** is the number of Unicode + codepoints it contains (which will be the same as its + JSON-encoded length in bytes if it's pure ASCII). + + - The length of an **array** is the number of elements. + + - The length of an **object** is the number of key-value pairs. + + - The length of **null** is zero. + + examples: + - program: '.[] | length' + input: '[[1,2], "string", {"a":2}, null]' + output: [2, 6, 1, 0] + + - title: `tonumber` + body: | + + The `tonumber` function parses its input as a number. It + will convert correctly-formatted strings to their numeric + equivalent, leave numbers alone, and give an error on all other input. + + examples: + - program: '.[] | tonumber' + input: '[1, "1"]' + output: [1,1] + + - title: `tostring` + body: | + + The `tostring` function prints its input as a + string. Strings are left unchanged, and all other values are + JSON-encoded. + + examples: + - program: '.[] | tostring' + input: '[1, "1", [1]]' + output: ['"1"', '"1"', '"[1]"'] + + - title: "String interpolation - `@(text)`" + body: | + + jq supports an alternative syntax for strings. Instead of + "foo", you can write `@(foo)`. When using this syntax, + `%(expression)` may be used to insert the value of + `expression` into the string (converted with `tostring`). + + String interpolation does not occur for normal double-quoted + strings (like `"foo"`) in order to be fully compatible with + JSON. + + All of the usual JSON escapes (`\n`, `\r` and the like) work + inside `@()`-quoted strings, as well as `\%` and `\)` if + those characters are needed literally. + + examples: + - program: '@(The input was %(.), which is one less than %(.+1))' + input: '42' + output: ['"The input was 42, which is one less than 43"'] + + + + + + + - title: Conditionals and Comparisons + entries: + - title: `==`, `!=` + body: | + + The expression 'a == b' will produce 'true' if the result of a and b + are equal (that is, if they represent equivalent JSON documents) and + 'false' otherwise. In particular, strings are never considered equal + to numbers. If you're coming from Javascript, jq's == is like + Javascript's === - considering values equal only when they have the + same type as well as the same value. + + != is "not equal", and 'a != b' returns the opposite value of 'a == b' + + examples: + - program: '.[] == 1' + input: '[1, 1.0, "1", "banana"]' + output: ['[true, true, false, false]'] + + - title: if-then-else + body: | + + `if A then B else C end` will act the same as `B` if `A` + produces a value other than false or null, but act the same + as `C` otherwise. + + Checking for false or null is a simpler notion of + "truthiness" than is found in Javascript or Python, but it + means that you'll sometimes have to be more explicit about + the condition you want: you can't test whether, e.g. a + string is empty using `if .name then A else B end`, you'll + need something more like 'if (.name | count) > 0 then A else + B end' instead. + + If the condition A produces multiple results, it is + considered "true" if any of those results is not false or + null. If it produces zero results, it's considered false. + + More cases can be added to an if using `elif A then B` syntax. + + examples: + - program: |- + if . == 0 then + "zero" + elif . == 1 then + "one" + else + "many" + end + input: 2 + output: ['"many"'] + + - title: and/or/not + body: | + + jq supports the normal Boolean operators and/or/not. They have the + same standard of truth as if expressions - false and null are + considered "false values", and anything else is a "true value". + + If an operand of one of these operators produces multiple + results, the operator itself will produce a result for each input. + + `not` is in fact a builtin function rather than an operator, + so it is called as a filter to which things can be piped + rather than with special syntax, as in `.foo and .bar | + not`. + + These three only produce the values "true" and "false", and + so are only useful for genuine Boolean operations, rather + than the common Perl/Python/Ruby idiom of + "value_that_may_be_null or default". If you want to use this + form of "or", picking between two values rather than + evaluating a condition, see the "//" operator below. + + examples: + - program: '42 and "a string"' + input: 'null' + output: ['true'] + - program: '(true, false) or false' + input: 'null' + output: ['true', 'false'] + - program: '(t |