Гугл открыла исходный код своего проекта Jsonnet, языка для конфигурации, который заменяет стандартный JSON и добавляет новые возможности без нарушения обратной совместимости. Среди таких возможностей: комментарии, ссылки, арифметические и условные операторы, массивы и работа с объектами, импорт, функции, локальные переменные. Программы на Jsonnet транслируются в совместимый JSON формат данный.
Комментарии. Jsonnet принимает комментарии в стиле С ( /* … */ ) и С++ ( // )
Ссылки. Ключевое слово self может быть использовано для ссылки на текущий объект. Оператор $ позволяет использовать корневой объект.
Арифметические и условные операторы. Оператор + может складывать числа, строки, массивы и объекты. Операторы == и != возвращают true или false. Оператор if работает как тернарный оператор ?: в С. Далее несколько примером с операторами языка и результат. Примеры взяты со страницы проекта.
// bar_menu.3.jsonnet { foo: 3, bar: 2 * self.foo, // Multiplication. baz: "The value " + self.bar + " is " + (if self.bar > 5 then "large" else "small") + ".", array: [1, 2, 3] + [4], obj: {a: 1, b: 2} + {b: 3, c: 4}, equality: 1 == "1", }
Результат:
{ "foo": 3, "bar": 6, "baz": "The value 6 is large.", "array": [1, 2, 3, 4], "obj": {a: 1, b: 3, c: 4}, "equality": false }
Создание массивов и объектов. Для создания массивов и объектов используется конструкция с оператором for, как показано в примере ниже:
{ foo: [1, 2, 3], bar: [x * x for x in self.foo if x >= 2], baz: { ["field" + x]: x for x in self.foo }, obj: { ["foo" + "bar"]: 3 }, }
Результат:
{ "foo": [ 1, 2, 3 ], "bar": [ 4, 9 ], "baz": { "field1": 1, "field2": 2, "field3": 3 }, "obj": { "foobar": 3 } }
Модульность. Код написанный на Jsonnet может быть разбит на несколько файлов и затем объединятся с помощью оператора import. Внутренняя механика заключается в простом склеивании файлов.
Функции. Jsonnet значения могут содержать функции. Они помечаются как скрытые поля и не транслируются в JSON. Пример такой функции представлен ниже:
// bar_menu_utils.jsonnet { equal_parts(size, ingredients):: if std.length(ingredients) == 0 then error "No ingredients specified." else [ { kind: i, qty: size/std.length(ingredients) } for i in ingredients ], id:: function(x) x, }
Jsonnet также включает в себя локальные переменные, способ для наследования объектов путём импортирования, вычисляемые и опциональные поля.
Движок языка написан на С++11 с предоставлением обёртки API в стиле С для более лёгкого портирования на другие языки. Команда разработчиков сразу может предоставить библиотеки для С и Питона. Реализация для С++ может быть скомпилирована в JS с Emscripten. Еще доступен неофициальный пакет для nodejs.
Полные спецификации можно посмотреть на странице спецификации.
Некоторое сравнение с другими языками
JSON. Собственно, JSON описывает все данные буквально. Jsonnet имеет более свободный синтаксис и комментарии, для облегчения чтения данных людьми.
YAML. Так же является некоторым расширением JSON, который позволяет генерировать правильный JSON. Синтаксис языка очень компактный и файлы на YAML гораздо, короче чем они потом выходят в JSON формате. Несмотря на то, что язык создан в тех же целях, что и Jsonnet, создание, трансляция и уточнение данных проигрывает Jsonnet. В частности, YAML и Jsonnet имеют различные точки зрения на то, что должно означать «1+1». YAML говорит, что это строка «1+1», тогда как Jsonnet считает, что результат должен быть 2.
Другие языки с шаблонами. Jsonnet является шаблонным языком, который генерирует данные по алгоритмам с перемеживанием буквальных данных с вычислительными конструкциями. Большинство таких языков считают программы и результат простым текстом. Это значит, что на выходе может получится некорректный результат, если мы говорим о JSON. Большинство таких шаблонных языков не обладают знаниями о синтаксисе выходных данных и не могут проверять результат на правильность. Jsonnet такого недостатка лишён, так как это узкоспециализированный инструмент.
Сравнение с другими инструментами и языками, такими как Haskel, Nix, Coil, Pystachio и другими можно в деталях прочитать в руководстве к Jsonnet.
Вопросы и ответы
В оригинальном топике появились интересные вопросы и ответы от ведущего разработчика проекта Дэвида Каннингэма (David Cunningham).
Вопрос: Почему бы не воспользоваться уже существующим открытым стандартом EDN? На мой взгляд в нем есть все те же самые фичи и уже есть порты под разные языки.
Ответ: Хороший вопрос, но EDN не очень-то похож на Jsonnet. EDN – это «только данные», он не знает ничего о вычислениях или абстракциях. Он расширяем, и вы можете добавить недостающие конструкции, но тогда вы получите по факту новый язык, который будет непонятен другим системам.
Когда мы создавали Jsonnet, мы думали о том, что нам надо следовать общим стандартам. Мы выбрали JSON из-за его популярности, но мы так же пытались следовать существующим моделям программирования (главным образом js и python) так близко, как только возможно.
Хочу также заметить, что можно интегрировать Jsonnet в системы, которые работают с EDN, потому что возможно генерировать EDN с помощью нашей системы. Необходимо только написать специальную функцию «manifest». Такая работа проделана для INI файлов, конфигурационных файлов Lua и Python.
Наконец, Jsonnet доступна для 3х языков (С, Python, Javascript) и для любого языка, который может работать с С интерфейсом. Порты на другие языки запланированы, возможно с помощью портирования на Haxe.
Вопрос. Мне очень нравится проект, но разработчики должны были использовать стандартные JavaScript функции, а не изобретать из в stdlib. Базовые функции пропущены и добавление новых не простая задача, так что это своего рода ограничитель и я, к сожалению, вернулся на старый предпроцессор JSON.
Ответ. Stdlib определённо самая слабая часть проекта и то, что должно быть переписано, улучшено, и задокументировано прежде чем мы выпустим версию 1.0. Мы очень ждём ваших отзывов, особенно с примерами из реальной жизни.
В целом есть возможность расширить stdlib самостоятельно и написать свою собственную библиотеку для Jsonnet. Пример ниже сначала использует маленький трюк для добавления метода add2 в stdlib:
local std2 = std { // Temporarily define std2 to avoid self-reference. add2(x):: x + 2, }; local std = std2; // Bind std2 over std. // Rest of Jsonnet file below: { foo: std.add2(10), // Expands to 12. }
В общем случае, может быть невозможно скопировать функции из поддерживаемых языков, так как семантика может не иметь смысла в Jsonnet. Однако мы понимаем, что иметь необоснованные различия никому не поможет. И это является основной причиной, почему stdlib функции отвечающие за форматирование текста в точности совпадают с оператором % в Python.
На основе материалов:
- http://www.infoq.com/news/2015/04/jsonnet — тема свежая и владелец библиотеки на связи, так что можно поспрашивать напрямую в топике.
- http://google.github.io/jsonnet/doc/
И мы опять хотим привлечь ваше внимание к предстоящей конференции API & Backend (C#). Если вам есть что рассказать про детали реализации и управления API, сервисом на бэкенде. Если у вас есть интересные случаи связанные с генерацией сложных сообщений: заголовков и содержимого – мы ждем ваших историй!
Автор: VioletTape