Сообщений 8 Оценка 1110 Оценить |
Печальная кончина NDoc Что такое Sandcastle? Процесс Выводы Источники информации |
В конце июля 2006 года, Кевин Даунс (Kevin Downs), основной (и единственный) разработчик NDoc — средства генерации документации для .NET — распространил заявление о том, что он прекращает свою работу над ним и вообще больше не будет участвовать в каких бы то ни было open-source проектах:
«… Разработка и выпуск NDoc 1.3 потребовали огромного объема работы, и по всем признакам, этот вклад был оценен по достоинству. К несчастью, несмотря на почти повсеместное использование NDoc, сообщество разработчиков на .Net не оказало проекту никакой поддержки, ни финансовой, ни своим вкладом в разработку. С тех пор, как версия 1.3 была выпущена, проекту было перечислено всего лишь 12 пожертвований. Фактически, если бы не подарок Олега Ткаченко, в виде подписки на MSDN, я бы даже не имел копии VS 2005, с которой мог бы продолжать работу! …»
Можно по-разному относится к такой ситуации, но это — тема для совсем другой статьи.
Итак, с января 2005 года проект NDoc почти не развивался. На форумах разработчиков довольно часто появляется вопрос «где найти NDoc для .Net 2.0?». И если версию NDoc, хоть как-то генерирующую документацию под .Net 2.0, еще можно найти, по-видимому, не существует версии NDoc, в полной мере поддерживающей все новые возможности нового фреймворка (в частности, generics).
В своем письме Кевин упоминает проект «Sandcastle», над которым работает одна из команд Microsoft, и который преследует (примерно) те же цели, что и NDoc. По убеждению Кевина, «после того, как ‘Sandcastle’ будет выпущен, он станет стандартом де-факто … Это случится в независимости от технических соображений, даже если Sandcastle будет предлагать меньше возможностей …».
Похоже, имеет смысл разобраться, что же это за «убийца NDoc» и чем он может быть нам полезен.
В блоге команды разработки Sandcastle первая запись появилась 27 июля 2006 года.
В качестве цели заявляется: «предоставить разработчикам библиотек классов по всему миру средство простого создания точной и информативной документации общепринятого вида» (вставка от отдела маркетинга?). Свойства Sandcastle:
По словам одного из разработчиков Sandcastle, первая версия Sandcastle состояла из двух компонентов — cDoc, вытягивающего метаданные из сборок в единый файл, и pDoc, создающего на основе этого файла топики для каждого пространства имен/типа/метода, а также создающего файлы содержания, предметного указателя и файлы проектов для последующей сборки через компилятор HTML Help. После выпуска Visual Studio 2005, было принято решение переписать Sandcastle, для повышения производительности и масштабируемости. Июльская CTP-версия Sandcastle 2.0 позволила сократить время компиляции .NET Framework с 10 часов до 30 минут! |
Интересный документирующий комментарий в шаблоне презентации Sandcastle:
/// <summary>To enable people and business throughout /// the world to realize their full potential.</summary> public class Microsoft { |
ПРЕДУПРЕЖДЕНИЕ Если вам требуется быстро получить результат и вы не хотите влезать во все тонкости, то все дальнейшее изложение можно смело опустить. Возьмите готовый инструмент, например такой как Sandcastle Help File Builder. |
Вы пишете свой код (на C#, VB.NET или другом языке), используя или не используя документирующие XML-комментарии. В результате компиляции получается сборка и (опционально) сопутствующий ей XML-файл с информацией из XML-комментариев. Либо, у вас есть сторонняя сборка, к которой может быть приложен XML-файл. В любом случае, задача состоит в получении справочника по этой сборке.
Важное отличие этого процесса от процесса NDoc: в Sandcastle основой всегда является сборка, на основе мета-информации сборки строится весь справочник, файл XML-комментариев является необязательным; в NDoc основным источником являются XML-комментарии, мета-информация из сборки используется только для тех объектов, которые упоминаются в файле XML-комментариев.
Действие начинается с работы утилиты MrefBuilder, которая, используя CCI (Common Compiler Infrastructure library — Microsoft.Cci.dll — тот же механизм, что используется в FxCop для получения мета-информации), получает информацию из сборки и выдает ее в выходной файл — Reflection.xml. Этот файл имеет следующую структуру:
<reflection> <assemblies> <assembly name="Foo" ... > ... </assembly> </assemblies> <apis> ... <api id="N:FooNamespace"> ... </api> <api id="T:FooNamespace.FooClass"> ... </api> <api id="M:FooNamespace.FooClass.FooMethod"> ... </api> ... </apis> </reflection> |
Для каждого объекта исходной сборки — пространства имен, класса, свойства, метода и т. п. — здесь есть свой тэг <api> с подробным описанием. В готовом справочнике, каждому тэгу <api> будет соответствовать свой HTML-файл описания.
Формат вызова MrefBuilder:
MrefBuilder <сборки> [/out:<выходной_файл>] [/config:<файл_конфигурации>] [/dep:<сборка_зависимости>] [/internal:+] |
где /dep указывает сборки, от которых зависят наши сборки, флаг /internal:+ показывает что нужно генерировать документацию для не-public классов/методов.
Пример использования MrefBuilder:
MrefBuilder MyAssembly.dll /out:Reflection.org |
Следующий шаг — дополнение файла Reflection.xml серией «искусственных» тэгов <api>. Для этого используются XSLT-преобразования, которые выполняются утилитой XslTransform. Судя по списку файлов в папке ProductionTransforms, нам уже доступны следующие способы дополнения файла Reflection.xml:
XSLT-преобразование | Описание |
---|---|
AddOverloads.xsl | Добавляет элементы <api id="Overload:..."> для методов с одним названием и разным набором параметров |
AddMemberLists.xsl | |
AddRoot.xsl | Добавляет корневой элемент <api>, для страницы со списком всех пространств имен (по-видимому, для Sandcastle November CTP этот шаг уже не нужен — элемент <api id="R:Project"> создается автоматически) |
AddGuidFilenames.xsl | Добавляет элемент <file name="..."/> в каждый элемент <api>, в качестве имен файлов задаются глобально уникальные идентификаторы |
AddFriendlyFilenames.xsl | Добавляет элемент <file name="..."/> с «дружественными» именами файлов: в качестве имен файлов задаются имена, содержащие названия объектов, например для класса — "T_FooNamespace_FooClass" |
AddXamlAttachedMembers.xsl |
Формат вызова XslTransform:
XslTransform <XML-файл> [/xsl:<XSLT-шаблон>[,...]] [/arg:<имя>=<значение>[,...]] [/out:<выходной_файл>] |
Пример обработки файла Reflection.org, полученного от MrefBuilder (для простоты, опущено указание путей):
XslTransform Reflection.org /xsl:AddOverloads.xsl /out:Reflection.st2 XslTransform Reflection.st2 /xsl:AddGuidFilenames.xsl /out:Reflection.xml |
Наконец, готовый Reflection.xml сформирован. На его основе, также при помощи XSLT, создается файл со списком топиков — Manifest.xml, имеющий вид:
<topics> ... <topic id="N:FooNamespace" /> <topic id="T:FooNamespace.FooClass" /> <topic id="Overload:FooNamespace.FooClass.FooMethod" /> <topic id="M:FooNamespace.FooClass.FooMethod" /> ... </topics> |
Пример преобразования для получения Manifest.xml:
XslTransform Reflection.xml /xsl:ReflectionToManifest.xsl /out:Manifest.xml |
Теперь, когда вся подготовительная работа проделана, публика разогрета, на сцену выходит суперзвезда этого шоу — BuildAssembler.
Результат работы BuildAssembler — логически группированные HTML-файлы топиков документации, пригодные к использованию компиляторами HTML Help 1.3 либо HTML Help 2.0.
Вызов BuildAssembler выглядит так:
BuildAssembler /config:Sandcastle.config manifest.xml |
Для каждого топика, указанного в файле Manifest.xml, BuildAssembler выполняет одну и ту же последовательность действий, описанную в файле Sandcastle.config. Типичный набор таких действий выглядит так:
Каждое действие описывается в Sandcastle.config в виде вызова определенного компонента с параметрами.
Итак, центральная часть процесса обработки топиков — это файл Sandcastle.config. Стоит рассмотреть его повнимательнее. Пожалуй, это наиболее интересная часть Sandcastle, и наименее документированная. Мне не удалось найти справочника по используемым компонентам, по-видимому, его вообще (пока) нет в открытом доступе, и все что нам остается — запастись терпением и ждать, либо взять Reflector и влезть с ногами в сборки Sandcastle.
Структура Sandcaste.config:
<configuration> <dduetools> <builder> <components> <component type="тип" assembly="путь к сборке"> <!-- настройки компонента --> ... </component> <!-- тэги вызова других компонентов --> ... </components> </builder> </dduetools> </configuration> |
Во время обработки, каждый топик представляет из себя XML-документ в памяти (экземпляр класса XmlDocument). Компоненты, перечисленные в Sandcastle.config — это классы, которые инстанциируются и выполняются один за другим над каждым топиком.
В целом, работа BuildAssembler проходит в несколько фаз:
Все компоненты являются наследниками абстрактного класса BuildComponent:
public abstract class BuildComponent { protected BuildComponent(XPathNavigator configuration) {} publicabstractvoid Apply(XmlDocument topic, string id); protectedvoid WriteMessage(LogLevel level, string message) {} } |
При инстанциировании компонента, в его конструктор передается соответствующая этому компоненту секция файла Sandcastle.config. Это позволяет компоненту «прочитать» свои настройки. Для выполнения компонента вызывается метод Apply, в который передается текущий топик (в виде XmlDocument) и идентификатор этого топика.
Одни компоненты изменяют документ, другие управляют потоком выполнения, третьи позволяют загрузить информацию в XML-документ из файла или сохранить текущее состояние документа в файл.
Вот некоторые из «стандартных» компонентов, содержащихся в сборке BuildComponents.dll:
Тип компонента | Описание |
---|---|
CopyFromFileComponent | Загрузка содержимого XML-файла в указанный элемент документа |
CopyFromIndexComponent | Загрузка некоторой части одного или нескольких XML-файлов в документ |
ResolveReferenceLinksComponent | Расставляет ссылки на другие страницы внутри документа, а также ссылки на внешние источники |
SharedContentComponent | Заменяет элементы <include> и <includeAttribute> содержимым внешних XML-файлов |
SyntaxComponent | Описывает синтаксис объекта на различных языках — C#, VB (объявление), VB (использование) управляемый C++, J#, JScript, XAML (использование) |
TransformComponent | Выполняет XSLT-преобразование над текущим содержанием |
SaveComponent | Сохраняет текущий XML-документ в указанный файл |
ForEachComponent | Выполняет набор компонентов над каждым узлом из набора, заданного XPath-выражением |
IfThenComponent | Выполняет или не выполняет вложенные компоненты в зависимости от условия |
SwitchComponent | Вычисляет XPath-выражение, находит ветку, подходящую под результат вычисления и выполняет компоненты этой ветки |
DisplayComponent | Выдает дамп текущего содержимого документа |
ValidateComponent | Валидирует текущий документ по XML-схеме (.xsd-файлу) |
Помимо логики создания топиков, описанной файлом Sandcastle.config, облик справочника определяется еще целым рядом файлов — это шаблоны страниц, стилевые файлы CSS, скрипты, изображения и т. п. Все эти файлы, плюс собственно Sandcastle.config составляют шаблон справочника.
Перед вызовом BuildAssembler, файлы шаблона копируются в рабочую папку, в которой и выполняется сборка справочника.
В составе Sandcastle, в папке Presentation есть два готовых шаблона:
Используя Reflection.xml с помощью XSLT-преобразования мы можем получить все файлы, необходимые для сборки .CHM: .HHC-файл содержания, .HHK-файл предметного указателя и .HHP-файл проекта справки. Впрочем, файл проекта можно подготовить и вручную — его не требуется изменять при каждой пересборке справки.
Пример получения этих файлов (для простоты, опущено указание путей):
XslTransform Reflection.xml /xsl:ReflectionToChmContents.xsl /out:test.hhc XslTransform Reflection.xml /xsl:ReflectionToChmIndex.xsl /out:test.hhk XslTransform Reflection.xml /xsl:ReflectionToChmProject.xsl /out:test.hhp |
Остается лишь выполнить сборку справочника, используя утилиту hhc.exe из HTML Help Workshop 1.3:
"C:\Program Files\HTML Help Workshop\hhc.exe" Foo.hhp |
Неприятная особенность: hhc.exe написан таким образом, что он возвращает код возврата «1» в случае удачного завершения, и «0» — в случае ошибки. Это отличается от обычной практики, когда после нормального завершения возвращается «0». Поэтому hhc.exe неудобно использовать с такими средствами сборки как NAnt или MSBuild. К счастью, есть простое решение этой проблемы — использовать «инвертирующий» .BAT-файл:
@echo off rem запустить компилятор help файлов %1 "%2"rem обработка ошибок, коды возврата: 0 - ошибка, 1 - успешное завершение, 2 и выше - ошибка if errorlevel 2 goto error if errorlevel 1 goto success if errorlevel 0 goto error0 :success exit 0 :error exit %ERRORLEVEL% :error0 exit 1 |
Пример использования:
hhc_wrapper.bat <hhc_exe_path> <hhp_path> |
Сообщений 8 Оценка 1110 Оценить |