mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 17:50:22 +00:00
Add a bunch of Perl 6 sample files
This commit is contained in:
97
samples/Perl6/01-dash-uppercase-i.t
Normal file
97
samples/Perl6/01-dash-uppercase-i.t
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
=begin pod
|
||||||
|
|
||||||
|
Test handling of -I.
|
||||||
|
|
||||||
|
Multiple C<-I> switches are supposed to
|
||||||
|
prepend left-to-right:
|
||||||
|
|
||||||
|
-Ifoo -Ibar
|
||||||
|
|
||||||
|
should make C<@*INC> look like:
|
||||||
|
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
...
|
||||||
|
|
||||||
|
Duplication of directories on the command line is mirrored
|
||||||
|
in the C<@*INC> variable, so C<pugs -Ilib -Ilib> will have B<two>
|
||||||
|
entries C<lib/> in C<@*INC>.
|
||||||
|
|
||||||
|
=end pod
|
||||||
|
|
||||||
|
# L<S19/Reference/"Prepend directories to">
|
||||||
|
|
||||||
|
my $fragment = '-e "@*INC.perl.say"';
|
||||||
|
|
||||||
|
my @tests = (
|
||||||
|
'foo',
|
||||||
|
'foo$bar',
|
||||||
|
'foo bar$baz',
|
||||||
|
'foo$foo',
|
||||||
|
);
|
||||||
|
|
||||||
|
plan @tests*2;
|
||||||
|
|
||||||
|
diag "Running under $*OS";
|
||||||
|
|
||||||
|
my ($pugs,$redir) = ($*EXECUTABLE_NAME, ">");
|
||||||
|
|
||||||
|
if $*OS eq any <MSWin32 mingw msys cygwin> {
|
||||||
|
$pugs = 'pugs.exe';
|
||||||
|
$redir = '>';
|
||||||
|
};
|
||||||
|
|
||||||
|
sub nonce () { return (".{$*PID}." ~ (1..1000).pick) }
|
||||||
|
|
||||||
|
sub run_pugs ($c) {
|
||||||
|
my $tempfile = "temp-ex-output" ~ nonce;
|
||||||
|
my $command = "$pugs $c $redir $tempfile";
|
||||||
|
diag $command;
|
||||||
|
run $command;
|
||||||
|
my $res = slurp $tempfile;
|
||||||
|
unlink $tempfile;
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
for @tests -> $t {
|
||||||
|
my @dirs = split('$',$t);
|
||||||
|
my $command;
|
||||||
|
# This should be smarter about quoting
|
||||||
|
# (currently, this should work for WinNT and Unix shells)
|
||||||
|
$command = join " ", map { qq["-I$_"] }, @dirs;
|
||||||
|
my $got = run_pugs( $command ~ " $fragment" );
|
||||||
|
$got .= chomp;
|
||||||
|
|
||||||
|
if (substr($got,0,1) ~~ "[") {
|
||||||
|
# Convert from arrayref to array
|
||||||
|
$got = substr($got, 1, -1);
|
||||||
|
};
|
||||||
|
|
||||||
|
my @got = EVAL $got;
|
||||||
|
@got = @got[ 0..@dirs-1 ];
|
||||||
|
my @expected = @dirs;
|
||||||
|
|
||||||
|
is @got, @expected, "'" ~ @dirs ~ "' works";
|
||||||
|
|
||||||
|
$command = join " ", map { qq[-I "$_"] }, @dirs;
|
||||||
|
$got = run_pugs( $command ~ " $fragment" );
|
||||||
|
|
||||||
|
$got .= chomp;
|
||||||
|
if (substr($got,0,1) ~~ "[") {
|
||||||
|
# Convert from arrayref to array
|
||||||
|
$got = substr($got, 1, -1);
|
||||||
|
};
|
||||||
|
|
||||||
|
@got = EVAL $got;
|
||||||
|
@got = @got[ 0..@dirs-1 ];
|
||||||
|
@expected = @dirs;
|
||||||
|
|
||||||
|
is @got, @expected, "'" ~ @dirs ~ "' works (with a space delimiting -I)";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
223
samples/Perl6/01-parse.t
Normal file
223
samples/Perl6/01-parse.t
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
use v6;
|
||||||
|
BEGIN { @*INC.push('lib') };
|
||||||
|
|
||||||
|
use JSON::Tiny::Grammar;
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
my @t =
|
||||||
|
'{}',
|
||||||
|
'{ }',
|
||||||
|
' { } ',
|
||||||
|
'{ "a" : "b" }',
|
||||||
|
'{ "a" : null }',
|
||||||
|
'{ "a" : true }',
|
||||||
|
'{ "a" : false }',
|
||||||
|
'{ "a" : { } }',
|
||||||
|
'[]',
|
||||||
|
'[ ]',
|
||||||
|
' [ ] ',
|
||||||
|
# stolen from JSON::XS, 18_json_checker.t, and adapted a bit
|
||||||
|
Q<<[
|
||||||
|
"JSON Test Pattern pass1",
|
||||||
|
{"object with 1 member":["array with 1 element"]},
|
||||||
|
{},
|
||||||
|
[]
|
||||||
|
]>>,
|
||||||
|
Q<<[1]>>,
|
||||||
|
Q<<[true]>>,
|
||||||
|
Q<<[-42]>>,
|
||||||
|
Q<<[-42,true,false,null]>>,
|
||||||
|
Q<<{ "integer": 1234567890 }>>,
|
||||||
|
Q<<{ "real": -9876.543210 }>>,
|
||||||
|
Q<<{ "e": 0.123456789e-12 }>>,
|
||||||
|
Q<<{ "E": 1.234567890E+34 }>>,
|
||||||
|
Q<<{ "": 23456789012E66 }>>,
|
||||||
|
Q<<{ "zero": 0 }>>,
|
||||||
|
Q<<{ "one": 1 }>>,
|
||||||
|
Q<<{ "space": " " }>>,
|
||||||
|
Q<<{ "quote": "\""}>>,
|
||||||
|
Q<<{ "backslash": "\\"}>>,
|
||||||
|
Q<<{ "controls": "\b\f\n\r\t"}>>,
|
||||||
|
Q<<{ "slash": "/ & \/"}>>,
|
||||||
|
Q<<{ "alpha": "abcdefghijklmnopqrstuvwyz"}>>,
|
||||||
|
Q<<{ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ"}>>,
|
||||||
|
Q<<{ "digit": "0123456789"}>>,
|
||||||
|
Q<<{ "0123456789": "digit"}>>,
|
||||||
|
Q<<{"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?"}>>,
|
||||||
|
Q<<{"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A"}>>,
|
||||||
|
Q<<{"true": true}>>,
|
||||||
|
Q<<{"false": false}>>,
|
||||||
|
Q<<{"null": null}>>,
|
||||||
|
Q<<{"array":[ ]}>>,
|
||||||
|
Q<<{"object":{ }}>>,
|
||||||
|
Q<<{"address": "50 St. James Street"}>>,
|
||||||
|
Q<<{"url": "http://www.JSON.org/"}>>,
|
||||||
|
Q<<{"comment": "// /* <!-- --"}>>,
|
||||||
|
Q<<{"# -- --> */": " "}>>,
|
||||||
|
Q<<{ " s p a c e d " :[1,2 , 3
|
||||||
|
|
||||||
|
,
|
||||||
|
|
||||||
|
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7]}>>,
|
||||||
|
|
||||||
|
Q<<{"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}"}>>,
|
||||||
|
Q<<{"quotes": "" \u0022 %22 0x22 034 ""}>>,
|
||||||
|
Q<<{ "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||||
|
: "A key can be any string"
|
||||||
|
}>>,
|
||||||
|
Q<<[ 0.5 ,98.6
|
||||||
|
,
|
||||||
|
99.44
|
||||||
|
,
|
||||||
|
|
||||||
|
1066,
|
||||||
|
1e1,
|
||||||
|
0.1e1
|
||||||
|
]>>,
|
||||||
|
Q<<[1e-1]>>,
|
||||||
|
Q<<[1e00,2e+00,2e-00,"rosebud"]>>,
|
||||||
|
Q<<[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]>>,
|
||||||
|
Q<<{
|
||||||
|
"JSON Test Pattern pass3": {
|
||||||
|
"The outermost value": "must be an object or array.",
|
||||||
|
"In this test": "It is an object."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>,
|
||||||
|
# from http://www.json.org/example.html
|
||||||
|
Q<<{
|
||||||
|
"glossary": {
|
||||||
|
"title": "example glossary",
|
||||||
|
"GlossDiv": {
|
||||||
|
"title": "S",
|
||||||
|
"GlossList": {
|
||||||
|
"GlossEntry": {
|
||||||
|
"ID": "SGML",
|
||||||
|
"SortAs": "SGML",
|
||||||
|
"GlossTerm": "Standard Generalized Markup Language",
|
||||||
|
"Acronym": "SGML",
|
||||||
|
"Abbrev": "ISO 8879:1986",
|
||||||
|
"GlossDef": {
|
||||||
|
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||||
|
"GlossSeeAlso": ["GML", "XML"]
|
||||||
|
},
|
||||||
|
"GlossSee": "markup"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>>,
|
||||||
|
Q<<{"menu": {
|
||||||
|
"id": "file",
|
||||||
|
"value": "File",
|
||||||
|
"popup": {
|
||||||
|
"menuitem": [
|
||||||
|
{"value": "New", "onclick": "CreateNewDoc()"},
|
||||||
|
{"value": "Open", "onclick": "OpenDoc()"},
|
||||||
|
{"value": "Close", "onclick": "CloseDoc()"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}>>,
|
||||||
|
Q<<{"widget": {
|
||||||
|
"debug": "on",
|
||||||
|
"window": {
|
||||||
|
"title": "Sample Konfabulator Widget",
|
||||||
|
"name": "main_window",
|
||||||
|
"width": 500,
|
||||||
|
"height": 500
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"src": "Images/Sun.png",
|
||||||
|
"name": "sun1",
|
||||||
|
"hOffset": 250,
|
||||||
|
"vOffset": 250,
|
||||||
|
"alignment": "center"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"data": "Click Here",
|
||||||
|
"size": 36,
|
||||||
|
"style": "bold",
|
||||||
|
"name": "text1",
|
||||||
|
"hOffset": 250,
|
||||||
|
"vOffset": 100,
|
||||||
|
"alignment": "center",
|
||||||
|
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||||
|
}
|
||||||
|
}}>>,
|
||||||
|
;
|
||||||
|
|
||||||
|
my @n =
|
||||||
|
'{ ',
|
||||||
|
'{ 3 : 4 }',
|
||||||
|
'{ 3 : tru }', # not quite true
|
||||||
|
'{ "a : false }', # missing quote
|
||||||
|
# stolen from JSON::XS, 18_json_checker.t
|
||||||
|
Q<<"A JSON payload should be an object or array, not a string.">>,
|
||||||
|
Q<<{"Extra value after close": true} "misplaced quoted value">>,
|
||||||
|
Q<<{"Illegal expression": 1 + 2}>>,
|
||||||
|
Q<<{"Illegal invocation": alert()}>>,
|
||||||
|
Q<<{"Numbers cannot have leading zeroes": 013}>>,
|
||||||
|
Q<<{"Numbers cannot be hex": 0x14}>>,
|
||||||
|
Q<<["Illegal backslash escape: \x15"]>>,
|
||||||
|
Q<<[\naked]>>,
|
||||||
|
Q<<["Illegal backslash escape: \017"]>>,
|
||||||
|
# skipped: wo don't implement no stinkin' aritifical limits.
|
||||||
|
# Q<<[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>>,
|
||||||
|
Q<<{"Missing colon" null}>>,
|
||||||
|
Q<<["Unclosed array">>,
|
||||||
|
Q<<{"Double colon":: null}>>,
|
||||||
|
Q<<{"Comma instead of colon", null}>>,
|
||||||
|
Q<<["Colon instead of comma": false]>>,
|
||||||
|
Q<<["Bad value", truth]>>,
|
||||||
|
Q<<['single quote']>>,
|
||||||
|
qq<["\ttab\tcharacter in string "]>,
|
||||||
|
Q<<["line
|
||||||
|
break"]>>,
|
||||||
|
Q<<["line\
|
||||||
|
break"]>>,
|
||||||
|
Q<<[0e]>>,
|
||||||
|
Q<<{unquoted_key: "keys must be quoted"}>>,
|
||||||
|
Q<<[0e+]>>,
|
||||||
|
Q<<[0e+-1]>>,
|
||||||
|
Q<<{"Comma instead if closing brace": true,>>,
|
||||||
|
Q<<["mismatch"}>>,
|
||||||
|
Q<<["extra comma",]>>,
|
||||||
|
Q<<["double extra comma",,]>>,
|
||||||
|
Q<<[ , "<-- missing value"]>>,
|
||||||
|
Q<<["Comma after the close"],>>,
|
||||||
|
Q<<["Extra close"]]>>,
|
||||||
|
Q<<{"Extra comma": true,}>>,
|
||||||
|
;
|
||||||
|
|
||||||
|
plan (+@t) + (+@n);
|
||||||
|
|
||||||
|
my $i = 0;
|
||||||
|
for @t -> $t {
|
||||||
|
my $desc = $t;
|
||||||
|
if $desc ~~ m/\n/ {
|
||||||
|
$desc .= subst(/\n.*$/, "\\n...[$i]");
|
||||||
|
}
|
||||||
|
my $parsed = 0;
|
||||||
|
try {
|
||||||
|
JSON::Tiny::Grammar.parse($t)
|
||||||
|
and $parsed = 1;
|
||||||
|
}
|
||||||
|
ok $parsed, "JSON string «$desc» parsed";
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for @n -> $t {
|
||||||
|
my $desc = $t;
|
||||||
|
if $desc ~~ m/\n/ {
|
||||||
|
$desc .= subst(/\n.*$/, "\\n...[$i]");
|
||||||
|
}
|
||||||
|
my $parsed = 0;
|
||||||
|
try { JSON::Tiny::Grammar.parse($t) and $parsed = 1 };
|
||||||
|
nok $parsed, "NOT parsed «$desc»";
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
|
|
||||||
9
samples/Perl6/A.pm
Normal file
9
samples/Perl6/A.pm
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# used in t/spec/S11-modules/nested.t
|
||||||
|
|
||||||
|
BEGIN { @*INC.push('t/spec/packages') };
|
||||||
|
|
||||||
|
module A::A {
|
||||||
|
use A::B;
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
148
samples/Perl6/ANSIColor.pm
Normal file
148
samples/Perl6/ANSIColor.pm
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
module Term::ANSIColor;
|
||||||
|
|
||||||
|
# these will be macros one day, yet macros can't be exported so far
|
||||||
|
sub RESET is export { "\e[0m" }
|
||||||
|
sub BOLD is export { "\e[1m" }
|
||||||
|
sub UNDERLINE is export { "\e[4m" }
|
||||||
|
sub INVERSE is export { "\e[7m" }
|
||||||
|
sub BOLD_OFF is export { "\e[22m" }
|
||||||
|
sub UNDERLINE_OFF is export { "\e[24m" }
|
||||||
|
sub INVERSE_OFF is export { "\e[27m" }
|
||||||
|
|
||||||
|
my %attrs =
|
||||||
|
reset => "0",
|
||||||
|
bold => "1",
|
||||||
|
underline => "4",
|
||||||
|
inverse => "7",
|
||||||
|
black => "30",
|
||||||
|
red => "31",
|
||||||
|
green => "32",
|
||||||
|
yellow => "33",
|
||||||
|
blue => "34",
|
||||||
|
magenta => "35",
|
||||||
|
cyan => "36",
|
||||||
|
white => "37",
|
||||||
|
default => "39",
|
||||||
|
on_black => "40",
|
||||||
|
on_red => "41",
|
||||||
|
on_green => "42",
|
||||||
|
on_yellow => "43",
|
||||||
|
on_blue => "44",
|
||||||
|
on_magenta => "45",
|
||||||
|
on_cyan => "46",
|
||||||
|
on_white => "47",
|
||||||
|
on_default => "49";
|
||||||
|
|
||||||
|
sub color (Str $what) is export {
|
||||||
|
my @res;
|
||||||
|
my @a = $what.split(' ');
|
||||||
|
for @a -> $attr {
|
||||||
|
if %attrs.exists($attr) {
|
||||||
|
@res.push: %attrs{$attr}
|
||||||
|
} else {
|
||||||
|
die("Invalid attribute name '$attr'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "\e[" ~ @res.join(';') ~ "m";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub colored (Str $what, Str $how) is export {
|
||||||
|
color($how) ~ $what ~ color('reset');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub colorvalid (*@a) is export {
|
||||||
|
for @a -> $el {
|
||||||
|
return False unless %attrs.exists($el)
|
||||||
|
}
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub colorstrip (*@a) is export {
|
||||||
|
my @res;
|
||||||
|
for @a -> $str {
|
||||||
|
@res.push: $str.subst(/\e\[ <[0..9;]>+ m/, '', :g);
|
||||||
|
}
|
||||||
|
return @res.join;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub uncolor (Str $what) is export {
|
||||||
|
my @res;
|
||||||
|
my @list = $what.comb(/\d+/);
|
||||||
|
for @list -> $elem {
|
||||||
|
if %attrs.reverse.exists($elem) {
|
||||||
|
@res.push: %attrs.reverse{$elem}
|
||||||
|
} else {
|
||||||
|
die("Bad escape sequence: {'\e[' ~ $elem ~ 'm'}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @res.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
=begin pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Term::ANSIColor - Color screen output using ANSI escape sequences
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Term::ANSIColor;
|
||||||
|
say color('bold'), "this is in bold", color('reset');
|
||||||
|
say colored('underline red on_green', 'what a lovely colours!');
|
||||||
|
say BOLD, 'good to be fat!', BOLD_OFF;
|
||||||
|
say 'ok' if colorvalid('magenta', 'on_black', 'inverse');
|
||||||
|
say '\e[36m is ', uncolor('\e36m');
|
||||||
|
say colorstrip("\e[1mThis is bold\e[0m");
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Term::ANSIColor provides an interface for using colored output
|
||||||
|
in terminals. The following functions are available:
|
||||||
|
|
||||||
|
=head2 C<color()>
|
||||||
|
|
||||||
|
Given a string with color names, the output produced by C<color()>
|
||||||
|
sets the terminal output so the text printed after it will be colored
|
||||||
|
as specified. The following color names are recognised:
|
||||||
|
|
||||||
|
reset bold underline inverse black red green yellow blue
|
||||||
|
magenta cyan white default on_black on_red on_green on_yellow
|
||||||
|
on_blue on_magenta on_cyan on_white on_default
|
||||||
|
|
||||||
|
The on_* family of colors correspond to the background colors.
|
||||||
|
|
||||||
|
=head2 C<colored()>
|
||||||
|
|
||||||
|
C<colored()> is similar to C<color()>. It takes two Str arguments,
|
||||||
|
where the first is the colors to be used, and the second is the string
|
||||||
|
to be colored. The C<reset> sequence is automagically placed after
|
||||||
|
the string.
|
||||||
|
|
||||||
|
=head2 C<colorvalid()>
|
||||||
|
|
||||||
|
C<colorvalid()> gets an array of color specifications (like those
|
||||||
|
passed to C<color()>) and returns true if all of them are valid,
|
||||||
|
false otherwise.
|
||||||
|
|
||||||
|
=head2 C<colorstrip()>
|
||||||
|
|
||||||
|
C<colorstrip>, given a string, removes all the escape sequences
|
||||||
|
in it, leaving the plain text without effects.
|
||||||
|
|
||||||
|
=head2 C<uncolor()>
|
||||||
|
|
||||||
|
Given escape sequences, C<uncolor()> returns a string with readable
|
||||||
|
color names. E.g. passing "\e[36;44m" will result in "cyan on_blue".
|
||||||
|
|
||||||
|
=head1 Constants
|
||||||
|
|
||||||
|
C<Term::ANSIColor> provides constants which are just strings of
|
||||||
|
appropriate escape sequences. The following constants are available:
|
||||||
|
|
||||||
|
RESET BOLD UNDERLINE INVERSE BOLD_OFF UNDERLINE_OFF INVERSE_OFF
|
||||||
|
|
||||||
|
=end pod
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
102
samples/Perl6/Bailador.pm
Normal file
102
samples/Perl6/Bailador.pm
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
use Bailador::App;
|
||||||
|
use Bailador::Request;
|
||||||
|
use Bailador::Response;
|
||||||
|
use Bailador::Context;
|
||||||
|
use HTTP::Easy::PSGI;
|
||||||
|
|
||||||
|
module Bailador;
|
||||||
|
|
||||||
|
my $app = Bailador::App.current;
|
||||||
|
|
||||||
|
our sub import {
|
||||||
|
my $file = callframe(1).file;
|
||||||
|
my $slash = $file.rindex('/');
|
||||||
|
if $slash {
|
||||||
|
$app.location = $file.substr(0, $file.rindex('/'));
|
||||||
|
} else {
|
||||||
|
$app.location = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub route_to_regex($route) {
|
||||||
|
$route.split('/').map({
|
||||||
|
my $r = $_;
|
||||||
|
if $_.substr(0, 1) eq ':' {
|
||||||
|
$r = q{(<-[\/\.]>+)};
|
||||||
|
}
|
||||||
|
$r
|
||||||
|
}).join("'/'");
|
||||||
|
}
|
||||||
|
|
||||||
|
multi parse_route(Str $route) {
|
||||||
|
my $r = route_to_regex($route);
|
||||||
|
return "/ ^ $r \$ /".eval;
|
||||||
|
}
|
||||||
|
|
||||||
|
multi parse_route($route) {
|
||||||
|
# do nothing
|
||||||
|
$route
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get(Pair $x) is export {
|
||||||
|
my $p = parse_route($x.key) => $x.value;
|
||||||
|
$app.add_route: 'GET', $p;
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub post(Pair $x) is export {
|
||||||
|
my $p = parse_route($x.key) => $x.value;
|
||||||
|
$app.add_route: 'POST', $p;
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub request is export { $app.context.request }
|
||||||
|
|
||||||
|
sub content_type(Str $type) is export {
|
||||||
|
$app.response.headers<Content-Type> = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub header(Str $name, Cool $value) is export {
|
||||||
|
$app.response.headers{$name} = ~$value;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub status(Int $code) is export {
|
||||||
|
$app.response.code = $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub template(Str $tmpl, *@params) is export {
|
||||||
|
$app.template($tmpl, @params);
|
||||||
|
}
|
||||||
|
|
||||||
|
our sub dispatch_request(Bailador::Request $r) {
|
||||||
|
return dispatch($r.env);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dispatch($env) {
|
||||||
|
$app.context.env = $env;
|
||||||
|
|
||||||
|
my ($r, $match) = $app.find_route($env);
|
||||||
|
|
||||||
|
if $r {
|
||||||
|
status 200;
|
||||||
|
if $match {
|
||||||
|
$app.response.content = $r.value.(|$match.list);
|
||||||
|
} else {
|
||||||
|
$app.response.content = $r.value.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $app.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dispatch-psgi($env) {
|
||||||
|
return dispatch($env).psgi;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub baile is export {
|
||||||
|
given HTTP::Easy::PSGI.new(port => 3000) {
|
||||||
|
.app(&dispatch-psgi);
|
||||||
|
say "Entering the development dance floor: http://0.0.0.0:3000";
|
||||||
|
.run;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
samples/Perl6/ContainsUnicode.pm
Normal file
7
samples/Perl6/ContainsUnicode.pm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module ContainsUnicode {
|
||||||
|
sub uc-and-join(*@things, :$separator = ', ') is export {
|
||||||
|
@things».uc.join($separator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
1431
samples/Perl6/Exception.pm
Normal file
1431
samples/Perl6/Exception.pm
Normal file
File diff suppressed because it is too large
Load Diff
146
samples/Perl6/Model.pm
Normal file
146
samples/Perl6/Model.pm
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
class Math::Model;
|
||||||
|
|
||||||
|
use Math::RungeKutta;
|
||||||
|
# TODO: only load when needed
|
||||||
|
use SVG;
|
||||||
|
use SVG::Plot;
|
||||||
|
|
||||||
|
has %.derivatives;
|
||||||
|
has %.variables;
|
||||||
|
has %.initials;
|
||||||
|
has @.captures is rw;
|
||||||
|
|
||||||
|
has %!inv = %!derivatives.invert;
|
||||||
|
# in Math::Model all variables are accessible by name
|
||||||
|
# in contrast Math::RungeKutta uses vectors, so we need
|
||||||
|
# to define an (arbitrary) ordering
|
||||||
|
# @!deriv-names holds the names of the derivatives in a fixed
|
||||||
|
# order, sod @!deriv-names[$number] turns the number into a name
|
||||||
|
# %!deriv-keying{$name} translates a name into the corresponding index
|
||||||
|
has @!deriv-names = %!inv.keys;
|
||||||
|
has %!deriv-keying = @!deriv-names Z=> 0..Inf;
|
||||||
|
|
||||||
|
# snapshot of all variables in the current model
|
||||||
|
has %!current-values;
|
||||||
|
|
||||||
|
has %.results;
|
||||||
|
has @.time;
|
||||||
|
|
||||||
|
has $.numeric-error is rw = 0.0001;
|
||||||
|
|
||||||
|
my sub param-names(&c) {
|
||||||
|
&c.signature.params».name».substr(1).grep({ $_ ne '_'});
|
||||||
|
}
|
||||||
|
|
||||||
|
method !params-for(&c) {
|
||||||
|
param-names(&c).map( {; $_ => %!current-values{$_} } ).hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
method topo-sort(*@vars) {
|
||||||
|
my %seen;
|
||||||
|
my @order;
|
||||||
|
sub topo(*@a) {
|
||||||
|
for @a {
|
||||||
|
next if %!inv.exists($_) || %seen{$_} || $_ eq 'time';
|
||||||
|
die "Undeclared variable '$_' used in model"
|
||||||
|
unless %.variables.exists($_);
|
||||||
|
topo(param-names(%.variables{$_}));
|
||||||
|
@order.push: $_;
|
||||||
|
%seen{$_}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
topo(@vars);
|
||||||
|
# say @order.perl;
|
||||||
|
@order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
method integrate(:$from = 0, :$to = 10, :$min-resolution = ($to - $from) / 20, :$verbose) {
|
||||||
|
for %.derivatives -> $d {
|
||||||
|
die "There must be a variable defined for each derivative, missing for '$d.key()'"
|
||||||
|
unless %.variables.exists($d.key) || %!inv.exists($d.key);
|
||||||
|
die "There must be an initial value defined for each derivative target, missing for '$d.value()'"
|
||||||
|
unless %.initials.exists($d.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
%!current-values = %.initials;
|
||||||
|
%!current-values<time> = $from;
|
||||||
|
|
||||||
|
my @vars-topo = self.topo-sort(%.variables.keys);
|
||||||
|
sub update-current-values($time, @values) {
|
||||||
|
%!current-values<time> = $time;
|
||||||
|
%!current-values{@!deriv-names} = @values;
|
||||||
|
for @vars-topo {
|
||||||
|
my $c = %.variables{$_};
|
||||||
|
%!current-values{$_} = $c.(|self!params-for($c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my @initial = %.initials{@!deriv-names};
|
||||||
|
|
||||||
|
sub derivatives($time, @values) {
|
||||||
|
update-current-values($time, @values);
|
||||||
|
my @r;
|
||||||
|
for %!inv{@!deriv-names} {
|
||||||
|
my $v = %.variables{$_};
|
||||||
|
@r.push: $v.defined
|
||||||
|
?? $v(|self!params-for($v))
|
||||||
|
!! %!current-values{$_};
|
||||||
|
}
|
||||||
|
@r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@!time = ();
|
||||||
|
for @.captures {
|
||||||
|
%!results{$_} = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub record($time, @values) {
|
||||||
|
update-current-values($time, @values);
|
||||||
|
@!time.push: $time;
|
||||||
|
say $time if $verbose;
|
||||||
|
|
||||||
|
for @.captures {
|
||||||
|
%!results{$_}.push: %!current-values{$_};;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record($from, %.initials{@!deriv-names});
|
||||||
|
|
||||||
|
adaptive-rk-integrate(
|
||||||
|
:$from,
|
||||||
|
:$to,
|
||||||
|
:@initial,
|
||||||
|
:derivative(&derivatives),
|
||||||
|
:max-stepsize($min-resolution),
|
||||||
|
:do(&record),
|
||||||
|
:epsilon($.numeric-error),
|
||||||
|
);
|
||||||
|
%!results;
|
||||||
|
}
|
||||||
|
|
||||||
|
method render-svg(
|
||||||
|
$filename,
|
||||||
|
:$x-axis = 'time',
|
||||||
|
:$width = 800,
|
||||||
|
:$height = 600,
|
||||||
|
:$title = 'Model output') {
|
||||||
|
my $f = open $filename, :w
|
||||||
|
or die "Can't open file '$filename' for writing: $!";
|
||||||
|
my @values = map { %!results{$_} }, @.captures.grep({ $_ ne $x-axis});
|
||||||
|
my @x = $x-axis eq 'time' ?? @!time !! %!results{$x-axis}.flat;
|
||||||
|
my $svg = SVG::Plot.new(
|
||||||
|
:$width,
|
||||||
|
:$height,
|
||||||
|
:@x,
|
||||||
|
:@values,
|
||||||
|
:$title,
|
||||||
|
).plot(:xy-lines);
|
||||||
|
$f.say(SVG.serialize($svg));
|
||||||
|
$f.close;
|
||||||
|
say "Wrote ouput to '$filename'";
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
317
samples/Perl6/Simple.pm
Normal file
317
samples/Perl6/Simple.pm
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
# ----------------------
|
||||||
|
# LWP::Simple for Perl 6
|
||||||
|
# ----------------------
|
||||||
|
use v6;
|
||||||
|
use MIME::Base64;
|
||||||
|
use URI;
|
||||||
|
|
||||||
|
class LWP::Simple:auth<cosimo>:ver<0.085>;
|
||||||
|
|
||||||
|
our $VERSION = '0.085';
|
||||||
|
|
||||||
|
enum RequestType <GET POST>;
|
||||||
|
|
||||||
|
has Str $.default_encoding = 'utf-8';
|
||||||
|
our $.class_default_encoding = 'utf-8';
|
||||||
|
|
||||||
|
# these were intended to be constant but that hit pre-compilation issue
|
||||||
|
my Buf $crlf = Buf.new(13, 10);
|
||||||
|
my Buf $http_header_end_marker = Buf.new(13, 10, 13, 10);
|
||||||
|
my Int constant $default_stream_read_len = 2 * 1024;
|
||||||
|
|
||||||
|
method base64encode ($user, $pass) {
|
||||||
|
my MIME::Base64 $mime .= new();
|
||||||
|
my $encoded = $mime.encode_base64($user ~ ':' ~ $pass);
|
||||||
|
return $encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
method get (Str $url) {
|
||||||
|
self.request_shell(RequestType::GET, $url)
|
||||||
|
}
|
||||||
|
|
||||||
|
method post (Str $url, %headers = {}, Any $content?) {
|
||||||
|
self.request_shell(RequestType::POST, $url, %headers, $content)
|
||||||
|
}
|
||||||
|
|
||||||
|
method request_shell (RequestType $rt, Str $url, %headers = {}, Any $content?) {
|
||||||
|
|
||||||
|
return unless $url;
|
||||||
|
|
||||||
|
my ($scheme, $hostname, $port, $path, $auth) = self.parse_url($url);
|
||||||
|
|
||||||
|
%headers{'Connection'} = 'close';
|
||||||
|
%headers{'User-Agent'} //= "LWP::Simple/$VERSION Perl6/$*PERL<compiler><name>";
|
||||||
|
|
||||||
|
if $auth {
|
||||||
|
$hostname = $auth<host>;
|
||||||
|
my $user = $auth<user>;
|
||||||
|
my $pass = $auth<password>;
|
||||||
|
my $base64enc = self.base64encode($user, $pass);
|
||||||
|
%headers<Authorization> = "Basic $base64enc";
|
||||||
|
}
|
||||||
|
|
||||||
|
%headers<Host> = $hostname;
|
||||||
|
|
||||||
|
if ($rt ~~ RequestType::POST && $content.defined) {
|
||||||
|
# Attach Content-Length header
|
||||||
|
# as recommended in RFC2616 section 14.3.
|
||||||
|
# Note: Empty content is also a content,
|
||||||
|
# header value equals to zero is valid.
|
||||||
|
%headers{'Content-Length'} = $content.encode.bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($status, $resp_headers, $resp_content) =
|
||||||
|
self.make_request($rt, $hostname, $port, $path, %headers, $content);
|
||||||
|
|
||||||
|
given $status {
|
||||||
|
|
||||||
|
when / 30 <[12]> / {
|
||||||
|
my %resp_headers = $resp_headers.hash;
|
||||||
|
my $new_url = %resp_headers<Location>;
|
||||||
|
if ! $new_url {
|
||||||
|
die "Redirect $status without a new URL?";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Watch out for too many redirects.
|
||||||
|
# Need to find a way to store a class member
|
||||||
|
#if $redirects++ > 10 {
|
||||||
|
# say "Too many redirects!";
|
||||||
|
# return;
|
||||||
|
#}
|
||||||
|
|
||||||
|
return self.request_shell($rt, $new_url, %headers, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
when /200/ {
|
||||||
|
# should be fancier about charset decoding application - someday
|
||||||
|
if $resp_headers<Content-Type> &&
|
||||||
|
$resp_headers<Content-Type> ~~
|
||||||
|
/ $<media-type>=[<-[/;]>+]
|
||||||
|
[ <[/]> $<media-subtype>=[<-[;]>+] ]? / &&
|
||||||
|
( $<media-type> eq 'text' ||
|
||||||
|
( $<media-type> eq 'application' &&
|
||||||
|
$<media-subtype> ~~ /[ ecma | java ]script | json/
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
my $charset =
|
||||||
|
($resp_headers<Content-Type> ~~ /charset\=(<-[;]>*)/)[0];
|
||||||
|
$charset = $charset ?? $charset.Str !!
|
||||||
|
self ?? $.default_encoding !! $.class_default_encoding;
|
||||||
|
return $resp_content.decode($charset);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $resp_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Response failed
|
||||||
|
default {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
method parse_chunks(Blob $b is rw, IO::Socket::INET $sock) {
|
||||||
|
my Int ($line_end_pos, $chunk_len, $chunk_start) = (0) xx 3;
|
||||||
|
my Blob $content = Blob.new();
|
||||||
|
|
||||||
|
# smallest valid chunked line is 0CRLFCRLF (ascii or other 8bit like EBCDIC)
|
||||||
|
while ($line_end_pos + 5 <= $b.bytes) {
|
||||||
|
while ( $line_end_pos +4 <= $b.bytes &&
|
||||||
|
$b.subbuf($line_end_pos, 2) ne $crlf
|
||||||
|
) {
|
||||||
|
$line_end_pos++
|
||||||
|
}
|
||||||
|
# say "got here x0x pos ", $line_end_pos, ' bytes ', $b.bytes, ' start ', $chunk_start, ' some data ', $b.subbuf($chunk_start, $line_end_pos +2 - $chunk_start).decode('ascii');
|
||||||
|
if $line_end_pos +4 <= $b.bytes &&
|
||||||
|
$b.subbuf(
|
||||||
|
$chunk_start, $line_end_pos + 2 - $chunk_start
|
||||||
|
).decode('ascii') ~~ /^(<.xdigit>+)[";"|"\r\n"]/
|
||||||
|
{
|
||||||
|
|
||||||
|
# deal with case of chunk_len is 0
|
||||||
|
|
||||||
|
$chunk_len = :16($/[0].Str);
|
||||||
|
# say 'got chunk len ', $/[0].Str;
|
||||||
|
|
||||||
|
# test if at end of buf??
|
||||||
|
if $chunk_len == 0 {
|
||||||
|
# this is a "normal" exit from the routine
|
||||||
|
return True, $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
# think 1CRLFxCRLF
|
||||||
|
if $line_end_pos + $chunk_len + 4 <= $b.bytes {
|
||||||
|
# say 'inner chunk';
|
||||||
|
$content ~= $b.subbuf($line_end_pos +2, $chunk_len);
|
||||||
|
$line_end_pos = $chunk_start = $line_end_pos + $chunk_len +4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# say 'last chunk';
|
||||||
|
# remaining chunk part len is chunk_len with CRLF
|
||||||
|
# minus the length of the chunk piece at end of buffer
|
||||||
|
my $last_chunk_end_len =
|
||||||
|
$chunk_len +2 - ($b.bytes - $line_end_pos -2);
|
||||||
|
$content ~= $b.subbuf($line_end_pos +2);
|
||||||
|
if $last_chunk_end_len > 2 {
|
||||||
|
$content ~= $sock.read($last_chunk_end_len -2);
|
||||||
|
}
|
||||||
|
# clean up CRLF after chunk
|
||||||
|
$sock.read(min($last_chunk_end_len, 2));
|
||||||
|
|
||||||
|
# this is a` "normal" exit from the routine
|
||||||
|
return False, $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# say 'extend bytes ', $b.bytes, ' start ', $chunk_start, ' data ', $b.subbuf($chunk_start).decode('ascii');
|
||||||
|
# maybe odd case of buffer has just part of header at end
|
||||||
|
$b ~= $sock.read(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# say join ' ', $b[0 .. 100];
|
||||||
|
# say $b.subbuf(0, 100).decode('utf-8');
|
||||||
|
die "Could not parse chunk header";
|
||||||
|
}
|
||||||
|
|
||||||
|
method make_request (
|
||||||
|
RequestType $rt, $host, $port as Int, $path, %headers, $content?
|
||||||
|
) {
|
||||||
|
|
||||||
|
my $headers = self.stringify_headers(%headers);
|
||||||
|
|
||||||
|
my IO::Socket::INET $sock .= new(:$host, :$port);
|
||||||
|
my Str $req_str = $rt.Stringy ~ " {$path} HTTP/1.1\r\n"
|
||||||
|
~ $headers
|
||||||
|
~ "\r\n";
|
||||||
|
|
||||||
|
# attach $content if given
|
||||||
|
# (string context is forced by concatenation)
|
||||||
|
$req_str ~= $content if $content.defined;
|
||||||
|
|
||||||
|
$sock.send($req_str);
|
||||||
|
|
||||||
|
my Blob $resp = $sock.read($default_stream_read_len);
|
||||||
|
|
||||||
|
my ($status, $resp_headers, $resp_content) = self.parse_response($resp);
|
||||||
|
|
||||||
|
|
||||||
|
if (($resp_headers<Transfer-Encoding> || '') eq 'chunked') {
|
||||||
|
my Bool $is_last_chunk;
|
||||||
|
my Blob $resp_content_chunk;
|
||||||
|
|
||||||
|
($is_last_chunk, $resp_content) =
|
||||||
|
self.parse_chunks($resp_content, $sock);
|
||||||
|
while (not $is_last_chunk) {
|
||||||
|
($is_last_chunk, $resp_content_chunk) =
|
||||||
|
self.parse_chunks(
|
||||||
|
my Blob $next_chunk_start = $sock.read(1024),
|
||||||
|
$sock
|
||||||
|
);
|
||||||
|
$resp_content ~= $resp_content_chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $resp_headers<Content-Length> &&
|
||||||
|
$resp_content.bytes < $resp_headers<Content-Length>
|
||||||
|
) {
|
||||||
|
$resp_content ~= $sock.read(
|
||||||
|
$resp_headers<Content-Length> - $resp_content.bytes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else { # a bit hacky for now but should be ok
|
||||||
|
while ($resp.bytes > 0) {
|
||||||
|
$resp = $sock.read($default_stream_read_len);
|
||||||
|
$resp_content ~= $resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sock.close();
|
||||||
|
|
||||||
|
return ($status, $resp_headers, $resp_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
method parse_response (Blob $resp) {
|
||||||
|
|
||||||
|
my %header;
|
||||||
|
|
||||||
|
my Int $header_end_pos = 0;
|
||||||
|
while ( $header_end_pos < $resp.bytes &&
|
||||||
|
$http_header_end_marker ne $resp.subbuf($header_end_pos, 4) ) {
|
||||||
|
$header_end_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($header_end_pos < $resp.bytes) {
|
||||||
|
my @header_lines = $resp.subbuf(
|
||||||
|
0, $header_end_pos
|
||||||
|
).decode('ascii').split(/\r\n/);
|
||||||
|
my Str $status_line = @header_lines.shift;
|
||||||
|
|
||||||
|
for @header_lines {
|
||||||
|
my ($name, $value) = .split(': ');
|
||||||
|
%header{$name} = $value;
|
||||||
|
}
|
||||||
|
return $status_line, %header.item, $resp.subbuf($header_end_pos +4).item;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "could not parse headers";
|
||||||
|
# if %header.exists('Transfer-Encoding') && %header<Transfer-Encoding> ~~ m/:i chunked/ {
|
||||||
|
# @content = self.decode_chunked(@content);
|
||||||
|
# }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
method getprint (Str $url) {
|
||||||
|
my $out = self.get($url);
|
||||||
|
if $out ~~ Buf { $*OUT.write($out) } else { say $out }
|
||||||
|
}
|
||||||
|
|
||||||
|
method getstore (Str $url, Str $filename) {
|
||||||
|
return unless defined $url;
|
||||||
|
|
||||||
|
my $content = self.get($url);
|
||||||
|
if ! $content {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
my $fh = open($filename, :bin, :w);
|
||||||
|
if $content ~~ Buf {
|
||||||
|
$fh.write($content)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$fh.print($content)
|
||||||
|
}
|
||||||
|
|
||||||
|
$fh.close;
|
||||||
|
}
|
||||||
|
|
||||||
|
method parse_url (Str $url) {
|
||||||
|
my URI $u .= new($url);
|
||||||
|
my $path = $u.path_query;
|
||||||
|
|
||||||
|
my $user_info = $u.grammar.parse_result<URI_reference><URI><hier_part><authority><userinfo>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
$u.scheme,
|
||||||
|
$user_info ?? "{$user_info}@{$u.host}" !! $u.host,
|
||||||
|
$u.port,
|
||||||
|
$path eq '' ?? '/' !! $path,
|
||||||
|
$user_info ?? {
|
||||||
|
host => $u.host,
|
||||||
|
user => ~ $user_info<likely_userinfo_component>[0],
|
||||||
|
password => ~ $user_info<likely_userinfo_component>[1]
|
||||||
|
} !! Nil
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
method stringify_headers (%headers) {
|
||||||
|
my Str $str = '';
|
||||||
|
for sort %headers.keys {
|
||||||
|
$str ~= $_ ~ ': ' ~ %headers{$_} ~ "\r\n";
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
207
samples/Perl6/Win32.pm
Normal file
207
samples/Perl6/Win32.pm
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
my class IO::Spec::Win32 is IO::Spec::Unix {
|
||||||
|
|
||||||
|
# Some regexes we use for path splitting
|
||||||
|
my $slash = regex { <[\/ \\]> }
|
||||||
|
my $notslash = regex { <-[\/ \\]> }
|
||||||
|
my $driveletter = regex { <[A..Z a..z]> ':' }
|
||||||
|
my $UNCpath = regex { [<$slash> ** 2] <$notslash>+ <$slash> [<$notslash>+ | $] }
|
||||||
|
my $volume_rx = regex { <$driveletter> | <$UNCpath> }
|
||||||
|
|
||||||
|
method canonpath ($path, :$parent) {
|
||||||
|
$path eq '' ?? '' !! self!canon-cat($path, :$parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
method catdir(*@dirs) {
|
||||||
|
return "" unless @dirs;
|
||||||
|
return self!canon-cat( "\\", |@dirs ) if @dirs[0] eq "";
|
||||||
|
self!canon-cat(|@dirs);
|
||||||
|
}
|
||||||
|
|
||||||
|
method splitdir($dir) { $dir.split($slash) }
|
||||||
|
method catfile(|c) { self.catdir(|c) }
|
||||||
|
method devnull { 'nul' }
|
||||||
|
method rootdir { '\\' }
|
||||||
|
|
||||||
|
method tmpdir {
|
||||||
|
first( { .defined && .IO.d && .IO.w },
|
||||||
|
%*ENV<TMPDIR>,
|
||||||
|
%*ENV<TEMP>,
|
||||||
|
%*ENV<TMP>,
|
||||||
|
'SYS:/temp',
|
||||||
|
'C:\system\temp',
|
||||||
|
'C:/temp',
|
||||||
|
'/tmp',
|
||||||
|
'/')
|
||||||
|
|| self.curdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
method path {
|
||||||
|
my @path = split(';', %*ENV<PATH>);
|
||||||
|
@path».=subst(:global, q/"/, '');
|
||||||
|
@path = grep *.chars, @path;
|
||||||
|
unshift @path, ".";
|
||||||
|
return @path;
|
||||||
|
}
|
||||||
|
|
||||||
|
method is-absolute ($path) {
|
||||||
|
# As of right now, this returns 2 if the path is absolute with a
|
||||||
|
# volume, 1 if it's absolute with no volume, 0 otherwise.
|
||||||
|
given $path {
|
||||||
|
when /^ [<$driveletter> <$slash> | <$UNCpath>]/ { 2 }
|
||||||
|
when /^ <$slash> / { 1 }
|
||||||
|
default { 0 }
|
||||||
|
} #/
|
||||||
|
}
|
||||||
|
|
||||||
|
method split ($path as Str is copy) {
|
||||||
|
$path ~~ s[ <$slash>+ $] = '' #=
|
||||||
|
unless $path ~~ /^ <$driveletter>? <$slash>+ $/;
|
||||||
|
|
||||||
|
$path ~~
|
||||||
|
m/^ ( <$volume_rx> ? )
|
||||||
|
( [ .* <$slash> ]? )
|
||||||
|
(.*)
|
||||||
|
/;
|
||||||
|
my ($volume, $directory, $basename) = (~$0, ~$1, ~$2);
|
||||||
|
$directory ~~ s/ <?after .> <$slash>+ $//;
|
||||||
|
|
||||||
|
|
||||||
|
if all($directory, $basename) eq '' && $volume ne '' {
|
||||||
|
$directory = $volume ~~ /^<$driveletter>/
|
||||||
|
?? '.' !! '\\';
|
||||||
|
}
|
||||||
|
$basename = '\\' if $directory eq any('/', '\\') && $basename eq '';
|
||||||
|
$directory = '.' if $directory eq '' && $basename ne '';
|
||||||
|
|
||||||
|
return (:$volume, :$directory, :$basename);
|
||||||
|
}
|
||||||
|
|
||||||
|
method join ($volume, $directory is copy, $file is copy) {
|
||||||
|
$directory = '' if $directory eq '.' && $file.chars;
|
||||||
|
if $directory.match( /^<$slash>$/ ) && $file.match( /^<$slash>$/ ) {
|
||||||
|
$file = '';
|
||||||
|
$directory = '' if $volume.chars > 2; #i.e. UNC path
|
||||||
|
}
|
||||||
|
self.catpath($volume, $directory, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
method splitpath($path as Str, :$nofile = False) {
|
||||||
|
|
||||||
|
my ($volume,$directory,$file) = ('','','');
|
||||||
|
if ( $nofile ) {
|
||||||
|
$path ~~
|
||||||
|
/^ (<$volume_rx>?) (.*) /;
|
||||||
|
$volume = ~$0;
|
||||||
|
$directory = ~$1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$path ~~
|
||||||
|
m/^ ( <$volume_rx> ? )
|
||||||
|
( [ .* <$slash> [ '.' ** 1..2 $]? ]? )
|
||||||
|
(.*)
|
||||||
|
/;
|
||||||
|
$volume = ~$0;
|
||||||
|
$directory = ~$1;
|
||||||
|
$file = ~$2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($volume,$directory,$file);
|
||||||
|
}
|
||||||
|
|
||||||
|
method catpath($volume is copy, $directory, $file) {
|
||||||
|
|
||||||
|
# Make sure the glue separator is present
|
||||||
|
# unless it's a relative path like A:foo.txt
|
||||||
|
if $volume.chars and $directory.chars
|
||||||
|
and $volume !~~ /^<$driveletter>/
|
||||||
|
and $volume !~~ /<$slash> $/
|
||||||
|
and $directory !~~ /^ <$slash>/
|
||||||
|
{ $volume ~= '\\' }
|
||||||
|
if $file.chars and $directory.chars
|
||||||
|
and $directory !~~ /<$slash> $/
|
||||||
|
{ $volume ~ $directory ~ '\\' ~ $file; }
|
||||||
|
else { $volume ~ $directory ~ $file; }
|
||||||
|
}
|
||||||
|
|
||||||
|
method rel2abs ($path is copy, $base? is copy) {
|
||||||
|
|
||||||
|
my $is_abs = self.is-absolute($path);
|
||||||
|
|
||||||
|
# Check for volume (should probably document the '2' thing...)
|
||||||
|
return self.canonpath( $path ) if $is_abs == 2;
|
||||||
|
|
||||||
|
if $is_abs {
|
||||||
|
# It's missing a volume, add one
|
||||||
|
my $vol;
|
||||||
|
$vol = self.splitpath($base)[0] if $base.defined;
|
||||||
|
$vol ||= self.splitpath($*CWD)[0];
|
||||||
|
return self.canonpath( $vol ~ $path );
|
||||||
|
}
|
||||||
|
|
||||||
|
if not defined $base {
|
||||||
|
# TODO: implement _getdcwd call ( Windows maintains separate CWD for each volume )
|
||||||
|
# See: http://msdn.microsoft.com/en-us/library/1e5zwe0c%28v=vs.80%29.aspx
|
||||||
|
#$base = Cwd::getdcwd( (self.splitpath: $path)[0] ) if defined &Cwd::getdcwd ;
|
||||||
|
#$base //= $*CWD ;
|
||||||
|
$base = $*CWD;
|
||||||
|
}
|
||||||
|
elsif ( !self.is-absolute( $base ) ) {
|
||||||
|
$base = self.rel2abs( $base );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$base = self.canonpath( $base );
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($path_directories, $path_file) = self.splitpath( $path )[1..2] ;
|
||||||
|
|
||||||
|
my ($base_volume, $base_directories) = self.splitpath( $base, :nofile ) ;
|
||||||
|
|
||||||
|
$path = self.catpath(
|
||||||
|
$base_volume,
|
||||||
|
self.catdir( $base_directories, $path_directories ),
|
||||||
|
$path_file
|
||||||
|
) ;
|
||||||
|
|
||||||
|
return self.canonpath( $path ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
method !canon-cat ( $first, *@rest, :$parent --> Str) {
|
||||||
|
|
||||||
|
$first ~~ /^ ([ <$driveletter> <$slash>?
|
||||||
|
| <$UNCpath>
|
||||||
|
| [<$slash> ** 2] <$notslash>+
|
||||||
|
| <$slash> ]?)
|
||||||
|
(.*)
|
||||||
|
/;
|
||||||
|
my Str ($volume, $path) = ~$0, ~$1;
|
||||||
|
|
||||||
|
$volume.=subst(:g, '/', '\\');
|
||||||
|
if $volume ~~ /^<$driveletter>/ {
|
||||||
|
$volume.=uc;
|
||||||
|
}
|
||||||
|
elsif $volume.chars && $volume !~~ / '\\' $/ {
|
||||||
|
$volume ~= '\\';
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = join "\\", $path, @rest.flat;
|
||||||
|
$path ~~ s:g/ <$slash>+ /\\/; # /xx\\yy --> \xx\yy
|
||||||
|
$path ~~ s:g/[ ^ | '\\'] '.' '\\.'* [ '\\' | $ ]/\\/; # xx/././yy --> xx/yy
|
||||||
|
if $parent {
|
||||||
|
while $path ~~ s:g { [^ | <?after '\\'>] <!before '..\\'> <-[\\]>+ '\\..' ['\\' | $ ] } = '' { };
|
||||||
|
}
|
||||||
|
$path ~~ s/^ '\\'+ //; # \xx --> xx NOTE: this is *not* root
|
||||||
|
$path ~~ s/ '\\'+ $//; # xx\ --> xx
|
||||||
|
if $volume ~~ / '\\' $ / { # <vol>\.. --> <vol>\
|
||||||
|
$path ~~ s/ ^ '..' '\\..'* [ '\\' | $ ] //;
|
||||||
|
}
|
||||||
|
|
||||||
|
if $path eq '' { # \\HOST\SHARE\ --> \\HOST\SHARE
|
||||||
|
$volume ~~ s/<?after '\\\\' .*> '\\' $ //;
|
||||||
|
$volume || '.';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$volume ~ $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
samples/Perl6/advent2009-day16.t
Normal file
75
samples/Perl6/advent2009-day16.t
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# http://perl6advent.wordpress.com/2009/12/16/day-16-we-call-it-the-old-switcheroo/
|
||||||
|
|
||||||
|
use v6;
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
|
||||||
|
sub weather($weather) {
|
||||||
|
given $weather {
|
||||||
|
when 'sunny' { return 'Aah! ☀' }
|
||||||
|
when 'cloudy' { return 'Meh. ☁' }
|
||||||
|
when 'rainy' { return 'Where is my umbrella? ☂' }
|
||||||
|
when 'snowy' { return 'Yippie! ☃' }
|
||||||
|
default { return 'Looks like any other day.' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is weather(Any), 'Looks like any other day.', 'Weather given/when';
|
||||||
|
|
||||||
|
{
|
||||||
|
sub probability($probability) {
|
||||||
|
given $probability {
|
||||||
|
when 1.00 { return 'A certainty' }
|
||||||
|
when * > 0.75 { return 'Quite likely' }
|
||||||
|
when * > 0.50 { return 'Likely' }
|
||||||
|
when * > 0.25 { return 'Unlikely' }
|
||||||
|
when * > 0.00 { return 'Very unlikely' }
|
||||||
|
when 0.00 { return 'Fat chance' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is probability(0.80), 'Quite likely', 'Probability given/when';
|
||||||
|
|
||||||
|
sub fib(Int $_) {
|
||||||
|
when * < 2 { 1 }
|
||||||
|
default { fib($_ - 1) + fib($_ - 2) }
|
||||||
|
}
|
||||||
|
is fib(5), 8, '6th fibonacci number';
|
||||||
|
}
|
||||||
|
|
||||||
|
class Card {
|
||||||
|
method bend() { return "Card bent" }
|
||||||
|
method fold() { return "Card folded" }
|
||||||
|
method mutilate() { return "Card mutilated" }
|
||||||
|
}
|
||||||
|
my Card $punch-card .= new;
|
||||||
|
|
||||||
|
my $actions;
|
||||||
|
given $punch-card {
|
||||||
|
$actions ~= .bend;
|
||||||
|
$actions ~= .fold;
|
||||||
|
$actions ~= .mutilate;
|
||||||
|
}
|
||||||
|
is $actions, 'Card bentCard foldedCard mutilated', 'Given as a sort of once-only for loop.';
|
||||||
|
|
||||||
|
|
||||||
|
my @list = 1, 2, 3, 4, 5;
|
||||||
|
my $castle = 'phantom';
|
||||||
|
my $full-of-vowels = 'aaaooouuuiiee';
|
||||||
|
is (.[0] + .[1] + .[2] given @list), 6, 'Statement ending given';
|
||||||
|
|
||||||
|
{
|
||||||
|
is ("My God, it's full of vowels!" when $full-of-vowels ~~ /^ <[aeiou]>+ $/), "My God, it's full of vowels!", 'Statement ending when';
|
||||||
|
is ('Boo!' when /phantom/ given $castle), 'Boo!', 'Nesting when inside given';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
#Test DNA one liner at the end
|
||||||
|
my $result;
|
||||||
|
for ^20 {my ($a,$b)=<AT CG>.pick.comb.pick(*); my ($c,$d)=sort map({6+4*sin($_/2)},($_,$_+4)); $result ~= sprintf "%{$c}s%{$d-$c}s\n",$a,$b}
|
||||||
|
is $result.chars , 169 , 'We got a bunch of DNA';
|
||||||
|
is $result.split("\n").Int , 21 , 'On 20 line';
|
||||||
|
is $result.subst(/\s/ , '' , :g).chars , 40 , 'Containing 20 pairs';
|
||||||
|
}
|
||||||
|
|
||||||
|
eval_lives_ok 'for ^20 {my ($a,$b)=<AT CG>.pick.comb.pick(*); my ($c,$d)=sort map {6+4*sin($_/2)},$_,$_+4; sprintf "%{$c}s%{$d-$c}s\n",$a,$b}' , 'Can handle "map {...} ,$x,$y"';
|
||||||
|
|
||||||
|
done;
|
||||||
48
samples/Perl6/basic-open.t
Normal file
48
samples/Perl6/basic-open.t
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use v6;
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
plan 9;
|
||||||
|
|
||||||
|
sub test_lines(@lines) {
|
||||||
|
#!rakudo todo 'line counts'
|
||||||
|
is @lines.elems, 3, 'Three lines read';
|
||||||
|
is @lines[0],
|
||||||
|
"Please do not remove this file, used by S16-io/basic-open.t",
|
||||||
|
'Retrieved first line';
|
||||||
|
is @lines[2],
|
||||||
|
"This is a test line.",
|
||||||
|
'Retrieved last line';
|
||||||
|
}
|
||||||
|
|
||||||
|
#?niecza skip 'TextReader.eof NYI'
|
||||||
|
{
|
||||||
|
my $fh = open('t/spec/S16-io/test-data');
|
||||||
|
my $count = 0;
|
||||||
|
while !$fh.eof {
|
||||||
|
my $x = $fh.get;
|
||||||
|
$count++ if $x.defined;
|
||||||
|
}
|
||||||
|
is $count, 3, 'Read three lines with while !$hanlde.eof';
|
||||||
|
}
|
||||||
|
|
||||||
|
# test that we can interate over $fh.lines
|
||||||
|
{
|
||||||
|
my $fh = open('t/spec/S16-io/test-data');
|
||||||
|
|
||||||
|
ok defined($fh), 'Could open test file';
|
||||||
|
my @lines;
|
||||||
|
for $fh.lines -> $x {
|
||||||
|
push @lines, $x;
|
||||||
|
}
|
||||||
|
test_lines(@lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
# test that we can get all items in list context:
|
||||||
|
{
|
||||||
|
my $fh = open('t/spec/S16-io/test-data');
|
||||||
|
ok defined($fh), 'Could open test file (again)';
|
||||||
|
my @lines = $fh.lines;
|
||||||
|
test_lines(@lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
209
samples/Perl6/calendar.t
Normal file
209
samples/Perl6/calendar.t
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
use v6;
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
# calendar.t: tests some calendar-related methods common to
|
||||||
|
# Date and DateTime
|
||||||
|
|
||||||
|
plan 130;
|
||||||
|
|
||||||
|
sub date($year, $month, $day) {
|
||||||
|
Date.new(:$year, :$month, :$day)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dtim($year, $month, $day) {
|
||||||
|
DateTime.new(:$year, :$month, :$day,
|
||||||
|
:hour(17), :minute(33), :second(2.9))
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/C<DateTime>/'truncated-to'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is ~date(1969, 7, 20).truncated-to(month), '1969-07-01', 'Date.truncated-to(month)';
|
||||||
|
is ~dtim(1969, 7, 20).truncated-to(month), '1969-07-01T00:00:00Z', 'DateTime.truncated-to(month)';
|
||||||
|
is ~date(1969, 7, 20).truncated-to(year), '1969-01-01', 'Date.truncated-to(year)';
|
||||||
|
is ~dtim(1969, 7, 20).truncated-to(year), '1969-01-01T00:00:00Z', 'DateTime.truncated-to(year)';
|
||||||
|
|
||||||
|
is ~date(1999, 1, 18).truncated-to(week), '1999-01-18', 'Date.truncated-to(week) (no change in day)';
|
||||||
|
is ~date(1999, 1, 19).truncated-to(week), '1999-01-18', 'Date.truncated-to(week) (short jump)';
|
||||||
|
is ~date(1999, 1, 17).truncated-to(week), '1999-01-11', 'Date.truncated-to(week) (long jump)';
|
||||||
|
is ~dtim(1999, 1, 17).truncated-to(week), '1999-01-11T00:00:00Z', 'DateTime.truncated-to(week) (long jump)';
|
||||||
|
is ~date(1999, 4, 2).truncated-to(week), '1999-03-29', 'Date.truncated-to(week) (changing month)';
|
||||||
|
is ~date(1999, 1, 3).truncated-to(week), '1998-12-28', 'Date.truncated-to(week) (changing year)';
|
||||||
|
is ~dtim(1999, 1, 3).truncated-to(week), '1998-12-28T00:00:00Z', 'DateTime.truncated-to(week) (changing year)';
|
||||||
|
is ~date(2000, 3, 1).truncated-to(week), '2000-02-28', 'Date.truncated-to(week) (skipping over Feb 29)';
|
||||||
|
is ~dtim(2000, 3, 1).truncated-to(week), '2000-02-28T00:00:00Z', 'DateTime.truncated-to(week) (skipping over Feb 29)';
|
||||||
|
is ~date(1988, 3, 3).truncated-to(week), '1988-02-29', 'Date.truncated-to(week) (landing on Feb 29)';
|
||||||
|
is ~dtim(1988, 3, 3).truncated-to(week), '1988-02-29T00:00:00Z', 'DateTime.truncated-to(week) (landing on Feb 29)';
|
||||||
|
|
||||||
|
# Verify .gist
|
||||||
|
# Example taken from S32 specs documentation.
|
||||||
|
#?niecza skip 'Undeclared routine: hour'
|
||||||
|
{
|
||||||
|
my $dt = DateTime.new('2005-02-01T15:20:35Z');
|
||||||
|
my $truncated = $dt.truncated-to(hour);
|
||||||
|
|
||||||
|
is $truncated.gist, "2005-02-01T15:00:00Z", "validate .gist output";
|
||||||
|
}
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'the synonym day-of-month'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is date(2003, 3, 18).day-of-month, 18, 'Date.day can be spelled as Date.day-of-month';
|
||||||
|
is dtim(2003, 3, 18).day-of-month, 18, 'DateTime.day can be spelled as DateTime.day-of-month';
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'day-of-week method'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
# much of this is blatantly stolen from the Date::Simple test suite
|
||||||
|
# and redistributed under the terms of the Artistic License 2.0 with
|
||||||
|
# permission of the original authors (John Tobey, Marty Pauly).
|
||||||
|
|
||||||
|
is date(1966, 10, 15).day-of-week, 6, 'Date.day-of-week (1966-10-15)';
|
||||||
|
is dtim(1966, 10, 15).day-of-week, 6, 'DateTime.day-of-week (1966-10-15)';
|
||||||
|
is date(2401, 3, 1).day-of-week, 4, 'Date.day-of-week (2401-03-01)';
|
||||||
|
is date(2401, 2, 28).day-of-week, 3, 'Date.day-of-week (2401-02-28)';
|
||||||
|
is date(2400, 3, 1).day-of-week, 3, 'Date.day-of-week (2400-03-01)';
|
||||||
|
is date(2400, 2, 29).day-of-week, 2, 'Date.day-of-week (2400-02-29)';
|
||||||
|
is date(2400, 2, 28).day-of-week, 1, 'Date.day-of-week (2400-02-28)';
|
||||||
|
is date(2101, 3, 1).day-of-week, 2, 'Date.day-of-week (2101-03-01)';
|
||||||
|
is date(2101, 2, 28).day-of-week, 1, 'Date.day-of-week (2101-02-28)';
|
||||||
|
is date(2100, 3, 1).day-of-week, 1, 'Date.day-of-week (2100-03-01)';
|
||||||
|
is dtim(2100, 3, 1).day-of-week, 1, 'DateTime.day-of-week (2100-03-01)';
|
||||||
|
is date(2100, 2, 28).day-of-week, 7, 'Date.day-of-week (2100-02-28)';
|
||||||
|
is dtim(2100, 2, 28).day-of-week, 7, 'DateTime.day-of-week (2100-02-28)';
|
||||||
|
is date(2001, 3, 1).day-of-week, 4, 'Date.day-of-week (2001-03-01)';
|
||||||
|
is date(2001, 2, 28).day-of-week, 3, 'Date.day-of-week (2001-02-28)';
|
||||||
|
is date(2000, 3, 1).day-of-week, 3, 'Date.day-of-week (2000-03-01)';
|
||||||
|
is date(2000, 2, 29).day-of-week, 2, 'Date.day-of-week (2000-02-29)';
|
||||||
|
is date(2000, 2, 28).day-of-week, 1, 'Date.day-of-week (2000-02-28)';
|
||||||
|
is date(1901, 3, 1).day-of-week, 5, 'Date.day-of-week (1901-03-01)';
|
||||||
|
is date(1901, 2, 28).day-of-week, 4, 'Date.day-of-week (1901-02-28)';
|
||||||
|
is date(1900, 3, 1).day-of-week, 4, 'Date.day-of-week (1900-03-01)';
|
||||||
|
is date(1900, 2, 28).day-of-week, 3, 'Date.day-of-week (1900-02-28)';
|
||||||
|
is date(1801, 3, 1).day-of-week, 7, 'Date.day-of-week (1801-03-01)';
|
||||||
|
is date(1801, 2, 28).day-of-week, 6, 'Date.day-of-week (1801-02-28)';
|
||||||
|
is date(1800, 3, 1).day-of-week, 6, 'Date.day-of-week (1800-03-01)';
|
||||||
|
is dtim(1800, 3, 1).day-of-week, 6, 'DateTime.day-of-week (1800-03-01)';
|
||||||
|
is date(1800, 2, 28).day-of-week, 5, 'Date.day-of-week (1800-02-28)';
|
||||||
|
is dtim(1800, 2, 28).day-of-week, 5, 'DateTime.day-of-week (1800-02-28)';
|
||||||
|
is date(1701, 3, 1).day-of-week, 2, 'Date.day-of-week (1701-03-01)';
|
||||||
|
is date(1701, 2, 28).day-of-week, 1, 'Date.day-of-week (1701-02-28)';
|
||||||
|
is date(1700, 3, 1).day-of-week, 1, 'Date.day-of-week (1700-03-01)';
|
||||||
|
is date(1700, 2, 28).day-of-week, 7, 'Date.day-of-week (1700-02-28)';
|
||||||
|
is date(1601, 3, 1).day-of-week, 4, 'Date.day-of-week (1601-03-01)';
|
||||||
|
is dtim(1601, 3, 1).day-of-week, 4, 'DateTime.day-of-week (1601-03-01)';
|
||||||
|
is date(1601, 2, 28).day-of-week, 3, 'Date.day-of-week (1601-02-28)';
|
||||||
|
is dtim(1601, 2, 28).day-of-week, 3, 'DateTime.day-of-week (1601-02-28)';
|
||||||
|
is date(1600, 3, 1).day-of-week, 3, 'Date.day-of-week (1600-03-01)';
|
||||||
|
is date(1600, 2, 29).day-of-week, 2, 'Date.day-of-week (1600-02-29)';
|
||||||
|
is date(1600, 2, 28).day-of-week, 1, 'Date.day-of-week (1600-02-28)';
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'The method week'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is date(1977, 8, 20).week.join(' '), '1977 33', 'Date.week (1977-8-20)';
|
||||||
|
is dtim(1977, 8, 20).week.join(' '), '1977 33', 'DateTime.week (1977-8-20)';
|
||||||
|
is date(1977, 8, 20).week-year, 1977, 'Date.week (1977-8-20)';
|
||||||
|
is dtim(1977, 8, 20).week-year, 1977, 'DateTime.week (1977-8-20)';
|
||||||
|
is date(1977, 8, 20).week-number, 33, 'Date.week-number (1977-8-20)';
|
||||||
|
is dtim(1977, 8, 20).week-number, 33, 'DateTime.week-number (1977-8-20)';
|
||||||
|
is date(1987, 12, 18).week.join(' '), '1987 51', 'Date.week (1987-12-18)';
|
||||||
|
is date(2020, 5, 4).week.join(' '), '2020 19', 'Date.week (2020-5-4)';
|
||||||
|
|
||||||
|
# From http://en.wikipedia.org/w/index.php?title=ISO_week_dtim&oldid=370553706#Examples
|
||||||
|
|
||||||
|
is date(2005, 01, 01).week.join(' '), '2004 53', 'Date.week (2005-01-01)';
|
||||||
|
is date(2005, 01, 02).week.join(' '), '2004 53', 'Date.week (2005-01-02)';
|
||||||
|
is date(2005, 12, 31).week.join(' '), '2005 52', 'Date.week (2005-12-31)';
|
||||||
|
is date(2007, 01, 01).week.join(' '), '2007 1', 'Date.week (2007-01-01)';
|
||||||
|
is date(2007, 12, 30).week.join(' '), '2007 52', 'Date.week (2007-12-30)';
|
||||||
|
is dtim(2007, 12, 30).week.join(' '), '2007 52', 'DateTime.week (2007-12-30)';
|
||||||
|
is date(2007, 12, 30).week-year, 2007, 'Date.week (2007-12-30)';
|
||||||
|
is dtim(2007, 12, 30).week-year, 2007, 'DateTime.week (2007-12-30)';
|
||||||
|
is date(2007, 12, 30).week-number, 52, 'Date.week-number (2007-12-30)';
|
||||||
|
is dtim(2007, 12, 30).week-number, 52, 'DateTime.week-number (2007-12-30)';
|
||||||
|
is date(2007, 12, 31).week.join(' '), '2008 1', 'Date.week (2007-12-31)';
|
||||||
|
is date(2008, 01, 01).week.join(' '), '2008 1', 'Date.week (2008-01-01)';
|
||||||
|
is date(2008, 12, 29).week.join(' '), '2009 1', 'Date.week (2008-12-29)';
|
||||||
|
is date(2008, 12, 31).week.join(' '), '2009 1', 'Date.week (2008-12-31)';
|
||||||
|
is date(2009, 01, 01).week.join(' '), '2009 1', 'Date.week (2009-01-01)';
|
||||||
|
is date(2009, 12, 31).week.join(' '), '2009 53', 'Date.week (2009-12-31)';
|
||||||
|
is date(2010, 01, 03).week.join(' '), '2009 53', 'Date.week (2010-01-03)';
|
||||||
|
is dtim(2010, 01, 03).week.join(' '), '2009 53', 'DateTime.week (2010-01-03)';
|
||||||
|
is date(2010, 01, 03).week-year, 2009, 'Date.week-year (2010-01-03)';
|
||||||
|
is dtim(2010, 01, 03).week-year, 2009, 'DateTime.week-year (2010-01-03)';
|
||||||
|
is date(2010, 01, 03).week-number, 53, 'Date.week-number (2010-01-03)';
|
||||||
|
is dtim(2010, 01, 03).week-number, 53, 'DateTime.week-number (2010-01-03)';
|
||||||
|
|
||||||
|
# day-of-week is tested each time show-dt is called.
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'The weekday-of-month method'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is date(1982, 2, 1).weekday-of-month, 1, 'Date.weekday-of-month (1982-02-01)';
|
||||||
|
is dtim(1982, 2, 1).weekday-of-month, 1, 'DateTime.weekday-of-month (1982-02-01)';
|
||||||
|
is date(1982, 2, 7).weekday-of-month, 1, 'Date.weekday-of-month (1982-02-07)';
|
||||||
|
is date(1982, 2, 8).weekday-of-month, 2, 'Date.weekday-of-month (1982-02-08)';
|
||||||
|
is date(1982, 2, 18).weekday-of-month, 3, 'Date.weekday-of-month (1982-02-18)';
|
||||||
|
is date(1982, 2, 28).weekday-of-month, 4, 'Date.weekday-of-month (1982-02-28)';
|
||||||
|
is dtim(1982, 2, 28).weekday-of-month, 4, 'DateTime.weekday-of-month (1982-02-28)';
|
||||||
|
is date(1982, 4, 4).weekday-of-month, 1, 'Date.weekday-of-month (1982-04-04)';
|
||||||
|
is date(1982, 4, 7).weekday-of-month, 1, 'Date.weekday-of-month (1982-04-07)';
|
||||||
|
is date(1982, 4, 8).weekday-of-month, 2, 'Date.weekday-of-month (1982-04-08)';
|
||||||
|
is date(1982, 4, 13).weekday-of-month, 2, 'Date.weekday-of-month (1982-04-13)';
|
||||||
|
is date(1982, 4, 30).weekday-of-month, 5, 'Date.weekday-of-month (1982-04-30)';
|
||||||
|
is dtim(1982, 4, 30).weekday-of-month, 5, 'DateTime.weekday-of-month (1982-04-30)';
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'The days-in-month method'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is date(1999, 5, 5).days-in-month, 31, 'Date.days-in-month (May 1999)';
|
||||||
|
is date(1999, 6, 5).days-in-month, 30, 'Date.days-in-month (Jun 1999)';
|
||||||
|
is date(1999, 2, 5).days-in-month, 28, 'Date.days-in-month (Feb 1999)';
|
||||||
|
is dtim(1999, 2, 5).days-in-month, 28, 'DateTime.days-in-month (Feb 1999)';
|
||||||
|
is date(2000, 2, 5).days-in-month, 29, 'Date.days-in-month (Feb 2000)';
|
||||||
|
is dtim(2000, 2, 5).days-in-month, 29, 'DateTime.days-in-month (Feb 2000)';
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'The day-of-year method'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
is date(1975, 1, 1).day-of-year, 1, 'Date.day-of-year (1975-01-01)';
|
||||||
|
is dtim(1975, 1, 1).day-of-year, 1, 'DateTime.day-of-year (1975-01-01)';
|
||||||
|
is date(1977, 5, 5).day-of-year, 125, 'Date.day-of-year (1977-05-05)';
|
||||||
|
is date(1983, 11, 27).day-of-year, 331, 'Date.day-of-year (1983-11-27)';
|
||||||
|
is date(1999, 2, 28).day-of-year, 59, 'Date.day-of-year (1999-02-28)';
|
||||||
|
is dtim(1999, 2, 28).day-of-year, 59, 'DateTime.day-of-year (1999-02-28)';
|
||||||
|
is date(1999, 3, 1).day-of-year, 60, 'Date.day-of-year (1999-03-01)';
|
||||||
|
is dtim(1999, 3, 1).day-of-year, 60, 'DateTime.day-of-year (1999-03-01)';
|
||||||
|
is date(1999, 12, 31).day-of-year, 365, 'Date.day-of-year (1999-12-31)';
|
||||||
|
is date(2000, 2, 28).day-of-year, 59, 'Date.day-of-year (2000-02-28)';
|
||||||
|
is dtim(2000, 2, 28).day-of-year, 59, 'DateTime.day-of-year (2000-02-28)';
|
||||||
|
is date(2000, 2, 29).day-of-year, 60, 'Date.day-of-year (2000-02-29)';
|
||||||
|
is dtim(2000, 2, 29).day-of-year, 60, 'DateTime.day-of-year (2000-02-29)';
|
||||||
|
is date(2000, 3, 1).day-of-year, 61, 'Date.day-of-year (2000-03-01)';
|
||||||
|
is date(2000, 12, 31).day-of-year, 366, 'Date.day-of-year (2000-12-31)';
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# L<S32::Temporal/Accessors/'The method is-leap-year'>
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
|
nok date(1800, 1, 1).is-leap-year, 'Date.is-leap-year (1800)';
|
||||||
|
nok date(1801, 1, 1).is-leap-year, 'Date.is-leap-year (1801)';
|
||||||
|
ok date(1804, 1, 1).is-leap-year, 'Date.is-leap-year (1804)';
|
||||||
|
nok date(1900, 1, 1).is-leap-year, 'Date.is-leap-year (1900)';
|
||||||
|
nok dtim(1900, 1, 1).is-leap-year, 'DateTime.is-leap-year (1900)';
|
||||||
|
ok date(1996, 1, 1).is-leap-year, 'Date.is-leap-year (1996)';
|
||||||
|
nok date(1999, 1, 1).is-leap-year, 'Date.is-leap-year (1999)';
|
||||||
|
ok date(2000, 1, 1).is-leap-year, 'Date.is-leap-year (2000)';
|
||||||
|
ok dtim(2000, 1, 1).is-leap-year, 'DateTime.is-leap-year (2000)';
|
||||||
|
|
||||||
|
done;
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
586
samples/Perl6/for.t
Normal file
586
samples/Perl6/for.t
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
#?pugs emit #
|
||||||
|
use MONKEY_TYPING;
|
||||||
|
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
=begin description
|
||||||
|
|
||||||
|
Tests the "for" statement
|
||||||
|
|
||||||
|
This attempts to test as many variations of the
|
||||||
|
for statement as possible
|
||||||
|
|
||||||
|
=end description
|
||||||
|
|
||||||
|
plan 77;
|
||||||
|
|
||||||
|
## No foreach
|
||||||
|
# L<S04/The C<for> statement/"no foreach statement any more">
|
||||||
|
{
|
||||||
|
my $times_run = 0;
|
||||||
|
eval_dies_ok 'foreach 1..10 { $times_run++ }; 1', "foreach is gone";
|
||||||
|
eval_dies_ok 'foreach (1..10) { $times_run++}; 1',
|
||||||
|
"foreach is gone, even with parens";
|
||||||
|
is $times_run, 0, "foreach doesn't work";
|
||||||
|
}
|
||||||
|
|
||||||
|
## for with plain old range operator w/out parens
|
||||||
|
|
||||||
|
{
|
||||||
|
my $a = "";
|
||||||
|
for 0 .. 5 { $a = $a ~ $_; };
|
||||||
|
is($a, '012345', 'for 0..5 {} works');
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... with pointy blocks
|
||||||
|
|
||||||
|
{
|
||||||
|
my $b = "";
|
||||||
|
for 0 .. 5 -> $_ { $b = $b ~ $_; };
|
||||||
|
is($b, '012345', 'for 0 .. 5 -> {} works');
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs todo 'slice context'
|
||||||
|
#?niecza skip 'slice context'
|
||||||
|
{
|
||||||
|
my $str;
|
||||||
|
my @a = 1..3;
|
||||||
|
my @b = 4..6;
|
||||||
|
for zip(@a; @b) -> $x, $y {
|
||||||
|
$str ~= "($x $y)";
|
||||||
|
}
|
||||||
|
is $str, "(1 4)(2 5)(3 6)", 'for zip(@a; @b) -> $x, $y works';
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... with referential sub
|
||||||
|
{
|
||||||
|
my $d = "";
|
||||||
|
for -2 .. 2 { $d ~= .sign };
|
||||||
|
is($d, '-1-1011', 'for 0 .. 5 { .some_sub } works');
|
||||||
|
}
|
||||||
|
|
||||||
|
## and now with parens around the range operator
|
||||||
|
{
|
||||||
|
my $e = "";
|
||||||
|
for (0 .. 5) { $e = $e ~ $_; };
|
||||||
|
is($e, '012345', 'for () {} works');
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... with pointy blocks
|
||||||
|
{
|
||||||
|
my $f = "";
|
||||||
|
for (0 .. 5) -> $_ { $f = $f ~ $_; };
|
||||||
|
is($f, '012345', 'for () -> {} works');
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... with implicit topic
|
||||||
|
|
||||||
|
{
|
||||||
|
$_ = "GLOBAL VALUE";
|
||||||
|
for "INNER VALUE" {
|
||||||
|
is( .lc, "inner value", "Implicit default topic is seen by lc()");
|
||||||
|
};
|
||||||
|
is($_,"GLOBAL VALUE","After the loop the implicit topic gets restored");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
# as statement modifier
|
||||||
|
$_ = "GLOBAL VALUE";
|
||||||
|
is( .lc, "inner value", "Implicit default topic is seen by lc()" )
|
||||||
|
for "INNER VALUE";
|
||||||
|
#?pugs todo
|
||||||
|
is($_,"GLOBAL VALUE","After the loop the implicit topic gets restored");
|
||||||
|
}
|
||||||
|
|
||||||
|
## and now for with 'topical' variables
|
||||||
|
|
||||||
|
# ... w/out parens
|
||||||
|
|
||||||
|
my $i = "";
|
||||||
|
for 0 .. 5 -> $topic { $i = $i ~ $topic; };
|
||||||
|
is($i, '012345', 'for 0 .. 5 -> $topic {} works');
|
||||||
|
|
||||||
|
# ... with parens
|
||||||
|
|
||||||
|
my $j = "";
|
||||||
|
for (0 .. 5) -> $topic { $j = $j ~ $topic; };
|
||||||
|
is($j, '012345', 'for () -> $topic {} works');
|
||||||
|
|
||||||
|
|
||||||
|
## for with @array operator w/out parens
|
||||||
|
|
||||||
|
my @array_k = (0 .. 5);
|
||||||
|
my $k = "";
|
||||||
|
for @array_k { $k = $k ~ $_; };
|
||||||
|
is($k, '012345', 'for @array {} works');
|
||||||
|
|
||||||
|
# ... with pointy blocks
|
||||||
|
|
||||||
|
my @array_l = (0 .. 5);
|
||||||
|
my $l = "";
|
||||||
|
for @array_l -> $_ { $l = $l ~ $_; };
|
||||||
|
is($l, '012345', 'for @array -> {} works');
|
||||||
|
|
||||||
|
## and now with parens around the @array
|
||||||
|
|
||||||
|
my @array_o = (0 .. 5);
|
||||||
|
my $o = "";
|
||||||
|
for (@array_o) { $o = $o ~ $_; };
|
||||||
|
is($o, '012345', 'for (@array) {} works');
|
||||||
|
|
||||||
|
# ... with pointy blocks
|
||||||
|
{
|
||||||
|
my @array_p = (0 .. 5);
|
||||||
|
my $p = "";
|
||||||
|
for (@array_p) -> $_ { $p = $p ~ $_; };
|
||||||
|
is($p, '012345', 'for (@array) -> {} works');
|
||||||
|
}
|
||||||
|
|
||||||
|
my @elems = <a b c d e>;
|
||||||
|
|
||||||
|
{
|
||||||
|
my @a;
|
||||||
|
for (@elems) {
|
||||||
|
push @a, $_;
|
||||||
|
}
|
||||||
|
my @e = <a b c d e>;
|
||||||
|
is(@a, @e, 'for (@a) { ... $_ ... } iterates all elems');
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @a;
|
||||||
|
for (@elems) -> $_ { push @a, $_ };
|
||||||
|
my @e = @elems;
|
||||||
|
is(@a, @e, 'for (@a)->$_ { ... $_ ... } iterates all elems' );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @a;
|
||||||
|
for (@elems) { push @a, $_, $_; }
|
||||||
|
my @e = <a a b b c c d d e e>;
|
||||||
|
is(@a, @e, 'for (@a) { ... $_ ... $_ ... } iterates all elems, not just odd');
|
||||||
|
}
|
||||||
|
|
||||||
|
# "for @a -> $var" is ro by default.
|
||||||
|
#?pugs skip 'parsefail'
|
||||||
|
{
|
||||||
|
my @a = <1 2 3 4>;
|
||||||
|
|
||||||
|
eval_dies_ok('for @a -> $elem {$elem = 5}', '-> $var is ro by default');
|
||||||
|
|
||||||
|
for @a <-> $elem {$elem++;}
|
||||||
|
is(@a, <2 3 4 5>, '<-> $var is rw');
|
||||||
|
|
||||||
|
for @a <-> $first, $second {$first++; $second++}
|
||||||
|
is(@a, <3 4 5 6>, '<-> $var, $var2 works');
|
||||||
|
}
|
||||||
|
|
||||||
|
# for with "is rw"
|
||||||
|
{
|
||||||
|
my @array_s = (0..2);
|
||||||
|
my @s = (1..3);
|
||||||
|
for @array_s { $_++ };
|
||||||
|
is(@array_s, @s, 'for @array { $_++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array = <a b c d>;
|
||||||
|
for @array { $_ ~= "c" }
|
||||||
|
is ~@array, "ac bc cc dc",
|
||||||
|
'mutating $_ in for works';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array_t = (0..2);
|
||||||
|
my @t = (1..3);
|
||||||
|
for @array_t -> $val is rw { $val++ };
|
||||||
|
is(@array_t, @t, 'for @array -> $val is rw { $val++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs skip "Can't modify const item"
|
||||||
|
{
|
||||||
|
my @array_v = (0..2);
|
||||||
|
my @v = (1..3);
|
||||||
|
for @array_v.values -> $val is rw { $val++ };
|
||||||
|
is(@array_v, @v, 'for @array.values -> $val is rw { $val++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs skip "Can't modify const item"
|
||||||
|
{
|
||||||
|
my @array_kv = (0..2);
|
||||||
|
my @kv = (1..3);
|
||||||
|
for @array_kv.kv -> $key, $val is rw { $val++ };
|
||||||
|
is(@array_kv, @kv, 'for @array.kv -> $key, $val is rw { $val++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs skip "Can't modify const item"
|
||||||
|
{
|
||||||
|
my %hash_v = ( a => 1, b => 2, c => 3 );
|
||||||
|
my %v = ( a => 2, b => 3, c => 4 );
|
||||||
|
for %hash_v.values -> $val is rw { $val++ };
|
||||||
|
is(%hash_v, %v, 'for %hash.values -> $val is rw { $val++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my %hash_kv = ( a => 1, b => 2, c => 3 );
|
||||||
|
my %kv = ( a => 2, b => 3, c => 4 );
|
||||||
|
try { for %hash_kv.kv -> $key, $val is rw { $val++ }; };
|
||||||
|
is( %hash_kv, %kv, 'for %hash.kv -> $key, $val is rw { $val++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
# .key //= ++$i for @array1;
|
||||||
|
class TestClass{ has $.key is rw };
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array1 = (TestClass.new(:key<1>),TestClass.new());
|
||||||
|
my $i = 0;
|
||||||
|
for @array1 { .key //= ++$i }
|
||||||
|
my $sum1 = [+] @array1.map: { $_.key };
|
||||||
|
is( $sum1, 2, '.key //= ++$i for @array1;' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# .key = 1 for @array1;
|
||||||
|
{
|
||||||
|
my @array1 = (TestClass.new(),TestClass.new(:key<2>));
|
||||||
|
|
||||||
|
.key = 1 for @array1;
|
||||||
|
my $sum1 = [+] @array1.map: { $_.key };
|
||||||
|
is($sum1, 2, '.key = 1 for @array1;');
|
||||||
|
}
|
||||||
|
|
||||||
|
# $_.key = 1 for @array1;
|
||||||
|
{
|
||||||
|
my @array1 = (TestClass.new(),TestClass.new(:key<2>));
|
||||||
|
|
||||||
|
$_.key = 1 for @array1;
|
||||||
|
my $sum1 = [+] @array1.map: { $_.key };
|
||||||
|
is( $sum1, 2, '$_.key = 1 for @array1;');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# rw scalars
|
||||||
|
#L<S04/The C<for> statement/implicit parameter to block read/write "by default">
|
||||||
|
{
|
||||||
|
my ($a, $b, $c) = 0..2;
|
||||||
|
try { for ($a, $b, $c) { $_++ } };
|
||||||
|
is( [$a,$b,$c], [1,2,3], 'for ($a,$b,$c) { $_++ }');
|
||||||
|
|
||||||
|
($a, $b, $c) = 0..2;
|
||||||
|
try { for ($a, $b, $c) -> $x is rw { $x++ } };
|
||||||
|
is( [$a,$b,$c], [1,2,3], 'for ($a,$b,$c) -> $x is rw { $x++ }');
|
||||||
|
}
|
||||||
|
|
||||||
|
# list context
|
||||||
|
|
||||||
|
{
|
||||||
|
my $a = '';
|
||||||
|
my $b = '';
|
||||||
|
for 1..3, 4..6 { $a ~= $_.WHAT.gist ; $b ~= Int.gist };
|
||||||
|
is($a, $b, 'List context');
|
||||||
|
|
||||||
|
$a = '';
|
||||||
|
for [1..3, 4..6] { $a ~= $_.WHAT.gist };
|
||||||
|
is($a, Array.gist, 'List context');
|
||||||
|
|
||||||
|
$a = '';
|
||||||
|
$b = '';
|
||||||
|
for [1..3], [4..6] { $a ~= $_.WHAT.gist ; $b ~= Array.gist };
|
||||||
|
is($a, $b, 'List context');
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
# this was a rakudo bug with mixed 'for' and recursion, which seems to
|
||||||
|
# confuse some lexical pads or the like, see RT #58392
|
||||||
|
my $gather = '';
|
||||||
|
sub f($l) {
|
||||||
|
if $l <= 0 {
|
||||||
|
return $l;
|
||||||
|
}
|
||||||
|
$gather ~= $l;
|
||||||
|
for 1..3 {
|
||||||
|
f($l-1);
|
||||||
|
$gather ~= '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(2);
|
||||||
|
|
||||||
|
is $gather, '21....1....1....', 'Can mix recursion and for';
|
||||||
|
}
|
||||||
|
|
||||||
|
# another variation
|
||||||
|
{
|
||||||
|
my $t = '';
|
||||||
|
my $c;
|
||||||
|
sub r($x) {
|
||||||
|
my $h = $c++;
|
||||||
|
r $x-1 if $x;
|
||||||
|
for 1 { $t ~= $h };
|
||||||
|
};
|
||||||
|
r 3;
|
||||||
|
is $t, '3210', 'can mix recursion and for (RT 103332)';
|
||||||
|
}
|
||||||
|
|
||||||
|
# grep and sort in for - these were pugs bugs once, so let's
|
||||||
|
# keep them as regression tests
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array = <1 2 3 4>;
|
||||||
|
my $output = '';
|
||||||
|
|
||||||
|
for (grep { 1 }, @array) -> $elem {
|
||||||
|
$output ~= "$elem,";
|
||||||
|
}
|
||||||
|
|
||||||
|
is $output, "1,2,3,4,", "grep works in for";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array = <1 2 3 4>;
|
||||||
|
my $output = '';
|
||||||
|
|
||||||
|
for @array.sort -> $elem {
|
||||||
|
$output ~= "$elem,";
|
||||||
|
}
|
||||||
|
|
||||||
|
is $output, "1,2,3,4,", "sort works in for";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my @array = <1 2 3 4>;
|
||||||
|
my $output = '';
|
||||||
|
|
||||||
|
for (grep { 1 }, @array.sort) -> $elem {
|
||||||
|
$output ~= "$elem,";
|
||||||
|
}
|
||||||
|
|
||||||
|
is $output, "1,2,3,4,", "grep and sort work in for";
|
||||||
|
}
|
||||||
|
|
||||||
|
# L<S04/Statement parsing/keywords require whitespace>
|
||||||
|
eval_dies_ok('for(0..5) { }','keyword needs at least one whitespace after it');
|
||||||
|
|
||||||
|
# looping with more than one loop variables
|
||||||
|
{
|
||||||
|
my @a = <1 2 3 4>;
|
||||||
|
my $str = '';
|
||||||
|
for @a -> $x, $y {
|
||||||
|
$str ~= $x+$y;
|
||||||
|
}
|
||||||
|
is $str, "37", "for loop with two variables";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
#my $str = '';
|
||||||
|
eval_dies_ok('for 1..5 -> $x, $y { $str ~= "$x$y" }', 'Should throw exception, no value for parameter $y');
|
||||||
|
#is $str, "1234", "loop ran before throwing exception";
|
||||||
|
#diag ">$str<";
|
||||||
|
}
|
||||||
|
|
||||||
|
#?rakudo skip 'optional variable in for loop (RT #63994)'
|
||||||
|
#?niecza 2 todo 'NYI'
|
||||||
|
{
|
||||||
|
my $str = '';
|
||||||
|
for 1..5 -> $x, $y? {
|
||||||
|
$str ~= " " ~ $x*$y;
|
||||||
|
}
|
||||||
|
is $str, " 2 12 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $str = '';
|
||||||
|
for 1..5 -> $x, $y = 7 {
|
||||||
|
$str ~= " " ~ $x*$y;
|
||||||
|
}
|
||||||
|
is $str, " 2 12 35", 'default values in for-loops';
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my @a = <1 2 3>;
|
||||||
|
my @b = <4 5 6>;
|
||||||
|
my $res = '';
|
||||||
|
for @a Z @b -> $x, $y {
|
||||||
|
$res ~= " " ~ $x * $y;
|
||||||
|
}
|
||||||
|
is $res, " 4 10 18", "Z -ed for loop";
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my @a = <1 2 3>;
|
||||||
|
my $str = '';
|
||||||
|
|
||||||
|
for @a Z @a Z @a Z @a Z @a -> $q, $w, $e, $r, $t {
|
||||||
|
$str ~= " " ~ $q*$w*$e*$r*$t;
|
||||||
|
}
|
||||||
|
is $str, " 1 {2**5} {3**5}", "Z-ed for loop with 5 arrays";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
eval_dies_ok 'for 1.. { };', "Please use ..* for indefinite range";
|
||||||
|
eval_dies_ok 'for 1... { };', "1... does not exist";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $c;
|
||||||
|
for 1..8 {
|
||||||
|
$c = $_;
|
||||||
|
last if $_ == 6;
|
||||||
|
}
|
||||||
|
is $c, 6, 'for loop ends in time using last';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $c;
|
||||||
|
for 1..* {
|
||||||
|
$c = $_;
|
||||||
|
last if $_ == 6;
|
||||||
|
}
|
||||||
|
is $c, 6, 'infinte for loop ends in time using last';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $c;
|
||||||
|
for 1..Inf {
|
||||||
|
$c = $_;
|
||||||
|
last if $_ == 6;
|
||||||
|
}
|
||||||
|
is $c, 6, 'infinte for loop ends in time using last';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #62478
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
try { EVAL('for (my $ii = 1; $ii <= 3; $ii++) { say $ii; }') };
|
||||||
|
ok "$!" ~~ /C\-style/, 'mentions C-style';
|
||||||
|
ok "$!" ~~ /for/, 'mentions for';
|
||||||
|
ok "$!" ~~ /loop/, 'mentions loop';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #65212
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my $parsed = 0;
|
||||||
|
try { EVAL '$parsed = 1; for (1..3)->$n { last }' };
|
||||||
|
ok ! $parsed, 'for (1..3)->$n fails to parse';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #71268
|
||||||
|
{
|
||||||
|
sub rt71268 { for ^1 {} }
|
||||||
|
#?pugs todo
|
||||||
|
lives_ok { ~(rt71268) }, 'can stringify "for ^1 {}" without death';
|
||||||
|
#?pugs skip 'Cannot cast from VList to VCode'
|
||||||
|
ok rt71268() ~~ (), 'result of "for ^1 {}" is ()';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT 62478
|
||||||
|
{
|
||||||
|
eval_dies_ok 'for (my $i; $i <=3; $i++) { $i; }', 'Unsupported use of C-style "for (;;)" loop; in Perl 6 please use "loop (;;)"';
|
||||||
|
}
|
||||||
|
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
try { EVAL 'for (my $x; $x <=3; $x++) { $i; }'; diag($!) };
|
||||||
|
ok $! ~~ / 'C-style' /, 'Sensible error message';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #64886
|
||||||
|
#?rakudo skip 'maybe bogus, for loops are not supposed to be lazy?'
|
||||||
|
{
|
||||||
|
my $a = 0;
|
||||||
|
for 1..10000000000 {
|
||||||
|
$a++;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
is $a, 1, 'for on Range with huge max value is lazy and enters block';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #60780
|
||||||
|
lives_ok {
|
||||||
|
for 1 .. 5 -> $x, $y? { }
|
||||||
|
}, 'Iteration variables do not need to add up if one is optional';
|
||||||
|
|
||||||
|
# RT #78232
|
||||||
|
{
|
||||||
|
my $a = 0;
|
||||||
|
for 1, 2, 3 { sub foo {}; $a++ }
|
||||||
|
is $a, 3, 'RT #78232';
|
||||||
|
}
|
||||||
|
|
||||||
|
# http://irclog.perlgeek.de/perl6/2011-12-29#i_4892285
|
||||||
|
# (Niecza bug)
|
||||||
|
{
|
||||||
|
my $x = 0;
|
||||||
|
for 1 .. 2 -> $a, $b { $x = $b } #OK not used
|
||||||
|
is $x, 2, 'Lazy lists interact properly with multi-element for loops';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #71270
|
||||||
|
# list comprehension
|
||||||
|
#?pugs skip 'Cannot cast from VList to VCode'
|
||||||
|
{
|
||||||
|
sub f() { for ^1 { } };
|
||||||
|
is ~f(), '', 'empty for-loop returns empty list';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #74060
|
||||||
|
# more list comprehension
|
||||||
|
#?pugs skip 'parsefail'
|
||||||
|
#?niecza todo "https://github.com/sorear/niecza/issues/180"
|
||||||
|
{
|
||||||
|
my @s = ($_ * 2 if $_ ** 2 > 3 for 0 .. 5);
|
||||||
|
is ~@s, '4 6 8 10', 'Can use statement-modifying "for" in list comprehension';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT 113026
|
||||||
|
#?rakudo todo 'RT 113026 array iterator does not track a growing array'
|
||||||
|
#?niecza todo 'array iterator does not track a growing array'
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my @rt113026 = 1 .. 10;
|
||||||
|
my $iter = 0;
|
||||||
|
for @rt113026 -> $n {
|
||||||
|
$iter++;
|
||||||
|
if $iter % 2 {
|
||||||
|
@rt113026.push: $n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is $iter, 20, 'iterating over an expanding list';
|
||||||
|
is @rt113026, <1 2 3 4 5 6 7 8 9 10 1 3 5 7 9 1 5 9 5 5>,
|
||||||
|
'array expanded in for loop is expanded';
|
||||||
|
}
|
||||||
|
|
||||||
|
# RT #78406
|
||||||
|
{
|
||||||
|
my $c = 0;
|
||||||
|
dies_ok { for ^8 { .=fmt('%03b'); $c++ } }, '$_ is read-only here';
|
||||||
|
is $c, 0, '... and $_ is *always* read-only here';
|
||||||
|
}
|
||||||
|
|
||||||
|
dies_ok
|
||||||
|
{
|
||||||
|
my class Foo {
|
||||||
|
has @.items;
|
||||||
|
method check_items { for @.items -> $item { die "bad" if $item == 2 } }
|
||||||
|
method foo { self.check_items; .say for @.items }
|
||||||
|
}
|
||||||
|
Foo.new(items => (1, 2, 3, 4)).foo
|
||||||
|
}, 'for in called method runs (was a sink context bug)';
|
||||||
|
|
||||||
|
# RT #77460
|
||||||
|
#?pugs todo
|
||||||
|
{
|
||||||
|
my @a = 1;
|
||||||
|
for 1..10 {
|
||||||
|
my $last = @a[*-1];
|
||||||
|
push @a, (sub ($s) { $s + 1 })($last)
|
||||||
|
};
|
||||||
|
is @a, [1, 2, 3, 4, 5, 6, 7, 8,9, 10, 11];
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
76
samples/Perl6/hash.t
Normal file
76
samples/Perl6/hash.t
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
plan(5);
|
||||||
|
|
||||||
|
unless EVAL 'EVAL("1", :lang<perl5>)' {
|
||||||
|
skip_rest;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
die unless
|
||||||
|
EVAL(q/
|
||||||
|
package My::Hash;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, $ref) = @_;
|
||||||
|
bless \$ref, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub hash {
|
||||||
|
my $self = shift;
|
||||||
|
return $$self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub my_keys {
|
||||||
|
my $self = shift;
|
||||||
|
return keys %{$$self};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub my_exists {
|
||||||
|
my ($self, $idx) = @_;
|
||||||
|
return exists $$self->{$idx};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub fetch {
|
||||||
|
my ($self, $idx) = @_;
|
||||||
|
return $$self->{$idx};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub store {
|
||||||
|
my ($self, $idx, $val) = @_;
|
||||||
|
$$self->{$idx} = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub push {
|
||||||
|
my ($self, $val) = @_;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
/, :lang<perl5>);
|
||||||
|
|
||||||
|
my $p5ha = EVAL('sub { My::Hash->new($_[0]) }', :lang<perl5>);
|
||||||
|
my %hash = (5 => 'a', 6 => 'b', 7 => 'c', 8 => 'd');
|
||||||
|
my $p5hash = $p5ha(\%hash);
|
||||||
|
|
||||||
|
my $rethash = $p5hash.hash;
|
||||||
|
my @keys = %hash.keys.sort;
|
||||||
|
my @p5keys;
|
||||||
|
try {
|
||||||
|
@p5keys = $p5hash.my_keys; # this doesn't even pass lives_ok ??
|
||||||
|
@p5keys .= sort;
|
||||||
|
};
|
||||||
|
|
||||||
|
is("{ @keys }", "{ @p5keys }");
|
||||||
|
|
||||||
|
ok($p5hash.store(9, 'e'), 'can store');
|
||||||
|
is(%hash{9}, 'e', 'store result');
|
||||||
|
|
||||||
|
is($p5hash.fetch(5), 'a', 'fetch result');
|
||||||
|
is($p5hash.my_exists(5), %hash<5>:exists, 'exists');
|
||||||
|
#?pugs todo 'bug'
|
||||||
|
is($p5hash.my_exists(12), %hash<12>:exists, 'nonexists fail');
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
630
samples/Perl6/htmlify.pl
Executable file
630
samples/Perl6/htmlify.pl
Executable file
@@ -0,0 +1,630 @@
|
|||||||
|
#!/usr/bin/env perl6
|
||||||
|
use v6;
|
||||||
|
|
||||||
|
# This script isn't in bin/ because it's not meant to be installed.
|
||||||
|
|
||||||
|
BEGIN say 'Initializing ...';
|
||||||
|
|
||||||
|
use Pod::To::HTML;
|
||||||
|
use URI::Escape;
|
||||||
|
use lib 'lib';
|
||||||
|
use Perl6::TypeGraph;
|
||||||
|
use Perl6::TypeGraph::Viz;
|
||||||
|
use Perl6::Documentable::Registry;
|
||||||
|
|
||||||
|
my $*DEBUG = False;
|
||||||
|
|
||||||
|
my $tg;
|
||||||
|
my %methods-by-type;
|
||||||
|
my $footer = footer-html;
|
||||||
|
my $head = q[
|
||||||
|
<link rel="icon" href="/favicon.ico" type="favicon.ico" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="/style.css" media="screen" title="default" />
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
sub url-munge($_) {
|
||||||
|
return $_ if m{^ <[a..z]>+ '://'};
|
||||||
|
return "/type/$_" if m/^<[A..Z]>/;
|
||||||
|
return "/routine/$_" if m/^<[a..z]>/;
|
||||||
|
# poor man's <identifier>
|
||||||
|
if m/ ^ '&'( \w <[[\w'-]>* ) $/ {
|
||||||
|
return "/routine/$0";
|
||||||
|
}
|
||||||
|
return $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub p2h($pod) {
|
||||||
|
pod2html($pod, :url(&url-munge), :$footer, :$head);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-gist(Pod::Block $pod, $level = 0) {
|
||||||
|
my $leading = ' ' x $level;
|
||||||
|
my %confs;
|
||||||
|
my @chunks;
|
||||||
|
for <config name level caption type> {
|
||||||
|
my $thing = $pod.?"$_"();
|
||||||
|
if $thing {
|
||||||
|
%confs{$_} = $thing ~~ Iterable ?? $thing.perl !! $thing.Str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@chunks = $leading, $pod.^name, (%confs.perl if %confs), "\n";
|
||||||
|
for $pod.content.list -> $c {
|
||||||
|
if $c ~~ Pod::Block {
|
||||||
|
@chunks.push: pod-gist($c, $level + 2);
|
||||||
|
}
|
||||||
|
elsif $c ~~ Str {
|
||||||
|
@chunks.push: $c.indent($level + 2), "\n";
|
||||||
|
} elsif $c ~~ Positional {
|
||||||
|
@chunks.push: $c.map: {
|
||||||
|
if $_ ~~ Pod::Block {
|
||||||
|
*.&pod-gist
|
||||||
|
} elsif $_ ~~ Str {
|
||||||
|
$_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@chunks.join;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub recursive-dir($dir) {
|
||||||
|
my @todo = $dir;
|
||||||
|
gather while @todo {
|
||||||
|
my $d = @todo.shift;
|
||||||
|
for dir($d) -> $f {
|
||||||
|
if $f.f {
|
||||||
|
take $f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@todo.push($f.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub first-code-block(@pod) {
|
||||||
|
if @pod[1] ~~ Pod::Block::Code {
|
||||||
|
return @pod[1].content.grep(Str).join;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub MAIN(Bool :$debug, Bool :$typegraph = False) {
|
||||||
|
$*DEBUG = $debug;
|
||||||
|
|
||||||
|
say 'Creating html/ subdirectories ...';
|
||||||
|
for '', <type language routine images op op/prefix op/postfix op/infix
|
||||||
|
op/circumfix op/postcircumfix op/listop> {
|
||||||
|
mkdir "html/$_" unless "html/$_".IO ~~ :e;
|
||||||
|
}
|
||||||
|
|
||||||
|
say 'Reading lib/ ...';
|
||||||
|
my @source = recursive-dir('lib').grep(*.f).grep(rx{\.pod$});
|
||||||
|
@source .= map: {; .path.subst('lib/', '').subst(rx{\.pod$}, '').subst(:g, '/', '::') => $_ };
|
||||||
|
|
||||||
|
say 'Reading type graph ...';
|
||||||
|
$tg = Perl6::TypeGraph.new-from-file('type-graph.txt');
|
||||||
|
{
|
||||||
|
my %h = $tg.sorted.kv.flat.reverse;
|
||||||
|
@source .= sort: { %h{.key} // -1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
my $dr = Perl6::Documentable::Registry.new;
|
||||||
|
|
||||||
|
say 'Processing Pod files ...';
|
||||||
|
for (0..* Z @source) -> $num, $_ {
|
||||||
|
my $podname = .key;
|
||||||
|
my $file = .value;
|
||||||
|
my $what = $podname ~~ /^<[A..Z]> | '::'/ ?? 'type' !! 'language';
|
||||||
|
printf "% 4d/%d: % -40s => %s\n", $num, +@source, $file.path, "$what/$podname";
|
||||||
|
|
||||||
|
my $pod = eval slurp($file.path) ~ "\n\$=pod";
|
||||||
|
$pod .= [0];
|
||||||
|
|
||||||
|
if $what eq 'language' {
|
||||||
|
write-language-file(:$dr, :$what, :$pod, :$podname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
say pod-gist($pod[0]) if $*DEBUG;
|
||||||
|
write-type-file(:$dr, :$what, :pod($pod[0]), :$podname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
say 'Composing doc registry ...';
|
||||||
|
$dr.compose;
|
||||||
|
|
||||||
|
write-disambiguation-files($dr);
|
||||||
|
write-op-disambiguation-files($dr);
|
||||||
|
write-operator-files($dr);
|
||||||
|
write-type-graph-images(:force($typegraph));
|
||||||
|
write-search-file($dr);
|
||||||
|
write-index-file($dr);
|
||||||
|
|
||||||
|
say 'Writing per-routine files ...';
|
||||||
|
my %routine-seen;
|
||||||
|
for $dr.lookup('routine', :by<kind>).list -> $d {
|
||||||
|
next if %routine-seen{$d.name}++;
|
||||||
|
write-routine-file($dr, $d.name);
|
||||||
|
print '.'
|
||||||
|
}
|
||||||
|
say '';
|
||||||
|
|
||||||
|
say 'Processing complete.';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-language-file(:$dr, :$what, :$pod, :$podname) {
|
||||||
|
spurt "html/$what/$podname.html", p2h($pod);
|
||||||
|
if $podname eq 'operators' {
|
||||||
|
my @chunks = chunks-grep($pod.content,
|
||||||
|
:from({ $_ ~~ Pod::Heading and .level == 2}),
|
||||||
|
:to({ $^b ~~ Pod::Heading and $^b.level <= $^a.level}),
|
||||||
|
);
|
||||||
|
for @chunks -> $chunk {
|
||||||
|
my $heading = $chunk[0].content[0].content[0];
|
||||||
|
next unless $heading ~~ / ^ [in | pre | post | circum | postcircum ] fix | listop /;
|
||||||
|
my $what = ~$/;
|
||||||
|
my $operator = $heading.split(' ', 2)[1];
|
||||||
|
$dr.add-new(
|
||||||
|
:kind<operator>,
|
||||||
|
:subkind($what),
|
||||||
|
:name($operator),
|
||||||
|
:pod($chunk),
|
||||||
|
:!pod-is-complete,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dr.add-new(
|
||||||
|
:kind<language>,
|
||||||
|
:name($podname),
|
||||||
|
:$pod,
|
||||||
|
:pod-is-complete,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-type-file(:$dr, :$what, :$pod, :$podname) {
|
||||||
|
my @chunks = chunks-grep($pod.content,
|
||||||
|
:from({ $_ ~~ Pod::Heading and .level == 2}),
|
||||||
|
:to({ $^b ~~ Pod::Heading and $^b.level <= $^a.level}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if $tg.types{$podname} -> $t {
|
||||||
|
$pod.content.push: Pod::Block::Named.new(
|
||||||
|
name => 'Image',
|
||||||
|
content => [ "/images/type-graph-$podname.png"],
|
||||||
|
);
|
||||||
|
$pod.content.push: pod-link(
|
||||||
|
'Full-size type graph image as SVG',
|
||||||
|
"/images/type-graph-$podname.svg",
|
||||||
|
);
|
||||||
|
|
||||||
|
my @mro = $t.mro;
|
||||||
|
@mro.shift; # current type is already taken care of
|
||||||
|
|
||||||
|
for $t.roles -> $r {
|
||||||
|
next unless %methods-by-type{$r};
|
||||||
|
$pod.content.push:
|
||||||
|
pod-heading("Methods supplied by role $r"),
|
||||||
|
pod-block(
|
||||||
|
"$podname does role ",
|
||||||
|
pod-link($r.name, "/type/$r"),
|
||||||
|
", which provides the following methods:",
|
||||||
|
),
|
||||||
|
%methods-by-type{$r}.list,
|
||||||
|
;
|
||||||
|
}
|
||||||
|
for @mro -> $c {
|
||||||
|
next unless %methods-by-type{$c};
|
||||||
|
$pod.content.push:
|
||||||
|
pod-heading("Methods supplied by class $c"),
|
||||||
|
pod-block(
|
||||||
|
"$podname inherits from class ",
|
||||||
|
pod-link($c.name, "/type/$c"),
|
||||||
|
", which provides the following methods:",
|
||||||
|
),
|
||||||
|
%methods-by-type{$c}.list,
|
||||||
|
;
|
||||||
|
for $c.roles -> $r {
|
||||||
|
next unless %methods-by-type{$r};
|
||||||
|
$pod.content.push:
|
||||||
|
pod-heading("Methods supplied by role $r"),
|
||||||
|
pod-block(
|
||||||
|
"$podname inherits from class ",
|
||||||
|
pod-link($c.name, "/type/$c"),
|
||||||
|
", which does role ",
|
||||||
|
pod-link($r.name, "/type/$r"),
|
||||||
|
", which provides the following methods:",
|
||||||
|
),
|
||||||
|
%methods-by-type{$r}.list,
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $d = $dr.add-new(
|
||||||
|
:kind<type>,
|
||||||
|
# TODO: subkind
|
||||||
|
:$pod,
|
||||||
|
:pod-is-complete,
|
||||||
|
:name($podname),
|
||||||
|
);
|
||||||
|
|
||||||
|
for @chunks -> $chunk {
|
||||||
|
my $name = $chunk[0].content[0].content[0];
|
||||||
|
say "$podname.$name" if $*DEBUG;
|
||||||
|
next if $name ~~ /\s/;
|
||||||
|
%methods-by-type{$podname}.push: $chunk;
|
||||||
|
# determine whether it's a sub or method
|
||||||
|
my Str $subkind;
|
||||||
|
{
|
||||||
|
my %counter;
|
||||||
|
for first-code-block($chunk).lines {
|
||||||
|
if ms/^ 'multi'? (sub|method)»/ {
|
||||||
|
%counter{$0}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if %counter == 1 {
|
||||||
|
($subkind,) = %counter.keys;
|
||||||
|
}
|
||||||
|
if %counter<method> {
|
||||||
|
write-qualified-method-call(
|
||||||
|
:$name,
|
||||||
|
:pod($chunk),
|
||||||
|
:type($podname),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dr.add-new(
|
||||||
|
:kind<routine>,
|
||||||
|
:$subkind,
|
||||||
|
:$name,
|
||||||
|
:pod($chunk),
|
||||||
|
:!pod-is-complete,
|
||||||
|
:origin($d),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
spurt "html/$what/$podname.html", p2h($pod);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub chunks-grep(:$from!, :&to!, *@elems) {
|
||||||
|
my @current;
|
||||||
|
|
||||||
|
gather {
|
||||||
|
for @elems -> $c {
|
||||||
|
if @current && ($c ~~ $from || to(@current[0], $c)) {
|
||||||
|
take [@current];
|
||||||
|
@current = ();
|
||||||
|
@current.push: $c if $c ~~ $from;
|
||||||
|
}
|
||||||
|
elsif @current or $c ~~ $from {
|
||||||
|
@current.push: $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
take [@current] if @current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-with-title($title, *@blocks) {
|
||||||
|
Pod::Block::Named.new(
|
||||||
|
name => "pod",
|
||||||
|
content => [
|
||||||
|
Pod::Block::Named.new(
|
||||||
|
name => "TITLE",
|
||||||
|
content => Array.new(
|
||||||
|
Pod::Block::Para.new(
|
||||||
|
content => [$title],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
@blocks.flat,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-block(*@content) {
|
||||||
|
Pod::Block::Para.new(:@content);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-link($text, $url) {
|
||||||
|
Pod::FormattingCode.new(
|
||||||
|
type => 'L',
|
||||||
|
content => [
|
||||||
|
join('|', $text, $url),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-item(*@content, :$level = 1) {
|
||||||
|
Pod::Item.new(
|
||||||
|
:$level,
|
||||||
|
:@content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pod-heading($name, :$level = 1) {
|
||||||
|
Pod::Heading.new(
|
||||||
|
:$level,
|
||||||
|
:content[pod-block($name)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-type-graph-images(:$force) {
|
||||||
|
unless $force {
|
||||||
|
my $dest = 'html/images/type-graph-Any.svg'.path;
|
||||||
|
if $dest.e && $dest.modified >= 'type-graph.txt'.path.modified {
|
||||||
|
say "Not writing type graph images, it seems to be up-to-date";
|
||||||
|
say "To force writing of type graph images, supply the --typegraph";
|
||||||
|
say "option at the command line, or delete";
|
||||||
|
say "file 'html/images/type-graph-Any.svg'";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
say 'Writing type graph images to html/images/ ...';
|
||||||
|
for $tg.sorted -> $type {
|
||||||
|
my $viz = Perl6::TypeGraph::Viz.new-for-type($type);
|
||||||
|
$viz.to-file("html/images/type-graph-{$type}.svg", format => 'svg');
|
||||||
|
$viz.to-file("html/images/type-graph-{$type}.png", format => 'png', size => '8,3');
|
||||||
|
print '.'
|
||||||
|
}
|
||||||
|
say '';
|
||||||
|
|
||||||
|
say 'Writing specialized visualizations to html/images/ ...';
|
||||||
|
my %by-group = $tg.sorted.classify(&viz-group);
|
||||||
|
%by-group<Exception>.push: $tg.types< Exception Any Mu >;
|
||||||
|
%by-group<Metamodel>.push: $tg.types< Any Mu >;
|
||||||
|
|
||||||
|
for %by-group.kv -> $group, @types {
|
||||||
|
my $viz = Perl6::TypeGraph::Viz.new(:types(@types),
|
||||||
|
:dot-hints(viz-hints($group)),
|
||||||
|
:rank-dir('LR'));
|
||||||
|
$viz.to-file("html/images/type-graph-{$group}.svg", format => 'svg');
|
||||||
|
$viz.to-file("html/images/type-graph-{$group}.png", format => 'png', size => '8,3');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub viz-group ($type) {
|
||||||
|
return 'Metamodel' if $type.name ~~ /^ 'Perl6::Metamodel' /;
|
||||||
|
return 'Exception' if $type.name ~~ /^ 'X::' /;
|
||||||
|
return 'Any';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub viz-hints ($group) {
|
||||||
|
return '' unless $group eq 'Any';
|
||||||
|
|
||||||
|
return '
|
||||||
|
subgraph "cluster: Mu children" {
|
||||||
|
rank=same;
|
||||||
|
style=invis;
|
||||||
|
"Any";
|
||||||
|
"Junction";
|
||||||
|
}
|
||||||
|
subgraph "cluster: Pod:: top level" {
|
||||||
|
rank=same;
|
||||||
|
style=invis;
|
||||||
|
"Pod::Config";
|
||||||
|
"Pod::Block";
|
||||||
|
}
|
||||||
|
subgraph "cluster: Date/time handling" {
|
||||||
|
rank=same;
|
||||||
|
style=invis;
|
||||||
|
"Date";
|
||||||
|
"DateTime";
|
||||||
|
"DateTime-local-timezone";
|
||||||
|
}
|
||||||
|
subgraph "cluster: Collection roles" {
|
||||||
|
rank=same;
|
||||||
|
style=invis;
|
||||||
|
"Positional";
|
||||||
|
"Associative";
|
||||||
|
"Baggy";
|
||||||
|
}
|
||||||
|
';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-search-file($dr) {
|
||||||
|
say 'Writing html/search.html ...';
|
||||||
|
my $template = slurp("search_template.html");
|
||||||
|
my @items;
|
||||||
|
my sub fix-url ($raw) { $raw.substr(1) ~ '.html' };
|
||||||
|
@items.push: $dr.lookup('language', :by<kind>).sort(*.name).map({
|
||||||
|
"\{ label: \"Language: {.name}\", value: \"{.name}\", url: \"{ fix-url(.url) }\" \}"
|
||||||
|
});
|
||||||
|
@items.push: $dr.lookup('type', :by<kind>).sort(*.name).map({
|
||||||
|
"\{ label: \"Type: {.name}\", value: \"{.name}\", url: \"{ fix-url(.url) }\" \}"
|
||||||
|
});
|
||||||
|
my %seen;
|
||||||
|
@items.push: $dr.lookup('routine', :by<kind>).grep({!%seen{.name}++}).sort(*.name).map({
|
||||||
|
"\{ label: \"{ (.subkind // 'Routine').tclc }: {.name}\", value: \"{.name}\", url: \"{ fix-url(.url) }\" \}"
|
||||||
|
});
|
||||||
|
sub escape(Str $s) {
|
||||||
|
$s.trans([</ \\ ">] => [<\\/ \\\\ \\">]);
|
||||||
|
}
|
||||||
|
@items.push: $dr.lookup('operator', :by<kind>).map({
|
||||||
|
qq[\{ label: "$_.human-kind() {escape .name}", value: "{escape .name}", url: "{ fix-url .url }"\}]
|
||||||
|
});
|
||||||
|
|
||||||
|
my $items = @items.join(",\n");
|
||||||
|
spurt("html/search.html", $template.subst("ITEMS", $items));
|
||||||
|
}
|
||||||
|
|
||||||
|
my %operator_disambiguation_file_written;
|
||||||
|
|
||||||
|
sub write-disambiguation-files($dr) {
|
||||||
|
say 'Writing disambiguation files ...';
|
||||||
|
for $dr.grouped-by('name').kv -> $name, $p is copy {
|
||||||
|
print '.';
|
||||||
|
my $pod = pod-with-title("Disambiguation for '$name'");
|
||||||
|
if $p.elems == 1 {
|
||||||
|
$p.=[0] if $p ~~ Array;
|
||||||
|
if $p.origin -> $o {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block(
|
||||||
|
pod-link("'$name' is a $p.human-kind()", $p.url),
|
||||||
|
' from ',
|
||||||
|
pod-link($o.human-kind() ~ ' ' ~ $o.name, $o.url),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block(
|
||||||
|
pod-link("'$name' is a $p.human-kind()", $p.url)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block("'$name' can be anything of the following"),
|
||||||
|
$p.map({
|
||||||
|
if .origin -> $o {
|
||||||
|
pod-item(
|
||||||
|
pod-link(.human-kind, .url),
|
||||||
|
' from ',
|
||||||
|
pod-link($o.human-kind() ~ ' ' ~ $o.name, $o.url),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pod-item( pod-link(.human-kind, .url) )
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
my $html = p2h($pod);
|
||||||
|
spurt "html/$name.html", $html;
|
||||||
|
if all($p>>.kind) eq 'operator' {
|
||||||
|
spurt "html/op/$name.html", $html;
|
||||||
|
%operator_disambiguation_file_written{$p[0].name} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
say '';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-op-disambiguation-files($dr) {
|
||||||
|
say 'Writing operator disambiguation files ...';
|
||||||
|
for $dr.lookup('operator', :by<kind>).classify(*.name).kv -> $name, @ops {
|
||||||
|
next unless %operator_disambiguation_file_written{$name};
|
||||||
|
my $pod = pod-with-title("Disambiguation for '$name'");
|
||||||
|
if @ops == 1 {
|
||||||
|
my $p = @ops[0];
|
||||||
|
if $p.origin -> $o {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block(
|
||||||
|
pod-link("'$name' is a $p.human-kind()", $p.url),
|
||||||
|
' from ',
|
||||||
|
pod-link($o.human-kind() ~ ' ' ~ $o.name, $o.url),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block(
|
||||||
|
pod-link("'$name' is a $p.human-kind()", $p.url)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$pod.content.push:
|
||||||
|
pod-block("'$name' can be anything of the following"),
|
||||||
|
@ops.map({
|
||||||
|
if .origin -> $o {
|
||||||
|
pod-item(
|
||||||
|
pod-link(.human-kind, .url),
|
||||||
|
' from ',
|
||||||
|
pod-link($o.human-kind() ~ ' ' ~ $o.name, $o.url),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pod-item( pod-link(.human-kind, .url) )
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
my $html = p2h($pod);
|
||||||
|
spurt "html/$name.html", $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-operator-files($dr) {
|
||||||
|
say 'Writing operator files ...';
|
||||||
|
for $dr.lookup('operator', :by<kind>).list -> $doc {
|
||||||
|
my $what = $doc.subkind;
|
||||||
|
my $op = $doc.name;
|
||||||
|
my $pod = pod-with-title(
|
||||||
|
"$what.tclc() $op operator",
|
||||||
|
pod-block(
|
||||||
|
"Documentation for $what $op, extracted from ",
|
||||||
|
pod-link("the operators language documentation", "/language/operators")
|
||||||
|
),
|
||||||
|
@($doc.pod),
|
||||||
|
);
|
||||||
|
spurt "html/op/$what/$op.html", p2h($pod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-index-file($dr) {
|
||||||
|
say 'Writing html/index.html ...';
|
||||||
|
my %routine-seen;
|
||||||
|
my $pod = pod-with-title('Perl 6 Documentation',
|
||||||
|
Pod::Block::Para.new(
|
||||||
|
content => ['Official Perl 6 documentation'],
|
||||||
|
),
|
||||||
|
# TODO: add more
|
||||||
|
pod-heading("Language Documentation"),
|
||||||
|
$dr.lookup('language', :by<kind>).sort(*.name).map({
|
||||||
|
pod-item( pod-link(.name, .url) )
|
||||||
|
}),
|
||||||
|
pod-heading('Types'),
|
||||||
|
$dr.lookup('type', :by<kind>).sort(*.name).map({
|
||||||
|
pod-item(pod-link(.name, .url))
|
||||||
|
}),
|
||||||
|
pod-heading('Routines'),
|
||||||
|
$dr.lookup('routine', :by<kind>).sort(*.name).map({
|
||||||
|
next if %routine-seen{.name}++;
|
||||||
|
pod-item(pod-link(.name, .url))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
spurt 'html/index.html', p2h($pod);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-routine-file($dr, $name) {
|
||||||
|
say 'Writing html/routine/$name.html ...' if $*DEBUG;
|
||||||
|
my @docs = $dr.lookup($name, :by<name>).grep(*.kind eq 'routine');
|
||||||
|
my $subkind = 'routine';
|
||||||
|
{
|
||||||
|
my @subkinds = @docs>>.subkind;
|
||||||
|
$subkind = @subkinds[0] if all(@subkinds>>.defined) && [eq] @subkinds;
|
||||||
|
}
|
||||||
|
my $pod = pod-with-title("Documentation for $subkind $name",
|
||||||
|
pod-block("Documentation for $subkind $name, assembled from the
|
||||||
|
following types:"),
|
||||||
|
@docs.map({
|
||||||
|
pod-heading(.origin.name ~ '.' ~ .name),
|
||||||
|
pod-block("From ", pod-link(.origin.name, .origin.url ~ '#' ~ .name)),
|
||||||
|
.pod.list,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
spurt "html/routine/$name.html", p2h($pod);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write-qualified-method-call(:$name!, :$pod!, :$type!) {
|
||||||
|
my $p = pod-with-title(
|
||||||
|
"Documentation for method $type.$name",
|
||||||
|
pod-block('From ', pod-link($type, "/type/{$type}#$name")),
|
||||||
|
@$pod,
|
||||||
|
);
|
||||||
|
spurt "html/{$type}.{$name}.html", p2h($p);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub footer-html() {
|
||||||
|
state $dt = ~DateTime.now;
|
||||||
|
qq[
|
||||||
|
<div id="footer">
|
||||||
|
<p>
|
||||||
|
Generated on $dt from the sources at
|
||||||
|
<a href="https://github.com/perl6/doc">perl6/doc on github</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This is a work in progress to document Perl 6, and known to be
|
||||||
|
incomplete. Your contribution is appreciated.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
];
|
||||||
|
}
|
||||||
76
samples/Perl6/listquote-whitespace.t
Normal file
76
samples/Perl6/listquote-whitespace.t
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use v6;
|
||||||
|
|
||||||
|
use Test;
|
||||||
|
|
||||||
|
# L<S02/Whitespace and Comments>
|
||||||
|
|
||||||
|
=begin kwid
|
||||||
|
|
||||||
|
= DESCRIPTION
|
||||||
|
|
||||||
|
Tests that the List quoting parser properly
|
||||||
|
ignores whitespace in lists. This becomes important
|
||||||
|
if your line endings are \x0d\x0a.
|
||||||
|
|
||||||
|
Characters that should be ignored are:
|
||||||
|
|
||||||
|
\t
|
||||||
|
\r
|
||||||
|
\n
|
||||||
|
\x20
|
||||||
|
|
||||||
|
Most likely there are more. James tells me that
|
||||||
|
the maximum Unicode char is \x10FFFF , so maybe
|
||||||
|
we should simply (re)construct the whitespace
|
||||||
|
list via IsSpace or \s on the fly.
|
||||||
|
|
||||||
|
Of course, in the parsed result, no item should
|
||||||
|
contain whitespace.
|
||||||
|
|
||||||
|
C<\xA0> is specifically an I<nonbreaking> whitespace
|
||||||
|
character and thus should B<not> break the list.
|
||||||
|
|
||||||
|
=end kwid
|
||||||
|
|
||||||
|
#?pugs emit if $?PUGS_BACKEND ne "BACKEND_PUGS" {
|
||||||
|
#?pugs emit skip_rest "PIL2JS and PIL-Run do not support EVAL() yet.";
|
||||||
|
#?pugs emit exit;
|
||||||
|
#?pugs emit }
|
||||||
|
|
||||||
|
my @list = <a b c d>;
|
||||||
|
my @separators = ("\t","\r","\n"," ");
|
||||||
|
my @nonseparators = (",","/","\\",";","\xa0");
|
||||||
|
|
||||||
|
plan +@separators + @nonseparators + 3;
|
||||||
|
|
||||||
|
for @separators -> $sep {
|
||||||
|
my $str = "<$sep" ~ @list.join("$sep$sep") ~ "$sep>";
|
||||||
|
my @res = EVAL $str;
|
||||||
|
|
||||||
|
my $vis = sprintf "%02x", ord $sep;
|
||||||
|
is( @res, @list, "'\\x$vis\\x$vis' is properly parsed as list whitespace")
|
||||||
|
};
|
||||||
|
|
||||||
|
for @nonseparators -> $sep {
|
||||||
|
my $ex = @list.join($sep);
|
||||||
|
my $str = "<" ~$ex~ ">";
|
||||||
|
my @res = EVAL $str;
|
||||||
|
|
||||||
|
my $vis = sprintf "%02x", ord $sep;
|
||||||
|
#?rakudo emit if $sep eq "\xa0" {
|
||||||
|
#?rakudo emit todo('\xa0 should not be a separator for list quotes');
|
||||||
|
#?rakudo emit };
|
||||||
|
#?niecza emit if $sep eq "\xa0" {
|
||||||
|
#?niecza emit todo('\xa0 should not be a separator for list quotes');
|
||||||
|
#?niecza emit };
|
||||||
|
is( @res, [@list.join($sep)], "'\\x$vis' does not split in a whitespace quoted list")
|
||||||
|
};
|
||||||
|
|
||||||
|
is < foo
|
||||||
|
>, 'foo', 'various combinations of whitespaces are stripped';
|
||||||
|
|
||||||
|
# RT #73772
|
||||||
|
isa_ok < >, Parcel, '< > (only whitespaces) is empty Parcel';
|
||||||
|
is < >.elems, 0, ".. and it's really empty";
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
32
samples/Perl6/man-or-boy.t
Normal file
32
samples/Perl6/man-or-boy.t
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use Test;
|
||||||
|
|
||||||
|
# stress test for lexicals and lexical subs
|
||||||
|
# See
|
||||||
|
# http://en.wikipedia.org/w/index.php?title=Man_or_boy_test&oldid=249795453#Perl
|
||||||
|
|
||||||
|
my @results = 1, 0, -2, 0, 1, 0, 1, -1, -10, -30;
|
||||||
|
|
||||||
|
# if we want to *really* stress-test, we can use a few more tests:
|
||||||
|
# my @results = 1, 0, -2, 0, 1, 0, 1, -1, -10, -30, -67, -138
|
||||||
|
# -291, -642, -1446, -3250, -7244, -16065, -35601, -78985;
|
||||||
|
|
||||||
|
plan +@results;
|
||||||
|
|
||||||
|
sub A($k is copy, &x1, &x2, &x3, &x4, &x5) {
|
||||||
|
my $B;
|
||||||
|
$B = sub (*@) { A(--$k, $B, &x1, &x2, &x3, &x4) };
|
||||||
|
if ($k <= 0) {
|
||||||
|
return x4($k, &x1, &x2, &x3, &x4, &x5)
|
||||||
|
+ x5($k, &x1, &x2, &x3, &x4, &x5);
|
||||||
|
}
|
||||||
|
return $B();
|
||||||
|
};
|
||||||
|
|
||||||
|
for 0 .. (@results-1) -> $i {
|
||||||
|
is A($i, sub (*@) {1}, sub (*@) {-1}, sub (*@) {-1}, sub (*@) {1}, sub (*@) {0}),
|
||||||
|
@results[$i],
|
||||||
|
"man-or-boy test for start value $i";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# vim: ft=perl6
|
||||||
Reference in New Issue
Block a user