Search code examples
rakuread-eval-print-loopintrospectioncode-documentationrakudo

How to get a "help" functionality in REPL


When I use REPL, I sometimes need to look up how a function functions e.g. splice. I usually go to the documentation website. But I don't always have internet and it'd be good if I could write help("splice") or something (e.g. splice?) in the REPL directly and see the result.

Then I thought p6doc that came with Rakudo Star can be used because p6doc Array.splice on command line gives documentation. Then I do this in REPL:

> run <p6doc Array.splice>

Proc.new(in => IO::Pipe, out => IO::Pipe, err => IO::Pipe, exitcode => 1,
         signal => 0, pid => Nil, command => ("p6doc", "Array.splice"))

but it has exitcode 1. When I capture outputs with :out and :err, both are empty strings but I don't know why.

Is there a way I can make this kind of help functionality in REPL work either with "run p6doc" or something else?

I use Windows10 with

Welcome to š‘ššš¤š®ššØā„¢ v2021.07.
Implementing the š‘ššš¤š®ā„¢ programming language v6.d.
Built on MoarVM version 2021.07.

Solution

  • Your specific question

    The error you're getting when you enter run <p6doc Array.splice> in the REPL looks like the error you'd get for a command that can't be found. You can confirm that by entering qx <p6doc Array.splice> ā€“ I suspect that you'll get an error that more clearly says that the p6doc command can't be found.

    Assuming that is the issue, it sounds like $PATH environmental variable isn't getting set correctly in your REPL. I'm not sure why that would be and I don't have a Windows box handy to test with. But, in any event, you should be able to work around that by specifying an absolute path to the p6doc executable. (For me, that'd be something like qx </home/dsock/.raku/bin/p6doc Array.splice>, but obviously you'll have a different path).

    (Oh, and you would probably be better off with qx or shell for this use rather than run, though both should work. See the shell quoting docs.)

    Broader question ā€“ state of the CLI doc ecosystem

    As JJ mentioned in there comment, the Raku ecosystem is in the process of migrating from p6doc to rakudoc source, and neither is 100% where it should be to offer great CLI/REPL documentation. It's definitely a work in progress and an area where we need to improve. Installing rakudoc (with zef install 'rakudoc:auth<github:Raku>') might offer a better experience but, as I said, it's something the community is still working on. PRs welcome!

    In the meantime, another option for offline access to the docs is to build the docs locally (instructions in the raku/doc README) and run a local server. This requires either docker or perl, graphviz, and nodejs (and we're also working to slim down those requirements). That way, while you'd still need to switch to a browser to check the docs, at least having slow/no Internet access wouldn't be a problem.

    Other options for info in the REPL

    You mentioned the idea of a function along the lines of help('splice'). Nothing exactly like that currently exists ā€“ though it'd be a good idea for a module. But Raku does provide rich tools for introspection, which can offer much of the same functionality.

    For example, if you wanted to check the order to provide the arguments, you can list all of the 30 (!) signatures for Array.splice with:

    for Array.^lookup('splice').candidatesĀ».signature { .say }
    # if "splice" weren't a multi method, you don't need `.candidatesĀ»`
    

    Some other good introspection methods to know:

    • &say.candidatesĀ».signtaure # same as above, but for independent sub/multi
    • Array.^methodsĀ».name
    • $x.VAR.WHAT # returns Ā«(Scalar)Ā» if $x was assigned rather than bound
    • Rat.^attributesĀ».name # all attributes (public and private)
    • Rat.^attributes.grep({Rat.^has_public_attribute(.name)})Ā».name
    • Array.^mro # All classes Array inherits from
    • Array.^roles
    • Foo.WHY # returns any declarator block for the type/method/sub/attribute

    The last is worth elaborating on: .WHY prints any declarator pod blocks for the item ā€“ that is, any comments in the source code that were made with #| or #= (for the preceding item). It's good practice to include these doc comments in the public items that your module exports, and many modules in the Raku ecosystem do. For a variety of reasons, the Rakudo source code doesn't include #| comments, so .WHY isn't useful for built-in types.

    (In my dream world, we'd see a REPL command such as the help you suggested that combines some filtered version of the output from rakudocs for built-in types with .WHY output for custom types, but we don't have anything like that yet.)