= Doxter, A PureBasic Documentation Generator Tristano Ajmone tajmone@gmail.com v0.2.5-alpha, 2018-11-29: PureBASIC 5.62 | MIT License :lang: en // TOC Settings: :toc: left :toclevels: 5 // Sections Numbering: :sectnums!: :sectnumlevels: 2 // Cross References: :xrefstyle: short :section-refsig: Sect. // Misc Settings: :experimental: true :icons: font :linkattrs: true :reproducible: true :sectanchors: :version-label: Doxter // :hide-uri-scheme:
// ===================================== // Custom Attributes for Reference Links // ===================================== :git_io_doxter: pass:q[link:https://git.io/doxter[https://git.io/doxter^]]
// Project assets paths: :DoxterLogo: docs/doxter_logo.svg
// Project files links:
:CHANGELOG: pass:q[link:CHANGELOG.adoc[CHANGELOG.adoc
]]
:docs_hjs: pass:q[link:docs/hjs/[docs/hjs/
]]
:docs_index_html: pass:q[link:./docs/index.html[docs/index.html
^]]
:doxter_engine_pbi: pass:q[link:./doxter_engine.pbi[doxter_engine.pbi
]]
:doxter_pb: pass:q[link:./doxter.pb[doxter.pb
]]
:hjs_README: pass:q[link:./docs/hjs/README.md[docs/hjs/README.md
]]
:hljs_license: pass:q[link:./docs/hjs/LICENSE[BSD_License]] :LICENSE: pass:q[link:LICENSE[
LICENSE]] :user_guide: pass:q[link:https://git.io/doxter[user guide
]]
// Project folders links:
:docs: pass:q[link:./docs/[/docs/
]]
:docs_src: pass:q[link:./docs_src/[/docs_src/
]]
:test: pass:q[link:./test/[/test/
]]
// // // Document Preamble // //
// tag::DoxterLogo[] image::{DoxterLogo}[Doxter Logo,align="center"] // end::DoxterLogo[]
================================================================================ // tag::welcome[]
:Alan_IF: pass:q[link:https://www.alanif.se/[Alan IF^]] :PureBasic: pass:q[link:https://www.purebasic.com/[PureBasic^]] :SpiderBasic: pass:q[link:https://www.spiderbasic.com/[SpiderBasic^]] :DRY: pass:q[link:https://en.wikipedia.org/wiki/Don%27t_repeat_yourself[DRY^]]
Welcome to Doxter, a {DRY} Documentation from source generator leveraging Asciidoctor tagged regions to allow contents reuse across documents via selective inclusions, and a custom weights-based system to control the order in which regions should be rearranged in the final document.
Written in PureBasic for {PureBasic}, {SpiderBasic} and {Alan_IF} (more languages coming soon).
// end::welcome[]
For the full documentation, see:
== Project Contents
[horizontal]
{docs} :: -> Documentation and website (autogenerated).
{docs_src} :: -> Scripts and assets to build contents of /docs/
.
{test} :: -> Test suite.
{CHANGELOG} :: -> Changelogs of Doxter CLI app and Doxter Engine.
{doxter_pb} :: -> Source code of Doxter CLI app.
{doxter_engine_pbi} :: -> Source code of Doxter Engine.
{LICENSE} :: -> MIT License.
== About Doxter
Doxter is a cross platform, fully standalone command line binary tool to generate AsciiDoc documentation from PureBasic, SpiderBasic or Alan source files.
Invoke Doxter by passing a source file of a supported language:
..................
doxter myfile.pb ..................
... Doxter will autodetect the language from its file extension, and it will create an AsciiDoc document from it, named myfile.asciidoc
(or myfile.ascidoc
).
=== The Philosophy Behind Doxter
:Asciidoctor_: pass:q[link:https://asciidoctor.org[AsciiDoctor^]] :tagged_regions: pass:q[link:https://asciidoctor.org/docs/user-manual/#by-tagged-regions[tagged regions^]]
Doxter leverages the power of {Asciidoctor_} to embed documentation inside source code files disguised as comments, using a notation system based on the native comment delimiters of the source language, followed by some special characters. These special comments are then parsed and stripped of the notational markers, and exported to the output AsciiDoc file.
The AsciiDoc syntax blends well within source file comments, providing a non disruptive way to produce nicely formatted and semantic documents by using a markup notation that is human friendly and looks nice in the source file too.
But the most important Asciidoctor feature leveraged by Doxter is the use of {tagged_regions} inside documents.
Asciidoctor allows using a special comments notation to delimit portions of code as uniquely tagged regions, which can then be imported into other AsciiDoc documents via the include
directive.
Every chunk of embedded Doxter documentation will be exported as a tagged region. The whole idea is to allow keeping the documentation as small fragments that go side by side with the code they refer to. These individual fragments will then be merged together into single regions tagged according to topic, and in the final document regions can be rearranged in a meaningful order.
Because of the nature of code, topics will often be documented as small fragment scattedered in various places in the source code, often occuring in a order of appearance which doesn't reflect the desired order in which the topic should be presented in documentation.
Doxter allows assigning to each fragment a specific subweight, which will then be used by Doxter to rearrange the framents within a region in ascending order, before merging them into a single tagged region.
Regions can be given weights too, allowing to control the order in which they will presented in the final document.
This system was designed with some specific goals in mind:
doxterized
" output of the various source files of the project, expanding on the various topics in a more detailed way (i.e. with commentaries and examples that would be out of place in the source file).Tagged regions are very versatile and allow reuse of both documentation and code across multiple documents, effectively creating a unified field of work where source code, documentation, wiki, website and README files all feed into/from each other, and where everything is always kept up to date since all documents will always be dynamically importing the latest code and documentation fragments.
:DRY: pass:q[link:https://en.wikipedia.org/wiki/Don%27t_repeat_yourself[DRY^]]
The strength of this approach is rooted in the {DRY} (don't repeat yourself) principle of software design -- as opposed to WET (write everything twice) -- which states that:
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
=== A Few Practical Examples
:ADoc_include_directive: pass:q[link:https://asciidoctor.org/docs/user-manual/#by-tagged-regions[AsciiDoctor include
directive^]]
Doxter works its magic by a special notation in comments delimiters to markup tagged regions of text and code that should be extracted and exported to the AsciiDoc document.
... in the output AsciiDoc document will become:
// tag::even_macro[] The following macro performs a bitwise AND operation to determine if an integer is even or not.
You can then selectively import tagged regions from the autogenerated doc into other documents, using {ADoc_include_directive}:
When documenting applications with modular design, you can then include selected regions from the doxterized file of each module, and Doxter will automatically keep your documentation up to date.
You can optionally assign weights to regions, to control their order in the extracted document. Doxter sorts regions according to their tag's weight, before saving them to file.
;>even_macro(200) ;| The following macro performs a bitwise AND operation to determine if an ;| integer is even or not. Macro IsEven(num) (num & 1 = 0) EndMacro ;<
;>macro_test(310) ;| Let's test that the macro actually works as expected. For i = 1 To 5 If isEven(i) Debug Str(i) +" is even." Else Debug Str(i) +" is odd." EndIf Next ;<
%
) is much much faster -- in
;| the order of hundreds of times faster!
;<
;>even_macro_explain(300)
;| This works because IsEven = ((i % 2) = 0)
equals IsEven = ((i & 1) = 0)
.
;<In the final document the regions will be sorted in this order:
// tag::even_macro_intro[] === The IsEven Macro
Using bitwise operations insted of modulo (%
) is much much faster -- in
the order of hundreds of times faster!
// end::even_macro_intro[]
// tag::even_macro[] The following macro performs a bitwise AND operation to determine if an integer is even or not.
// end::even_macro[]
// tag::even_macro_explain[]
This works because IsEven = ((i % 2) = 0)
equals IsEven = ((i & 1) = 0)
.
// end::even_macro_explain[]
// tag::macro_test[] Let's test that the macro actually works as expected.
This brief introductory tour ends here. There are more Doxter markers than covered in these examples. To discover the full list of Doxter's features, see the autogenerated {user_guide}.
// tag::Acknowledgements[]
== Acknowledgements
:Cod: pass:q[link:http://lou.wtf/cod/[Cod^]] :Lou_Acresti: pass:q[link:http://lou.wtf/[Lou Acresti^]] :namuol: pass:q[link:https://github.com/namuol[@namuol^]]
Although quite different in design, Doxter was inspired by Lou Acresti’s {Cod}, an unassuming doc format (Documentus modestus). The simplicity of Cod sparkled the idea that I could implement something similar, but exploiting AsciiDoc tagged regions instead.
My gratitude to {Lou_Acresti} (aka {namuol}) for having created such an inspiring tool like Cod.
// end::Acknowledgements[]
== License
// tag::LICENSE[]
Doxter is released under MIT License.
============================================================================= MIT License
Copyright (c) 2018 Tristano Ajmone + https://github.com/tajmone/doxter
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// end::LICENSE[]
For the license terms and credits of third party components in the binary release of Doxter (added by the PureBasic compiler) read the full {LICENSE} file.
== Third Party Components
This repository also contains the third party components listed below, which retain their own license.
=== Highlight.js
:Highlight_js: pass:q[link:https://highlightjs.org[Highlight.js^]] :isagalaev: pass:q[link:https://github.com/isagalaev[@isagalaev^]]
The above folder contains a custom release of {Highlight_js}, with a modified version of the PureBasic syntax (original and modified versions by Tristano Ajmone) and some other languages.
Highlight.js is Copyright (C) by Ivan Sagalaev {isagalaev}, 2006, and is released under the {hljs_license}.
For more details see {hjs_README}.
// tag::Roadmap[] == Roadmap
Doxter it's still a young application, and there is always room for improvements. Here is a list of upcoming features, waiting to be implemented.
Support More Languages. The ultimate goal is to make Doxter a language agnostic tool, usable with any language, by extending the set of natively supported languages and by allowing to specify via command line options a custom comment delimiter and set the default language name to be used in AsciiDoc source code blocks.
Configuration Files.
When a doxter.json
file is found in the current folder, Doxter will use
it to extract options and settings to use when doxterizing sources.
Once this feature is implemented, it will open the door to more advanced
features:
* Automated Documentation Tasks*. If Doxter is invoked without specifying an input file, the settings file will be scanned to find "doxter tasks" -- i.e. a list of files which should be doxterized and (optionally) converted via Asciidoctor, allowing custom options and settings for both Doxter and Asciidoctor. This will allow to fully automate maintainance of Doxter documentation in projects.
// end::Roadmap[]
// EOF //