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