Format NEON
NEON to czytelny dla człowieka format danych strukturalnych. W Nette używany jest do plików konfiguracyjnych. Używa się go też do danych strukturalnych, jak ustawienia, tłumaczenia językowe itd. Wypróbuj go w piaskownicy.
NEON to skrót od Nette Object Notation. Jest mniej złożony i uciążliwy niż XML czy JSON, ale daje podobne możliwości. Jest bardzo podobny do YAML-a. Główną zaletą jest to, że NEON ma tak zwane encje, dzięki którym konfiguracja usług DI jest taka sexy. I pozwala używać tabulatorów do wcięć.
NEON od podstaw zbudowany jest tak, żeby był łatwy w użyciu.
Integracja
- NetBeans (ma wbudowane wsparcie)
- PhpStorm (plugin)
- Visual Studio Code (Nette Latte + Neon albo Nette for VS Code)
- Sublime Text 3 (plugin)
- Sublime Text 2 (plugin)
- VIM (plugin)
- Emacs (plugin)
- Prism.js (zintegrowany język)
Składnia
Plik napisany w NEON-ie reprezentuje zwykle sekwencję albo mapowanie.
Mapowania
Mapowanie to zbiór par klucz-wartość; w PHP nazywałoby się tablicą asocjacyjną. Każda para zapisywana jest jako
klucz: wartość, spacja po : jest wymagana. Wartością może być cokolwiek: ciąg, liczba, wartość
logiczna, null, sekwencja albo kolejne mapowanie.
street: 742 Evergreen Terrace
city: Springfield
country: USA
W PHP tę samą strukturę zapisalibyśmy jako:
[ // PHP
'street' => '742 Evergreen Terrace',
'city' => 'Springfield',
'country' => 'USA',
]
Zapis ten nazywa się blokowym, bo wszystkie pozycje są w osobnych liniach i mają to samo wcięcie (w tym przypadku żadne). NEON wspiera też zapis inline dla mapowania, który zamykany jest w nawiasach klamrowych, wcięcia nie odgrywają roli, a separatorem elementów jest albo przecinek, albo złamanie linii:
{street: 742 Evergreen Terrace, city: Springfield, country: USA}
To samo zapisane w wielu liniach (wcięcia nie mają znaczenia):
{
street: 742 Evergreen Terrace
city: Springfield, country: USA
}
Alternatywnie zamiast : można użyć =, zarówno w zapisie blokowym, jak i inline:
{street=742 Evergreen Terrace, city=Springfield, country=USA}
Sekwencje
Sekwencje to w PHP tablice indeksowane. Zapisywane są jako linie zaczynające się myślnikiem -, po którym
następuje spacja. Znów wartością może być cokolwiek: ciąg, liczba, wartość logiczna, null, sekwencja albo kolejne
mapowanie.
- Cat
- Dog
- Goldfish
W PHP tę samą strukturę zapisalibyśmy jako:
[ // PHP
'Cat',
'Dog',
'Goldfish',
]
Zapis ten nazywa się blokowym, bo wszystkie pozycje są w osobnych liniach i mają to samo wcięcie (w tym przypadku żadne). NEON wspiera też zapis inline dla sekwencji, który zamykany jest w nawiasach kwadratowych, wcięcia nie odgrywają roli, a separatorem elementów jest albo przecinek, albo złamanie linii:
[Cat, Dog, Goldfish]
To samo zapisane w wielu liniach (wcięcia nie mają znaczenia):
[
Cat, Dog
Goldfish
]
Myślników (punktorów) nie da się używać w zapisie inline.
Kombinacje
Wartościami mapowań i sekwencji mogą być inne mapowania i sekwencje. Główną rolę odgrywa poziom wcięcia. W
poniższym przykładzie myślnik oznaczający pozycje sekwencji ma większe wcięcie niż klucz pets, więc pozycje
stają się wartością pierwszej linii:
pets:
- Cat
- Dog
cars:
- Volvo
- Skoda
W PHP tę samą strukturę zapisalibyśmy jako:
[ // PHP
'pets' => [
'Cat',
'Dog',
],
'cars' => [
'Volvo',
'Skoda',
],
]
Zapis blokowy i inline można łączyć:
pets: [Cat, Dog]
cars: [
Volvo,
Skoda,
]
Zapisu blokowego nie da się użyć wewnątrz zapisu inline; to nie zadziała:
item: [
pets:
- Cat # TO NIE JEST MOŻLIWE!!!
- Dog
]
W poprzednim przypadku zapisaliśmy mapowanie, którego elementami były sekwencje. Spróbujmy teraz odwrotnie i utwórzmy sekwencję zawierającą mapowania:
-
name: John
age: 35
-
name: Peter
age: 28
Myślniki nie muszą być w osobnych liniach, można umieścić je też tak:
- name: John
age: 35
- name: Peter
age: 28
To od Ciebie zależy, czy wyrównasz klucze w kolumnie spacjami, czy użyjesz tabulatora.
Ponieważ PHP używa dla mapowań i sekwencji tej samej struktury (czyli tablic), oba da się połączyć. Wcięcie jest tym razem takie samo:
- Cat
street: 742 Evergreen Terrace
- Goldfish
W PHP tę samą strukturę zapisalibyśmy jako:
[ // PHP
'Cat',
'street' => '742 Evergreen Terrace',
'Goldfish',
]
Ciągi
Ciągi w NEON-ie można zamykać w apostrofach albo cudzysłowach. Ale jak widzisz, mogą też być bez nich.
- An unquoted string in NEON
- 'A single-quoted string in NEON'
- "A double-quoted string in NEON"
Jeśli ciąg zawiera znaki ` # " ' ` , : = - [ ] { } ( ) `, które mogłyby zostać pomylone ze składnią NEON-a,
musi być zamknięty w cudzysłowach albo apostrofach. Zalecamy używanie apostrofów, bo nie używają escapowania. Jeśli musisz
umieścić w takim ciągu apostrof, zdubluj go:
'A single quote '' inside a single-quoted string'
Cudzysłowy pozwalają używać sekwencji escape do zapisania znaków specjalnych za pomocą odwrotnych ukośników
\. Wspierane są wszystkie sekwencje escape wspierane przez format JSON, plus \_, które reprezentuje
twardą spację, czyli \u00A0.
- "\t \n \r \f \b \" \\ \/ \_"
- "\u00A9"
Są jeszcze inne przypadki, w których trzeba zamknąć ciągi w cudzysłowach:
- zaczynają się albo kończą spacjami
- wyglądają jak liczby, wartości logiczne albo null
- NEON zinterpretowałby je jako daty
Ciągi wieloliniowe
Ciąg wieloliniowy zaczyna się i kończy potrójnymi apostrofami w osobnych liniach. Wcięcie pierwszej linii jest ignorowane dla wszystkich linii:
'''
first line
second line
third line
'''
W PHP zapisalibyśmy to samo jako:
"first line\n\tsecond line\nthird line" // PHP
Sekwencje escape działają tylko dla ciągów zamkniętych w cudzysłowach zamiast apostrofów:
"""
Copyright \u00A9
"""
Liczby
NEON rozumie liczby zapisane w notacji naukowej, a także liczby w systemie binarnym, ósemkowym i szesnastkowym:
- 12 # liczba całkowita
- 12.3 # liczba zmiennoprzecinkowa
- +1.2e-34 # liczba wykładnicza
- 0b11010 # liczba binarna
- 0o666 # liczba ósemkowa
- 0x7A # liczba szesnastkowa
Nulle
Null można wyrazić w NEON-ie za pomocą null albo przez pominięcie wartości. Dozwolone są też warianty
z wielką pierwszą literą albo wszystkimi wielkimi literami (Null, NULL).
a: null
b:
Wartości logiczne
Wartości logiczne wyraża się w NEON-ie za pomocą true / false albo yes /
no. Dozwolone są też warianty z wielką pierwszą literą albo wszystkimi wielkimi literami (True,
TRUE, False, FALSE, Yes, YES, No,
NO).
[true, TRUE, True, false, yes, no]
Daty
NEON używa do wyrażania dat poniższych formatów i automatycznie konwertuje je na obiekty
DateTimeImmutable:
- 2016-06-03 # data
- 2016-06-03 19:00:00 # data i czas
- 2016-06-03 19:00:00.1234 # data i mikroczas
- 2016-06-03 19:00:00 +0200 # data, czas i strefa czasowa
- 2016-06-03 19:00:00 +02:00 # data, czas i strefa czasowa
Encje
Encja to struktura przypominająca wywołanie funkcji:
Column(type: int, nulls: yes)
W PHP parsowana jest jako obiekt Nette\Neon\Entity:
// PHP
new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true])
Encje można też łączyć w łańcuch:
Column(type: int, nulls: yes) Field(id: 1)
Co w PHP parsowane jest tak:
// PHP
new Nette\Neon\Entity(Nette\Neon\Neon::Chain, [
new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true]),
new Nette\Neon\Entity('Field', ['id' => 1]),
])
Wewnątrz nawiasów obowiązują reguły zapisu inline używanego dla mapowań i sekwencji, więc może być wieloliniowy, a przecinki nie są konieczne:
Column(
type: int
nulls: yes
)
Komentarze
Komentarze zaczynają się od #, a wszystkie kolejne znaki na prawo są ignorowane:
# ta linia zostanie zignorowana przez interpreter
street: 742 Evergreen Terrace
city: Springfield # to też jest ignorowane
country: USA
NEON kontra JSON
JSON to podzbiór NEON-a. Każdy JSON da się więc sparsować jako NEON:
{
"php": {
"date.timezone": "Europe\/Prague",
"zlib.output_compression": true
},
"database": {
"driver": "mysql",
"username": "root",
"password": "password123"
},
"users": [
"Dave", "Kryten", "Rimmer"
]
}
A co, gdybyśmy pominęli cudzysłowy?
{
php: {
date.timezone: Europe/Prague,
zlib.output_compression: true
},
database: {
driver: mysql,
username: root,
password: password123
},
users: [
Dave, Kryten, Rimmer
]
}
A co z klamrami i przecinkami?
php:
date.timezone: Europe/Prague
zlib.output_compression: true
database:
driver: mysql
username: root
password: password123
users: [
Dave, Kryten, Rimmer
]
Czy listy z punktorami nie są czytelniejsze?
php:
date.timezone: Europe/Prague
zlib.output_compression: true
database:
driver: mysql
username: root
password: password123
users:
- Dave
- Kryten
- Rimmer
Dodamy komentarze?
# my web application config
php:
date.timezone: Europe/Prague
zlib.output_compression: true # use gzip
database:
driver: mysql
username: root
password: password123
users:
- Dave
- Kryten
- Rimmer
Hurra, znasz już składnię NEON-a!