Почему двухсторонний YAML не анализируется как четырехслойный YAML?
Я вижу странное поведение при разборе YAML (с использованием Ruby 2.5/Psych), созданного с использованием двух пробелов. На мой взгляд, тот же файл с четырьмя пробелами в строке работает, как и ожидалось.
Два пространства:
windows:
- shell:
panes:
- echo hello
приводит к следующему хешу:
{"windows"=>[{"shell"=>nil, "panes"=>["echo hello"]}]}
Принимая во внимание использование четырех пробелов:
windows:
- shell:
panes:
- echo hello
результаты в:
{"windows"=>[{"shell"=>{"panes"=>["echo hello"]}}]}
Я просто просмотрел спецификацию и не увидел ничего, имеющего отношение к этому вопросу.
Ожидается ли такое поведение? Если так, я был бы очень признателен за ссылки на ресурсы, объясняющие почему.
2 ответа
Проблема в том, что вы не можете просто заменить каждые два пробела четырьмя пробелами. Это потому, что в этой паре строк:
- shell:
panes:
эти два пробела во второй строке:
panes:
^^
Являются сокращением для "- " в строке выше. Если бы вторая строка не была сокращена, то пара строк была бы:
- shell:
- panes:
Таким образом, при удвоении отступа вторая из этих строк должна иметь только удвоенную первую пару пробелов, а не вторую. Это даст правильный отступ для пары:
- shell:
panes:
Итак, если вы расширите только первую пару пробелов в строке "панели:", вы получите:
windows:
- shell:
panes:
- git status
Что правильно парсит к ожидаемому результату.
В то время как решение Уэйна верное, объяснение кажется немного неправильным, поэтому я добавлю мое:
В ЯМЛ -
для элементов последовательности блоков (например, ?
а также :
для блочных отображений) рассматривается как отступ ( спецификация):
Символы "-", "?" И ":", используемые для обозначения записей набора блоков, воспринимаются людьми как часть отступа. Это обрабатывается в каждом конкретном случае соответствующими постановками.
Более того, все коллекции блоков (последовательности и отображения) берут свои отступы от своего первого элемента (поскольку нет явного начального индикатора). Так в линии - shell:
, -
определяет уровень отступа вновь начатой последовательности, в то же время shell:
определяет уровень отступа вновь начатого отображения, который является содержимым элемента последовательности. Обратите внимание, как -
рассматривается как отступ для определения уровня отступа отображения.
Теперь вернемся к вашему первому примеру:
windows:
- shell:
panes:
- echo hello
panes:
находится на том же уровне, что и shell:
, Это означает, что YAML анализирует его как ключ отображения, запущенного shell:
Это означает, что ключ shell
имеет пустое значение. Значения сопоставления неявных ключей, если они не находятся в одной строке, всегда должны иметь отступ больше, чем соответствующий ключ сопоставления ( спецификация):
Свойства узла блока могут занимать несколько строк. В этом случае они должны иметь отступ не менее чем на один пробел больше, чем в коллекции блоков, независимо от отступа записей коллекции блоков.
OTOH, во втором примере:
windows:
- shell:
panes:
- echo hello
panes:
находится на более глубоком уровне отступа по сравнению с shell:
, Это означает, что он анализируется как значение ключа shell
и, таким образом, запускает новое, вложенное отображение блоков.
Наконец, имейте в виду, что с -
рассматривается как часть отступа, "отступ двух пробелов" также может означать следующее:
windows:
- shell:
panes:
- echo hello
Обратите внимание, как -
не более отступ, чем их ключи сопоставления. Это работает, потому что спецификация говорит:
Поскольку люди воспринимают индикатор "-" как отступ, вложенные последовательности блоков могут иметь отступ на один пробел меньше для компенсации, за исключением, разумеется, если они вложены в другую последовательность блоков (контекст блокировки или контекст блокировки).