Rosetta Code/List authors of task descriptions: Difference between revisions
Thundergnat (talk | contribs) (Save over corrupted page) |
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Change output format to sortable wiki-table) |
||
Line 286: | Line 286: | ||
# Friendlier descriptions for task categories |
# Friendlier descriptions for task categories |
||
my %cat = ( |
my %cat = ( |
||
'Programming_Tasks' => 'Task |
'Programming_Tasks' => 'Task', |
||
'Draft_Programming_Tasks' => 'Draft |
'Draft_Programming_Tasks' => 'Draft' |
||
); |
); |
||
Line 294: | Line 294: | ||
my $url = 'http://rosettacode.org/mw'; |
my $url = 'http://rosettacode.org/mw'; |
||
my $ |
my $tablefile = './RC_Authors.txt'; |
||
my $hashfile = './RC_Authors.json'; |
my $hashfile = './RC_Authors.json'; |
||
my %tasks; |
my %tasks; |
||
Line 325: | Line 325: | ||
)} |
)} |
||
).map({ |
).map({ |
||
print clear, 1 + $++, ' ', %cat{$category}, ' ', .[0]<title>; |
|||
%tasks{.[0]<title>}<category> = %cat{$category}; |
%tasks{.[0]<title>}<category> = %cat{$category}; |
||
%tasks{.[0]<title>}<author> = .[0]<revisions>[0]<user>; |
%tasks{.[0]<title>}<author> = .[0]<revisions>[0]<user>; |
||
Line 332: | Line 332: | ||
) |
) |
||
} |
} |
||
print clear; |
|||
# Save information to a local file |
# Save information to a local file |
||
Line 342: | Line 344: | ||
%tasks = $hashfile.IO.e ?? $hashfile.IO.slurp.&from-json !! ( ); |
%tasks = $hashfile.IO.e ?? $hashfile.IO.slurp.&from-json !! ( ); |
||
# Convert saved task / author info to |
# Convert saved task / author info to a table |
||
note "\nBuilding |
note "\nBuilding table..."; |
||
my $count = +%tasks; |
my $count = +%tasks; |
||
my $taskcnt = +%tasks.grep: *.value.<category> eq %cat<Programming_Tasks>; |
my $taskcnt = +%tasks.grep: *.value.<category> eq %cat<Programming_Tasks>; |
||
my $draftcnt = $count - $taskcnt; |
my $draftcnt = $count - $taskcnt; |
||
# |
# Open a file handle to dump table in |
||
my $out = open($ |
my $out = open($tablefile, :w) or die "$!\n"; |
||
# Add table boilerplate and header |
# Add table boilerplate and header |
||
$out.say: |
|||
$out.say( '<table border="1" cellpadding="4"><tr><th colspan="2">As of ', Date.today, ' | Total: ', |
|||
"<div style=\"height:80ex;overflow:scroll;border-style:ridge;padding-left:2em;\">\n", |
|||
"$count / Tasks: $taskcnt / Draft Tasks: $draftcnt / By {+%tasks{*}».<author>.unique} Authors", |
|||
"\{|class=\"wikitable\"\n", |
|||
'<tr><th>User</th><th>Authored</th></tr>' ); |
|||
"|+ As of { Date.today } :: Total Tasks: { $count }:: Tasks: { $taskcnt }", |
|||
" :: Draft Tasks: { $draftcnt }\n", |
|||
"! Author !! Authored" |
|||
; |
|||
# Get sorted unique list of task authors |
# Get sorted unique list of task authors |
||
for %tasks{*}».<author>.unique.sort( |
for %tasks{*}».<author>.unique.sort(*.&naturally) -> $author { |
||
# Get list of tasks by this author |
|||
my @these = %tasks.grep( { $_.value.<author> eq $author } ); |
|||
my $s = +@these == 1 ?? '' !! 's'; |
|||
# Add author and contributions link to the first cell |
# Add author and contributions link to the first cell |
||
$out. |
$out.say: "|-\n| [[User:$author|$author]] : [[Special:Contributions/$author|", |
||
" { +@these } task{ $s }]]"; |
|||
$out.say: "|style=\"padding: 0px;\"|\n", |
|||
"\{|class=\"broadtable sortable\" style=\"width: 100%;\"\n", |
|||
"! Task Name !! Date Added !! Status"; |
|||
# Tasks by this author, sorted by name |
|||
for @these.sort({.key.&naturally}) -> $task { |
|||
my $color = $task.value.<category> eq 'Draft' ?? '#ffd' !! '#fff'; |
|||
# Get list of tasks by this author, sorted by name |
|||
for %tasks.grep( { $_.value.<author> eq $author } ).sort({.key.&naturally}) -> $task { |
|||
# |
# add the task link, date and status to the table in the second cell |
||
$out.say: "|-\n|style=\"background-color: $color;\"", |
|||
$out.print( "<li>{$task.value.<date>} - {$task.value.<category>}", |
|||
( $task.key ~~ /\d/ |
|||
?? " data-sort-value=\"{ $task.key.&naturally }\"| [[{uri-escape $task.key}|{$task.key}]]\n" |
|||
) |
|||
!! "| [[{uri-escape $task.key}|{$task.key}]]\n" |
|||
), |
|||
"|style=\"width: 10em; background-color: $color;\"| {$task.value.<date>}\n", |
|||
"|style=\"width: 6em; background-color: $color;\"| {$task.value.<category>}", |
|||
} |
} |
||
$out.say |
$out.say: '|}' |
||
} |
} |
||
$out.say( '</ |
$out.say( "|}\n", '</div>' ); |
||
$out.close; |
$out.close; |
||
note "HTML table file saved as: {$htmlfile.IO.absolute}"; |
|||
note "Table file saved as: {$tablefile.IO.absolute}"; |
|||
sub mediawiki-query ($site, $type, *%query) { |
sub mediawiki-query ($site, $type, *%query) { |
||
Line 391: | Line 413: | ||
sub uri-query-string (*%fields) { %fields.map({ "{.key}={uri-escape .value}" }).join("&") } |
sub uri-query-string (*%fields) { %fields.map({ "{.key}={uri-escape .value}" }).join("&") } |
||
</lang> |
|||
sub sort-key ($a) { $a.lc.subst(/(\d+)/, ->$/ {0~(65+$0.chars).chr~$0},:g) } |
|||
;Sample output |
|||
sub clear { "\r" ~ ' ' x 100 ~ "\r" } |
|||
<table border="1" cellpadding="4"><tr><th colspan="2">As of 2017-12-21 | Total: 1071 / Tasks: 867 / Draft Tasks: 204 / By 247 Authors<tr><th>User</th><th>Authored</th></tr> |
|||
</lang> |
|||
<tr><td><ul>[[User:2Powers|2Powers]] [[Special:Contributions/2Powers|?]]</ul></td><td><ul><ol><li>2013-05-16 - Draft: [[Names%20to%20numbers|Names to numbers]]</li><li>2013-05-16 - Draft: [[Solving%20coin%20problems|Solving coin problems]]</li></ol></ul></td></tr> |
|||
<tr><td><ul>[[User:12.175.32.19|12.175.32.19]] [[Special:Contributions/12.175.32.19|?]]</ul></td><td><ul><ol><li>2009-11-12 - Task: [[Soundex|Soundex]]</li></ol></ul></td></tr> |
|||
<tr><td><ul>[[User:12Me21|12Me21]] [[Special:Contributions/12Me21|?]]</ul></td><td><ul><ol><li>2015-05-04 - Task: [[Draw%20a%20rotating%20cube|Draw a rotating cube]]</li></ol></ul></td></tr> |
|||
{{out|Sample output}} |
|||
<tr><td colspan='2'><br/> Many rows omitted... <br/></td></tr> |
|||
<div style="height:80ex;overflow:scroll;border-style:ridge;padding-left:2em;"> |
|||
<tr><td><ul>[[User:Zorro1024|Zorro1024]] [[Special:Contributions/Zorro1024|?]]</ul></td><td><ul><ol><li>2015-04-16 - Task: [[Perfect%20shuffle|Perfect shuffle]]</li><li>2015-03-21 - Draft: [[Vector|Vector]]</li></ol></ul></td></tr> |
|||
{|class="wikitable" |
|||
<tr><td><ul>[[User:Zzo38|Zzo38]] [[Special:Contributions/Zzo38|?]]</ul></td><td><ul><ol><li>2015-09-20 - Task: [[Thue-Morse|Thue-Morse]]</li></ol></ul></td></tr> |
|||
|+ As of 2018-03-31 :: Total Tasks: 1080:: Tasks: 871 :: Draft Tasks: 209 |
|||
<tr><td><ul>[[User:Русский|Русский]] [[Special:Contributions/Русский|?]]</ul></td><td><ul><ol><li>2012-08-31 - Task: [[Main%20step%20of%20GOST%2028147-89|Main step of GOST 28147-89]]</li><li>2013-01-09 - Draft: [[Old%20Russian%20measure%20of%20length|Old Russian measure of length]]</li><li>2013-05-24 - Draft: [[Transportation%20problem|Transportation problem]]</li></ol></ul></td></tr> |
|||
! Author !! Authored |
|||
</table> |
|||
|- |
|||
| [[User:2Powers|2Powers]] : [[Special:Contributions/2Powers| 2 tasks]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #ffd;"| [[Names%20to%20numbers|Names to numbers]] |
|||
|style="width: 10em; background-color: #ffd;"| 2013-05-16 |
|||
|style="width: 6em; background-color: #ffd;"| Draft |
|||
|- |
|||
|style="background-color: #ffd;"| [[Solving%20coin%20problems|Solving coin problems]] |
|||
|style="width: 10em; background-color: #ffd;"| 2013-05-16 |
|||
|style="width: 6em; background-color: #ffd;"| Draft |
|||
|} |
|||
|- |
|||
| [[User:12.175.32.19|12.175.32.19]] : [[Special:Contributions/12.175.32.19| 1 task]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #fff;"| [[Soundex|Soundex]] |
|||
|style="width: 10em; background-color: #fff;"| 2009-11-12 |
|||
|style="width: 6em; background-color: #fff;"| Task |
|||
|} |
|||
|- |
|||
| [[User:12Me21|12Me21]] : [[Special:Contributions/12Me21| 1 task]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #fff;"| [[Draw%20a%20rotating%20cube|Draw a rotating cube]] |
|||
|style="width: 10em; background-color: #fff;"| 2015-05-04 |
|||
|style="width: 6em; background-color: #fff;"| Task |
|||
|} |
|||
|- |
|||
|colspan="2"|many rows omitted... |
|||
|- |
|||
| [[User:Zorro1024|Zorro1024]] : [[Special:Contributions/Zorro1024| 2 tasks]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #fff;"| [[Perfect%20shuffle|Perfect shuffle]] |
|||
|style="width: 10em; background-color: #fff;"| 2015-04-16 |
|||
|style="width: 6em; background-color: #fff;"| Task |
|||
|- |
|||
|style="background-color: #ffd;"| [[Vector|Vector]] |
|||
|style="width: 10em; background-color: #ffd;"| 2015-03-21 |
|||
|style="width: 6em; background-color: #ffd;"| Draft |
|||
|} |
|||
|- |
|||
| [[User:Zzo38|Zzo38]] : [[Special:Contributions/Zzo38| 1 task]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #fff;"| [[Thue-Morse|Thue-Morse]] |
|||
|style="width: 10em; background-color: #fff;"| 2015-09-20 |
|||
|style="width: 6em; background-color: #fff;"| Task |
|||
|} |
|||
|- |
|||
| [[User:Русский|Русский]] : [[Special:Contributions/Русский| 3 tasks]] |
|||
|style="padding: 0px;"| |
|||
{|class="broadtable sortable" style="width: 100%;" |
|||
! Task Name !! Date Added !! Status |
|||
|- |
|||
|style="background-color: #fff;" data-sort-value="main step of gost 0�28147-0�89 |
Revision as of 16:15, 31 March 2018
In this task, the goal is to compile an authorship list for task descriptions. A pseudocode example (in imperative style) that should accomplish this is as follows:
<lang pseudocode>for each task page
grab page source, discard everything after the first ==section==.
Cache as $previous. Note $author.
for each revision grab page source, discard everything after first ==section==.
Cache as $previous2. Note $author2
compare $previous2 to $previous. If different, record $author to $list. replace $previous with $previous2 replace $author with $author2</lang>
The following resources for HTTP interface information for MediaWiki may prove to be useful:
- https://www.mediawiki.org/wiki/Index.php#Raw
- https://www.mediawiki.org/wiki/Index.php#History
- https://www.mediawiki.org/wiki/API:Main_page
Conversely, some languages have libraries which abstract these interfaces into language-native idioms. Use of these abstractions is perfectly fine.
Please DO NOT add a full output for each programming language; just show a representative sample. One full list is useful. Multiple full lists just use space and bandwidth.
Perl 6
The pseudocode above is no longer really useful as the page format has changed significantly since this task was written. Rather than checking every edit to see if it was a change to the task description, we'll just assume the user that created the page is the task author. This isn't 100% accurate; a very few pages got renamed and recreated by someone other than the original author without preserving the history, so they are misreported (15 Puzzle Game for instance,) but is as good as it is likely to get without extensive manual intervention. Subsequent edits to the task description are not credited. As it is, we must still make thousands of requests and pound the server pretty hard. Checking every edit would make the task several of orders of magnitude more abusive of the server (and my internet connection.)
<lang perl6>use HTTP::UserAgent; use URI::Escape; use JSON::Fast; use Sort::Naturally;
- Friendlier descriptions for task categories
my %cat = (
'Programming_Tasks' => 'Task', 'Draft_Programming_Tasks' => 'Draft'
);
my $client = HTTP::UserAgent.new;
my $url = 'http://rosettacode.org/mw';
my $tablefile = './RC_Authors.txt'; my $hashfile = './RC_Authors.json';
my %tasks;
- clear screen
run($*DISTRO.is-win ?? 'cls' !! 'clear');
- =begin update
note 'Retreiving task information...';
for %cat.keys -> $category {
mediawiki-query( $url, 'pages', :generator<categorymembers>, :gcmtitle("Category:$category"), :gcmlimit<350>, :rawcontinue(), :prop<title> ).map({ mediawiki-query( $url, 'pages', :titles(.<title>), :prop<revisions>, :rvprop<user|timestamp>, :rvstart<2000-01-01T01:01:01Z>, :rvdir<newer>, :rvlimit<1> )} ).map({ print clear, 1 + $++, ' ', %cat{$category}, ' ', .[0]<title>; %tasks{.[0]<title>}<category> = %cat{$category}; %tasks{.[0]<title>}<author> = .[0]<revisions>[0]<user>; %tasks{.[0]<title>}<date> = .[0]<revisions>[0]<timestamp>.subst(/'T'.+$/, ) } )
}
print clear;
- Save information to a local file
note "\nTask information saved to local file: {$hashfile.IO.absolute}"; $hashfile.IO.spurt(%tasks.&to-json);
- =end update
- Load information from local file
%tasks = $hashfile.IO.e ?? $hashfile.IO.slurp.&from-json !! ( );
- Convert saved task / author info to a table
note "\nBuilding table..."; my $count = +%tasks; my $taskcnt = +%tasks.grep: *.value.<category> eq %cat<Programming_Tasks>; my $draftcnt = $count - $taskcnt;
- Open a file handle to dump table in
my $out = open($tablefile, :w) or die "$!\n";
- Add table boilerplate and header
$out.say:
"
"\{|class=\"wikitable\"\n", "|+ As of { Date.today } :: Total Tasks: { $count }:: Tasks: { $taskcnt }", " :: Draft Tasks: { $draftcnt }\n", "! Author !! Authored"
- Get sorted unique list of task authors
for %tasks{*}».<author>.unique.sort(*.&naturally) -> $author {
# Get list of tasks by this author my @these = %tasks.grep( { $_.value.<author> eq $author } ); my $s = +@these == 1 ?? !! 's';
# Add author and contributions link to the first cell $out.say: "|-\n| $author : ", " { +@these } task{ $s }";
$out.say: "|style=\"padding: 0px;\"|\n", "\{|class=\"broadtable sortable\" style=\"width: 100%;\"\n", "! Task Name !! Date Added !! Status";
# Tasks by this author, sorted by name for @these.sort({.key.&naturally}) -> $task {
my $color = $task.value.<category> eq 'Draft' ?? '#ffd' !! '#fff';
# add the task link, date and status to the table in the second cell $out.say: "|-\n|style=\"background-color: $color;\"", ( $task.key ~~ /\d/ ?? " data-sort-value=\"{ $task.key.&naturally }\"| [[{uri-escape $task.key}|{$task.key}]]\n" !! "| [[{uri-escape $task.key}|{$task.key}]]\n" ), "|style=\"width: 10em; background-color: $color;\"| {$task.value.<date>}\n", "|style=\"width: 6em; background-color: $color;\"| {$task.value.<category>}", } $out.say: '|}'
}
$out.say( "|}\n", '' );
$out.close;
note "Table file saved as: {$tablefile.IO.absolute}";
sub mediawiki-query ($site, $type, *%query) {
my $url = "$site/api.php?" ~ uri-query-string( :action<query>, :format<json>, :formatversion<2>, |%query); my $continue = ;
gather loop { my $response = $client.get("$url&$continue"); my $data = from-json($response.content); take $_ for $data.<query>.{$type}.values; $continue = uri-query-string |($data.<query-continue>{*}».hash.hash or last); }
}
sub uri-query-string (*%fields) { %fields.map({ "{.key}={uri-escape .value}" }).join("&") }
sub sort-key ($a) { $a.lc.subst(/(\d+)/, ->$/ {0~(65+$0.chars).chr~$0},:g) }
sub clear { "\r" ~ ' ' x 100 ~ "\r" } </lang>
- Sample output:
Author | Authored | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
2Powers : 2 tasks |
| |||||||||
12.175.32.19 : 1 task |
| |||||||||
12Me21 : 1 task |
| |||||||||
many rows omitted... | ||||||||||
Zorro1024 : 2 tasks |
| |||||||||
Zzo38 : 1 task |
| |||||||||
Русский : 3 tasks |
|