Open patrickbkr opened 5 days ago
Just to get the discussion started, here is the first thing I was able to come up with.
Given this piece of code in a file called foo/bar/frobnicator.rakumod
:
#| The class C<Foo::Bar::Frobnicator> is the one stop shop for all your frobnication needs.
class Foo::Bar::Frobnicator is Affector[I] does Helping {
#| Perform a frobnication.
method frobnicate(
Str() $thingy = "something", #= The thing you want to frobnicate.
:$quiet #= Do it quietly.
) { ... }
}
#| User expertise levels.
enum Level
ONE, #= Beginner.
TWO, #= Expert.
;
#| Default config values.
my %config =
size docs "How big should the buffer be?" => 5,
;
The output in a file foo/bar/frobnicator.rakudoc
might be:
=begin dock :type("class")
= :name("Foo::Bar::Frobnicator")
= :code("class Foo::Bar::Frobnicator is Affector[I] does Helping")
= :file("foo/bar/frobnicator.rakumod")
The class C<Foo::Bar::Frobnicator> is the one stop shop for all your frobnication needs.
=end dock
=begin dock :type("method")
= :name("frobnicate")
= :code("method frobnicate(Str() $thingy = \"something\", :$quiet)")
= :file("foo/bar/frobnicator.rakumod")
= :context(class => "Foo::Bar::Frobnicator")
Perform a frobnication.
=end dock
=begin dock :type("parameter")
= :name("thingy")
= :code("Str() $thingy = \"something\"")
= :file("foo/bar/frobnicator.rakumod")
= :context(class => "Foo::Bar::Frobnicator", method => "frobnicate")
The thing you want to frobnicate.
=end dock
=begin dock :type("parameter")
= :name("quiet")
= :code(":$quiet")
= :file("foo/bar/frobnicator.rakumod")
= :context(class => "Foo::Bar::Frobnicator", method => "frobnicate")
Do it quietly.
=end dock
=begin dock :type("enum")
= :name("Level")
= :code("enum Level")
= :file("foo/bar/frobnicator.rakumod")
User expertise levels.
=end dock
=begin dock :type("literal")
= :name("ONE")
= :code("ONE")
= :file("foo/bar/frobnicator.rakumod")
= :context(enum => "Level")
Beginner.
=end dock
=begin dock :type("literal")
= :name("TWO")
= :code("TWO")
= :file("foo/bar/frobnicator.rakumod")
= :context(enum => "Level")
Expert.
=end dock
=begin dock :type("variable")
= :name("config")
= :code("my %config")
= :file("foo/bar/frobnicator.rakumod")
Default config values.
=end dock
=begin dock :type("key")
= :name("size")
= :code("size")
= :file("foo/bar/frobnicator.rakumod")
= :context(variable => "config")
How big should the buffer be?
=end dock
Immediate questions:
thingy
could have :positional(0)
, :default("something")
, :sig-type("Str()")
and so on. How much is too much?:context
and :file
can not be as simple as I make them be in the above example. Are there conditions in which the naive approach above fails?@finanalyst I believe you currently have the deepest insight into implementing renderers. Thus the ping.
I forgot but just found that back in 2020 we did get the ability to keep the leading declarator block in its original form with use of an environment variable RAKUDO_POD_DECL_BLOCK_USER_FORMAT. That implementation was the quickest and easiest way to affect Raku parsing.
When that is true, and you run 'raku --doc ...', you will get text from the leading declarator blocks as input by the author of the code.
I used that for documenting my code. I hope that is retained and improved for RakuAST.
The test for it is in roast file 'S26-documentation/block-leading-user-format.t'. I
It is retained if you use $=pod
.
What I implemented for --rakudoc
now:
#| before subset
subset Positive of Int where * > 0; #= after subset
#| before enum
enum Frobnicate <Yes No>; #= after enum
#| before regex
my regex zippo { z } #= after regex
#| before block
{ … } #= after block
#| before pointy block
{ … } #= after pointy block
#| the main class
class A { #= that we have
#| a method before
multi method a( #= method after
#| parameter before
Int:D $foo #= parameter after
) {
#| a variable
my $a = 42; #= with the answer
}
}
produces:
=begin doc-subset :name<Positive>
=leading before subset
=trailing after subset
=end doc-subset
=begin doc-enum :name<Frobnicate>
=leading before enum
=trailing after enum
=end doc-enum
=begin doc-regex :name<zippo>
=leading before regex
=trailing after regex
=end doc-regex
=begin doc-block
=leading before block
=trailing after block
=end doc-block
=begin doc-block
=leading before pointy block
=trailing after pointy block
=end doc-block
=begin doc-class :name<A>
=leading the main class
=trailing that we have
=begin doc-method :multi :name<a>
=leading a method before
=trailing method after
=begin doc-parameter :name<Int:D $foo where { ... }>
=leading parameter before
=trailing parameter after
=end doc-parameter
=begin doc-variable :name<$a>
=leading a variable
=trailing with the answer
=end doc-variable
=end doc-method
=end doc-class
Note that this was just a first attempt and no way intended to be cast in stone... Very much open to improvements :-)
@lizmat It's a nice surprise you actually started working on it already. I did not see that coming. You've implemented support for quite a list already. Nice!
The first elements that come to mind I still miss are: doc-sub, doc-constant, doc-has, doc-token, doc-rule, doc-grammar
Questions:
my
variables.augment
?:code()
in my attempt.)#|
and #=
different meanings? If not, then we can get rid of =leading
and =trailing
and just have the contents directly in there.I still miss: doc-sub, doc-constant, doc-has, doc-token, doc-rule, doc-grammar
Hmmm looks like decks on constants are currently broken.
Re: doc-sub
these all fall out of generic Routine handling
#| before sub
sub foo() { #= after sub
}
produces:
=begin doc-sub :name<foo>
=leading before sub
=trailing after sub
=end doc-sub
But it looks like submethod
is being rendered as "doc-method" instead of "doc-submethod"
Looks like has
is being rendered as "doc-variable" instead of "doc-has". Hmmmm...
"doc-token" and "doc-rule" are already being rendered correctly, as they are a special case of "doc-regex".
"doc-grammar" and all other package types, are already being rendered.
Is there any point in putting a Dock on a block?
There are spectests for it.
Same can be asked for my variables.No, it makes perfect sense - e.g. for IDE support for maintainers.
And there the line between internal and external documentation blurs. So are decks for external or internal documentation?
Nesting the hierarchies is nice. Are there cases where this might not be easily possible? E.g. When having a class spread multiple files using augment?
All RakuDoc is based on a RakuAST tree. However you build such a tree, is open to debate. I guess one could join multiple ASTs from different files into a single AST. Then it all depends on the scoping of such a merge.
Can we have the literal code of the respective element in there? (What I put in :code() in my attempt.)
Yes, you could. But this could become quite a lot. And wasn't it the point to not have any code in safe RakuDoc?
Semantically, do we want to give #| and #= different meanings? If not, then we can get rid of =leading and =trailing and just have the contents directly in there.
Sure, we could do that.
https://github.com/rakudo/rakudo/commit/27565cc1f7 now renders attributes as doc-attribute
.
https://github.com/rakudo/rakudo/commit/8162f3eb3b now renders submethod
s as doc-submethod
.
The point is to not have any Ralu code that needs to parsed. But a string containing some Raku code (i.e. no different from a =code block in RakuDoc) is no problem at all.
My feeling is, that (at least in the case of routines) the declarator carries a lot of meaning in itself and would help loads to have it available in the docs. In JavaDoc they do that as well. E.g. when looking at some class in the POI docs https://poi.apache.org/apidocs/5.0/ there the literal method declarator is shown. Without that declarator in there the rest of the docs would make a lot less sense.
On September 22, 2024 1:01:39 PM GMT+02:00, Elizabeth Mattijsen @.***> wrote:
Can we have the literal code of the respective element in there? (What I put in :code() in my attempt.)
Yes, you could. But this could become quite a lot. And wasn't it the point to not have any code in safe RakuDoc?
-- Reply to this email directly or view it on GitHub: https://github.com/Raku/problem-solving/issues/439#issuecomment-2366727081 You are receiving this because you authored the thread.
Message ID: @.***>
That's a question that is difficult to answer. There is clearly a use case for both. Question is, which of the use cases do we want to support? My feeling is that explicitly excluding one of the two use cases diminishes the usability.
I would say, let's just leave it unspecified for now, provide a generic tool and see how it's used and what works and what doesn't. If we find, that there is a need to separate the two uses more strongly, we can adjust later on.
On September 22, 2024 12:58:38 PM GMT+02:00, Elizabeth Mattijsen @.***> wrote:
Same can be asked for my variables.No, it makes perfect sense - e.g. for IDE support for maintainers.And there the line between internal and external documentation blurs. So are decks for external or internal documentation?
-- Reply to this email directly or view it on GitHub: https://github.com/Raku/problem-solving/issues/439#issuecomment-2366726171 You are receiving this because you authored the thread.
Message ID: @.***>
Prelude:
Toolchain wise we've long had the issue that tools to display documentation (GitHub, GitLab, raku.land, ...) have an issue with running the Rakudo parser on source code to reach for the embedded docs as that code can contain BEGIN blocks, which is a big safety concern.
A possible way forward is to split the task of rendering RakuDoc (and Declarator Docs in particular) into two phases:
Extractor
extracts and converts all docs in a Raku source file and outputs a pure .rakudoc file. This is an unsafe procedure.RakuDoc parser
, then parses that pure.rakudoc
file. It barfs on anything that is not plain RakuDoc. This is a safe process.Platforms that wish to render RakuDoc (e.g. GitHub) can safely use the
RakuDoc
parser. Platforms that want to render the full documentation (e.g. raku.land) can run theExtractor
in a sandbox.All of the above is not part of the issue this ticket wants to address.
The question I want to discuss is: What should the output of the above mentioned
Extractor
that can convert a.rakumod
file into a.rakudoc
file look like?The issue is mostly orthogonal to https://github.com/Raku/problem-solving/issues/438 in that it is not concerned with how Declarator Docs should look in code, but how they should be represented in RakuDoc.