Rosetta Code/Run examples: Difference between revisions

Content added Content deleted
(→‎{{header|Perl 6}}: Substantial upgrades to configurability and capability)
(→‎{{header|Perl 6}}: More switches & updates, roughed in multi-language code, will now run Perl & Python as well as Perl6)
Line 263: Line 263:
=={{header|Perl 6}}==
=={{header|Perl 6}}==
{{works with|Rakudo|2018.03}}
{{works with|Rakudo|2018.03}}
This is a fairly comprehensive task code runner. It is set up to work for Perl 6 at this point, but can be easily tweaked to work with other languages. There is so much variation to the task requirements and calling conventions that it would be problematic to make a general purpose, language agnostic code runner so some configuration is necessary to make it work with other languages.
This is a fairly comprehensive task code runner. It is set up to work for Perl 6 by default, but has basic configurations to run Perl and Python tasks as well. It can be easily tweaked to work with other languages by adding a load-lang('whatever'){} routine similar to the Perl6, Perl and Python ones. (And ensuring that the appropriate compiler is installed and accessible.) There is so much variation to the task requirements and calling conventions that it would be problematic to make a general purpose, language agnostic code runner so some configuration is necessary to make it work with other languages.


By default, this will download the Perl 6 section of any (every) task that has a Perl 6 example, extract the code blocks and attempt to run them. Many tasks require files or user interaction to proceed, others are not complete runnable code blocks (example code fragments), some tasks run forever. To try to deal with and compensate for this, this implementation can load a %resource hash that will: supply input files where necessary, skip unrunnable code fragments, limit long and/or infinite running blocks, supply user interaction code where possible, and skip blocks where user interaction is unavoidable.
By default, this will download the Perl 6 section of any (every) task that has a Perl 6 example, extract the code blocks and attempt to run them. Many tasks require files or user interaction to proceed, others are not complete runnable code blocks (example code fragments), some tasks run forever. To try to deal with and compensate for this, this implementation can load a %resource hash that will: supply input files where necessary, skip unrunnable code fragments, limit long and/or infinite running blocks, supply user interaction code where possible, and skip blocks where user interaction is unavoidable.
Line 284: Line 284:
my %*SUB-MAIN-OPTS = :named-anywhere;
my %*SUB-MAIN-OPTS = :named-anywhere;


unit sub MAIN(
unit sub MAIN( Str $run = '', Bool :f(:$force), Bool :l(:$local), Bool :r(:$remote) );
Str $run = '', # Task or file name
Str :$lang = 'perl6', # Language, default perl6 - should be same as in the <lang *> tags
Int :$skip = 0, # Skip # to continue partially into a list
Bool :f(:$force), # Override any task-skip parameter in %resource hash
Bool :l(:$local), # Only use task code from local cache
Bool :r(:$remote), # Only use code from remote server (refresh local cache)
Bool :q(:$quiet), # Less verbose, don't display source code
Bool :d(:$deps), # Load dependencies if necessary
Bool :p(:$pause), # pause after each task
);


die 'You can select local or remote, but not both...' if $local && $remote;
die 'You can select local or remote, but not both...' if $local && $remote;
Line 290: Line 300:
my $client = HTTP::UserAgent.new;
my $client = HTTP::UserAgent.new;
my $url = 'http://rosettacode.org/mw';
my $url = 'http://rosettacode.org/mw';

my %l = ( # Language specific variables Adjust to suit
language => 'Perl_6', # language category name
exe => 'perl6', # executable name to run perl6 in a shell
ext => '.p6', # file extension for perl6 code
dir => 'perl6', # directory to save tasks to
header => 'Perl 6', # header text
# tags marking blocks of code - spaced out to placate wiki formatter
# and to avoid getting tripped up when trying to run _this_ task
tag => rx/<?after '<lang ' 'perl6' '>' > .*? <?before '</' 'lang>'>/,
);


my %c = ( # text colors
my %c = ( # text colors
Line 310: Line 309:
);
);


my $view = 'xdg-open'; # image viewer, this will open default under Linux
my $view = 'xdg-open'; # image viewer, this will open default under Linux
my %resource = load-resources();
my %l = load-lang($lang); # load languge paramters
my %resource = load-resources($lang);
my $get-tasks = True;
my $get-tasks = True;


Line 320: Line 320:


if $run {
if $run {
if $run.IO.e and $run.IO.f {
if $run.IO.e and $run.IO.f {# is it a file?
@tasks = $run.IO.lines;
@tasks = $run.IO.lines; # yep, treat each line as a task name
} else { # must be a single task name
} else {
@tasks = ($run);
@tasks = ($run); # treat it so
}
}
$get-tasks = False;
$get-tasks = False; # don't need to retreive task names from web
}
}


if $get-tasks { # load tasks from web if no cache is not found, older than one day or forced
if $get-tasks {
if (("%l<language>.tasks".IO.modified//0 - now) > 86400 ) or $remote {
if !"%l<language>.tasks".IO.e or ("%l<language>.tasks".IO.modified - now) > 86400 or $remote {
@tasks = mediawiki-query(
@tasks = mediawiki-query( # get tasks from web
$url, 'pages',
$url, 'pages',
:generator<categorymembers>,
:generator<categorymembers>,
Line 340: Line 340:
"%l<exe>.tasks".IO.spurt: @tasks.sort.join("\n");
"%l<exe>.tasks".IO.spurt: @tasks.sort.join("\n");
} else {
} else {
@tasks = "%l<language>.tasks".IO.slurp;
@tasks = "%l<language>.tasks".IO.slurp; # load tasks from file
}
}
}
}

note "Skipping first $skip tasks..." if $skip;


for @tasks -> $title {
for @tasks -> $title {
# If you want to resume partially into automatic
# downloads, adjust $skip to skip that many tasks
my $skip = 0;
next if $++ < $skip;
next if $++ < $skip;
next unless $title ~~ /\S/; # filter blank lines (from files)
note "Skipping first $skip tasks..." if $skip;
next unless $title ~~ /\S/; # filter blank lines
say $skip + ++$, ") $title";
say $skip + ++$, " $title";


my $name = $title.subst(/<-[-0..9A..Za..z]>/, '_', :g);
my $name = $title.subst(/<-[-0..9A..Za..z]>/, '_', :g);
Line 359: Line 357:


my $entry;
my $entry;
if $remote or (($modified - now) > 86400 * 7) {
if $remote or !"$taskdir/name.txt".IO.e or (($modified - now) > 86400 * 7) {
my $page = $client.get("{ $url }/index.php?title={ uri-escape $title }&action=raw").content;
my $page = $client.get("{ $url }/index.php?title={ uri-escape $title }&action=raw").content;


say %c<warn>, "Whoops, can't find page: $url/$title :check spelling.", %c<clr> and next if $page.elems == 0;
uh-oh("Whoops, can't find page: $url/$title :check spelling.") and next if $page.elems == 0;
say "Getting code from: http://rosettacode.org/wiki/{ $title.subst(' ', '_', :g) }#%l<language>";
say "Getting code from: http://rosettacode.org/wiki/{ $title.subst(' ', '_', :g) }#%l<language>";


my $header = %l<header>; # can't interpolate hash into regex
my $header = %l<header>; # can't interpolate hash into regex
$entry = $page.comb(/'=={{header|' $header '}}==' .+? [<?before \n'=='<-[={]>*'{{header'> || $] /).Str // whoops;
$entry = $page.comb(/'=={{header|' $header '}}==' .+? [<?before \n'=='<-[={]>*'{{header'> || $] /).Str //
uh-oh("No code found\nMay be bad markup");


my $lang = %l<language>; # can't interpolate hash into regex
my $lang = %l<language>; # can't interpolate hash into regex
Line 387: Line 386:


unless @blocks {
unless @blocks {
whoops unless %resource{"$name"}<skip> ~~ /'ok to skip'/;
uh-oh("No code found\nMay be bad markup") unless %resource{"$name"}<skip> ~~ /'ok to skip'/;
say "Skipping $name: ", %resource{"$name"}<skip>, "\n" if %resource{"$name"}<skip>
say "Skipping $name: ", %resource{"$name"}<skip>, "\n" if %resource{"$name"}<skip>
}
}
Line 406: Line 405:
run-it($taskdir, "$name$n");
run-it($taskdir, "$name$n");
}
}
say '=' x 79;
say %c<delim>, '=' x 79, %c<clr>;
pause if $pause;
}
}


Line 428: Line 428:
copy "$current/rc/resources/{$fn}", "./{$fn}"
copy "$current/rc/resources/{$fn}", "./{$fn}"
}
}
dump-code ("$code%l<ext>");
dump-code ("$code%l<ext>") unless $quiet;
check-modules("$code%l<ext>") if %l<language> eq 'Perl_6';
check-dependencies("$code%l<ext>", $lang) if $deps;
my @cmd = %resource{$code}<cmd> ?? |%resource{$code}<cmd> !! "%l<exe> $code%l<ext>\n";
my @cmd = %resource{$code}<cmd> ?? |%resource{$code}<cmd> !! "%l<exe> $code%l<ext>\n";
for @cmd -> $cmd {
for @cmd -> $cmd {
Line 437: Line 437:
chdir $current;
chdir $current;
say "\nDone $code";
say "\nDone $code";
}

sub pause {
prompt "Press enter to procede: >";
# or
# sleep 5;
}
}


Line 449: Line 455:
sub clear { "\r" ~ ' ' x 100 ~ "\r" }
sub clear { "\r" ~ ' ' x 100 ~ "\r" }


sub whoops { say %c<warn>,"{'#' x 79}\n\nNo code found\nMay be bad markup\n\n{'#' x 79}",%c<clr> }
sub uh-oh ($err) { put %c<warn>, "{'#' x 79}\n\n $err \n\n{'#' x 79}", %c<clr> }


multi check-dependencies ($fn, 'perl6') {
sub uh-oh ($err) { put %c<warn>, "{'#' x 79}\n\n$err;\n\n{'#' x 79}", %c<clr> }

sub check-modules ($fn) {
my @use = $fn.IO.slurp.comb(/<?after $$ 'use '> \N+? <?before \h* ';'>/);
my @use = $fn.IO.slurp.comb(/<?after $$ 'use '> \N+? <?before \h* ';'>/);
if +@use {
if +@use {
Line 464: Line 468:
}
}


multi check-dependencies ($fn, $unknown) {
sub load-resources { () } # load resources for finer control
note "Sorry, don't know how to handle dependancies for $unknown language."
</lang>
};

multi load-lang ('perl6') { ( # Language specific variables. Adjust to suit.
language => 'Perl_6', # language category name
exe => 'perl6', # executable name to run perl6 in a shell
ext => '.p6', # file extension for perl6 code
dir => 'perl6', # directory to save tasks to
header => 'Perl 6', # header text
# tags marking blocks of code - spaced out to placate wiki formatter
# and to avoid getting tripped up when trying to run _this_ task
tag => rx/<?after '<lang ' 'perl6' '>' > .*? <?before '</' 'lang>'>/,
) }

multi load-lang ('perl') { (
language => 'Perl',
exe => 'perl',
ext => '.pl',
dir => 'perl',
header => 'Perl',
tag => rx/<?after '<lang ' 'perl' '>' > .*? <?before '</' 'lang>'>/,
) }

multi load-lang ('python') { (
language => 'Python',
exe => 'python',
ext => '.py',
dir => 'python',
header => 'Python',
tag => rx/<?after '<lang ' 'python' '>' > .*? <?before '</' 'lang>'>/,
) }

multi load-lang ($unknown) { die "Sorry, don't know how to handle $unknown language." };

multi load-resources ($unknown) { () };</lang>


{{out}} with command line: '''perl6 RC-run.p6 "Determine if a string is numeric"'''
{{out}} with command line: '''perl6 RC-run.p6 -q "Determine if a string is numeric"'''
<pre>Retrieving tasks
<pre>Retrieving tasks
1 Determine if a string is numeric
1 Determine if a string is numeric
Line 501: Line 539:
===============================================================================</pre>
===============================================================================</pre>
Or, if the full %resource hash is loaded it will automatically feed input parameters to tasks that require them:<br>
Or, if the full %resource hash is loaded it will automatically feed input parameters to tasks that require them:<br>
'''perl6 RC-run.p6 Lucky_and_even_lucky_numbers'''
'''perl6 RC-run.p6 Lucky_and_even_lucky_numbers''' -q
<pre>Retrieving tasks
<pre>Retrieving tasks
1 Lucky_and_even_lucky_numbers
1 Lucky_and_even_lucky_numbers