Worked on literate output using Markdown as the text markup language.

* Added CSS based on Docco (blatantly copied).
* Updated sample text to better fit the emerging usage patterns. Some of the
  things I did to make it render nicely for the Literate output may cause
  problems when we go to render API output. I will cross that bridge when I come
  to it.
* Added parsing infrastructure to the Generator behaviour to allow a
  pre-processing pass over the document. Current the LiterateMarkdownGenerator
  is using this to compile a map of `@org` references.
* Tweaked the HTML output slightly.
* Added a layer over the PegDownProcessor in LiterateMarkdownGenerator to
  capture and transform `jlp://` links into relative links.
This commit is contained in:
Jonathan Bernard 2011-09-06 16:13:21 -05:00
parent c2c2f9da3d
commit 7a5870dc09
8 changed files with 520 additions and 90 deletions

2
doc/issues/0000tn3.rst Normal file
View File

@ -0,0 +1,2 @@
Implement working internal links using ``jlp://`` schema.
=========================================================

1
doc/issues/0001tn3.rst Normal file
View File

@ -0,0 +1 @@
Implement language-specific code parsing and comprehension.

193
resources/main/docco.css Normal file
View File

@ -0,0 +1,193 @@
/*--------------------- Layout and Typography ----------------------------*/
body {
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 15px;
line-height: 22px;
color: #252519;
margin: 0; padding: 0;
}
a { color: #261a3b; }
a:visited { color: #261a3b; }
p { margin: 0 0 15px 0; }
h1, h2, h3, h4, h5, h6 { margin: 0px 0 15px 0; }
h1 { margin-top: 40px; }
dt { font-weight: bold; }
ul {
margin: 0;
padding: 0 0 0 2em; }
#container { position: relative; }
#background {
position: fixed;
top: 0; left: 525px; right: 0; bottom: 0;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
z-index: -1;
}
#jump_to, #jump_page {
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 10px Arial;
text-transform: uppercase;
cursor: pointer;
text-align: right;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
display: none;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 5px 10px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
table td {
border: 0;
outline: 0;
}
td.docs, th.docs {
max-width: 450px;
min-width: 450px;
min-height: 5px;
padding: 10px 25px 1px 50px;
overflow-x: hidden;
vertical-align: top;
text-align: left;
}
.docs pre {
background: #f8f8ff;
border: 1px solid #dedede;
margin: 15px 0 15px;
padding-left: 15px;
}
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
.pilwrap {
position: relative;
}
.pilcrow {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
td.docs:hover .pilcrow {
opacity: 1;
}
td.code, th.code {
padding: 14px 15px 16px 25px;
width: 100%;
vertical-align: top;
background: #f5f5ff;
border-left: 1px solid #e5e5ee;
}
pre, tt, code {
font-size: 12px; line-height: 18px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

132
resources/main/jlp.css Normal file
View File

@ -0,0 +1,132 @@
body {
font-family: 'Palatine Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
font-size: 15px;
line-height: 22px;
color: #252519;
margin: 0;
padding 0; }
a { color: #261a3b; }
a:visited { color: #261a3b; }
p{ margin: 0 0 15px 0; }
h1, h2, h3, h4, h5, h6 { margin: 0 0 15px 0; }
h1 { margin-top: 40px; }
dt { font-weight: bold; }
ul {
margin: 0;
padding-top: 0; }
#container { position: relative; }
table td {
border: 0;
outline: 0; }
td.docs, th.docs {
max-width: 450px;
min-width: 450px;
min-height: 5pc;
padding: 10px 25px 1px 50px;
overflow-x: hidden;
vertical-align: top;
text-align: left; }
.docs pre {
background: #f8f8ff;
border: 1px solid #dedede;
margin: 15px 0 15px;
padding-left: 15px; }
.docs p tt, .docs p code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em; }
.docs table {
border: thin solid #dedede;
margin-left: 30px; }
td.code, th.code {
padding: 14px 15px 16px 25px;
width: 100%;
vertical-align: top;
background: #f5f5ff;
border-left: 1px solid #e5e5ee; }
pre, tt, code {
font-size: 12px;
line-height: 18px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0; }
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
body .hll { background-color: #ffffcc }
body .c { color: #408080; font-style: italic } /* Comment */
body .err { border: 1px solid #FF0000 } /* Error */
body .k { color: #954121 } /* Keyword */
body .o { color: #666666 } /* Operator */
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
body .cp { color: #BC7A00 } /* Comment.Preproc */
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
body .cs { color: #408080; font-style: italic } /* Comment.Special */
body .gd { color: #A00000 } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #FF0000 } /* Generic.Error */
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
body .gi { color: #00A000 } /* Generic.Inserted */
body .go { color: #808080 } /* Generic.Output */
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
body .gt { color: #0040D0 } /* Generic.Traceback */
body .kc { color: #954121 } /* Keyword.Constant */
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
body .kp { color: #954121 } /* Keyword.Pseudo */
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
body .kt { color: #B00040 } /* Keyword.Type */
body .m { color: #666666 } /* Literal.Number */
body .s { color: #219161 } /* Literal.String */
body .na { color: #7D9029 } /* Name.Attribute */
body .nb { color: #954121 } /* Name.Builtin */
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
body .no { color: #880000 } /* Name.Constant */
body .nd { color: #AA22FF } /* Name.Decorator */
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
body .nf { color: #0000FF } /* Name.Function */
body .nl { color: #A0A000 } /* Name.Label */
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
body .nv { color: #19469D } /* Name.Variable */
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #666666 } /* Literal.Number.Float */
body .mh { color: #666666 } /* Literal.Number.Hex */
body .mi { color: #666666 } /* Literal.Number.Integer */
body .mo { color: #666666 } /* Literal.Number.Oct */
body .sb { color: #219161 } /* Literal.String.Backtick */
body .sc { color: #219161 } /* Literal.String.Char */
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
body .s2 { color: #219161 } /* Literal.String.Double */
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
body .sh { color: #219161 } /* Literal.String.Heredoc */
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
body .sx { color: #954121 } /* Literal.String.Other */
body .sr { color: #BB6688 } /* Literal.String.Regex */
body .s1 { color: #219161 } /* Literal.String.Single */
body .ss { color: #19469D } /* Literal.String.Symbol */
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
body .vc { color: #19469D } /* Name.Variable.Class */
body .vg { color: #19469D } /* Name.Variable.Global */
body .vi { color: #19469D } /* Name.Variable.Instance */
body .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@ -1,4 +1,5 @@
import com.jdblabs.jlp.*
import com.jdblabs.jlp.experimental.LiterateMarkdownGenerator
import org.parboiled.Parboiled
import org.parboiled.parserunners.ReportingParseRunner
import org.parboiled.parserunners.RecoveringParseRunner
@ -54,3 +55,24 @@ vbsTest = {
return [vbsParsed, vbsResult]
}
experimentalTest = {
makeExperimentalParser()
println "Parsing vbs_db_records.hrl into 'vbsResult'."
println "--------------------------------------------"
vbsTestFile = new File('vbs_db_records.hrl')
println "vbsTestFile is ${vbsTestFile.exists() ? 'present' : 'absent'}."
vbsTestInput = vbsTestFile.text
vbsParsed = parseRunner.run(vbsTestInput)
vbsResult = LiterateMarkdownGenerator.generateDocuments(["vbs_db_records.hrl": vbsParsed.resultValue])."vbs_db_records.hrl"
println "Writing to file 'vbs_result.html'."
println "----------------------------------"
(new File('vbs_result.html')).withWriter { out -> out.println vbsResult }
}

View File

@ -2,6 +2,8 @@
%% @author Jonathan Bernard <jdb@jdb-labs.com>
%% @copyright 2010-2011 JDB Labs Inc.
%% #Overview
%%
%% The VBS database API is centered around the data records:
%%
%% * Tables are named after the records. ``vbs_adult`` records are stored in
@ -14,89 +16,99 @@
%% #Record Definitions
%% Here are the record definitions:
%% ## vbs_adult ##
%% @api Information about an adult in the VBS system.
%% @org records/vbs_adult
-record(vbs_adult, {
%% @api A unique number. This is the record's primary identification and
%% @api * A unique number. This is the record's primary identification and
%% the table's primary key
%% @org records/vbs_adult/id
id,
%% @api A unique full name.
%% @example "John Smith", "Fae Alice McDonald"
%% @api * A unique full name.
%%
%% *Examples:* `"John Smith", "Fae Alice McDonald"`
%% @org records/vbs_adult/name
name,
%% @api The adult's age (optional).
%% @api * The adult's age (optional).
%% @org records/vbs_adult/age
age = 0,
%% @api A list of phone numbers (strings).
%% @example ["512-555-1155", "123-456-7890"]
%% @api * A list of phone numbers (strings).
%%
%% *Examples:* `["512-555-1155", "123-456-7890"]`
%% @org records/vbs_adult/phone_numbers
phone_numbers,
%% @api The adult's address (optional). There is not pre-defined format,
%% @api * The adult's address (optional). There is not pre-defined format,
%% this is a string that can be formatted s desired (linebreaks are ok,
%% for example).
%% @example
%%
%% "123 Grant Drive
%% Plainsville, TX, 78707"
%% *Example:*
%%
%% "123 Grant Drive
%% Plainsville, TX, 78707"
%%
%% @org records/vbs_adult/address
address = "",
%% @api The adult's email address as a string.
%% @example "john_smith@mailco.com"
%% @api * The adult's email address as a string.
%%
%% *Example:* `"john_smith@mailco.com"`
%% @org records/vbs_adult/email
email = ""}).
%% ## vbs_attendance ##
%% @api An entry recording a person's attendance.
%% @org records/vbs_attendance
-record(vbs_attendance, {
%% @api A unique number. This is the record's primary identification and the
%% @api * A unique number. This is the record's primary identification and the
%% table's primary key.
%% @org records/vbs_attendance/id
id,
%% @api The id of person who attended. This is a foreign key onto either the
%% @api * The id of person who attended. This is a foreign key onto either the
%% [`vbs_worker`](jlp://records/vbs_worker) or
%% [`vbs_child`](jlp://records/vbs_child) table, depending on the value of
%% the [`person_type`](jlp://records/vbs_attendance/person_type) field.
%% @org records/vbs_attendance/person_id
person_id,
%% @api The type of person who attended. This determines which table the
%% @api * The type of person who attended. This determines which table the
%% [`person_id`](jlp://records/vbs_attendance/person_id) links on. The
%% possible values and the corresponding link tables are:
%%
%% Value | Link Table
%% --------|----------------------------------------
%% `child` |[`vbs_child`](jlp://records/vbs_child)
%% `worker`|[`vbs_worker`](jlp://records/vbs_worker)
%% Value | Link Table
%% --------|----------------------------------------
%% `child` |[`vbs_child`](jlp://records/vbs_child)
%% `worker`|[`vbs_worker`](jlp://records/vbs_worker)
%%
%% @org records/vbs_attendance/person_type
person_type,
%% @api The date of attendance, stored as {Year, Month, Day}.
%% @example {2011, 6, 14}
%% @api * The date of attendance, stored as `{Year, Month, Day}.`
%%
%% *Example:* `{2011, 6, 14}`
%%
%% @org records/vbs_attendance/date
date = {1900, 1, 1},
%% @api A timestamp taken when the person was signed in, stored as
%% {Hour, Minute, Second}
%% @example {5, 22, 13}
%% @api * A timestamp taken when the person was signed in, stored as
%% `{Hour, Minute, Second}`
%%
%% *Example:* `{5, 22, 13}`
%% @org records/vbs_attendance/sign_in
sign_in = false, % {hour, minute, second}
%% @api A timestamp taken when the person is signed out, stored as
%% {Hour, Minute, Second}
%% @api * A timestamp taken when the person is signed out, stored as
%% `{Hour, Minute, Second}`
%% @org records/vbs_attendance/sign_out
sign_out = false, % {hour, minute, second}
%% @api A list of {Key, Value} pairs that can be used to store additional
%% @api * A list of {Key, Value} pairs that can be used to store additional
%% information. This is intended to allow callers to store optional data,
%% or client-specific data, without having to alter the database schema.
%% When working with `vbs_attendance` records, a caller should ignore
@ -104,196 +116,207 @@
%% @org records/vbs_attendance/ext_data
ext_data = [],
%% @api Any comments for the day about this person.
%% @api * Any comments for the day about this person.
%% @org records/vbs_attendance/comments
comments = ""}).
%% @api Information about a child in the VBS program.
%% ## vbs_child ##
%% @org records/vbs_child
%% @api Information about a child in the VBS program.
-record(vbs_child, {
%% @api A unique number. This is the record's primary identification and the
%% @api * A unique number. This is the record's primary identification and the
%% table's primary key.
%% @org records/vbs_child/id
id,
%% @api The id of the crew to which this child has been assigned. This is a
%% @api * The id of the crew to which this child has been assigned. This is a
%% foreign key linking to a [`vbs_crew.id`](jlp://records/vbs_crew/id).
%% @org records/vbs_child/crew_id
crew_id,
%% @api The child's full name.
%% @example "Mary Scott", "Gregory Brown"
%% @api * The child's full name.
%%
%% *Example:* `"Mary Scott", "Gregory Brown"`
%% @org records/vbs_child/name
name,
%% @api The child's date of birth, stored as {Year, Month, Day}
%% @example {1998, 12, 22}
%% @api * The child's date of birth, stored as `{Year, Month, Day}`
%%
%% *Example:* `{1998, 12, 22}`
%% @org records/vbs_child/date_of_birth
date_of_birth,
%% @api The child's gender, either `male` or `female`
%% @api * The child's gender, either `male` or `female`
%% @org records/vbs_child/gender
gender,
%% @api The child's grade level in school.
%% @api * The child's grade level in school.
%% @org records/vbs_child/grade
grade,
%% @api A list of ids representing the child's legal guardians. These link
%% @api * A list of ids representing the child's legal guardians. These link
%% the child record to adult records by the
%% [`vbs_adult.id`](jlp://records/vbs_adult/id)
%% @example [4, 5]
%%
%% *Example:* `[4, 5]`
%% @org records/vbs_child/guardian_ids
guardian_ids,
%% @api A list of ids, similar to `guardian_ids`, but representing the
%% @api * A list of ids, similar to `guardian_ids`, but representing the
%% adults that are allowed to pick the children up. These link the child
%% record to adult records by
%% ['vbs_adult.id`](jlp://records/vbs_adult/id).
%% @org records/vbs_child/pickup_ids
pickup_ids,
%% @api A list of ids, similar to `guardian_ids` and `pickup_ids`, but
%% @api * A list of ids, similar to `guardian_ids` and `pickup_ids`, but
%% representing adults that should be contacted if there is an emergency
%% involving this child (injury, for example). These link the child record
%% to adult records by [`vbs_adult.id`](jlp://records/vbs_adult/id).
%% @org records/vbs_child/emerency_ids
emerency_ids,
%% @api The child's home church, usually used if they are not a member of
%% @api * The child's home church, usually used if they are not a member of
%% the hosting church.
%% @org records/vbs_child/home_church
home_church,
%% @api If this child is a visitor, this is used to track who invited them,
%% @api * If this child is a visitor, this is used to track who invited them,
%% or who brought them.
%% @org records/vbs_child/visitor_of
visitor_of,
%% @api Answers the question: Is this child a visitor? Valid values are
%% @api * Answers the question: Is this child a visitor? Valid values are
%% `true` and `false`.
%% @org records/vbs_child/is_visitor
is_visitor,
%% @api The date the child registered, stored as {Year, Month, Day}
%% @api * The date the child registered, stored as `{Year, Month, Day}`
%% @org records/vbs_child/registration_date
registration_date,
%% @api The child's shirt size, stored as a string.
%% @api * The child's shirt size, stored as a string.
%% @org records/vbs_child/shirt_size
shirt_size,
%% @api Any special needs this child has that should be accomodated.
%% @api * Any special needs this child has that should be accomodated.
%% @org records/vbs_child/special_needs
special_needs,
%% @api Any known allergies this child has.
%% @api * Any known allergies this child has.
%% @org records/vbs_child/allergies
allergies,
%% @api Additional comments about this child.
%% @api * Additional comments about this child.
%% @org records/vbs_child/comments
comments}).
%% @api Information about a crew in the VBS system.
%% ## vbs_crew ##
%% @api * Information about a crew in the VBS system.
%% @org records/vbs_crew
-record(vbs_crew, {
%% @api A unique number. This is the record's primary identification and the
%% @api * A unique number. This is the record's primary identification and the
%% table's primary key.
%% @org records/vbs_crew/id
id, % primary key
%% @api The crew number.
%% @api * The crew number.
%% @org records/vbs_crew/number
number,
%% @api The crew type. This is a foreign key on
%% @api * The crew type. This is a foreign key on
%% [`vbs_crew_type.id`](jlp://records/vbs_crew_type/id).
%% @org records/vbs_crew/crew_type_id
crew_type_id, % foreign key onto crew_type
%% @api The name of the crew, stored as a string.
%% @api * The name of the crew, stored as a string.
%% @org records/vbs_crew/name
name,
%% @api Any comments about the crew.
%% @api * Any comments about the crew.
%% @org records/vbs_crew/comments
comments = ""}).
%% @api Information about a crew type. Crew types are often used when a VBS
%% ## vbs_crew_type ##
%% @api * Information about a crew type. Crew types are often used when a VBS
%% program has seperate activities set up for different types of children
%% (usually based on age). For example, having two type: Elementary and Pre-K
%% is common when there is a seperate set of activities for smaller children.
%% @org records/vbs_crew_type
-record(vbs_crew_type, {
%% @api A unique number. This is the record's primary identification and the
%% @api * A unique number. This is the record's primary identification and the
%% table's primary key.
%% @org records/vbs_crew_type/id
id,
%% @api The displayed name of the crew type.
%% @api * The displayed name of the crew type.
%% @org records/vbs_crew_type/name
name}).
%% @api The id counter records are used to keep track of the next valid id for a
%% ## vbs_id_counter ##
%% @api * The id counter records are used to keep track of the next valid id for a
%% specific purpose. This is how the unique id fields in other records is
%% implmented.
%% @org records/vbs_id_counter
-record(vbs_id_counter, {
%% @api A name for the counter. This is the primary key for the table and
%% @api * A name for the counter. This is the primary key for the table and
%% must be unique.
%% @example `vbs_adult_id`
%%
%% *Example:* `vbs_adult_id`
%% @org records/vbs_id_counter/name
name,
%% @api The next value for this counter.
%% @api * The next value for this counter.
%% @org records/vbs_id_counter/next_value
next_value = 0}).
%% @api Information about workers involved in the VBS program.
%% ## vbs_worker ##
%% @api * Information about workers involved in the VBS program.
%% @org records/vbs_worker
-record(vbs_worker, {
%% @api A unique number. This is the record's primary identification and the
%% @api * A unique number. This is the record's primary identification and the
%% table's primary key.
%% @org records/vbs_worker/id
id,
%% @api Links this worker record to a [`vbs_adult`](jlp://records/vbs_adult)
%% @api * Links this worker record to a [`vbs_adult`](jlp://records/vbs_adult)
%% @org records/vbs_worker/adult_id
adult_id, % foreign key on adult
%% @api The crew this worker is assigned to. This is a link to
%% @api * The crew this worker is assigned to. This is a link to
%% [`vbs_crew.id`](jlp://records/vbs_crew/id). The most common way to deal
%% with workers who are not assigned to a particular crew is to create a
%% special administrative crew and assign all these workers to that crew.
%% @org records/vbs_worker/crew_id
crew_id = 0,
%% @api
%% @api *
%% @org records/vbs_worker/worker_type_id
worker_type_id, % foreign key on worker_type
%% @api
%% @api *
%% @org records/vbs_worker/shirt_size
shirt_size,
%% @api
%% @api *
%% @org records/vbs_worker/ext_data
ext_data = []}).
%% @api
%% ## vbs_worker_type ##
%% @api * Worker types.
%% @org records/vbs_worker_type
-record(vbs_worker_type, {
%% @api
%% @api *
%% @org records/vbs_worker_type/id
id,
%% @api
%% @api *
%% @org records/vbs_worker_type/name
name}).

View File

@ -15,18 +15,43 @@ public abstract class JLPBaseGenerator {
protected Map<String, String> generate(Map<String, SourceFile> sources) {
Map result = [:]
// run the parse phase
sources.each { sourceId, sourceAST ->
// set up the current generator state for this source
docState.currentDocId = sourceId
docState.codeTrees[sourceId] = sourceAST.codeAST
parse(sourceAST) }
// run the emit phase
sources.each { sourceId, sourceAST ->
// set up the current generator state for this source
docState.currentDocId = sourceId
// generate the doc for this source
result[sourceId] = emit(sourceAST) }
// return our results
return result }
protected void parse(SourceFile sourceFile) {
sourceFile.blocks.each { block -> parse(block) } }
protected void parse(Block block) {
parse(block.docBlock)
parse(block.codeBlock) }
protected void parse(DocBlock docBlock) {
docBlock.directives.each { directive -> parse(directive) }
docBlock.docTexts.each { docText -> parse(docText) } }
protected abstract void parse(Directive directive)
protected abstract void parse(CodeBlock codeBlock)
protected abstract void parse(DocText docText)
protected abstract String emit(SourceFile sourceFile)
protected abstract String emit(Block block)
protected abstract String emit(DocBlock docBlock)

View File

@ -16,13 +16,29 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
super()
pegdown = new PegDownProcessor(
Extensions.TABLES & Extensions.DEFINITIONS) }
Extensions.TABLES | Extensions.DEFINITIONS) }
protected static Map<String, String> generateDocuments(
Map<String, SourceFile> sources) {
LiterateMarkdownGenerator inst = new LiterateMarkdownGenerator()
return inst.generate(sources) }
protected void parse(Directive directive) {
switch(directive.type) {
case DirectiveType.Org:
def orgMap = [:]
orgMap.id = directive.value
orgMap.directive = directive
orgMap.sourceDocId = docState.currentDocId
docState.orgs[directive.value] = orgMap
break;
default:
break // do nothing
} }
protected void parse(CodeBlock codeBlock) {} // nothing to do
protected void parse(DocText docText) {} // nothing to do
protected String emit(SourceFile sourceFile) {
StringBuilder sb = new StringBuilder()
@ -34,13 +50,13 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
<head>
<title>${docState.currentDocId}</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- <link rel="syltesheet" media="all" href=""/> -->
<link rel="stylesheet" media="all" href="docco.css"/>
</head>
<body>
<div id="container">
<table cellpadding="0" cellspacing="0">
<thead><tr>
<th class="doc"><h1>${docState.currentDocId}</h1></th>
<th class="docs"><h1>${docState.currentDocId}</h1></th>
<th class="code"/>
</tr></thead>
<tbody>""")
@ -70,7 +86,7 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
else { sb.append("<tr>") }
// Create the `td` for the documentation.
sb.append('\n<td class="doc">')
sb.append('\n<td class="docs">')
sb.append(emit(block.docBlock))
sb.append('</td>')
@ -94,14 +110,11 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
emitQueue = docBlock.directives.collect { directive ->
def queueItem = [lineNumber: directive.lineNumber, value: directive]
switch(directive.type) {
case DirectiveType.Api: queueItem.priority = 12; break
case DirectiveType.Api: queueItem.priority = 50; break
case DirectiveType.Author: queueItem.priority = 10; break
case DirectiveType.Copyright: queueItem.priority = 11; break
case DirectiveType.Example: queueItem.priority = 50; break
case DirectiveType.Org:
docState.orgs[directive.value] = directive
queueItem.priority = 0
break }
case DirectiveType.Org: queueItem.priority = 0; break }
return queueItem }
@ -110,14 +123,11 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
[lineNumber: docText.lineNumber, priority: 50, value: docText] })
println emitQueue
println "----------"
// Sort the emit queue by priority, then line number.
emitQueue.sort(
{i1, i2 -> i1.priority != i2.priority ?
i1.priority - i2.priority :
i1.line - i2.line} as Comparator)
i1.lineNumber - i2.lineNumber} as Comparator)
// Finally, we want to treat the whole block as one markdown chunk, so
// we will concatenate the values in the emit queue and then process
@ -125,7 +135,7 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
sb = new StringBuilder()
emitQueue.each { queueItem -> sb.append(emit(queueItem.value)) }
return pegdown.markdownToHtml(sb.toString())
return processMarkdown(sb.toString())
}
protected String emit(CodeBlock codeBlock) {
@ -153,19 +163,41 @@ public class LiterateMarkdownGenerator extends JLPBaseGenerator {
// process input inside HTML elements).
case DirectiveType.Api:
return "<div class='api'>" +
pegdown.markdownToHtml(directive.value) + "</div>\n"
processMarkdown(directive.value) + "</div>\n"
// An `@author` directive is turned into a definition list.
case DirectiveType.Author:
return "Author\n: ${directive.value}\n"
case DirectiveType.Copyright:
return "&copy; ${directive.value}\n"
return "\n&copy; ${directive.value}\n"
// An `@example` directive is returned as is
case DirectiveType.Example: return directive.value
case DirectiveType.Example:
return directive.value
// An `@org` directive is ignored.
case DirectiveType.Org: return "" }
}
protected String processMarkdown(String markdown) {
// convert to HTML from Markdown
String html = pegdown.markdownToHtml(markdown)
// replace internal `jlp://` links with actual links based on`@org`
// references
html = html.replaceAll(/jlp:\/\/([^\s"]+)/) { wholeMatch, linkId ->
def link = docState.orgs[linkId]
String newLink
if (!link) {
/* TODO: log error */
newLink = "broken_link(${linkId})" }
else if (docState.currentDocId == link.sourceDocId) {
newLink = "#$linkId" }
else { newLink = "${link.sourceDocId}#${linkId}" }
return newLink }
return html;
}
}