Человекочитаемый JSON с помощью Perl

Давно хотел найти возможность создавать pretty JSON из Perl структур. Задачка-то совершенно тривиальная, на CPAN есть куча модулей как сериализовать JSON, но мне хотелось, чтобы соблюдалось два условия:

Отступ в 4 пробела

В моем текстовом редакторе настроено, что по нажатии на tab создается отступ в 4 пробела. Это достаточно стандартная настройка, очень много кода написано именно с соблюдением этого стандарта.

Но почему-то многие Perl библиотеки для работы с JSON используют в качестве отступа по умолчанию 3 пробела. Из-за этого возникает проблемы: из Perl я создаю JSON c тремя пробелами, комичу этот файл в проект, а потом когда руками хочу что-то поправить, выясняется, что тот формат, как я хочу писать, не соответствует формату в файле.

Сортировка ключей в объекте

Для Perl хеша или объекта JavaScript порядок ключей не определен. Поэтому сериализатор вполне может использовать любой порядок ключей и это будет валидно. Но такой вариант очень неудобен: создали JSON с одним порядком ключей, закомитили в проект. Потом решили перегенерить JSON и повторно его создали — и, бац, все ключи в другом порядке "git diff" показывает кучу изменений, из которых сложно понять, что реально изменилось.

Поэтому хочется чтобы JSON всегда формировался одинаково, а для этого нужно определить какое-то правило, в каком порядке должны располагаться ключи. Самое простое правило — это чтобы ключи были отсортированы.

Решение

Оказалось, что решение этой задачи весьма простое. Нужно взять JSON::PP и использовать его вот таким образом:

use JSON::PP qw();

sub to_pretty_json {
    my ($data) = @_;

    my $json_coder = JSON::PP
        ->new
        ->pretty
        ->canonical
        ->indent_length(4)
        ;

    my $pretty_json = $json_coder->encode($data);

    return $pretty_json;
}

say to_pretty_json $data;

Вот полный текст скрипта-примера.

JSON::PP входит в дефолтную поставку Perl начиная с версии 5.14, так что такое решение будет работать из коробки на всех современных операционных системах.

Иван Бессарабов
ivan@bessarabov.ru

20 марта 2015

Edit this post on GitHub