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.

uzluisf
  • 2,586
  • 1
  • 9
  • 27
menfon
  • 1,587
  • 1
  • 11
  • 28

3 Answers3

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
uzluisf
  • 2,586
  • 1
  • 9
  • 27
Mustafa Aydın
  • 17,645
  • 4
  • 15
  • 38
  • Thanks for providing an explanation! On another note, does SO already support syntax highlighting for Raku? It seems to be the case now. – uzluisf Jun 07 '23 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](https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md) but [this](https://github.com/highlightjs/highlightjs-raku) exists; not sure how easy it is to take some action there for the support.) – Mustafa Aydın Jun 07 '23 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 Jun 07 '23 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 Jun 08 '23 at 12:19
  • 1
    so as a 1-liner ```raku -e '{.d ?? .dir».&?BLOCK !! .put}(".".IO)'``` ? maybe – librasteve Jun 09 '23 at 21:03
  • @librasteve Maybe, but that would still have the problem that *`»` is specified to iterate in randomized order*. (Even if some version of Rakudo happens to iterate sequentially instead.) One way to solve that is to return values like I did (because hypers return values in the same order as the input). Another way is to not use `»` but instead a "regular" mapping function which is all that is functionally wanted anyway. For example, `raku -e '{.d ?? .dir.map(&?BLOCK).eager !! .put}(".".IO)'` would work. (`map` is lazy so one has to explicitly force eager evaluation.) Not concise imo, but works. – raiph Jun 10 '23 at 19:18
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'
Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
  • 3
    so that's ```raku -e 'use paths; .say for paths(:recurse)'``` – librasteve Jun 07 '23 at 18:19
  • is paths module in the standard rakudo distribution? – librasteve Jun 07 '23 at 18:20
  • 1
    @librasteve or maybe: `raku -Mpaths -e '.say for paths(:recurse);'` – jubilatious1 Jun 07 '23 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 Jun 08 '23 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

jubilatious1
  • 1,999
  • 10
  • 18