CommonMark

Пару недель назад в блоге Coding Horror появилась запись о том, что объединённые усилия GitHub, StackOverflow и ещё нескольких компаний увенчались успехом и они готовы представить общественности точную спецификацию стандарта Markdown.

Ну как точную. По моему мнению, спецификация, основанная на примерах, а не на точных формулировках, не может быть абсолютно точной. Иначе придётся описывать множество всяческих граничных вариантов. И нет гарантий, что кто-нибудь не придумает пример, который не покрывается спецификацией. У меня, например, это получилось. Зато такой подход позволяет объединить спецификацию и набор тестов для проверки парсеров в один файл.

Когда создатели только объявили об окончании основных работ над спецификацией, её назвали Standard Markdown. И тут же поднялось множество криков, что они пытаются украсть авторство Markdown у Джона Грубера. Ведь действительно, кто будет смотреть на просто Markdown, когда есть Standard Markdown. Но позиция самого Грубера тоже не очень понятна. За 10 лет существования формата он не предпринял ничего, чтобы исправить все те проблемы и неясности, что существуют в Markdown. По мнению Джона, именно эта неточность формулировок и сыграла главную роль в популярности этого формата. Но теперь, когда другие проделали эту работу, он высказал свое «фи». Что же, автор есть автор. И после некоторого обсуждения проект переименовали в CommonMark.

Вообще Markdown интересный язык разметки. На нем очень удобно писать, что, вероятно, и сделало его таким популярным. В нём большая часть разметки интуитивно понятна, сразу видно где список, где цитата. Конечно, нужно раз взглянуть, как добавлять ссылки и картинки, но больше проблем с этим не возникает.

Проблемы начинаются, когда пишешь парсер для этого формата. Из-за отсутствия чёткой спецификации каждый начинает изгаляться как может. Один и тот же текст может подразумевать несколько различных вариантов разбора, и нужно быть очень осторожным, если, например, хочешь добавить блок с кодом куда-нибудь в список. Спецификация CommonMark предлагает наиболее логичные варианты чтения текста, но не самые простые. Поэтому, чтобы написать парсер, соответствующий данной спецификации, придётся изрядно постараться.

Но хочется верить, что когда большая часть парсеров начнёт соответствовать этой спецификации, значительно упростится переносимость текстов между различными приложениями.

Dart и highlight.js

Когда я создавал этот блог, нужно было что-то делать с подсветкой синтаксиса для примеров кода, которые здесь появляются. После рассмотрения различных альтернатив (уже и не помню, каких именно) я остановился на highlight.js. На тот момент эта библиотека поддерживала все необходимые мне языки. А потом я решил поэкспериментировать с
Dart… Ну и написать пару постов о нём. Смотрю, а поддержки Dart в highlight.js нет. На сайте проекта сказано, что разработчики не выполняют заказы на добавление новых языков, если хотите поддержку нового языка, то реализуйте её сами.

Что делать, реализовал поддержку и отправил pull request на добавление языка в библиотеку. А пока использовал свою сборку из своего репозитория. Прошло полгода — и теперь мой патч наконец включили в библиотеку! Более того, новая версия 8.2 уже вышла и вы можете ей воспользоваться, чтобы добавить поддержку подсветки исходного кода на Dart (и других языках) к себе на сайт.

Как сделать свою карту

Сегодня я расскажу вам, как с помощью JavaScript и d3 нарисовать карту, подобную моей.

Читать далее...
Store as Global Variable

Совершенно случайно обнаружил в свежей версии Google Chrome полезную функцию: Store as Global Variable. Она позволяет сохранить любой объект из консоли в виде глобальной переменной. Пару версий хрома назад её ещё точно не было.

Зачем это надо? Зачастую проще написать в коде console.log() в некоторых критичных местах и потом посмотреть результат, чем построчно отлаживать свою программу дебаггером. Теперь этот способ стал ещё информативнее. Например, можно запросто определить, есть ли среди десяти прототипов в цепочке наследования какой-нибудь требуемый метод.

Или можно сделать что-нибудь с объектом во время исполнения. Всё зависит только от потребностей.

Happy Debugging!

Проблемы с запуском планировщика

Поделюсь некоторыми сложностями, с которыми я столкнулся, запуская планировщик маршрута.

Конечно, во время самой разработки все сложности сводились к алгоритмическим. В Dartium всё работало как положено с нужным количеством ошибок и предупреждений. Проблемы начались сразу после компиляции в JavaScript и запуске в обычном браузере (кто бы сомневался). Проект не запустился, выдав странного вида stack trace. Ну что же, пересобираем проект без минификации. Stack trace стал читаемым, ошибки понятными. Как оказалось, вся проблема была в аннотации @MirrorsUsed. Дело в том, что mirrors (так называется reflection в Dart) занимает непозволительно много места в скомпилированном коде. И для того, чтобы этого избежать, авторы Dart предлагают использовать эту аннотацию для указания библиотек и классов, информацию о которых нужно будет получить во время исполнения (кстати, в будущем обещают доработать компилятор, что избавит от необходимости использовать эту аннотацию). Так вот, мой класс контроллера не был указан в @MirrorsUsed и, соответственно, AngularDart не мог с ним работать.

Исправил, скомпилировал, не запустилось. Правда, в этот раз я увидел несколько больше, чем просто пустую страницу. Немного поисков — и обнаружилась вторая проблема: нельзя в шаблонах AngularDart использовать методы встроенных объектов Dart. То есть в Dart можно, а в JavaScript нельзя. Конкретно в моем случае было написано:

{{segment[0].distanceTo(segment[1]).round()}}

Понятное дело, JavaScript и не догадывается о методе round у типа double. Да, собственно, про существование double он тоже не догадывается. Поэтому нужно писать геттер или вспомогательную функцию. Например так:

{{segment[0].distanceToRound(segment[1])}}

Ура, запустилось! Теперь осталось собрать минифицированную версию и выложить. Но после сборки проект снова упал с непонятным stack trace, как и в самом начале.

Не один час был потрачен на гугление всевозможных причин. Дело почти дошло до того, чтобы написать новый багрепорт о неправильной компиляции. Но я вовремя остановился, и хорошо, потому что ошибка была у меня и, кстати, довольна простая: я пытался проинициализировать Яндекс.Карты, а функция-конструктор не существовала. Вот проблемная строка, она соответствует map = new ymaps.Map(“map”, options); в JavaScript:

map = new JsObject(context['ymaps']['Map'], ["map",  options]);

Но ведь несжатая версия работает! Моё предположение, что сжатая версия приложения инициализируется значительно быстрее и поэтому API Яндекс.Карт ещё не готово к тому времени, оказалось верным, и вызов функции ymaps.ready всё исправил.

Итог. Более-менее сложное Dart-приложение хорошо работает в браузерах без поддержки Dart. Но зато когда сталкиваешься с проблемой, которая возникает только в скомпилированном и минифицированном коде, можно потратить довольно много времени на поиск решения просто потому, что подсказок никто не даст, а код выглядит довольно запутанно. Но в своей практике я сталкивался со случаями, когда и обычное JavaScript-приложение после сжатия начинало вести себя неправильно и возникали те же проблемы поиска решения.

Хочется отметить минификатор JS, встроенный в Dart. Он заменяет все ; на переводы строк. Из-за этого в результате получается файл со множеством строк, а не с одной, как в случае с другими минификаторами. А это, в свою очередь, сильно упрощает ручной анализ кода.

← СтаршеМоложе →