Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1919 lines (1386 sloc) 48.9 KB
language: php
title: enophp
version: 0.1.1
-- intro
> Everyone is welcome to improve this documentation by editing [php.eno](https://github.com/eno-lang/eno-lang.org/blob/master/src/docs/php.eno) and submitting a Pull Request!
Installation via Composer
```shell
composer require eno-lang/enophp
```
## Getting started
Create an eno document, for instance `intro.eno`:
```eno
Greeting: Hello World!
```
A minimal example to read this file with `enophp`:
```php
use Eno\Parser;
$input = file_get_contents('intro.eno');
$document = Parser::parse($input);
echo( $document->field('Greeting') ); // prints 'Hello World!'
```
## Links
Package on packagist - <https://packagist.org/packages/eno-lang/enophp>\
Repository on github - <https://github.com/eno-lang/enophp/>
-- intro
# Modules
## Eno\Parser
-- class description
The main class. You'll be calling `parse` on this, and possibly supplying a custom
locale (such as `'de'`, `'es'`, ...), reporter type (`Text`, `HTML`, `Terminal` are available)
or source label (usually to have a filename appear in error messages) to that call.
-- class description
### parse
syntax:
- parse($input) → Section
- parse($input, $options) → Section
-- description
Parse a string in eno notation.
-- description
-- eno
color: blue
-- eno
-- php
Parser::parse($input); // returns [Section document elements=1]
// Errors will be ...
Parser::parse($input, [ 'locale' => 'es' ]); // In spanish - ¡hola!
Parser::parse($input, [ 'reporter' => HTML ]); // HTML for e.g. web integration
Parser::parse($input, [ 'reporter' => Terminal ]); // Colored for terminal output
Parser::parse($input, [ 'source_label' => 'my-file.eno' ]); // Annotated with a label as context
Parser::parse($input, [ 'zero_indexing' => true ]); // Counting line and column numbers from 0
-- php
#### parameters
$input: A string containing text in eno notation.
$options:
locale = A string specifying the code of the locale to use for error messages (e.g. `'de'`, `'es'`), by default `'en'`.
reporter = One of `Eno\Reporters\Text`, `Eno\Reporters\HTML`, `Eno\Reporters\Terminal`.
source_label = A string that labels where the input comes from (e.g. a filename), this is included with error messages to help the user located the file.
zero_indexing = `true` or `false` (default), set `true` to display `0,1,2,..` line and column numbers in all error messages instead of the default `1,2,3,..` indexing.
#### return value
description: A `Section` representing the document.
## Eno\Loaders
-- class description
enophp provides a set of core loaders for important types that are available out
of the box (in addition to the possiblity to define your own custom loaders,
which can be passed as parameter to all accessors).
The loaders are exposed through the API as drop in replacements to the standard accessors:
- `Field`
- `value()` => `[loaderName]()`
- `Fieldset`
- `entry()` => `[loaderName]()`
- `ListElement`
- `items()` => `[loaderName]Items()`
- `Section`
- `field()` => `[loaderName]()`
- `list()` => `[loaderName]List()`
So for instance, instead of calling ...
```php
$document->field('done', [ 'required' => true ]); // returns 'yes'
$document->list('visitor_counts', [ 'required' => true ]); // returns [ '476', '213', '330', ... ]
```
... you can just replace `field` or augment `list` with the loader name ...
```php
$document->boolean('done', [ 'required' => true ]); // returns true
$document->integerList('visitor_counts', [ 'required' => true ]); // returns [ 476, 213, 330, ... ]
```
Here's another full example:
```php
use Eno\Parser;
$doc = Parser::parse(
<<<DOC
publish: yes
location: 36.987094, -25.091719
contact: contact@faulty
DOC
);
$doc->boolean('publish');
// returns true
$doc->latLng('location');
// returns [
// 'lat' => 36.987094,
// 'lng' => -25.091719
// ]
$doc->email('contact');
// throws a ValidationError: 'contact' must contain a valid email address, for instance 'jane.doe@eno-lang.org'.
```
Note that some loaders only perform validation and return their input unaltered
as string (e.g. `color`, `email`), while others both validate and transform the
value into a new type (e.g. `float`, `boolean`) or even associative array (e.g.
`latLng`).
-- class description
### boolean
-- description
Accepts `true`, `false`, `yes` and `no`, returns a `boolean` (or throws a ValidationError for invalid values).
-- description
syntax:
- boolean() → boolean
- booleanItems() → array
- booleanList() → array
-- eno
enabled: true
publish: no
visible: not
-- eno
-- php
$document = Parser::parse($input);
$document->boolean('enabled'); // returns true
$document->boolean('publish'); // returns false
$document->boolean('visible');
// throws a ValidationError: 'visible' must contain a boolean - allowed values are 'true', 'false', 'yes' and 'no'.
-- php
### color
-- description
Accepts values formatted as `#RRGGBB` or `#RGB` (case insensitive), returns the value unchanged (or throws a ValidationError for invalid values).
-- description
syntax:
- color() → string
- colorItems() → array
- colorList() → array
-- eno
active: #F00
hover: #ff0000
focus: blue
-- eno
-- php
$document = Parser::parse($input);
$document->color('active'); // returns '#F00'
$document->color('hover'); // returns '#ff0000'
$document->color('focus');
// throws a ValidationError: 'focus' must contain a color, for instance '#B6D918', '#fff' or '#01b'.
-- php
### commaSeparated
-- description
Splits a comma-separated listing (single line, think a list of tags e.g.) into an array and trims whitespace.
-- description
syntax:
- commaSeparated() → array
- commaSeparatedItems() → array
- commaSeparatedList() → array
-- eno
Tags: Coffee, Desk, Flavor
Categories: Computing , High performance , Cluster
-- eno
-- php
$document = Parser::parse($input);
$document->commaSeparated('Tags'); // returns ['Coffee', 'Desk', 'Flavor']
$document->commaSeparated('Categories'); // returns ['Computing', 'High performance', 'Cluster']
-- php
### date
-- description
Accepts `YYYY-MM-DD` and returns a PHP `DateTime` object (or throws a ValidationError for invalid values).
-- description
syntax:
- date() → DateTime
- dateItems() → array
- dateList() → array
-- eno
start: 1992-12-01
end: 1994-03-04
invalid: 2018-03-14 13:10
-- eno
-- php
$document = Parser::parse($input);
$document->date('start'); // returns [DateTime]
$document->date('end'); // returns [DateTime]
$document->date('invalid');
// throws a ValidationError: 'invalid' must contain a valid date, for instance '1993-11-18'.
-- php
### datetime
-- description
Accepts a subset of ISO 8601 date/time formats described in this W3C note: <https://www.w3.org/TR/NOTE-datetime>
Returns a PHP `DateTime` object (or throws a ValidationError for invalid values).
Some possible example values that match the format:
- `1990`
- `1990-12`
- `1990-12-31`
- `1990-12-31T23:59Z`
- `1990-12-31T23:59:00+01:00`
- `1990-12-31T23:59:00.999+01:00`
Note that spaces as separators are not allowed.
Development note:
A more appealing, less technical datetime format or an additional loader to serve that requirement would be generally welcome,
the current format is basically just an initial draft that should cover many usecases and is standardized through its
ISO origin, feel free to get in touch and propose an extension/update if you'd be interested in such development.
-- description
syntax:
- datetime() → DateTime
- datetimeItems() → array
- datetimeList() → array
-- eno
start: 1992-12-01
end: 1994-03-04T13:14Z
invalid: 2018-03-14 13:10
-- eno
-- php
$document = Parser::parse($input);
$document->datetime('start'); // returns [DateTime]
$document->datetime('end'); // returns [DateTime]
$document->datetime('invalid');
// throws a ValidationError: 'invalid' must contain a valid date or date and time, for instance '1997-07-16' or '1994-11-05T13:15Z' (see https://www.w3.org/TR/NOTE-datetime).
-- php
### float
-- description
Accepts floats (decimal part can be missing though), returns a float (or throws a ValidationError for malformed values).
-- description
syntax:
- float() → float
- floatItems() → array
- floatList() → array
-- eno
good: 49.9
fine: -2
bad: three
-- eno
-- php
$document = Parser::parse($input);
$document->float('good'); // returns 49.9
$document->float('fine'); // returns -2.0
$document->float('bad');
// throws a ValidationError: 'bad' must contain a decimal number, for instance '13.0', '-9.159' or '42'.
-- php
### integer
-- description
Accepts integers only (float is not clipped but triggers an error), returns an integer.
-- description
syntax:
- integer() → int
- integerItems() → array
- integerList() → array
-- eno
good: -13
bad: 0.3
-- eno
-- php
$document = Parser::parse($input);
$document->integer('good'); // returns -13
$document->integer('bad');
// throws a ValidationError: 'bad' must contain an integer, for instance '42' or '-21'.
-- php
### json
-- description
Parses the value as JSON and returns the result (or passes on the parser error for malformed JSON).
-- description
syntax:
- json() → object/array/value
- jsonItems() → array
- jsonList() → array
-- eno
-- json payload
{
"status": 500
}
-- json payload
-- eno
-- php
$document = Parser::parse($input);
$document->json('json payload'); // returns [ 'status' => 500 ]
-- php
### latLng
-- description
Accepts lat/lng coordinates of the form `dd.ddddd, dd.ddddd` (but with any number of decimal digits), returns an associative array (see example below) (or throws a ValidationError for invalid values).
-- description
syntax:
- latLng() → object
- latLngItems() → array
- latLngList() → array
-- eno
location: 36.987094, -25.091719
-- eno
-- php
$document = Parser::parse($input);
$document->latLng('location');
// returns [
// 'lat' => 36.987094,
// 'lng' => -25.091719
// ]
-- php
### number
-- description
An alias for the `integer` loader.
-- description
syntax:
- number() → int
- numberItems() → array
- numberList() → array
-- eno
good: -13
bad: 0.3
-- eno
-- php
$document = Parser::parse($input);
$document->number('good'); // returns -13
$document->number('bad');
// throws a ValidationError: 'bad' must contain an integer, for instance '42' or '-21'.
-- php
### string
-- description
Technically not a loader, but a wrapper for the standard accessors (which always
return strings), you can use it if you prefer a 100% type-oriented value access
terminology in your code.
-- description
syntax:
- string() → string
- stringItems() → array
- stringList() → array
-- eno
name: Alice
number: 13
-- eno
-- php
$document = Parser::parse($input);
$document->string('name'); // returns 'Alice'
$document->string('number'); // returns '13'
// .... these are completely identical to ...
$document->field('name'); // returns 'Alice'
$document->field('number'); // returns '13'
-- php
### url
-- description
Validates a URL and returns it unaltered (or throws a ValidationError for an invalid URL).
-- description
syntax:
- url() → string
- urlItems() → array
- urlList() → array
-- eno
good: https://json.org
bad: www.boom
-- eno
-- php
$document = Parser::parse($input);
$document->url('good'); // returns 'https://json.org'
$document->url('bad');
// throws a ValidationError: 'bad' must contain valid URL, for instance 'https://eno-lang.org'.
-- php
## Eno\Section
-- class description
Every section in an eno document, such as for instance `# notes` or `### Appendix`, maps to a `Section`.
More prominently though **the document itself is represented as a `Section`**,
consequently this is the interface you'll be utilizing most for many usecases.
-- class description
### assertAllTouched
syntax:
- assertAllTouched()
- assertAllTouched($options)
- assertAllTouched($message, $options)
- assertAllTouched($message_function, $options)
-- description
Assert that all elements of this section (and also, recursively, of all
subsections) that were present in the parsed eno document were also queried (and
therefore *touched*) by the application. This, combined with eno's query
methods, serves to ensure a two-way guarantee for both users and developers: No
data that the application requires can be left out, and no data that the
application does not process can be supplied.
-- description
-- eno
Important data A: I need to be processed!
Important data B: Me too!
-- eno
-- php
$document = Parser::parse($input);
$data_a = $document->field('Important data A');
// ... processing happens only for data_a
$document->assertAllTouched(); // throws a ValidationError with the default message
$document->assertAllTouched([ 'only' => ['Important data A'] ]); // passes
$document->assertAllTouched([ 'except' => ['Important data B'] ]); // passes
$document->assertAllTouched(function($name, $value) { // throws a ValidationError "Important data B is not ..."
return "{$name} is not supported by the application, please contact support if you think it should be"
});
-- php
#### parameters
-- $message or $message_function
Optional, usually the default message (*An excess element named [NAME] was
found, is it possibly a typo?*) will do fine. If you want to override it,
provide either a static message as a string, or alternatively a function
returning a string. (The function is passed `$name` and `$value` in that order, although
`$value` can be `null` if the untouched element is a fieldset or section)
-- $message or $message_function
$options:
only = An array of strings, e.g. `['name', 'email']`, which specifies to only check these elements for whether they've been touched.
except = An array of strings, e.g. `['phone number']`, which specifies to exclude these elements from checking whether they've been touched.
### element
syntax:
- element($name) → element or null
- element($name, $options) → element or null
-- description
Retrieve a single element of any type from the section by its name.
Optionally specify whether it's optional or mandatory for the element to be
present in the eno document (by default it's optional).
-- description
-- eno
title: Artfest 2018
tags:
- art
- code
# content
> ...
-- eno
-- php
$document = Parser::parse($input);
$document->element('title'); // returns [Field name="title" value="Artfest 2018"]
$document->element('tags'); // returns [List name="tags" items=2]
$document->element('content'); // returns [Section name="content" items=14]
$document->element('fantasy'); // returns null
$document->element('fantasy', [ 'enforce_element' => true ]); // throws a ValidationError
$document->element('fantasy', [ 'required' => true ]); // throws a ValidationError
-- php
#### parameters
$name: The name of the element to fetch from the section as a string.
$options:
enforce_element = Whether the element must be present in the document (`true` or `false`, defaults to `false`)
required = Alias for `enforce_element` (this exists on many methods and depending on context refers to either element or value)
#### return value
description: An element (e.g. `ListElement`, `Field`, etc.) or `null`.
### elements
syntax: elements() → array
-- description
Retrieve the elements of this section in sequential order. This seamlessly lets
you switch from associative readout to sequential readout, allowing sections
within, or the whole document, to represent document-like structures (think
generic markup) instead of just associative data stores.
-- description
-- eno
date: 2018-03-01
title: My blog post
# page
h1: Hello world
p: This is my first post, I'm so happy!
-- eno
-- php
$document = Parser::parse($input);
metadata = [
'date' => $document->field('date', $my_date_loader_function),
'title' => $document->field('title')
];
$html = '';
foreach($document->section('page')->elements() as $element) {
$html .= "<{$element->name}>{$element->value()}</{$element->name}>";
}
file_put_contents('index.html', $html);
-- php
#### return value
description: An array containing the elements of this section.
### enforceAllElements
syntax:
- enforceAllElements()
- enforceAllElements($enforce)
-- description
Set the default for all following queries on this section of whether the
presence of elements in the eno input text should be enforced (by default it is
not). This can be used to prevent "template decay" - with presence enforcement
enabled elements may be empty, but they (at least their declaration) must be
there in the eno text and consequently they can not disappear from a template
over time without triggering an error.
-- description
-- eno
color: blue
-- eno
-- php
$document = Parser::parse($input);
$document->field('sound'); // returns null
$document->enforceAllElements();
$document->field('sound'); // throws a ValidationError
$document->field('sound', [ 'enforce_element' => false ]); // returns null
-- php
#### parameters
$enforce: An optional boolean indicating whether to enforce or not. (`true` is the default if left out)
### field
syntax:
- field($name) → value or null
- field($name, $options) → array/value or null
- field($name, $loader) → value or null
- field($name, $loader, $options) → array/value or null
-- description
Retrieve a field's value from the section, optionally supplying a loader to
validate and/or transform the value, and/or an options array.
-- description
-- eno
color: blue
sound:
-- eno
-- php
$section->field('color'); // returns 'blue'
$section->field('sound'); // returns null
$section->field('sound', [ 'required' => true ]); // throws a ValidationError
$section->field('sound', [ 'enforce_element' => true ]); // returns null
$section->field('texture', [ 'enforce_element' => true ]); // throws a ValidationError
$section->field('color', function($value) { return strtoupper($value); }); // returns 'BLUE'
$section->field('color', function($value) { // throws a ValidationError: Only green is allowed!
if($value != 'green') {
throw new Exception('Only green is allowed!');
}
return $value;
});
$section->field('color', [ 'with_element' => true ]);
// returns [ 'element' => [Field name="blue" value="blue"], 'value' => 'blue' ]
-- php
#### parameters
$name: A string representing the name of the field to return.
-- $loader
A `function` returning the transformed/validated value or throwing an error.
(The function is applied to each list item on its own and its argument signature
is dynamic, you can either use `($value)` or `($name, $value)`)
-- $loader
$options:
enforce_element = Whether the field must be present in the document (`true` or `false`, defaults to `false`)
enforce_value = Whether there must be a value or the field is allowed to be empty (defaults to `false`)
required = Alias for `enforce_value` (this exists on many methods and depending on context refers to either element or value)
with_element = Whether to return an array of the form `[ 'element' => ..., 'value' => ... ]` instead of just the value (default `false`)
#### return value
description:
\ The value of the field, or `null` if empty, or an array of the form
\ `[ 'element' => ..., 'value' => ... ]` when the option `with_element` is specified.
### fields
syntax: fields($name) → array
-- description
Retrieve fields with the specified name from this current section.
-- description
-- eno
color: blue
color: red
color: orange
-- eno
-- php
$document = Parser::parse($input);
$colors = $document->fields('color');
foreach($colors as $color) {
echo( $color->value() );
}
-- php
#### parameters
$name: A string specifying the name of the fields to retrieve.
#### return value
description: An array of `Field`s.
### fieldset
syntax:
- fieldset($name) → Fieldset or null
- fieldset($name, $options) → Fieldset or null
-- description
Retrieve a fieldset from the section, optionally supplying an options array.
-- description
-- eno
color ratings:
red = 5
green = 7
blue = 3
-- eno
-- php
$section->fieldset('color ratings'); // returns [Fieldset name="color ratings" entries=3]
$section->fieldset('temperature ratings'); // throws a ValidationError
$section->fieldset('temperature ratings', [ 'required' => false ]); // returns null
$section->fieldset('temperature ratings', [ 'enforce_element' => true ]); // throws a ValidationError
-- php
#### parameters
$name: A string representing the name of the field to return.
$options:
enforce_element = A boolean stating whether the fieldset must exist in the document (defaults to `false`)
required = Alias for `enforce_element` (this exists on many methods and depending on context refers to either element or value)
#### return value
description: A `Fieldset`, or `null`.
### fieldsets
syntax: fieldsets($name) → array
-- description
Retrieve fieldsets with the specified name from this current section.
-- description
-- eno
image:
src = red-roses.jpg
image:
src = white-roses.jpg
-- eno
-- php
$document = Parser::parse($input);
$images = $document->fieldsets('image');
foreach($images as $image) {
echo( $image->entry('src') );
});
-- php
#### parameters
$name: A string specifying the name of the fieldsets to retrieve.
#### return value
description: An array of `Fieldset`s.
### list
syntax:
- list() → array
- list($options) → array
- list($loader) → array
- list($loader, $options) → array
-- description
Retrieve the items of a list, optionally supplying a loader and options.
-- description
-- eno
colors:
- pink
- peach
textures:
-
-- eno
-- php
$document = Parser::parse($input);
$document->list('colors'); // returns [ 'pink', 'peach' ]
$document->list('sounds'); // returns []
$document->list('textures'); // throws a ValidationError
$document->list('textures', [ 'enforce_values' => false ]); // returns [ null ]
$document->list('sounds', [ 'required' => true ]); // throws a ValidationError
$document->list('sounds', [ 'enforce_element' => true ]); // throws a ValidationError
$document->list('colors', function($value) { return strtoupper($value); }); // returns [ 'PINK', 'PEACH' ]
$document->list('colors', function($value) { // throws a ValidationError
if($value == 'peach') {
throw new Exception('Peach may not be on the list!');
}
return "I like {$value}";
]);
$document->list('colors', [ 'with_elements': true ]);
// returns [{ element: [Field value="pink"], 'value' => 'pink' },
// { element: [Field value="pink"], 'value' => 'peach' }]
$document->list('colors', [ 'min_count' => 3 ]); // throws a ValidationError
-- php
#### parameters
$name: The name of the list to return as a string.
-- $loader
A `function` returning the transformed/validated value or throwing an error.
(The function is applied to each list item on its own, and its argument
signature is dynamic, you can either use `($value)` or `($name, $value)`)
-- $loader
$options:
enforce_element = Whether the list must be present in the document (defaults to `false`)
enforce_values = Whether empty list items (`- ` in the document, mapping to `null`) are disallowed (defaults to `true`)
exact_count = Validate that there are exactly `n` items in the list (takes a number, defaults to `null`)
min_count = Validate that there are at least `n` items in the list (takes a number, defaults to `null`)
max_count = Validate that there are at most `n` items in the list (takes a number, defaults to `null`)
required = Alias for `enforce_element` (this exists on many methods and depending on context refers to either element or value)
with_elements = Whether to return an array of arrays of the form `[ 'element' => ..., 'value' => ... ]` instead of just the values (defaults to `false`)
#### return value
description:
| The (optionally transformed/validated) values of the items of this list as an array.
| With `with_elements` set to `true` it returns an array of arrays of the form `[ 'element' => ..., 'value' => ... ]` instead.
### lists
syntax: lists($name) → array
-- description
Retrieve lists with the specified name from this current section.
-- description
-- eno
route:
- vienna
- paris
- rome
route:
- moscow
- riga
-- eno
-- php
$document = Parser::parse($input);
$routes = $document->lists('route');
foreach($routes as $route) {
print_r( $route->items() );
}
// prints ...
// [ 'vienna', 'paris', 'rome']
// [ 'moscow', 'riga' ]
-- php
#### parameters
$name: A string specifying the name of the lists to retrieve.
#### return value
description: An array of `ListElement`s.
### lookup
syntax:
- lookup($index) → array or null
- lookup($line, $column) → array or null
-- description
Ask the document *Hey what's at column X in line Y in my eno file?*. The lookup **always** returns an element for valid indices
(the document/section in case of an empty line/space), only indices outside the range of the document return `null`. Note that
all arguments are zero-indexed, i.e. the first lines and columns are numbered `0`, not `1`.
-- description
-- eno
color: blue
# notes
-- eno
-- php
$document = Parser::parse($input);
$document->lookup(3); // 'o'
// returns [ 'element' => [Field name="color" value="blue"], 'zone' => 'name' }
$document->lookup(7); // 'b'
// returns [ 'element' => [Field name="color" value="blue"], 'zone' => 'value' }
$document->lookup(0, 3); // 'o'
// returns [ 'element' => [Field name="color" value="blue"], 'zone' => 'name' }
$document->lookup(0, 7); // 'b'
// returns [ 'element' => [Field name="color" value="blue"], 'zone' => 'value' }
$document->lookup(13); // '#'
// returns [ 'element' => [Section name="notes" elements=0], 'zone' => 'sectionOperator' }
$document->lookup(19); // 's'
// returns [ 'element' => [Section name="notes" elements=0], 'zone' => 'name' }
$document->lookup(2, 0); // '#'
// returns [ 'element' => [Section name="notes" elements=0], 'zone' => 'sectionOperator' }
$document->lookup(2, 6); // 's'
// returns [ 'element' => [Section name="notes" elements=0], 'zone' => 'name' }
-- php
#### parameters
$index: A one-dimensional index to look up (0-indexed, i.e. the first position is 0, not 1)- only applies when it's the only given argument.
$line: The line to look up (0-indexed, i.e. the first line is 0, not 1) - only applies when you supply `$column` as well.
$column: The column to look up (0-indexed, i.e. the first column is 0, not 1) - only applies when you supply `$line` as well.
#### return value
-- description
For all valid indices within the document returns an array with two keys:
`zone`: A string denoting the token at the index, here's the full list:
`'[empty-lines-and-spaces-between-tokens]'` => `element`
`'[inside-blocks]'` => `content`
`'[inside-comments]'` => `comment`
`'[name]'` => `name`
`'[template]'` => `value`
`'[value]'` => `value`
`':'` => `name_operator`
`'-'` => `item_operator`
`'='` => `entry_operator`
`'--'` => `block_operator`
`'>'` => `comment_operator`
``'`'`` => `escape_begin_operator`
``'`'`` => `escape_end_operator`
`'|'` => `newline_continuation_operator`
`'\'` => `line_continuation_operator`
`'#'` => `section_operator`
`'<'` => `copy_operator`
`'<<'` => `deep_copy_operator`
`element`: A `Section`, `Fieldset`, `Field`.. . For empty lines you get the containing section.
When an index outside the document is supplied, `null` is returned.
-- description
### raw
syntax: raw() → array
-- description
Retrieve a native PHP associative array representation of the section.
-- description
-- eno
color: blue
-- eno
-- php
$document = Parser::parse($input);
$document->raw(); // returns [[ 'color' => 'blue' ]]
-- php
#### return value
description: An array of elements (also returned in their raw representation).
### section
syntax:
- section($name) → Section or null
- section($name, $options) → Section or null
-- description
Retrieve the subsection with the specified name from this current section.
-- description
-- eno
# content
title: A Manifest
# notes
-- eno
-- php
$document = Parser::parse($input);
$document->section('content'); // returns [Section name="content" elements=1]
$document->section('notes'); // returns [Section name="notes" elements=0]
$document->section('metadata'); // throws a ValidationError
$document->section('metadata', [ 'required' => false ]); // returns null
$document->section('notes', [ 'enforce_element' => true ]); // returns [Section name="notes" elements=0]
$document->section('metadata', [ 'enforce_element' => true ]); // throws a ValidationError
-- php
#### parameters
$name: A string specifying the name of the section to retrieve.
$options:
enforce_element = Whether the section must be present in the document (defaults to `false`)
required = Alias for `enforce_element` (this exists on many methods and depending on context refers to either element or value)
#### return value
description: A `Section`, or `null`.
### sections
syntax: sections($name) → array
-- description
Retrieve subsections with the specified name from this current section.
-- description
-- eno
# Article
> ...
# Article
> ...
-- eno
-- php
$document = Parser::parse($input);
$sections = $document->sections('Article');
foreach($sections as $section) {
// do something with each Article
}
-- php
#### parameters
$name: A string specifying the name of the sections to retrieve.
#### return value
description: An array of `Section`s.
## Eno\Field
-- class description
All values in an eno document, such as the value of a field like `name: value`, the value of a block,
the value of a list item, the value of a fieldset entry, and so on, map to a `Field`. Usually you
don't interact with this because you directly get the values from a section or fieldset in most cases.
When you, for instance, sequentially iterate a section (with `Section`'s '`elements` method) or explicitly ask
for the `Field` by using an accessor with the `[ 'with_element' => true ]` option (for delayed error triggering)
you will get to interact with this class.
-- class description
### error
syntax:
- error() → ValidationError
- error($message) → ValidationError
- error($message_function) → ValidationError
-- description
Generate an error in the context of the element. The error includes a generic
message by default, or a custom one if you supply it (which is the recommended
practice). You can also pass a message function which (like the loader functions
too) gets the name and value as arguments and returns a message string. This
serves to create highly informative error messages that pin-point to the exact
origin of the error, even when the initial reading of data is already past, e.g.
when the error condition is only apparent later, when more processing has
occurred or other data is available.
-- description
-- eno
color: cozy
-- eno
-- php
$document = Parser::parse($input);
$result = $document->field('color', [ 'with_element' => true ]);
// ...
if($result['value'] == 'cozy') {
throw $result['element']->error('Postprocessing determined that "cozy" is not a color after all.');
}
-- php
#### parameters
-- $message or $message_function
Highly recommended to provide one (but it's optional).
Either directly pass a string, or alternatively a function returning a string.
(That function then gets `$name` and `$value`, in that order)
-- $message or $message_function
#### return value
description:
| A `ValidationError` in the context of the element's value
| (and with an optional custom message).
### isEmpty
syntax: isEmpty() → boolean
-- description
Query whether the value is empty (e.g. `comment: ` in an eno document), which in PHP terms is equivalent of `null`.
-- description
#### return value
description: `true` if empty, otherwise `false`.
### raw
syntax: raw() → array or value
-- description
Retrieve a native PHP associative array representation of the value.
The raw representation differs depending on whether there is a name (e.g. for a field value),
or not (applies only to list item values).
-- description
-- eno
color: blue
numbers:
- 13
- 42
-- eno
-- php
$document = Parser::parse($input);
$document->element('color')->raw(); // returns [ 'color' => 'blue' ]
$list_tems = $document->element('numbers')->elements();
$list_tems[0]->raw(); // returns '13'
-- php
#### return value
description: A native representation of the value element.
### value
syntax:
- value() → value or null
- value($options) → value or null
- value($loader) → value or null
- value($loader, $options) → value or null
-- description
Retrieve the value of a `Field`, optionally passing it through a loader
function and/or supplying options.
-- description
-- eno
flag color: beige
towel color:
|
-- eno
-- php
$document = Parser::parse($input);
$flag_color = $document->element('flag color');
$towel_color = $document->element('towel color');
$flag_color->value(); // returns 'beige'
$towel_color->value(); // returns null
$flag_color->value(function($value) { return str_replace('eig', 'lu' , $value); }); // returns 'blue'
-- php
#### parameters
-- $loader
A `function` returning the transformed/validated value or throwing an error.
(The function's argument signature is dynamic, you can either use `($value)` or
`($name, $value)`)
-- $loader
$options:
enforce_value = Whether there must be a value or the field is allowed to be empty (default to `false`)
required = Alias for `enforce_value` (this exists on many methods and depending on context refers to either element or value)
#### return value
description: The (optionally transformed/validated) value of this `Field`.
## Eno\ListElement
-- class description
Lists such as the one below are represented as a `ListElement`:
```eno
things:
- toys
- plants
```
Like `Field`, you will seldom interact with this class, and instead use the `list`
accessor on the document or its sections to directly obtain the values of a list.
-- class description
### elements
syntax: elements() → array
-- description
Retrieve the items of this list as `Field` elements (instead of
their direct values) in sequential order.
-- description
-- eno
numbers:
- 6
- 8
- 19
-- eno
-- php
$list = Parser::parse($input)->element('numbers');
$list->elements();
// returns [ [Field value="6"], [Field value="8"], [Field value="19"] ]
-- php
#### return value
description: An array containing the items of this list as `Field` elements.
### items
syntax:
- items() → array
- items($options) → array
- items($loader) → array
- items($loader, $options) → array
-- description
Retrieve the items of the list, optionally passing them through a loader function.
-- description
-- eno
colors:
- pink
- peach
-- eno
-- php
$list = Parser::parse($input)->element('colors');
$list->items(); // returns ['pink', 'peach']
$list->items(function($value) { return "{$value}!!"; }); // returns ['pink!!', 'peach!!']
-- php
#### parameters
-- $loader
A `function` returning the transformed/validated value or throwing an error.
(The function is applied to each list item on its own and its argument signature
is dynamic, you can either use `($value)` or `($name, $value)`)
-- $loader
$options:
elements = Whether to return the elements (as `Field`) instead of the values of the list items. (defaults to `false`)
enforce_values = Whether empty list items (`- ` in the document, mapping to `null`) are disallowed (defaults to `true`)
with_elements = Whether to return an array of arrays of the form `[ 'element' => ..., 'value' => ... ]` instead of just the values (defaults to `false`)
#### return value
description: The (optionally transformed/validated) items of this list as an array.
### length
syntax: length() → number
-- description
Returns the count of items in the list.
-- description
-- eno
colors:
- pink
- peach
-- eno
-- php
$list = Parser::parse($input)->element('colors');
$list->length(); // returns 2
-- php
#### return value
description: The number of items in the list as a number.
### raw
syntax: raw() → object
-- description
Retrieve a native representation of the list.
-- description
-- eno
colors:
- pink
- peach
-- eno
-- php
$list = Parser::parse($input)->element('colors');
$list->raw(); // returns [ 'colors' => ['pink', 'peach'] ]
-- php
#### return value
description: A native PHP representation of the list.
## Eno\Fieldset
-- class description
Fieldsets are represented as a `Fieldset`:
```eno
rated things:
toys = 5 stars
plants = 3 stars
```
You will mostly obtain an instance of this through the `fieldset` accessor on a document/section.
-- class description
### assertAllTouched
syntax:
- assertAllTouched()
- assertAllTouched($options)
- assertAllTouched($message, $options)
- assertAllTouched($message_function, $options)
-- description
Assert that all entries of this fieldset that were present in the parsed eno document
were also queried (and therefore *touched*) by the application. This, combined with eno's
query methods, serves to ensure a two-way guarantee for both users and developers:
No data that the application requires can be left out, and no data that the application
does not process can be supplied.
-- description
-- eno
Important data:
A = I need to be processed!
B = Me too!
-- eno
-- php
$document = Parser::parse($input);
$fieldset = $document->fieldset('Important data');
$data_a = $fieldset->entry('A');
// ... processing happens only for data_a
$fieldset->assertAllTouched(); // throws a ValidationError
$fieldset->assertAllTouched([ 'only' => ['A'] ]) // passes
$fieldset->assertAllTouched([ 'except' => ['B'] ]) // passes
$fieldset->assertAllTouched(function($name, $value) { // throws a ValidationError "B is not ..."
return "{$name} is not supported by the application, please contact support if you think it should be";
});
-- php
#### parameters
-- $message or $message_function
Optional, usually the default message (*An excess element named [NAME] was
found, is it possibly a typo?*) will do fine. If you want to override it,
provide either a static message as a string, or alternatively a function
returning a string. (The function is passed `$name` and `$value`, in that order)
-- $message or $message_function
$options:
only = An array of strings, e.g. `['name', 'email']`, which specifies to only check these elements for whether they've been touched.
except = An array of strings, e.g. `['phone number']`, which specifies to exclude these elements from checking whether they've been touched.
### element
syntax:
- element($name) → element or null
- element($name, $options) → element or null
-- description
Retrieve a single entry as `Field` (instead of
its direct value) from the fieldset by its name.
Optionally specify whether it's optional or mandatory for the entry to be
present in the eno document (by default it's optional).
-- description
-- eno
years:
2007 = Year of the gooseberry
2010 = Year of the awesome beanstalk
2011 = Year of yearning
-- eno
-- php
$fieldset = Parser::parse($input)->fieldset('years');
fieldset->element('2010'); // returns [Field name="2010" value="Year of the awesome beanstalk"]
fieldset->element('2020'); // returns null
fieldset->element('2020', [ 'enforce_element' => true ]); // throws a ValidationError
fieldset->element('2020', [ 'required' => true ]); // throws a ValidationError
-- php
#### parameters
$name: The name of the entry to fetch from the fieldset as a string.
$options:
enforce_element = Whether the element must be present in the document (`true` or `false`, defaults to `false`)
required = Alias for `enforce_element` (this exists on many methods and depending on context refers to either element or value)
#### return value
description: An element (e.g. `Field`, `ListElement`, etc.) or `null`.
### elements
syntax: elements() → array
-- description
Retrieve the entries of this fieldset as `Field` elements (instead of
their direct values) in sequential order. This seamlessly lets you switch from
associative readout to sequential readout, allowing fieldsets to also represent
document-like structures instead of just associative data.
-- description
-- eno
dialogue:
alice = hi
bob = hey
alice = sup?
bob = nothin'
-- eno
-- php
$document = Parser::parse($input);
$dialogue = $document->fieldset('dialogue');
$html = '<h1>Observe this fascinating dialogue, presented in html!</h1>';
foreach($dialogue->elements() as $element) {
$html .= "<strong>{$element->name}</strong>: \"{$element->value()}\"";
}
file_put_contents('index.html', $html);
-- php
#### return value
description: An array containing the elements of this section.
### enforceAllElements
syntax:
- enforceAllElements()
- enforceAllElements($enforce)
-- description
Set the default for all following queries on this fieldset of whether the
presence of elements in the eno input text should be enforced (by default it is
not). This can be used to prevent "template decay" - with presence enforcement
enabled entries may be empty, but they (at least their declaration) must be
there in the eno document and consequently they can not disappear from a
template at any point without triggering an error.
-- description
-- eno
conversions:
0001 = 1
0010 = 2
-- eno
-- php
$document = Parser::parse($input);
$conversions = $document->fieldset('conversions');
$conversions->enforceAllElements();
$conversions->entry('0011'); // throws a ValidationError
$conversions->entry('0011', [ 'enforce_element' => false ]); // returns null
-- php
#### parameters
$enforce: An optional boolean indicating whether to enforce or not. (otherwise `true` is assumed)
### entry
syntax:
- entry($name) → value or null
- entry($name, $options) → array/value or null
- entry($name, $loader) → value or null
- entry($name, $loader, $options) → array/value or null
-- description
Retrieve an entry's value from the fieldset, optionally supplying a loader to
validate and/or transform the value, and/or an options array.
-- description
-- eno
Q&A:
Meaning = 42
Green = Yes
Purpose =
-- eno
-- php
$document = Parser::parse($input);
$qa = $document->fieldset('Q&A');
$qa->entry('Meaning'); // returns '42'
$qa->entry('Purpose'); // returns null
$qa->entry('Purpose', [ 'required' => true ]); // throws a ValidationError
$qa->entry('Purpose', [ 'enforce_element' => true ]); // returns null
$qa->entry('Beige', [ 'enforce_element' => true ]); // throws a ValidationError
$qa->entry('Green', function($value) { return strtoupper($value); }); // returns 'YES'
$qa->entry('Meaning', function($value) { // throws a ValidationError
if($value === '42') {
throw new Exception("That one's getting old!");
}
return $value;
});
$qa->entry('Meaning', [ 'with_element' => true ]);
// returns [ 'element' => [Field name="Meaning" value="42"], 'value' => '42' ]
-- php
#### parameters
$name: The name of the entry as a string.
$loader:
| A function returning the transformed/validated value or throwing an error.
| (The function argument signature is dynamic, you can either use `($value)` or
| `($name, $value)`)
$options:
enforce_element = Whether the entry must be present in the document (`true` or `false`, defaults to `false`)
enforce_value = Whether there must be a value or the entry is allowed to be empty (default to `false`)
required = Alias for `enforce_value` (this exists on many methods and depending on context refers to either element or value)
with_element = Whether to return an array with both the element and the value (defaults to `false`)
#### return value
description: The entry's value, or `null` if empty.
### raw
syntax: raw() → object
-- description
Retrieve a native representation of the fieldset.
-- description
-- eno
weights:
apple = 100g
pineapple = 800g
-- eno
-- php
$document = Parser::parse($input);
$document->fieldset('weights')->raw();
// returns [ 'weights' => [[ 'apple' => '100g' ], [ 'pineapple' => '800g' ]] ]
-- php
#### return value
description: A native object representation of the fieldset.
## Eno\EmptyElement
-- class description
This represents empty elements such as `color:`, where it is not clear if it is an empty field, list, or fieldset.
-- class description
### error
syntax:
- error() → ValidationError
- error($message) → ValidationError
- error($message_function) → ValidationError
-- description
Generate an error in the context of the element. The error includes a generic
message by default, or a custom one if you supply it (which is the recommended
practice). You can also pass a message function which (like the loader functions
too) gets the name and value as arguments and returns a message string. This
serves to create highly informative error messages that pin-point to the exact
origin of the error, even when the initial reading of data is already past, e.g.
when the error condition is only apparent later, when more processing has
occurred or other data is available.
-- description
-- eno
color:
-- eno
-- php
$document = Parser::parse($input);
$result = $document->field('color', [ 'with_element' => true ]);
// ...
if($result['value'] === null) {
throw $result['element']->error('Postprocessing determined that this value needs to be provided.');
}
-- php
#### parameters
$message or $message_function:
| Highly recommended to provide one (but it's optional).
|
| Either directly pass a string, or alternatively a function returning a string.
| (The function is passed `$name` and `$value` inside a single object parameter.)
#### return value
description:
| A `ValidationError` in the context of the element's value
| (and with an optional custom message).
### raw
syntax: raw() → object
-- description
Retrieve a native representation of the empty element.
-- description
-- eno
color:
-- eno
-- php
$empty = Parser::parse($input)->element('color');
$empty->raw(); // returns [ 'color' => null ]
-- php
#### return value
description: A native representation of the empty element.
### value
syntax: value() → null
-- description
Retrieve the value (always returns `null`).
-- description
-- eno
note:
-- eno
-- php
$empty = Parser::parse($input)->element('note');
$empty->value(); // returns null
-- php
#### return value
description: Always `null`.
## Eno\Error
-- class description
The single generic error interface for all (user) errors that eno generates.
Note that this is never thrown by itself, but only in one of it's subclassed
variants (`ParseError` and `ValidationError`). However, you can still
utilize this generic class in cases where you want to catch both parser and
validation errors indiscriminately, like so:
```php
try {
// ...
} catch(Error $e) { // catches both ParseError and ValidationError
// ...
}
```
-- class description
### cursor
syntax: cursor → [line, column]
-- description
Returns a cursor position as an array of the form [line, column], indicating
where a cursor should be placed if an application wants to offer the user a way
to move the cursor straight to the error location.
-- description
-- php
try {
// ...
} catch(Error $e) {
$e->cursor; // returns [3, 14]
}
-- php
#### return value
description: An array, where [0] is the line number, and [1] is the column number.
### selection
syntax: selection → [[line, column], [line, column]]
-- description
Returns a selection as an array of the form [[line, column], [line, column]],
indicating a text range to select if an application wants to offer the user a
way to get a selection for the error in the input.
-- description
-- php
try {
// ...
} catch(Error $e) {
$e->selection; // returns [[3, 14], [3, 23]]
}
-- php
#### return value
description:
| An array, where [0] is the begin of the selection and [1] is the end,
| and both begin and end are each again an array, where [0] is the
| line number, and [1] is the column number.
### message
syntax: message → string
-- description
Contains both the error text as well as the snippet. This is also what you
get in the console when you don't catch the error.
-- description
-- php
try {
// ...
} catch(Error $e) {
$e->message; // returns "In line 4 'a' is copied into itself.\n\n Line | Content\n ..."
}
-- php
#### return value
description: Both the error text as well as the snippet.
### snippet
syntax: snippet → string
-- description
Returns a formatted excerpt of those passage(s) from the input where the error occurred.
-- description
-- php
try {
// ...
} catch(Error $e) {
$e->snippet;
// returns something like ...
//
// Line | Content
// 1 |
// * 2 | # a
// * 3 | ## b
// > 4 | ### c < a
// 5 |
}
-- php
#### return value
description: A formatted excerpt of those passage(s) from the input where the error occurred.
### text
syntax: text → string
-- description
Returns a one-liner that describes the error in human language.
-- description
-- php
try {
// ...
} catch(Error $e) {
$e->message; // returns 'In line 4 'a' is copied into itself.'
}
-- php
#### return value
description: A single sentence that describes the error in human language.
## Eno\ParseError
-- class description
When this is thrown, it indicates an error regarding syntax or grammatical semantics of the document.
Functionally this behaves exactly like `Error`, therefore the interface methods are not repeated here and can
be looked up on the `Error` documentation.
-- class description
## Eno\ValidationError
-- class description
When this is thrown, it indicates an error regarding application-specific requirements for the document.
Functionally this behaves exactly like `Error`, therefore the interface methods are not repeated here and can
be looked up on the `Error` documentation.
-- class description