-
Notifications
You must be signed in to change notification settings - Fork 240
Single line tags
Lets implement a @license
tag to describe how we license our
software. It should take as a parameter the name of the license:
/**
* @class My.Class
* An example class.
* @license GNU General Public License v3
* @license MIT License
*/
And here's an implementation for that:
require "jsduck/tag/tag"
class License < JsDuck::Tag::Tag
def initialize
@tagname = :license
@pattern = "license"
@html_position = POS_DOC + 0.1
@repeatable = true
end
def parse_doc(scanner, position)
text = scanner.match(/.*$/)
return { :tagname => :license, :text => text }
end
def process_doc(context, license_tags, position)
context[:license] = license_tags.map {|tag| tag[:text] }
end
def to_html(context)
licenses = context[:license].map {|license| "<b>#{license}</b>" }.join(" and ")
<<-EOHTML
<p>This software is licensed under: #{licenses}.</p>
EOHTML
end
end
There's quite a lot of stuff in here, so lets go over it all step-by-step.
First thing to note is that this time we inherit our tag class from
JsDuck::Tag::Tag. In previous chapter we
extended BooleanTag, which in turn extended the JsDuck::Tag::Tag
and performed a simple parsing and processing behind the scenes. This
time around we implement our own parse_doc
and process_doc
methods.
We also define @repeatable = true
to allow multiple @license tags
to be used inside a single doc-comment.
def parse_doc(scanner, position)
text = scanner.match(/.*$/)
return { :tagname => :license, :text => text }
end
parse_doc
gets called every time the parser encounters our
@license
tag inside a doc-comment. JSDuck parses the name of the
tag by itself and then passes control over to parse_doc
to parse
anything after the tag name, passing in an instance of
JsDuck::Doc::Scanner on which we call the match
method
with a regex to extract all the text following the tag up to the end
of line.
For our purposes we have now done enough of parsing and successfully extracted the name of the license. (See More about parsing for a deeper look at the Scanner object.)
At this point we need to return a hash with our extracted data. The
hash must contain a :tagname
field which must match up with the
@tagname
variable we defined in initialize
. Anything else inside
this hash is our custom data we store there for later processing -
which in our case is just the name of the license.
The second position
parameter contains file name and line number,
which can be used for error reporting.
def process_doc(context, license_tags, position)
context[:license] = license_tags.map {|tag| tag[:text] }
end
The hashes returned by parse_doc
within one doc-comment get grouped
together by the :tagname
we specified and passed to process_doc
.
In our example case the value of license_tags
parameter will be the
following:
[
{:tagname => :license, :text => "GNU General Public License"},
{:tagname => :license, :text => "MIT License"},
]
The task of the process_doc
method is to do any additional
processing on this data and save it into the context
hash (usually
under the same key as our :tagname
). In our case we just extract the
names of our licenses.
The third position
parameter contains file name and line number,
which can be used for error reporting.
def to_html(context)
licenses = context[:license].map {|license| "<b>#{license}</b>" }.join(" and ")
<<-EOHTML
<p>This software is licensed under: #{licenses}.</p>
EOHTML
end
This time inside to_html
we make use of the context
parameter,
which is the same context
that we modified in process_doc
. So we
just take the value we saved under :license
key and turn it into
HTML.
The result of this all will look as follows: