Rosetta Code/List authors of task descriptions: Difference between revisions

Content added Content deleted
(Added Wren)
Line 673: Line 673:
|}
|}
|}
|}

=={{header|Wren}}==
{{trans|Go}}
{{libheader|libcurl}}
{{libheader|Wren-pattern}}
{{libheader|Wren-fmt}}
An embedded program so we can use libcurl.

Takes a little over an hour to run as the history page(s) for each task need to be downloaded and parsed to find the author.
<lang ecmascript>/* rc_list_authors_of_task_descriptions.wren */

import "./pattern" for Pattern
import "./fmt" for Fmt

var CURLOPT_URL = 10002
var CURLOPT_FOLLOWLOCATION = 52
var CURLOPT_WRITEFUNCTION = 20011
var CURLOPT_WRITEDATA = 10001

foreign class Buffer {
construct new() {} // C will allocate buffer of a suitable size

foreign value // returns buffer contents as a string
}

foreign class Curl {
construct easyInit() {}

foreign easySetOpt(opt, param)

foreign easyPerform()

foreign easyCleanup()
}

var curl = Curl.easyInit()

var getContent = Fn.new { |url|
var buffer = Buffer.new()
curl.easySetOpt(CURLOPT_URL, url)
curl.easySetOpt(CURLOPT_FOLLOWLOCATION, 1)
curl.easySetOpt(CURLOPT_WRITEFUNCTION, 0) // write function to be supplied by C
curl.easySetOpt(CURLOPT_WRITEDATA, buffer)
curl.easyPerform()
return buffer.value
}

var p1 = Pattern.new("<li><a href/=\"//wiki//[+1^\"]\"")
var i = "\"&"
var p2 = Pattern.new("a href/=\"//[wiki//User:|mw//index.php?title/=User:|wiki//Special:Contributions//][+1/I]\"", 0, i)
var tasks = []
var urls = [
"http://rosettacode.org/wiki/Category:Programming_Tasks",
"http://rosettacode.org/wiki/Category:Draft_Programming_Tasks"
]
for (url in urls) {
var content = getContent.call(url)
var matches = p1.findAll(content)
for (m in matches) {
var task = m.capsText[0]
// exclude any 'category' references
if (!task.startsWith("Category:")) tasks.add(task)
}
}
var authors = {}
for (task in tasks) {
// check the last or only history page for each task
var url = "http://rosettacode.org/mw/index.php?title=%(task)&dir=prev&action=history"
var content = getContent.call(url)
var matches = p2.findAll(content)
// the task author should be the final user on that page
var author = matches[-1].capsText[1].replace("_", " ")
// add this task to the author's count
if (authors.containsKey(author)) {
authors[author] = authors[author] + 1
} else {
authors[author] = 1
}
}

// sort the authors in descending order by number of tasks created
var authorNumbers = authors.toList
authorNumbers.sort { |a, b| a.value > b.value }
// print the top thirty say
System.print("Total tasks : %(tasks.count)")
System.print("Total authors : %(authors.count)")
System.print("\nThe top 30 authors by number of tasks created are:\n")
System.print("Pos Tasks Author")
System.print("==== ===== ======")
var lastNumber = 0
var lastIndex = -1
i = 0
for (authorNumber in authorNumbers.take(30)) {
var j = i
var eq = " "
if (authorNumber.value == lastNumber) {
j = lastIndex
eq = "="
} else {
lastIndex = i
lastNumber = authorNumber.value
}
Fmt.print("$3d$s $3d $s", j+1, eq, authorNumber.value, authorNumber.key)
i = i + 1
}
curl.easyCleanup()</lang>
<br>
We now embed this script in the following C program, build and run.
<lang c>/* gcc rc_list_authors_of_task_descriptions.c -o rc_list_authors_of_task_descriptions -lcurl -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"

struct MemoryStruct {
char *memory;
size_t size;
};

/* C <=> Wren interface functions */

static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}

mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}

void C_bufferAllocate(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct MemoryStruct));
ms->memory = malloc(1);
ms->size = 0;
}

void C_bufferFinalize(void* data) {
struct MemoryStruct *ms = (struct MemoryStruct *)data;
free(ms->memory);
}

void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}

void C_value(WrenVM* vm) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 0);
wrenSetSlotString(vm, 0, ms->memory);
}

void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_perform(curl);
}

void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}

void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
if (opt < 10000) {
long lparam = (long)wrenGetSlotDouble(vm, 2);
curl_easy_setopt(curl, opt, lparam);
} else if (opt < 20000) {
if (opt == CURLOPT_WRITEDATA) {
struct MemoryStruct *ms = (struct MemoryStruct *)wrenGetSlotForeign(vm, 2);
curl_easy_setopt(curl, opt, (void *)ms);
} else if (opt == CURLOPT_URL) {
const char *url = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, url);
}
} else if (opt < 30000) {
if (opt == CURLOPT_WRITEFUNCTION) {
curl_easy_setopt(curl, opt, &WriteMemoryCallback);
}
}
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
methods.allocate = C_bufferAllocate;
methods.finalize = C_bufferFinalize;
} else if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}

WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Buffer") == 0) {
if (!isStatic && strcmp(signature, "value") == 0) return C_value;
} else if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}

char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}

static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}

WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}

int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "rc_list_authors_of_task_descriptions.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</lang>

{{out}}
Position as at 6th January, 2022.
<pre>
Total tasks : 1492
Total authors : 307

The top 30 authors by number of tasks created are:

Pos Tasks Author
==== ===== ======
1 199 Paddy3118
2 128 CalmoSoft
3 71 Markhobley
4 66 Gerard Schildberger
5 55 Mwn3d
6 44 Thundergnat
7 39 NevilleDNZ
8 36 Nigel Galloway
9 33 Short Circuit
10 23 Grondilu
11 21 Blue Prawn
12 20 Fwend
12= 20 Dkf
14 18 Kernigh
15 17 Dmitry-kazakov
15= 17 Wherrera
15= 17 ShinTakezou
15= 17 Ledrug
19 16 PureFox
20 13 Paulo Jorente
20= 13 Waldorf
20= 13 Abu
23 12 Ce
23= 12 Kevin Reid
25 10 Tinku99
25= 10 Bearophile
27 9 TimSC
27= 9 Puppydrum64
27= 9 Trizen
27= 9 EMBee
</pre>