In Perl 5, I was able to set an option multiple times like in this question:
Perl Getopt Using Same Option Multiple Times
I am wondering if it's possible to do the same with Perl 6 and the MAIN sub ?
If you define your named parameters as an array then it just works :
perl6 -e 'sub MAIN( :#test ) { say #test }' --test=1 --test=2 --test=3
[1 2 3]
Related
Here learning my way around Raku (neé Perl 6), very nice all around. But I sorely miss the magic <> from Perl 5, where you can just:
my $x = <>;
print $x;
while(<>) {
print join(':', split);
}
(read next input line into $x, loop over the rest; input is from the files named as input or standard input if no file given). The "Perl 5 to 6" tutorials/migration guides/... just talk about slurping the whole file, or opening individual files by name. No magic "take input from named files in sequence" I can find.
I want the magic back!
The functionality you're looking for largely exists. This script:
my $x = get();
say "First: $x";
for lines() {
.say
}
Given these inputs files:
$ cat foo
foo line 1
foo line 2
$ cat bar
bar line 1
bar line 2
Will, when invoked as:
raku script.p6 foo bar
Produce the output:
First: foo line 1
foo line 2
bar line 1
bar line 2
It will also take output from $*IN if there aren't files. The only thing that doesn't exist is a single replacement for <>, since that would depend on wantarray-like functionality, which is incompatible with multiple dispatch (and Raku considers multiple dispatch is far more useful).
The zero-arg candidates for get and lines are implemented in terms of $*ARGFILES, a file handle that provides the functionality of taking the files from the argument list or from $*IN - meaning one can pass it to any code that expects a file handle.
Enough magic for you?
sub MAIN( Str $file where *.IO.f )
{
.say for $file.IO.lines.map: *.comb.join(':');
}
I tried for a while to get the fish shell equivalent for the sketch cli initialization commands. Can anyone help?
For fish it the first line seems to work if you remove the '$' character. Second line for the argument passing I've tried removing the $, the quotes, & several different formats. Couldn't find documentation for argument passing initialization in fish.
#!/bin/sh
SKETCH=$(mdfind kMDItemCFBundleIdentifier == 'com.bohemiancoding.sketch3' | head -n 1)
# pass on all given arguments
"$SKETCH/Contents/Resources/sketchtool/bin/sketchtool" "$#"
reference: https://developer.sketch.com/cli/
Try:
set SKETCH (mdfind kMDItemCFBundleIdentifier == 'com.bohemiancoding.sketch3' | head -n 1)
$SKETCH/Contents/Resources/sketchtool/bin/sketchtool $argv
The following Perl 5 script:
use strict;
use warnings;
use Data::Printer;
my #a = (1,2,3,4);
p #a;
gives output:
(note the blue color), whereas this Perl 6 scripts:
use Data::Printer:from<Perl5>;
my #a = 1,2,3,4;
p #a;
gives output:
[
[0] 1,
[1] 2,
[2] 3,
[3] 4
]
but the numbers are not colored (as for the Perl 5 case above).
System information:
$ perl --version
This is perl 5, version 29, subversion 3 (v5.29.3) built for x86_64-linux
$ perl6 -e '.say for $*DISTRO, $*VM, $*PERL.compiler.version'
ubuntu (18.10.Cosmic.Cuttlefish)
moar (2018.11)
v2018.11
This seems to be an issue with version 0.40 of Data::Printer which is the current version on metacpan. If I install version 0.99 from GitHub I get colors with Perl 6 also. See also this issue.
I debugged version 0.40 a little bit, and it seems like the only difference between the call to p #a from Perl 5 version versus the same call from Perl 6, is that the Perl 6 call is called in list context, so wantarray returns true for the Perl 6 call, this apparantly makes Data::Printer turn off coloring somehow.
I'm trying to import a Perl5 module I really like https://metacpan.org/pod/Data::Printer
using advice from the manual page https://modules.perl6.org/dist/Inline::Perl5:cpan:NINE
using a very simple script
use Inline::Perl5;
my $p5 = Inline::Perl5.new;
$p5.use('Data::Printer');
but then I get this error:
Unsupported type NativeCall::Types::Pointer<94774650480224> in p5_to_p6
in method p5_to_p6_type at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 298
in method unpack_return_values at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 375
in method invoke at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 446
in method import at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 776
in method use at /usr/lib/perl6/site/sources/130449F27E85303EEC9A19017246A5ED249F99E4 (Inline::Perl5) line 898
in block <unit> at inline_perl5.p6 line 4
what is going wrong here? How can I import this perl5 module into perl6? I would also be happy if there is a similar way to get the colored/tabbed output in Perl6 like I would get from Data::Printer because I can't find it.
EDIT: This is solved here: how to load Perl5's Data::Printer in Perl6?
I think you stumbled on a bug in Inline::Perl5 that seems to happen for the Data::Printer Perl 5 module, so I would suggest you open an issue for it at https://github.com/niner/Inline-Perl5/issues .
Meanwhile, the syntax has become much simpler. Once you have Inline::Perl5 installed, you only need to add the :from<Perl5> adverb to load a module from Perl 5:
use Data::Printer:from<Perl5>;
Unfortunately, at this moment that creates the same error that you already described:
===SORRY!===
Unsupported type NativeCall::Types::Pointer<140393737675456> in p5_to_p6
So I don't think there is a solution this that wouldn't require an upgrade of either Inline::Perl5 or Rakudo Perl 6.
From the github page, https://github.com/niner/Inline-Perl5/issues/128
> perl6 -Ilib -e 'use Data::Printer:from<Perl5>; my #a = 1, 2, [3, 4, ${a => 1}]; p #a'
[
[0] 1,
[1] 2,
[2] [
[0] 3,
[1] 4,
[2] {
a 1
} (tied to Perl6::Hash)
]
]
I'm not particularly happy with this though. This is much more complicated than perl5 would have been. One of the main points of using Perl6 over Perl5 is simpler use and syntax. This isn't it. The 'Inline::Perl5' module should be able to be loaded within the script like every other module, not as an option at the command line.
I've been previously working only with bash regular expressions, grep, sed, awk etc. After trying Perl 6 regexes I've got an impression that they work slower than I would expect, but probably the reason is that I handle them incorrectly.
I've made a simple test to compare similar operations in Perl 6 and in bash. Here is the Perl 6 code:
my #array = "aaaaa" .. "fffff";
say +#array; # 7776 = 6 ** 5
my #search = <abcde cdeff fabcd>;
my token search {
#search
}
my #new_array = #array.grep({/ <search> /});
say #new_array;
Then I printed #array into a file named array (with 7776 lines), made a file named search with 3 lines (abcde, cdeff, fabcd) and made a simple grep search.
$ grep -f search array
After both programs produced the same result, as expected, I measured the time they were working.
$ time perl6 search.p6
real 0m6,683s
user 0m6,724s
sys 0m0,044s
$ time grep -f search array
real 0m0,009s
user 0m0,008s
sys 0m0,000s
So, what am I doing wrong in my Perl 6 code?
UPD: If I pass the search tokens to grep, looping through the #search array, the program works much faster:
my #array = "aaaaa" .. "fffff";
say +#array;
my #search = <abcde cdeff fabcd>;
for #search -> $token {
say ~#array.grep({/$token/});
}
$ time perl6 search.p6
real 0m1,378s
user 0m1,400s
sys 0m0,052s
And if I define each search pattern manually, it works even faster:
my #array = "aaaaa" .. "fffff";
say +#array; # 7776 = 6 ** 5
say ~#array.grep({/abcde/});
say ~#array.grep({/cdeff/});
say ~#array.grep({/fabcd/});
$ time perl6 search.p6
real 0m0,587s
user 0m0,632s
sys 0m0,036s
The grep command is much simpler than Perl 6's regular expressions, and it has had many more years to get optimized. It is also one of the areas that hasn't seen as much optimizing in Rakudo; partly because it is seen as being a difficult thing to work on.
For a more performant example, you could pre-compile the regex:
my $search = "/#search.join('|')/".EVAL;
# $search = /abcde|cdeff|fabcd/;
say ~#array.grep($search);
That change causes it to run in about half a second.
If there is any chance of malicious data in #search, and you have to do this it may be safer to use:
"/#search».Str».perl.join('|')/".EVAL
The compiler can't quite generate that optimized code for /#search/ as #search could change after the regex gets compiled. What could happen is that the first time the regex is used it gets re-compiled into the better form, and then cache it as long as #search doesn't get modified.
(I think Perl 5 does something similar)
One important fact you have to keep in mind is that a regex in Perl 6 is just a method that is written in a domain specific sub-language.