Акелла промахнулся — дважды! ;) На хабре окошко с редактором находится сразу за последним комментарием, отчего складывается впечатление, что отвечаешь на него. А перенести комментарий после создания уже нельзя.
Поправьте меня, если ошибаюсь, но беглый осмотр выявил несоответствие списку требований, сформулированных в начале:
GitLab CI бесплатен только если проект хостится на GitLab
Semaphore CI не поддерживает Mac OS X
Circle CI не бесплатен для Mac OS X
На самом деле, при выборе сервисов я прежде всего просканировал, что в основном используют opensource разработчики, хостящиеся на GitHub — с большим отрывом лидирует Travis и AppVeyor.
В принципе, производительность Travis меня вполне устраивает — как мне кажется, CI далеко не является критической по времени задачей. А вот что вполне могло бы заставить меня мигрировать на другой сервис, так это наличие более широкого спектра платформ для сборки/тестирования: Ubuntu посвежее, Arch, Fedora, и т.д.
Тут дело даже не в том, запускается или нет Docker на Windows или Mac OS X (как вы верно отметили, да, запускается). Проблема в том, что Travis CI предоставляет Docker-контейнер для сборки только под Linux, а AppVeyor вообще не даёт возможности выбирать между полновесной виртуальной машиной и Docker-контейнером.
Но это, на мой взгляд, и не важно. Выигрыш всего в минуту (!) в таком длительном, да и, чего уж там, совсем не критичном по времени исполнения процессе, как непрерывная интеграция, просто не стоит того, чтоб с ним заморачиваться.
Ну я собственно и не противопоставлял — просто сказал, что и с Doxyrest тоже можно создавать самостоятельные страницы с документацией как обычные .rst файлы. И конечно, и с Doxygen, и с Doxyrest из этих самостоятельных страниц можно ссылаться на авто-сгенерированные страницы API.
Другое дело что Doxyrest перекладывает всю работу по созданию финальной красивой HTML страницы на инструмент, который прекрасно с этим справляется (значительно лучше, чем Doxygen). Вот и всё.
Ну и опять же, любые дополнительные выделения в тексте (за исключением строго оговоренных, когда читатель заранее знает, что значит каждый болд или италик), будь то смайлики или разноцветье шрифтов — это компенсация недостаточного владения классическими выразительными средствами письменной речи.
А мне кажется, визуальные акценты помогают-таки при просматривании статей по диагонали. Вопрос количества и баланса, конечно, открытый (и во многом субъективный). Но вообще я за акценты. Как говорится, let's agree to disagree :)
Вопрос по сути статьи — скажите, а doxygen вроде бы умеет выдавать выхлоп в docbook-формате. а уж для него всяких генераторов в разных форматов написано немало. Такой вариант чем-то не устроил?
Если честно, то не пробовал генерировать HTML из доксигеновского DocBook выхода. Навскидку не вижу причин, почему это может давать намного лучший результат, чем просто подкрутка CSS и шапок у доксигеновского HTML. Впрочем, если у вас пример красивой документации, полученной таким методом — кидайте, можно будет обсудить более предметно.
Всё правильно. А в случае с использованием Doxyrest, отдельные страницы с абстрактным описанием — это будут просто .rst файлы, скармливаемые Sphinx напрямую.
В чём разница между поддержанием документации в отдельном файле или в коде?
Я уже писал выше — при авто-генерации документации имеется гарантия релевантности всех объявлений. Вы можете побегать по API, посмотреть какие аргументы принимаются, что возвращается, какие есть поля и т.д.
По личному опыту документация Doxygen совершенно бестолкова.
Бестолковость абсолютного большинства примеров Доксигеновской документации, действительно имеет место быть. Но это проблема конкретного контента, а не подхода, согласитесь? Можно ведь взять и написать толковую документацию, а не просто: open открывает, get возвращает. Но у меня есть смелая теория, почему сейчас всё обстоит именно так.
Разработчики не хотят тратить усилия на написание толковых комментариев, потому что — барабанная дробь — конечная Доксигеновская документация всё равно будет выглядеть как говно!
Исправить это — и есть главная цель проекта Doxyrest.
Совершенно верно — как средство разбора и вытаскивания документирующих комментариев он пока не имеет равных. Кроме того, когда допилится интеграция с Clang (а то сейчас она какая-то уж слишком экспериментальная), этих самых равных и искать никакого смысла не будет.
А сделать красивый вывод по информации, полученной Доксигеном — в этом и есть вся соль предлагаемого мной проекта. Доксиген умеет доставать информацию из исходников. Sphinx умеет генерировать красивый — и, что главное, настраиваемый, — HTML. Doxyrest — мост между этими двумя товарищами.
Посмотрел описание языка шаблонизации — ой, зря они свой язык стали писать, ой зря...
Им бы взять Lua или Python — и то, и другое легко встраивается в плюсовые приложения. Сейчас вся эта кухня с новым языком даёт слишком уж ограниченные возможности по настройке вывода — на неизвестном и неотлаженном языке, без стандартной библиотеки, да ещё и с вырвиглазным синтаксисом (standardese_for, standardese_else_if и т.д.).
Потом, сама идея с опциональностью шаблонов наводит на мысль, что шаблоны эти планируется использовать лишь как дополнение к автосгенерированному дереву объявлений, на внешний вид которого можно повлиять только настроечными переменными — как и в Doxygen.
Вполне возможно, я что-то упсутил, но у них, увы, нет примеров использования этих шаблонов — в репозитории только плюсы, bash и cmake..
Если они не используют шаблонизатор (а судя по составу репозитория, там есть только CPP и Bash), то наступают на те же самые грабли, что и Doxygen — нельзя хардкодить генерацию HTML.
То есть всё, что они получат в итоге — это Doxygen с Clang в качестве парсера, но с таким же деревянным выходом. Кстати, если не ошибаюсь, автор Doxygen уже начал прикручивать Clang и сам.
Дело в том, что если сначала пишется API как получится, а потом пост-фактум под него пишется документация, то качество этого API будет стремиться к нулю или даже дальше в минус бесконечность. При правильном подходе, документация пишется на этапе проектирования и всегда опережает код. А код и тесты пишутся уже в соответствии с документацией. При таком подходе, и код будет чище, и если имплементация в результате будет отличаться от документации, тесты это покажут.
Это работает только для сферических проектов в вакууме. На практике же набросанные на этапе проектирования интерфейсы безжалостно корёжатся при столкновениях с действительностью. Добавляются и убираются аргументы, методы и целые классы. Именно поэтому документация должна генерироваться по исходникам, а не быть написана отдельно (заранее или нет).
Какая разница, хранится документация в отдельном файле или в комментариях в файле с исходниками, если она все равно пишется пост-фактум, и никто не заметит, если какие-то ее части не будут соответствовать реализации? Если этап проектирования пропустили и правят код по наитию, скорее всего, интерфейсы будут меняться много раз по ходу работы, и кое-где забудут обновить комментарий с описанием.
Разница очень большая. Безусловно вы правы в том, что при любом подходе смысловой контент документации может отстать от эволюционирующего API. Но вот дерево объявлений в случае с авто-генерацией всегда будет релеванто — в отличие от отдельной документации. Глядя в авто-сгенерированную документацию вы всегда видите, какие аргументы принимает метод и что он возвращает. И всегда можно покликать и попутешествовать по типам, посмотреть, гда есть какие поля, методы, свойства и т.д.
Вы вольны использовать любые конструкции Sphinx внутри комментариев, а от Доксигена брать только синтаксис привязки комментария с документацией к конкретному объекту исходников.
Типа:
/*!
Detailed documentation for ``foo`` with some **reStructuredText** markup.
Usage:
.. code:: cpp
foo ("bar"); // <-- OK
foo (NULL); // error, name can't be NULL
In master conf.py you can add your own Sphinx extensions and then invoke custom directives:
.. my-custom-directive::
my-custom-directive-content
*/
void foo (const char* name);
А вообще по-моему мы сходимся в оценке Sphinx как удачного средства генерации финального варианта документации. Что предлагается в данном продукте — так это автоматическая генерация объявлений и автоматическая же привязка к ним смыслового наполнения документации.
Встречал и прямо противополжное мнение — что использование смысловых акцентов здорово помогает при чтении при диагонали. Я раньше вот тоже не любил жирные акценты, а сейчас склоняюсь к тому, что и вправду помогает. Одно очевидно — всем не угодишь.
Каждый из стейтментов компилируется в функцию-обработчик, которая при старте подписывается на все свои «управляющие» события (для reactor_expression_stmt — это будет множество связываемых свойств в правой части выражения; для reactor_onevent_stmt — множество событий после ключевого слова onevent). Между самими стейтментами прямой зависимости нет (думайте про каждое из них как про метод), так что в этом плане порядок «формул» и обработчиков «onevent» значения не имеет.
Порядок играет роль лишь при старте реактора — в этот момент нам надо выполнить все стейтменты реактора, чтобы:
вычислить адреса управляющих событий — ведь они могут быть и не статическими (например, членами классов)
как минимум попытаться обеспечить справедливость всех указанных в реакторе формул (понятно, что реактор можно спроектировать так, что все выражения не могут выполняться одновременно: например a = b + 1; b = a + 1)
Так вот, при старте все стейтменты (за исключением, разумеется, содержимого «onevent») выполняются сверху вниз.
А зачем пробрасывать исключения через границу jancy->c++ или c++->jancy? Подход, который отлично работает не только в случае разных языков, но и просто разных модулей — это ловить все исключения на границе между языками/модулями и преобразовывать их в ошибки, которые понимаются другим языком/модулем. А после перехода границы, можно снова выбрасить исключение имеющее смысл уже для данного модуля. В общем, мне кажется, что ваша «ненадёжность» исключений основывается на их неправильном использовании.
ОК, значит возникло недопонимание. Вы говорили про ABI-стандарт для исключений и я понял так, что предлагается ловить и бросать плюсовые исключения. Хорошо, значит мы сходимся в главном: исключения — в каком бы виде они ни были реализованы — на границах языков надо преобразовывать. Так вот, Jancy предлагает модель исключений, которая является *самой простой* при организации межязыковых взаимодействий. Причём в обе стороны: поймать Jancy-исключение = проверить код возврата и считать расширенную информацию об ошибке из TLS; бросить Jancy-исключение = записать расширенную информацию в TLS и вернуть «ошибочный» код возврата.
Далее, с кодами возврата не всё гладко. Во первых, у вас появляется соглашение о том, что является ошибкой (null, -1, etc), а что нет.
Совершенно верно. «Бросающие» функции должны следовать определённому протоколу.
Во вторых, типа ошибки нигде нет. Напротив, в Питоне, например, тип ошибки — это тип исключения, и разные типы ошибок можно обрабатывать по-разному.
Вступаю на взрывоопасную поверхность, поэтому дисклеймер: нижеследующее является не более, чем моим личным мнением ;) Я считаю, что сама концепция писать разные блоки catch под разные типы исключений — глубоко порочна. По сути стандартные типы исключений решают искусственную проблему — в блоке catch мы как правило хотим ловить *любые* исключения. Безусловно, вы можете придумать примеры, в которых надо проверять тип исключения и обрабатывать их в разных catch-ах. Но эти примеры всегда можно переписать так, что блок catch останется один. А во-вторых, подход Jancy ничему не противоречит — всегда можно проанализировать расширенную информацию об ошибке из TLS и построить соответвующее ветвление.
В третьих, синтаксический сахар для обрабоки ошибок мне показался неудобным. Как пробросить ошибку через несколько уровней вызовов и сделать так, чтобы код промежуточных уровней остался не затронутым, т.е. не знал вообще что на нижнем уровне происходит ошибка, а на верхнем она обрабатывается? В вашем подходе на каждом промежуточном уровне прийдётся писать try.
Вовсе нет. Если имеется глубокий стек вызовов из бросающих функций, и где-то в глубине произошла ошибка, то будет цепной возврат до ближайшего catch. Уже в нём вы вольны анализировать и обрабатывать это псевдо-исключение, основываясь на расширенной информации из TLS.
Безусловно, данная модель не универсальна и имеет ряд ограничений — например, нельзя бросать исключения из void-функций или функций, возращающих некие структуры. Обойти всё это можно, несколько подправив прототипы «бросающих» функций — так, чтобы они удовлетворяли протоколу псевдо-исключений Jancy. В целом же, согласитесь, ограничения присущи любой модели, и для эффективного её использования требуется некоторым образом «отформатировать» под неё мозг — уж к плюсовым исключеним это относится в полной мере ;)
Спасибо за развёрнутый комментарий. Да, внутри компании в качестве version control мы используем git. Под опасениями я имел в виду скорее не то, что код на гитхабе пропадёт, а то, что я пока не до конца представляю себе, как заниматься управлением пулл-реквестов от совершенно незнакомых мне людей. Но ничего, разберёмся :)
Ваша правда, мой косяк.
Акелла промахнулся — дважды! ;) На хабре окошко с редактором находится сразу за последним комментарием, отчего складывается впечатление, что отвечаешь на него. А перенести комментарий после создания уже нельзя.
Поправьте меня, если ошибаюсь, но беглый осмотр выявил несоответствие списку требований, сформулированных в начале:
На самом деле, при выборе сервисов я прежде всего просканировал, что в основном используют opensource разработчики, хостящиеся на GitHub — с большим отрывом лидирует Travis и AppVeyor.
В принципе, производительность Travis меня вполне устраивает — как мне кажется, CI далеко не является критической по времени задачей. А вот что вполне могло бы заставить меня мигрировать на другой сервис, так это наличие более широкого спектра платформ для сборки/тестирования: Ubuntu посвежее, Arch, Fedora, и т.д.
Не подскажете, есть ли такие?
Тут дело даже не в том, запускается или нет Docker на Windows или Mac OS X (как вы верно отметили, да, запускается). Проблема в том, что Travis CI предоставляет Docker-контейнер для сборки только под Linux, а AppVeyor вообще не даёт возможности выбирать между полновесной виртуальной машиной и Docker-контейнером.
Но это, на мой взгляд, и не важно. Выигрыш всего в минуту (!) в таком длительном, да и, чего уж там, совсем не критичном по времени исполнения процессе, как непрерывная интеграция, просто не стоит того, чтоб с ним заморачиваться.
Ну я собственно и не противопоставлял — просто сказал, что и с Doxyrest тоже можно создавать самостоятельные страницы с документацией как обычные
.rst
файлы. И конечно, и с Doxygen, и с Doxyrest из этих самостоятельных страниц можно ссылаться на авто-сгенерированные страницы API.Другое дело что Doxyrest перекладывает всю работу по созданию финальной красивой HTML страницы на инструмент, который прекрасно с этим справляется (значительно лучше, чем Doxygen). Вот и всё.
А мне кажется, визуальные акценты помогают-таки при просматривании статей по диагонали. Вопрос количества и баланса, конечно, открытый (и во многом субъективный). Но вообще я за акценты. Как говорится, let's agree to disagree :)
Если честно, то не пробовал генерировать HTML из доксигеновского DocBook выхода. Навскидку не вижу причин, почему это может давать намного лучший результат, чем просто подкрутка CSS и шапок у доксигеновского HTML. Впрочем, если у вас пример красивой документации, полученной таким методом — кидайте, можно будет обсудить более предметно.
Что правда то правда. Тогда я переформулирую:
Даже в тех (редких) случаях, когда разработчики и рады были бы написать нечто толковое в документации, их останавливает то, что… и дальше по тексту ;)
Всё правильно. А в случае с использованием Doxyrest, отдельные страницы с абстрактным описанием — это будут просто
.rst
файлы, скармливаемые Sphinx напрямую.Я уже писал выше — при авто-генерации документации имеется гарантия релевантности всех объявлений. Вы можете побегать по API, посмотреть какие аргументы принимаются, что возвращается, какие есть поля и т.д.
Бестолковость абсолютного большинства примеров Доксигеновской документации, действительно имеет место быть. Но это проблема конкретного контента, а не подхода, согласитесь? Можно ведь взять и написать толковую документацию, а не просто:
open
открывает,get
возвращает. Но у меня есть смелая теория, почему сейчас всё обстоит именно так.Разработчики не хотят тратить усилия на написание толковых комментариев, потому что — барабанная дробь — конечная Доксигеновская документация всё равно будет выглядеть как говно!
Исправить это — и есть главная цель проекта Doxyrest.
Совершенно верно — как средство разбора и вытаскивания документирующих комментариев он пока не имеет равных. Кроме того, когда допилится интеграция с Clang (а то сейчас она какая-то уж слишком экспериментальная), этих самых равных и искать никакого смысла не будет.
А сделать красивый вывод по информации, полученной Доксигеном — в этом и есть вся соль предлагаемого мной проекта. Доксиген умеет доставать информацию из исходников. Sphinx умеет генерировать красивый — и, что главное, настраиваемый, — HTML. Doxyrest — мост между этими двумя товарищами.
Вся цепочка рассуждений исходит из неверных предположений, что заказчик знает, чего хочет, а с задачей можно полностью разобраться до начала работ.
Посмотрел описание языка шаблонизации — ой, зря они свой язык стали писать, ой зря...
Им бы взять Lua или Python — и то, и другое легко встраивается в плюсовые приложения. Сейчас вся эта кухня с новым языком даёт слишком уж ограниченные возможности по настройке вывода — на неизвестном и неотлаженном языке, без стандартной библиотеки, да ещё и с вырвиглазным синтаксисом (
standardese_for
,standardese_else_if
и т.д.).Потом, сама идея с опциональностью шаблонов наводит на мысль, что шаблоны эти планируется использовать лишь как дополнение к автосгенерированному дереву объявлений, на внешний вид которого можно повлиять только настроечными переменными — как и в Doxygen.
Вполне возможно, я что-то упсутил, но у них, увы, нет примеров использования этих шаблонов — в репозитории только плюсы, bash и cmake..
То есть всё, что они получат в итоге — это Doxygen с Clang в качестве парсера, но с таким же деревянным выходом. Кстати, если не ошибаюсь, автор Doxygen уже начал прикручивать Clang и сам.
Это работает только для сферических проектов в вакууме. На практике же набросанные на этапе проектирования интерфейсы безжалостно корёжатся при столкновениях с действительностью. Добавляются и убираются аргументы, методы и целые классы. Именно поэтому документация должна генерироваться по исходникам, а не быть написана отдельно (заранее или нет).
Разница очень большая. Безусловно вы правы в том, что при любом подходе смысловой контент документации может отстать от эволюционирующего API. Но вот дерево объявлений в случае с авто-генерацией всегда будет релеванто — в отличие от отдельной документации. Глядя в авто-сгенерированную документацию вы всегда видите, какие аргументы принимает метод и что он возвращает. И всегда можно покликать и попутешествовать по типам, посмотреть, гда есть какие поля, методы, свойства и т.д.
Ваше право.
Вы вольны использовать любые конструкции Sphinx внутри комментариев, а от Доксигена брать только синтаксис привязки комментария с документацией к конкретному объекту исходников.
Типа:
А вообще по-моему мы сходимся в оценке Sphinx как удачного средства генерации финального варианта документации. Что предлагается в данном продукте — так это автоматическая генерация объявлений и автоматическая же привязка к ним смыслового наполнения документации.
Каждый из стейтментов компилируется в функцию-обработчик, которая при старте подписывается на все свои «управляющие» события (для reactor_expression_stmt — это будет множество связываемых свойств в правой части выражения; для reactor_onevent_stmt — множество событий после ключевого слова onevent). Между самими стейтментами прямой зависимости нет (думайте про каждое из них как про метод), так что в этом плане порядок «формул» и обработчиков «onevent» значения не имеет.
Порядок играет роль лишь при старте реактора — в этот момент нам надо выполнить все стейтменты реактора, чтобы:
Так вот, при старте все стейтменты (за исключением, разумеется, содержимого «onevent») выполняются сверху вниз.
ОК, значит возникло недопонимание. Вы говорили про ABI-стандарт для исключений и я понял так, что предлагается ловить и бросать плюсовые исключения. Хорошо, значит мы сходимся в главном: исключения — в каком бы виде они ни были реализованы — на границах языков надо преобразовывать. Так вот, Jancy предлагает модель исключений, которая является *самой простой* при организации межязыковых взаимодействий. Причём в обе стороны: поймать Jancy-исключение = проверить код возврата и считать расширенную информацию об ошибке из TLS; бросить Jancy-исключение = записать расширенную информацию в TLS и вернуть «ошибочный» код возврата.
Совершенно верно. «Бросающие» функции должны следовать определённому протоколу.
Вступаю на взрывоопасную поверхность, поэтому дисклеймер: нижеследующее является не более, чем моим личным мнением ;) Я считаю, что сама концепция писать разные блоки catch под разные типы исключений — глубоко порочна. По сути стандартные типы исключений решают искусственную проблему — в блоке catch мы как правило хотим ловить *любые* исключения. Безусловно, вы можете придумать примеры, в которых надо проверять тип исключения и обрабатывать их в разных catch-ах. Но эти примеры всегда можно переписать так, что блок catch останется один. А во-вторых, подход Jancy ничему не противоречит — всегда можно проанализировать расширенную информацию об ошибке из TLS и построить соответвующее ветвление.
Вовсе нет. Если имеется глубокий стек вызовов из бросающих функций, и где-то в глубине произошла ошибка, то будет цепной возврат до ближайшего catch. Уже в нём вы вольны анализировать и обрабатывать это псевдо-исключение, основываясь на расширенной информации из TLS.
Безусловно, данная модель не универсальна и имеет ряд ограничений — например, нельзя бросать исключения из void-функций или функций, возращающих некие структуры. Обойти всё это можно, несколько подправив прототипы «бросающих» функций — так, чтобы они удовлетворяли протоколу псевдо-исключений Jancy. В целом же, согласитесь, ограничения присущи любой модели, и для эффективного её использования требуется некоторым образом «отформатировать» под неё мозг — уж к плюсовым исключеним это относится в полной мере ;)