Rosetta Code/List authors of task descriptions

From Rosetta Code
Rosetta Code/List authors of task descriptions is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
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:
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

The following resources for HTTP interface information for MediaWiki may prove to be useful:

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.

As of 2018-02-27 | Total: 1077 / Tasks: 869 / Draft Tasks: 208 / By 249 Authors
    1. 2008-09-25 - Task: HTTP
    1. 2007-01-23 - Task: SOAP
    1. 2010-04-08 - Task: A+B
    1. 2011-01-20 - Draft: VList

Perl 6[edit]

Works with: Rakudo version 2017.11

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.)

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 =;
my $url = '';
my $htmlfile = './RC_Authors.html';
my $hashfile = './RC_Authors.json';
my %tasks;
# clear screen
run($* ?? 'cls' !! 'clear');
#=begin update
note 'Retreiving task information...';
for %cat.keys -> $category {
$url, 'pages',
$url, 'pages',
say 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'.+$/, '')
# Save information to a local file
note "\nTask information saved to local file: {$hashfile.IO.absolute}";
#=end update
# Load information from local file
%tasks = $hashfile.IO.e ?? $hashfile.IO.slurp.&from-json !! ( );
# Convert saved task / author info to an HTML table
note "\nBuilding HTML table...";
my $count = +%tasks;
my $taskcnt = +%tasks.grep: *.value.<category> eq %cat<Programming_Tasks>;
my $draftcnt = $count - $taskcnt;
# Dump an HTML table to a file
my $out = open($htmlfile, :w) or die "$!\n";
# Add table boilerplate and header
$out.say( '<table border="1" cellpadding="4"><tr><th colspan="2">As of ',, ' | Total: ',
"$count / Tasks: $taskcnt / Draft Tasks: $draftcnt / By {+%tasks{*}».<author>.unique} Authors",
'<tr><th>User</th><th>Authored</th></tr>' );
# Get sorted unique list of task authors
for %tasks{*}».<author>.unique.sort({.&naturally}) -> $author {
# Add author and contributions link to the first cell
$out.print( "<tr><td><ul>[[User:$author|$author]] [[Special:Contributions/$author|?]]</ul></td><td><ul><ol>" );
# Get list of tasks by this author, sorted by name
for %tasks.grep( { $_.value.<author> eq $author } ).sort({.key.&naturally}) -> $task {
# and add the date, status and task link to the list in the second cell
$out.print( "<li>{$task.value.<date>} - {$task.value.<category>}",
" [[{uri-escape $task.key}|{$task.key}]]</li>"
$out.say( '</ol></ul></td></tr>' );
$out.say( '</table>' );
note "HTML table file saved as: {$htmlfile.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) {{ "{.key}={uri-escape .value}" }).join("&") }
Sample output
As of 2017-12-21 | Total: 1071 / Tasks: 867 / Draft Tasks: 204 / By 247 Authors

Many rows omitted...