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

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!

wersja: 3.x