13

I mean usable in one-liners. For example this:

raku -e 'dir(".")==>say()'

prints all files and directories in the current directory. How do I update it so it works recursively (without libraries and/or user-defined routines)? Or is it not possible?

I saw the :recursive flag mentioned somewhere, but that doesn't work:

> raku -e 'dir(".", :recursive)==>say()'
Cannot resolve caller dir(Str:D, :recursive); none of these signatures matches:
    (IO(Any) $path, Mu :$test!)
    (IO(Any) $path)
    (Mu :$test!)
    ()
  in block <unit> at -e line 1

It could be useful in environments with missing shell tools (on Windows) or with different versions/forks of common tools.

3 Answers 3

14

Documentation for &?BLOCK actually gives its example for your use case, so here is a way:

for '.' {
    .Str.say when !.IO.d;
    .IO.dir()».&?BLOCK when .IO.d # let's recurse a little! 
}
  • it starts from the current directory '.'
  • if it's not a directory (!.IO.d), then stringify and print
  • else, it's a directory; so get the .dir of that and repeat this procedure recursively (thanks to &?BLOCK) over all contents (thanks to >>) of this directory

This can be rearranged and modified a little to get

!.IO.d ?? .put !! .IO.dir».&?BLOCK for "."
  • the 2 when checks are unified into a ternary since they are collectively exhaustive and mutually exclusive
  • .Str.say is actually .Str.gist.put but put would be already stringifying and the gist of a string is itself, so .Str.say is reducible to .put
  • no need for parantheses after dir to disambiguate it from anything, so we erase that as well
  • we switch to the statement modifier version of the for loop since we have a single statement going on
  • here no curlies are present but there is still a block attached to the for loop (comprising of that single statement), so &?BLOCK still works
6
  • Thanks for providing an explanation! On another note, does SO already support syntax highlighting for Raku? It seems to be the case now.
    – uzluisf
    Commented Jun 7, 2023 at 16:24
  • 2
    hi @uzluisf, thanks for the response and the edits. i've used "lang-raku" in a hope to color the code for a couple of times now and it seemed to work, yet with your query i looked at the HTML of this page and see "hljs language-ruby"... so unfortunately no support yet it seems. (not listed in here but this exists; not sure how easy it is to take some action there for the support.) Commented Jun 7, 2023 at 16:42
  • 1
    You're welcome, @Mustafa Aydın! That makes sense, I've seen lang-perl being used to get around that since both Raku and Perl share quite a bit of syntax. It's interesting that lang-raku gets turned into syntax highlighting for Ruby
    – uzluisf
    Commented Jun 7, 2023 at 20:34
  • 1
    Maybe cherry pick from {.d ?? .dir».&?BLOCK !! $_}('.'.IO)? I DRY'd the .IO. Eliminated double negative (! and !!). Yielded $_ instead of running .put. (» semantics mean .put may (actually technically should) list files in random order. That may not be OK. Yielded values are kept ordered). I topicalized with (...) rather than for which was a poor choice in the doc example imo. Also, for your code to work with ==>say(), it needs to be an expression, not a statement. You may as well invoke the block rather than use a for which would then need to be wrapped in parens.
    – raiph
    Commented Jun 8, 2023 at 12:19
  • 1
    so as a 1-liner raku -e '{.d ?? .dir».&?BLOCK !! .put}(".".IO)' ? maybe
    – librasteve
    Commented Jun 9, 2023 at 21:03
11

There is no quick solution in Raku core.

There are several solutions in the Raku ecosystem. Personally, I prefer paths. But then I'm the author of that module, and thus biased :-)

EDIT:

$ zef install paths
$ raku -Mpaths -e '.say for paths'
4
  • 3
    so that's raku -e 'use paths; .say for paths(:recurse)'
    – librasteve
    Commented Jun 7, 2023 at 18:19
  • is paths module in the standard rakudo distribution?
    – librasteve
    Commented Jun 7, 2023 at 18:20
  • 1
    @librasteve or maybe: raku -Mpaths -e '.say for paths(:recurse);' Commented Jun 7, 2023 at 19:24
  • Well, it works. But is not without external dependencies. I can't just say "use this one-liner in Raku", I have to also write a script or description how to install the library (and how to install zef, because you can have rakudo without it...). Why isn't this functionality part of Raku standard library? I thought focus of Raku was (at least in part) on scripting. Its often very terse syntax is ideal for powerful one-liners.
    – menfon
    Commented Jun 8, 2023 at 10:14
9

Adapting the answer from the Raku Docs:

~$ raku -e 'my @stack = ".".IO;
            my $all-files = gather while @stack {
              with @stack.pop {
                when :d { @stack.append: .dir };
                .take
              };
            };
            $all-files.join("\n").put;'

Of course, with Raku you don't have to worry about mashing that answer onto one physical line:

~$ raku -e 'my @stack = ".".IO; my $all-files = gather while @stack { with @stack.pop { when :d { @stack.append: .dir }; .take }; }; $all-files.join("\n").put;'

Note, in the one-liner each closing-} curlie is followed by a semicolon. Raku makes them optional if followed immediately by a newline (at least that's how I understand it). See link below.

https://docs.raku.org/language/syntax#Separating_Statements_with_Semicolons

Not the answer you're looking for? Browse other questions tagged or ask your own question.