Rosetta Code/Find unimplemented tasks

From Rosetta Code
Jump to: navigation, search
Task
Rosetta Code/Find unimplemented tasks
You are encouraged to solve this task according to the task description, using any language you may know.

Given the name of a language on Rosetta Code, find all tasks which are not implemented in that language.

Note: Implementations should allow for fetching more data than can be returned in one request to Rosetta Code.

You'll need to use the Media Wiki API, which you can find out about locally, here, or in Media Wiki's API documentation at, API:Query

Contents

[edit] Ada

Library: AWS

Parsing XML with XMLAda from Adacore

with Aws.Client, Aws.Messages, Aws.Response, Aws.Resources, Aws.Url;
with Dom.Readers, Dom.Core, Dom.Core.Documents, Dom.Core.Nodes, Dom.Core.Attrs;
with Input_Sources.Strings, Unicode, Unicode.Ces.Utf8;
with Ada.Strings.Unbounded, Ada.Text_IO, Ada.Command_Line;
with Ada.Containers.Vectors;
 
use Aws.Client, Aws.Messages, Aws.Response, Aws.Resources, Aws.Url;
use Dom.Readers, Dom.Core, Dom.Core.Documents, Dom.Core.Nodes, Dom.Core.Attrs;
use Aws, Ada.Strings.Unbounded, Input_Sources.Strings;
use Ada.Text_IO, Ada.Command_Line;
 
procedure Not_Coded is
 
package Members_Vectors is new Ada.Containers.Vectors (
Index_Type => Positive,
Element_Type => Unbounded_String);
use Members_Vectors;
 
All_Tasks, Language_Members : Vector;
 
procedure Get_Vector (Category : in String; Mbr_Vector : in out Vector) is
Reader : Tree_Reader;
Doc  : Document;
List  : Node_List;
N  : Node;
A  : Attr;
Page  : Aws.Response.Data;
S  : Messages.Status_Code;
 
-- Query has cmlimit value of 100, so we need 5 calls to
-- retrieve the complete list of Programming_category
Uri_Xml  : constant String  :=
"http://rosettacode.org/mw/api.php?action=query&list=categorymembers"
&
"&format=xml&cmlimit=100&cmtitle=Category:";
Cmcontinue : Unbounded_String := Null_Unbounded_String;
begin
loop
Page :=
Aws.Client.Get (Uri_Xml & Category & (To_String (Cmcontinue)));
S  := Response.Status_Code (Page);
if S not in Messages.Success then
Put_Line
("Unable to retrieve data => Status Code :" &
Image (S) &
" Reason :" &
Reason_Phrase (S));
raise Connection_Error;
end if;
declare
Xml  : constant String := Message_Body (Page);
Source : String_Input;
begin
Open
(Xml'Unrestricted_Access,
Unicode.Ces.Utf8.Utf8_Encoding,
Source);
Parse (Reader, Source);
Close (Source);
end;
Doc  := Get_Tree (Reader);
List := Get_Elements_By_Tag_Name (Doc, "cm");
for Index in 1 .. Length (List) loop
N := Item (List, Index - 1);
A := Get_Named_Item (Attributes (N), "title");
Members_Vectors.Append
(Mbr_Vector,
To_Unbounded_String (Value (A)));
end loop;
Free (List);
List := Get_Elements_By_Tag_Name (Doc, "query-continue");
if Length (List) = 0 then
-- we are done
Free (List);
Free (Reader);
exit;
end if;
N  := First_Child (Item (List, 0));
A  := Get_Named_Item (Attributes (N), "cmcontinue");
Cmcontinue :=
To_Unbounded_String
("&cmcontinue=" & Aws.Url.Encode (Value (A)));
Free (List);
Free (Reader);
end loop;
end Get_Vector;
 
procedure Quick_Diff (From : in out Vector; Substract : in Vector) is
Beginning, Position : Extended_Index;
begin
-- take adavantage that both lists are already sorted
Beginning := First_Index (From);
for I in First_Index (Substract) .. Last_Index (Substract) loop
Position :=
Find_Index
(Container => From,
Item => Members_Vectors.Element (Substract, I),
Index => Beginning);
if not (Position = No_Index) then
Delete (From, Position);
Beginning := Position;
end if;
end loop;
end Quick_Diff;
 
begin
if Argument_Count = 0 then
Put_Line ("Can't process : No language given!");
return;
else
Get_Vector (Argument (1), Language_Members);
end if;
 
Get_Vector ("Programming_Tasks", All_Tasks);
Quick_Diff (All_Tasks, Language_Members);
 
for I in First_Index (All_Tasks) .. Last_Index (All_Tasks) loop
Put_Line (To_String (Members_Vectors.Element (All_Tasks, I)));
end loop;
Put_Line
("Numbers of tasks not implemented :=" &
Integer'Image (Last_Index ((All_Tasks))));
end Not_Coded;

[edit] AutoHotkey

The GUI overkill version with comments.

 
#NoEnv ; do not resolve environment variables (speed)
#SingleInstance force ; allow only one instance
SetBatchLines, -1 ; set to highest script speed
SetControlDelay, 0 ; set delay between control commands to lowest
 
; additional label, for clarity only
AutoExec:
Gui, Add, DDL, x10 y10 w270 r20 vlngStr ; add drop-down list
Gui, Add, Button, x290 y10 gShowLng, Show Unimplemented ; add button
Gui, Add, ListView, x10 y36 w400 h300 vcatLst gOnLV, Unimplemented ; add listview
Gui, Add, StatusBar, vsbStr, ; add statusbar
Gui, Show, , RosettaCode unimplemented list ; show the gui
allLng := getList("lng") ; get a list of all available languages
selectStr = Select language... ; set selection string for ddl
GuiControl, , LngStr, |%selectStr%||%allLng% ; set the ddl to new contents
SB_SetIcon("user32.dll", 5) ; change statusbar icon
SB_SetText("Done loading languages. Select from menu.") ; change statusbar text
Return ; end of the autoexec section. Script waits for input.
 
; subroutine for language list in ddl update
ShowLng:
Gui, Submit, NoHide ; refresh all gui variables
If (lngStr != selectStr) ; if the current selected language is not the selection string
{
SB_SetIcon("user32.dll", 2) ; set statusbar icon to exclamation
SB_SetText("Loading unimplemented tasks... Please wait.") ; set statusbar text
allTsk := getList("tsk") ; get a list of all tasks
allThis := getList(lngStr) ; get a list of all done tasks for this language
Loop, Parse, allTsk, | ; parse the list of all tasks
{
If !InStr(allThis,A_LoopField) ; if the current task is not found in the list of all tasks
notImpl .= A_LoopField . "|" ; add the current field to the notImpl variable
allTskCnt := A_Index ; save the index for final count
}
StringTrimRight, notImpl, notImpl, 1 ; remove last delimiter
LV_Delete() ; emty the listview
GuiControl, -Redraw, catLst ; set the listview to not redraw while adding (speed)
Loop, Parse, notImpl, | ; parse the list of not implemented tasks
{
LV_Add("", A_LoopField) ; add them to the listview, field by field
notImplCnt := A_Index ; save the index for final count
}
GuiControl, +Redraw, catLst ; set the listview back to normal
SB_SetIcon("user32.dll", 5) ; change statusbar icon to information
SB_SetText("There are " . notImplCnt . " of " . allTskCnt
. " tasks unimplemented. Double-click task to open in browser.") ; set the statusbar text
notImpl = ; empty the notImpl variable
notImplCnt = 0 ; set the count back to 0
}
Return
 
; subroutine for action on listview
OnLV:
If (A_GuiEvent = "DoubleClick") ; if the listview was double-clicked
{
LV_GetText(rowTxt, A_EventInfo) ; get the text of the clicked row
rowTxt := Enc_Uri(rowTxt) ; uri-encode the text
StringReplace, rowTxt, rowTxt, `%20, _, All ; replace all space-encodings with underscores
Run % "http://rosettacode.org/wiki/" . rowTxt ; run the resulting link in the default browser
}
Return
 
; generic function to gather list
getList(category)
{
fileName = temp.xml ; set temp-file name
If (category = "lng") ; if the category received is lng
{
category = Programming_Languages ; set the category
fileName = lng.xml ; set temp-file name
IfExist, %fileName% ; if the file already exists
{
FileGetTime, modTime, %fileName% ; get the last modified time
EnvSub, modTime, %A_Now%, days ; get the difference between now and last modified time in days
If (modTime < 3) ; if the result is less than 3
Goto, GetFileNoDL ; go to function-internal subroutine to parse
}
SB_SetIcon("user32.dll", 2) ; set statusbar icon
SB_SetText("Loading languages... Please wait.") ; set statusbar text
}
If (category = "tsk") ; if the category received is tsk
category = Programming_Tasks ; set the category
 
getFile: ; function-internal subroutine for getting a file and parsing it
; construct the url
url := "http://www.rosettacode.org/w/api.php?action=query&list="
. "categorymembers&cmtitle=Category:" . category
. "&cmlimit=500&format=xml" . doContinue
UrlDownloadToFile, %url%, %fileName% ; download the url
 
getFileNoDL: ; function-internal subroutine for parsing a file
FileRead, data, %fileName% ; read file into variable
pos = 1 ; set while-loop counter
rxp = title="(.*?)" ; set regular expression
While (pos := RegExMatch(data, rxp, title, pos)) ; get the contents of the title fields one-by-one
{
If InStr(title1, "Category:") ; if the contents contain Category:
StringTrimLeft, title1, title1, 9 ; remove that from the contents
StringReplace, title1, title1, |, `|, All ; escape all containing delimiters
title1 := Dec_XML(UTF82Ansi(title1)) ; convert to ansi first and then decode html entities
allTitles .= title1 . "|" ; add this title to list
pos++ ; increment counter
}
rxp = cmcontinue="(.*?)" ; set regular expression
If RegExMatch(data, rxp, next) ; when found
{
doContinue = &cmcontinue=%next1% ; set continuation string to add to url
Goto getFile ; go to function-internal subroutine to redownload and parse
}
StringTrimRight, allTitles, allTitles, 1 ; remove last delimiter from result
Return allTitles ; return result
}
 
; function to convert html entities to ansi equivalents
Dec_XML(str)
{
Loop
If RegexMatch(str, "S)(&#(\d+);)", dec)
StringReplace, str, str, %dec1%, % Chr(dec2), All
Else If RegexMatch(str, "Si)(&#x([\da-f]+);)", hex)
StringReplace, str, str, %hex1%, % Chr("0x" . hex2), All
Else
Break
StringReplace, str, str, &nbsp;, %A_Space%, All
StringReplace, str, str, &quot;, ", All
StringReplace, str, str, &apos;, ', All
StringReplace, str, str, &lt;, <, All
StringReplace, str, str, &gt;, >, All
StringReplace, str, str, &amp;, &, All
return, str
}
 
; function to uri-encode input string
Enc_Uri(str)
{
f = %A_FormatInteger%
SetFormat, Integer, Hex
If RegExMatch(str, "^\w+:/{0,2}", pr)
StringTrimLeft, str, str, StrLen(pr)
StringReplace, str, str, `%, `%25, All
Loop
If RegExMatch(str, "i)[^\w\.~%/:]", char)
StringReplace, str, str, %char%, % "%" . SubStr(Asc(char),3), All
Else Break
SetFormat, Integer, %f%
Return, pr . str
}
 
; function to convert unicode to ansi text
UTF82Ansi(zString)
{
Ansi2Unicode(zString, wString, 65001)
Unicode2Ansi(wString, sString, 0)
Return sString
}
 
; helper function for unicode to ansi function
Ansi2Unicode(ByRef sString, ByRef wString, CP = 0)
{
nSize := DllCall("MultiByteToWideChar", "Uint", CP
, "Uint", 0, "Uint", &sString, "int", -1
, "Uint", 0, "int", 0)
VarSetCapacity(wString, nSize * 2)
DllCall("MultiByteToWideChar"
, "Uint", CP, "Uint", 0, "Uint", &sString, "int", -1
, "Uint", &wString, "int", nSize)
}
 
; helper function for unicode to ansi function
Unicode2Ansi(ByRef wString, ByRef sString, CP = 0)
{
nSize := DllCall("WideCharToMultiByte"
, "Uint", CP, "Uint", 0, "Uint", &wString, "int", -1
, "Uint", 0, "int", 0, "Uint", 0, "Uint", 0)
VarSetCapacity(sString, nSize)
DllCall("WideCharToMultiByte"
, "Uint", CP, "Uint", 0, "Uint", &wString, "int", -1
, "str", sString, "int", nSize, "Uint", 0, "Uint", 0)
}
 
; subroutine called when user closes the gui
GuiClose:
ExitApp ; exit the script
Return
 

[edit] Output

Loads a list of all languages. Pick the language you would like to see the unimplemented tasks of, press the button, double click the selected task to launch in default browser. It will download the languages to file and redownload if older than 3 days (to save unnecessary bandwith).

Ahk find unimplemented.png

[edit] C#

Using JSON (not parsed, just Regex.)

To help demonstrate paging, the cmlimit parameter has been omitted from the search query so that 10 rows are returned by default

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Net;
 
class Program {
static List<string> GetTitlesFromCategory(string category) {
string searchQueryFormat = "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:{0}&format=json{1}";
List<string> results = new List<string>();
string cmcontinue = string.Empty;
 
do {
string cmContinueKeyValue;
 
//append continue variable as needed
if (cmcontinue.Length > 0)
cmContinueKeyValue = String.Format("&cmcontinue={0}", cmcontinue);
else
cmContinueKeyValue = String.Empty;
 
//execute query
string query = String.Format(searchQueryFormat, category, cmContinueKeyValue);
string content = new WebClient().DownloadString(query);
 
results.AddRange(new Regex("\"title\":\"(.+?)\"").Matches(content).Cast<Match>().Select(x => x.Groups[1].Value));
 
//detect if more results are available
cmcontinue = Regex.Match(content, @"{""cmcontinue"":""([^""]+)""}", RegexOptions.IgnoreCase).Groups["1"].Value;
} while (cmcontinue.Length > 0);
 
return results;
}
 
static string[] GetUnimplementedTasksFromLanguage(string language) {
List<string> alltasks = GetTitlesFromCategory("Programming_Tasks");
List<string> lang = GetTitlesFromCategory(language);
 
return alltasks.Where(x => !lang.Contains(x)).ToArray();
}
 
static void Main(string[] args) {
string[] unimpl = GetUnimplementedTasksFromLanguage(args[0]);
 
foreach (string i in unimpl) Console.WriteLine(i);
}
}

[edit] Clojure

This uses a couple of core libraries, and a Java method for URL encoding.

(require
'[clojure.xml :as xml]
'[clojure.set :as set]
'[clojure.string :as string])
(import '[java.net URLEncoder])

The titles-cont function fetches and parses an XML response, and walks over it extracting titles. It also extracts the cmcontinue value, if present. Returns a pair [titles,cmcontinue].

(defn titles-cont [url]
(let [docseq (-> url xml/parse xml-seq)]
((juxt #(filter string? %), #(-> (filter map? %) first :cmcontinue))
(for [{:keys [tag attrs content]} docseq :when (#{:cm :query-continue} tag)]
(if (= tag :cm)
(attrs :title)
(-> content first :attrs))))))

The get-titles function has 1- and 2-argument versions. The former takes the name of a category, composes the appropriate URL query, and calls the 2-argument version. The 2-argument version gets a title list (with possible cmcontinue value), chaining further calls as necessary into the lazy sequence result.

(defn urlencode [s] (URLEncoder/encode s "UTF-8"))
(defn param [p v] (str p (urlencode v)))
 
(defn get-titles
([category]
(let [urlbase "http://www.rosettacode.org/w/api.php"
params ["action=query"
"list=categorymembers"
"format=xml"
"cmlimit=200"
(param "cmtitle=Category:" category)]
url (str urlbase "?" (string/join "&" params)]
(get-titles url nil)))
([url continue-at]
(let [continue-param (if continue-at (param "&cmcontinue=" continue-at))
[titles continue] (titles-cont (str url continue-param))]
(if continue
(lazy-cat titles (get-titles url continue))
titles))))

The unimplemented function gets a set of all titles and of language-implemented titles and returns the difference. It uses future in order to do the necessary URL requests in parallel.

(defn unimplemented [lang-name]
(let [title-set #(future (apply sorted-set (get-titles %)))
all-titles (title-set "Programming_Tasks")
lang-titles (title-set lang-name)]
(seq (set/difference @all-titles @lang-titles))))
 
(let [titles (unimplemented "Clojure")]
(doseq [title titles] (println title))
(println "count: " (count titles)))
(shutdown-agents)

[edit] E

Using JSON.

#!/usr/bin/env rune
 
# NOTE: This program will not work in released E, because TermL is an
# imperfect superset of JSON in that version: it does not accept "\/".
# If you build E from the latest source in SVN then it will work.
#
# Usage: rosettacode-cat-subtract.e [<lang e>]
#
# Prints a list of tasks which have not been completed in the language.
# If unspecified, the default language is E.
 
pragma.syntax("0.9")
pragma.enable("accumulator")
 
def termParser := <import:org.quasiliteral.term.makeTermParser>
def jURLEncoder := <unsafe:java.net.makeURLEncoder>
 
def urlEncode(text) {
return jURLEncoder.encode(text, "UTF-8")
}
 
/** Convert JSON-as-term-tree to the corresponding natural E data structures. */
def jsonTermToData(term) {
switch (term) {
 
# JSON object to E map
match term`{@assocs*}` {
return accum [].asMap() for term`@{key :String}: @valueJson` in assocs {
_.with(key, jsonTermToData(valueJson))
}
}
 
# JSON array to E list
match term`[@elements*]` {
return accum [] for elem in elements { _.with(jsonTermToData(elem)) }
}
 
# Literals just need to be coerced
match lit :any[String, int, float64] {
return lit
}
 
# Doesn't support true/false/null, but we don't need that for this application.
}
}
 
def fetchCategoryAccum(name, membersSoFar :Set, extraArgs) {
stderr.println(`Fetching Category:$name $extraArgs...`)
 
def categoryAPIResource := <http>[`//rosettacode.org/w/api.php?` +
`action=query&list=categorymembers&cmtitle=Category:${urlEncode(name)}&` +
`format=json&cmlimit=500&cmprop=title$extraArgs`]
 
def members :=
when (def responseJSON := categoryAPIResource <- getTwine()) -> {
# stderr.println(`Fetched Category:$name $extraArgs, parsing...`)
def response := jsonTermToData(termParser(responseJSON))
 
# stderr.println(`Parsed Category:$name $extraArgs response, extracting data...`)
def [
"query" => ["categorymembers" => records],
"query-continue" => continueData := null
] := response
def members := accum membersSoFar for record in records { _.with(record["title"]) }
 
switch (continueData) {
match ==null {
stderr.println(`Got all ${members.size()} for Category:$name.`)
members
}
match ["categorymembers" => ["cmcontinue" => continueParam]] {
stderr.println(`Fetched ${members.size()} members for Category:$name...`)
fetchCategoryAccum(name, members, `&cmcontinue=` + urlEncode(continueParam))
}
}
} catch p { throw(p) }
 
return members
}
 
def fetchCategory(name) {
return fetchCategoryAccum(name, [].asSet(), "")
}
 
# Interpret program arguments
def lang := switch (interp.getArgs()) {
match [lang] { lang }
match [] { "E" }
}
 
# Fetch categories
when (def allTasks := fetchCategory("Programming_Tasks"),
def doneTasks := fetchCategory(lang),
def omitTasks := fetchCategory(lang + "/Omit")
) -> {
 
# Compute difference and report
def notDoneTasks := allTasks &! (doneTasks | omitTasks)
println()
println("\n".rjoin(notDoneTasks.getElements().sort()))
 
} catch p {
# Whoops, something went wrong
stderr.println(`$p${p.eStack()}`)
}

[edit] Go

XML, stepping through the elements.

package main
 
import (
"encoding/xml"
"fmt"
"io"
"net/http"
"net/url"
)
 
const language = "Go"
 
var baseQuery = "http://rosettacode.org/mw/api.php?action=query" +
"&format=xml&list=categorymembers&cmlimit=100"
 
func req(u string, foundCm func(string)) string {
resp, err := http.Get(u)
if err != nil {
fmt.Println(err) // connection or request fail
return ""
}
defer resp.Body.Close()
for p := xml.NewDecoder(resp.Body); ; {
t, err := p.RawToken()
switch s, ok := t.(xml.StartElement); {
case err == io.EOF:
return ""
case err != nil:
fmt.Println(err)
return ""
case !ok:
continue
case s.Name.Local == "cm":
for _, a := range s.Attr {
if a.Name.Local == "title" {
foundCm(a.Value)
}
}
case s.Name.Local == "categorymembers" && len(s.Attr) > 0 &&
s.Attr[0].Name.Local == "cmcontinue":
return url.QueryEscape(s.Attr[0].Value)
}
}
return ""
}
 
func main() {
// get language members, store in a map
langMap := make(map[string]bool)
storeLang := func(cm string) { langMap[cm] = true }
languageQuery := baseQuery + "&cmtitle=Category:" + language
continueAt := req(languageQuery, storeLang)
for continueAt > "" {
continueAt = req(languageQuery+"&cmcontinue="+continueAt, storeLang)
}
 
// a quick check to avoid long output
if len(langMap) == 0 {
fmt.Println("no tasks implemented for", language)
return
}
 
// get tasks, print as we go along
printUnImp := func(cm string) {
if !langMap[cm] {
fmt.Println(cm)
}
}
taskQuery := baseQuery + "&cmtitle=Category:Programming_Tasks"
continueAt = req(taskQuery, printUnImp)
for continueAt > "" {
continueAt = req(taskQuery+"&cmcontinue="+continueAt, printUnImp)
}
}

[edit] Haskell

Library: HTTP XML
from HackageDB
import Network.Browser
import Network.HTTP
import Network.URI
import Data.List
import Data.Maybe
import Text.XML.Light
import Control.Arrow
import Data.Char
 
getRespons url = do
rsp <- Network.Browser.browse $ do
setAllowRedirects True
setOutHandler $ const (return ()) -- quiet
request $ getRequest url
return $ rspBody $ snd rsp
 
replaceWithSpace c = (\x -> if c==x then ' ' else x)
 
encl = chr 34
 
unimpTasks lang = do
allTasks <- getRespons "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml"
impl <- getRespons ( "http://rosettacode.org/json/isb/" ++ lang ++ ".json")
let langxx = map (map(replaceWithSpace '_')) $ filter (/=",") $ words $ map (replaceWithSpace encl ) $ init $ drop 1 impl
xml = onlyElems $ parseXML allTasks
allxx = concatMap (map (fromJust.findAttr (unqual "title")). filterElementsName (== unqual "cm")) xml
mapM_ putStrLn $ sort $ allxx \\ langxx

[edit] J

Solution:

require 'strings web/gethttp'
 
findUnimpTasks=: ('Programming_Tasks' -.&getCategoryMembers ,&'/Omit') ([ #~ -.@e.) getCategoryMembers
 
getTagContents=: dyad define
'starttag endtag'=. x
('\' -.~ endtag&taketo)&.>@(starttag&E. <@((#starttag)&}.);.1 ]) y
)
 
NB. RosettaCode Utilities
parseTitles=: ('"title":"';'"')&getTagContents
parseCMcontinue=:('"cmcontinue":"';'"')&getTagContents
getCMcontquery=: ('&cmcontinue=' , urlencode)^:(0 < #)@>@parseCMcontinue
 
getCategoryMembers=: monad define
buildqry=. 'action=query&list=categorymembers&cmtitle=Category:' , ,&'&cmlimit=500&format=json'
url=.'http://www.rosettacode.org/w/api.php'
uri=. url ,'?', buildqry urlencode y
catmbrs=. qrycont=. ''
whilst. #qrycont=. getCMcontquery jsondat do.
jsondat=. gethttp uri , qrycont
catmbrs=. catmbrs, parseTitles jsondat
end.
catmbrs
)

Example Usage:

   4{. findUnimpTasks 'J'     NB. get first 4 unimplemented tasks for J
+-------------+--------------+----------------+------------------------------+
|Active object|Atomic updates|Basic input loop|Call foreign language function|
+-------------+--------------+----------------+------------------------------+

[edit] Oz

Library: OzHttpClient

By parsing XML and using an XPath-like mechanism:

declare
[HTTPClient] = {Link ['x-ozlib://mesaros/net/HTTPClient.ozf']}
[XMLParser] = {Link ['x-oz://system/xml/Parser.ozf']}
 
fun {FindUnimplementedTasks Language}
AllTasks = {FindCategory "Programming Tasks"}
LangTasks = {FindCategory Language}
in
{ListDiff AllTasks LangTasks}
end
 
fun {FindCategory Cat}
CatUrl = "http://www.rosettacode.org/mw/api.php?action=query"
#"&list=categorymembers"
#"&cmtitle=Category:"#{PercentEncode Cat}
#"&cmlimit=500&format=xml"
 
fun {Loop CMContinue}
[_ Doc] = {Parse {GetPage CatUrl#CMContinue}}
Titles = {XPath Doc
[api query categorymembers cm {Attribute title}]}
in
case {XPath Doc
[api 'query-continue' categorymembers {Attribute cmcontinue}]}
of nil then Titles
[] [NewCMContinueAtom] then
NewCMContinue = {PercentEncode {Atom.toString NewCMContinueAtom}}
in
{Append Titles
{Loop "&cmcontinue="#NewCMContinue}}
end
end
in
{Loop nil}
end
 
 
%% XPath emulation
fun {XPath Doc Path}
P|Pr = Path
in
Doc.name = P %% assert
{FoldL Pr XPathStep [Doc]}
end
 
Nothing = {NewName}
fun {NotNothing X} X \= Nothing end
 
fun {XPathStep Elements P}
if {Atom.is P} then
{FilteredChildren Elements P}
elseif {Procedure.is P} then
{Filter {Map Elements P} NotNothing}
end
end
 
%% A flat list of all Type-children of all Elements.
fun {FilteredChildren Elements Type}
{Flatten
{Map Elements
fun {$ E}
{Filter E.children
fun {$ X}
case X of element(name:!Type ...) then true
else false
end
end}
end}}
end
 
fun {Attribute Attr}
fun {$ Element}
case {Filter Element.attributes fun {$ A} A.name == Attr end}
of [A] then A.value
else Nothing
end
end
end
 
 
%% GetPage
Client = {New HTTPClient.urlGET init(inPrms(toFile:false toStrm:true) _)}
fun {GetPage RawUrl}
Url = {VirtualString.toString RawUrl}
OutParams
in
{Client getService(Url ?OutParams ?_)}
OutParams.sOut
end
 
fun {PercentEncode Xs}
case Xs of nil then nil
[] X|Xr then
if {Char.isDigit X} orelse {Member X [&- &_ &. &~]}
orelse X >= &a andthen X =< &z
orelse X >= &z andthen X =< &Z then
X|{PercentEncode Xr}
else
{Append &%|{ToHex2 X} {PercentEncode Xr}}
end
end
end
 
fun {ToHex2 X}
[{ToHex1 X div 16} {ToHex1 X mod 16}]
end
 
fun {ToHex1 X}
if X >= 0 andthen X =< 9 then &0 + X
elseif X >= 10 andthen X =< 15 then &A + X - 10
end
end
 
 
%% Parse
local
Parser = {New XMLParser.parser init}
in
fun {Parse Xs} {Parser parseVS(Xs $)} end
end
 
fun {ListDiff Xs Ys}
{FoldL Ys List.subtract Xs}
end
in
%% show tasks not implemented in Oz
{ForAll {FindUnimplementedTasks "Oz"} System.showInfo}

[edit] Perl

Using JSON (not parsed, just Regex.)

use LWP::Simple 'get';
 
my $fmt = 'http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:%s&cmlimit=500&format=json';
my $lang = shift
or die "No language given.\n";
 
sub urlencode
{join '', map {sprintf '%%%02x', ord} split //, shift}
sub tasks
{my $category = urlencode shift;
my @tasks;
my $json = get sprintf $fmt, $category;
for (;;)
{push @tasks, $json =~ /"title":"(.+?)"}/g;
$json =~ /"cmcontinue":"(.+?)"}/ or last;
$json = get sprintf $fmt . '&cmcontinue=%s',
$category, urlencode $1;}
return @tasks;}
 
my @all = tasks 'Programming_Tasks';
my %lang = map {$_, 1} tasks $lang
or die "No such category.\n";
$lang{$_} or print "$_\n"
foreach @all;

See also: User:ImplSearchBot/Code

[edit] Perl 6

Works with: Rakudo Star version 2013.02
  • Pages are mirrored on disk between runs, and refreshed when older than 1 day.
  • The language's page is retrieved before Programming_Tasks' page, to prevent a needless GET when the language is not found.
  • Pages are retrieved via Curl, due to a bug in LWP::Simple that mishandles the headers that RC sends. Change to use LWP's getstore() after the bug is fixed.
use JSON::Tiny;
sub MAIN ( Str $language = 'Perl_6' ) {
my @done_tasks = set tasks($language);
my @all_tasks = set tasks('Programming_Tasks');
.say for @all_tasks (-) @done_tasks;
}
 
sub url_of ( Str $category, Str $continue? ) {
my $cat = $category.subst( /<-[ A..Z a..z 0..9 . ~ _ - ]>/,
*.ord.fmt('%%%02X'), :g );
 
return 'http://rosettacode.org/mw/api.php?action=query&cmlimit=500'
~ "&format=json&list=categorymembers&cmtitle=Category:$cat"
~ ("&cmcontinue=$continue" if $continue);
}
 
sub get_mirrored_page ( Str $url, Str $filename ) {
if $filename.IO !~~ :e or (now - $filename.IO.modified) > 3600 {
run('curl', '-sSo', $filename, $url) or die;
}
return slurp $filename;
}
 
sub tasks ( Str $category ) {
my $continue = '';
my @tasks = gather for 1..* -> $page_num {
my $href = from-json get_mirrored_page(
url_of( $category, $continue ),
"{$category}_{$page_num}.json",
);
 
take map *.<title>, $href.<query>.<categorymembers>.list;
 
$continue = $href.<query-continue>.<categorymembers>.<cmcontinue>
or last;
} or die "Nothing found for category '$category'";
 
return @tasks;
}

[edit] PicoLisp

(load "@lib/http.l" "@lib/xm.l")
 
(de rosettaCategory (Cat)
(let (Cont NIL Xml)
(make
(loop
(client "rosettacode.org" 80
(pack
"mw/api.php?action=query&list=categorymembers&cmtitle=Category:"
Cat
"&cmlimit=200&format=xml"
Cont )
(while (line))
(setq Xml (and (xml?) (xml))) )
(NIL Xml)
(for M (body Xml 'query 'categorymembers)
(link (attr M 'title)) )
(NIL (attr Xml 'query-continue' categorymembers 'cmcontinue))
(setq Cont (pack "&cmcontinue=" @)) ) ) ) )
 
(de unimplemented (Task)
(diff
(rosettaCategory "Programming_Tasks")
(rosettaCategory Task) ) )

[edit] Python

Using XML.

import xml.dom.minidom
import urllib, sys
 
def findrc(category):
name = "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:%s&cmlimit=500&format=xml" % urllib.quote(category)
cmcontinue, titles = '', []
while True:
u = urllib.urlopen(name + cmcontinue)
xmldata = u.read()
u.close()
x = xml.dom.minidom.parseString(xmldata)
titles += [i.getAttribute("title") for i in x.getElementsByTagName("cm")]
cmcontinue = filter( None,
(urllib.quote(i.getAttribute("cmcontinue"))
for i in x.getElementsByTagName("categorymembers")) )
if cmcontinue:
cmcontinue = '&cmcontinue=' + cmcontinue[0]
else:
break
return titles
 
alltasks = findrc("Programming_Tasks")
lang = findrc(sys.argv[1])
 
for i in [i for i in alltasks if i not in lang]:
print i

[edit] R

Library: XML (R)
library(XML)
find.unimplemented.tasks <- function(lang="R"){
PT <- xmlInternalTreeParse( paste("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml",sep="") )
PT.nodes <- getNodeSet(PT,"//cm")
PT.titles = as.character( sapply(PT.nodes, xmlGetAttr, "title") )
language <- xmlInternalTreeParse( paste("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:",
lang, "&cmlimit=500&format=xml",sep="") )
lang.nodes <- getNodeSet(language,"//cm")
lang.titles = as.character( sapply(lang.nodes, xmlGetAttr, "title") )
unimplemented <- setdiff(PT.titles, lang.titles)
unimplemented
}
# Usage
find.unimplemented.tasks(lang="Python")
langs <- c("R","python","perl")
sapply(langs, find.unimplemented.tasks) # fetching data for multiple languages

[edit] Racket

 
#lang racket
 
(require net/url net/uri-codec json (only-in racket/dict [dict-ref ref]))
 
(define (RC-get verb params)
((compose1 get-pure-port string->url format)
"http://rosettacode.org/mw/~a.php?~a" verb (alist->form-urlencoded params)))
 
(define (get-category catname)
(let loop ([c #f])
(define t
((compose1 read-json RC-get) 'api
`([action . "query"] [format . "json"]
[list . "categorymembers"] [cmtitle . ,(format "Category:~a" catname)]
[cmcontinue . ,(and c (ref c 'cmcontinue))] [cmlimit . "500"])))
(define (c-m key) (ref (ref t key '()) 'categorymembers #f))
(append (for/list ([page (c-m 'query)]) (ref page 'title))
(cond [(c-m 'query-continue) => loop] [else '()]))))
 
;; The above is the required "library" code, same as the "Rosetta
;; Code/Count" entry
 
(define (show-unimplemented lang)
(for-each displayln (remove* (get-category lang)
(get-category 'Programming_Tasks))))
 
(show-unimplemented 'Racket) ; see all of the Racket entries
 

[edit] Ruby

Finds tasks that are either not implemented or omitted. Sorts by task creation time.

Uses the RosettaCode module from Count programming examples#Ruby

require 'rosettacode'
require 'time'
 
module RosettaCode
def self.get_unimplemented(lang)
programming_tasks = []
category_members("Programming_Tasks") {|task| programming_tasks << task}
 
lang_tasks = []
category_members(lang) {|task| lang_tasks << task}
 
lang_tasks_omit = []
category_members("#{lang}/Omit") {|task| lang_tasks_omit << task}
 
[programming_tasks - lang_tasks, lang_tasks_omit]
end
 
def self.created_time(title)
url = get_api_url({
"action" => "query",
"titles" => title,
"format" => "xml",
"rvlimit" => 500,
"prop" => "revisions",
"rvprop" => "timestamp"
})
doc = REXML::Document.new open(url)
REXML::XPath.each(doc, "//rev").collect do |node|
Time.parse( node.attribute("timestamp").value )
end.min
end
 
end
 
puts Time.now
lang = ARGV[0] || "Ruby"
unimplemented, omitted = RosettaCode.get_unimplemented(lang)
unimplemented.collect {|title| [title, RosettaCode.created_time(title)]} .
sort_by {|e| e[1]} .
each do |title, date|
puts "%s %6s %s" % [
date.strftime("%Y-%m-%d"),
omitted.include?(title) ? "[omit]" : "" ,
title
]
end
 

Output for Ruby

2010-04-05 11:08:07 -0500
2007-01-14        Table creation
2007-01-25 [omit] Pointers and references
2007-02-04        SQL-based authentication
2007-02-09        Metered concurrency
2007-02-27 [omit] Address of a variable
2007-02-27 [omit] Variable size/Set
2007-02-27        Variable size/Get
2007-06-08        OpenGL
2007-06-08        HTTPS/Authenticated
2007-11-06        Pattern matching
2007-11-08 [omit] Parametric polymorphism
2007-11-13        Special characters
2007-12-11        Arithmetic evaluation
2007-12-21 [omit] Proof
2007-12-24        Plot coordinate pairs
2007-12-24        Polynomial regression
2007-12-24        Compare sorting algorithms' performance
2008-03-27        Dragon curve
2008-03-28        Formal power series
2008-09-11        RCRPG
2008-11-02        Active object
2008-11-13        Window creation/X11
2008-12-05 [omit] Constrained genericity
2009-02-17        Rendezvous
2009-03-22        Arena storage pool
2009-05-23        Ray-casting algorithm
2009-05-26 [omit] Memory allocation
2009-05-26        Simulate input/Mouse
2009-05-27        Mouse position
2009-05-27        Keyboard macros
2009-05-27        Window management
2009-05-27        Color of a screen pixel
2009-06-01        HTTPS/Client-authenticated
2009-06-02        Simulate input/Keyboard
2009-06-08 [omit] Create an object at a given address
2009-06-10        Events
2009-06-10        Scope modifiers
2009-08-09        Verify distribution uniformity/Chi-squared test
2009-08-11        Call a function from a foreign language
2009-08-12        Safe addition
2009-12-05        Rate counter
2010-01-02        Loading Animated 3D Data
2010-01-06        Catmull–Clark subdivision surface
2010-01-21        Hough transform
2010-01-25        Compile-time calculation
2010-02-14        Knapsack problem/Bounded
2010-02-21        Deconvolution/1D
2010-02-23        Deconvolution/2D+
2010-02-24        Knapsack problem/Continuous
2010-03-23        Sutherland-Hodgman polygon clipping
2010-03-23        Find Common Directory Path

[edit] Run BASIC

Find tasks not implemented. Select Language from DropDown and click [GO] or [Exit].

WordWrap$ = "style='white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap;word-wrap: break-word'"
a$ = httpGet$("http://rosettacode.org/wiki/Category:Programming_Languages")
a$ = word$(a$,2,"mw-subcategories")
a$ = word$(a$,1,"</table>")
i = instr(a$,"/wiki/Category:")
html "<B> Select language from list<BR>"
html "<SELECT name='lang'>"
while i <> 0
j = instr(a$,""" title=""Category:",i)
lang$ = mid$(a$,i+15,j-i-15)
k = instr(a$,""">",j + 18)
langName$ = mid$(a$,j + 18,k-(j+18))
count = count + 1
html "<option value='";lang$;"'>";langName$;"</option>"
i = instr(a$,"/wiki/Category:",k)
wend
html "</select>"
html "<p>Number of Languages:";count;"<BR> "
button #go,"GO", [go]
html " "
button #ex, "Exit", [exit]
wait
 
[go]
cls
lang$ = #request get$("lang")
h$ = "http://rosettacode.org/wiki/Reports:Tasks_not_implemented_in_";lang$
a$ = httpGet$(h$)
a$ = word$(a$,3,"mw-content-ltr")
html "<table border=1><tr>"
i = instr(a$,"<a href=""/wiki/")
while i > 0
i = instr(a$,"title=""",i)
j = instr(a$,""">",i+7)
if c mod 4 = 0 then html "</tr><tr ";WordWrap$;">"
c = c + 1
html "<td>";mid$(a$,i+7,j-(i+7));"</td>"
i = instr(a$,"<a href=""/wiki/",i+7)
wend
html "</tr></table>"
print "Total unImplemented Tasks:";c
[exit]
end
24 game/SolveAbstract typeAccumulator factoryActive Directory/ConnectActive Directory/Search for a user
Arena storage poolArithmetic/RationalArithmetic evaluationAverage loop lengthAverages/Mean angle
Averages/Mean time of dayBitcoin/address validationBitmap/PPM conversion through a pipeBitmap/Read an image through a pipeBreak OO privacy
CRC-32CSV to HTML translationCalendarCalendar - for "real" programmersCall a function
Call an object methodCanny edge detectorCarmichael 3 strong pseudoprimes, or Miller Rabin's nemesisCatmull–Clark subdivision surfaceChat server
Check Machin-like formulasCholesky decompositionColour pinstripe/PrinterCompare sorting algorithms' performanceConstrained genericity
Continued fractionContinued fraction arithmetic/Continued fraction r2cf(Rational N)Continued fraction arithmetic/G(matrix NG, Contined Fraction N)Continued fraction arithmetic/G(matrix NG, Contined Fraction N1, Contined Fraction N2)Count the coins
Zebra puzzleZeckendorf number representation

Total unImplemented Tasks:177

[edit] Tcl

First, find all members of the Programming_Tasks category, then find all members of the $lang category. The difference is the list of unimplemented tasks.

Library: Tcllib (Package: json)
Library: Tcllib (Package: struct::set)
package require Tcl 8.5
package require http
package require json
package require struct::set
 
fconfigure stdout -buffering none
 
# Initialize a cache of lookups
array set cache {}
proc log msg {
#puts -nonewline $msg
}
 
proc get_tasks {category} {
global cache
if {[info exists cache($category)]} {
return $cache($category)
}
set base_url http://www.rosettacode.org/w/api.php
set query {
action query
list categorymembers
cmtitle Category:%s
format json
cmlimit 500
}
set query [list {*}$query]; # remove excess whitespace
set this_query [dict create {*}[split [format $query $category]]]
set tasks [list]
 
while {1} {
set url [join [list $base_url [http::formatQuery {*}$this_query]] ?]
while 1 {
set response [http::geturl $url]
# Process redirects
if {[http::ncode $response] == 301} {
set newurl [dict get [http::meta $response] Location]
if {[string match http://* $newurl]} {
set url $newurl
} else {
set url [regexp -inline {http://[^/]+} $url]
append url $newurl
}
continue
}
# Check for oopsies!
if {
[set s [http::status $response]] ne "ok"
|| [http::ncode $response] != 200
} then {
error "Oops: url=$url\nstatus=$s\nhttp code=[http::code $response]"
}
break
}
 
# Get the data out of the message
set data [json::json2dict [http::data $response]]
http::cleanup $response
 
# add tasks to list
foreach task [dict get $data query categorymembers] {
lappend tasks [dict get [dict create {*}$task] title]
}
 
if {[catch {
dict get $data query-continue categorymembers cmcontinue
} continue_task]} then {
# no more continuations, we're done
break
}
dict set this_query cmcontinue $continue_task
}
return [set cache($category) $tasks]
}
 
proc get_unimplemented {lang} {
set tasks [get_tasks Programming_Tasks]
set collected [get_tasks Collection_Members]
set doneTasks [get_tasks $lang]
set omittedTasks [get_tasks $lang/Omit]
 
# Map generic collection task categories to specific ones
set tasks [regsub -all {Category:(\S+)} $tasks "\\1/$lang"]
 
set collectOfLang [struct::set intersect $collected $doneTasks]
set ignorable [struct::set union $doneTasks $omittedTasks $collectOfLang]
set unimplemented [struct::set difference $tasks $ignorable]
 
puts "\n$lang has [llength $unimplemented] unimplemented programming tasks:"
if {[llength $unimplemented]} {
puts " [join [lsort $unimplemented] "\n "]"
}
}
 
foreach lang {Perl Python Ruby Tcl} {
get_unimplemented $lang
}
Personal tools
Namespaces

Variants
Actions
Community
Explore
Misc
Toolbox