Rosetta Code/Find unimplemented tasks: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Tcl}}: Minor improvement)
(→‎{{header|Tcl}}: An upgrade that now knows about omitted tasks and collections)
Line 313: Line 313:
package require json
package require json
package require struct::set
package require struct::set

fconfigure stdout -buffering none
fconfigure stdout -buffering none


# Initialize a cache of lookups
array set cache {}
proc log msg {
#puts -nonewline $msg
}
proc get_tasks {category} {
proc get_tasks {category} {
global cache
set start [clock milliseconds]
puts -nonewline "getting $category members..."
if {[info exists cache($category)]} {
return $cache($category)
}
set base_url http://www.rosettacode.org/w/api.php
set base_url http://www.rosettacode.org/w/api.php
set query {
set query {action query list categorymembers cmtitle Category:%s format json cmlimit 500}
action query
list categorymembers
cmtitle Category:%s
format json
cmlimit 500
}
set this_query [dict create {*}[split [format $query $category]]]
set this_query [dict create {*}[split [format $query $category]]]
set tasks [list]
set tasks [list]

while {1} {
while {1} {
set url [join [list $base_url [http::formatQuery {*}$this_query]] ?]
set url [join [list $base_url [http::formatQuery {*}$this_query]] ?]
while 1 {
while 1 {
set response [http::geturl $url]
set response [http::geturl $url]
# Process redirects
if {[http::ncode $response] == 301} {
if {[http::ncode $response] == 301} {
set newurl [dict get [http::meta $response] Location]
set newurl [dict get [http::meta $response] Location]
Line 338: Line 353:
continue
continue
}
}
# Check for oopsies!
if {[set s [http::status $response]] ne "ok" || [http::ncode $response] != 200} {
if {
[set s [http::status $response]] ne "ok"
|| [http::ncode $response] != 200
} then {
error "Oops: url=$url\nstatus=$s\nhttp code=[http::code $response]"
error "Oops: url=$url\nstatus=$s\nhttp code=[http::code $response]"
}
}
break
break
}
}

# Get the data out of the message
set data [json::json2dict [http::data $response]]
set data [json::json2dict [http::data $response]]
http::cleanup $response
http::cleanup $response
# add tasks to list
# add tasks to list
foreach task [dict get $data query categorymembers] {
foreach task [dict get $data query categorymembers] {
lappend tasks [dict get [dict create {*}$task] title]
lappend tasks [dict get [dict create {*}$task] title]
}
}
if {[catch {
if {[catch {dict get $data query-continue categorymembers cmcontinue} continue_task] != 0} {
dict get $data query-continue categorymembers cmcontinue
} continue_task]} then {
# no more continuations, we're done
# no more continuations, we're done
break
break
Line 357: Line 380:
dict set this_query cmcontinue $continue_task
dict set this_query cmcontinue $continue_task
}
}
return [set cache($category) $tasks]
puts " found [llength $tasks] tasks in [expr {[clock milliseconds] - $start}] milliseconds"
return $tasks
}
}

proc get_unimplemented {lang} {
proc get_unimplemented {lang} {
set unimplemented [struct::set difference [get_tasks Programming_Tasks] [get_tasks $lang]]
set tasks [get_tasks Programming_Tasks]
set doneTasks [get_tasks $lang]
set omittedTasks [get_tasks $lang/Omit]
set ts [struct::set difference $tasks $doneTasks]
set ts [struct::set difference $ts $omittedTasks]
set unimplemented {}
foreach t $ts {
# No elegant way to detect {{collection}} template right now
if {[string match Category:RC* $t]} {
set t [string range $t 9 end]/$lang
if {$t in $doneTasks} {
continue
}
}
lappend unimplemented $t
}
puts "\n$lang has [llength $unimplemented] unimplemented programming tasks:"
puts "\n$lang has [llength $unimplemented] unimplemented programming tasks:"
puts [join [lsort $unimplemented] \n]
if {[llength $unimplemented]} {
puts " [join [lsort $unimplemented] "\n "]"
}
}
}

foreach lang {Perl Python Ruby Tcl} {
get_unimplemented Tcl</lang>
get_unimplemented $lang
}</lang>


{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have network access. -->
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} <!-- Does not have network access. -->

Revision as of 15:41, 2 November 2009

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. Use these JSON files as source information.

AutoHotkey

This example is incorrect. Please fix the code and remove this message.

Details: Does not implement fetching more than one page of results.

<lang AutoHotkey>MsgBox % getUnimplemented("AutoHotkey") MsgBox % getUnimplemented("Python")

getUnimplemented(category) {

 url := "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:"

. category . "&cmlimit=500&format=xml"

 url2 := "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml"
 UrlDownloadToFile, %url%, unimplemented.html
 UrlDownloadToFile, %url2%, alltasks.html
 FileRead, category2, unimplemented.html
 FileRead, alltasks, alltasks.html
 pos = 1
 reg = title="[^"]+"  ; "
 While (pos := RegexMatch(alltasks, reg, title, pos))
 {
   StringReplace, title, title, title=
   StringReplace, title, title, `", ,All ; "
   If !InStr(category2, title)
     todo .= title . "`n"
   pos += 1
 }
 Return todo

} </lang>

C#

This example is incorrect. Please fix the code and remove this message.

Details: Does not implement fetching more than one page of results.

Using JSON (not parsed, just Regex.)

<lang csharp>using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Net;

class Program {

   static string[] GetTitlesFromCategory(string category) {
       string content = new WebClient().DownloadString(
           String.Format("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:{0}&cmlimit=500&format=json", category)
       );
       return new Regex("\"title\":\"(.+?)\"").Matches(content).Cast<Match>().Select(x => x.Groups[1].Value).ToArray();
   }
   static string[] GetUnimplementedTasksFromLanguage(string language) {
       List<string> alltasks = GetTitlesFromCategory("Programming_Tasks").ToList();
       List<string> lang = GetTitlesFromCategory(language).ToList();
       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);
   }

}</lang>

E

Using JSON.

<lang e>#!/usr/bin/env rune

  1. NOTE: This program will not work in released E, because TermL is an
  2. imperfect superset of JSON in that version: it does not accept "\/".
  3. If you build E from the latest source in SVN then it will work.
  4. Usage: rosettacode-cat-subtract.e [<language>]
  5. Prints a list of tasks which have not been completed in the language.
  6. 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(), "")

}

  1. Interpret program arguments

def lang := switch (interp.getArgs()) {

 match [lang] { lang }
 match [] { "E" }

}

  1. 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()}`)

}</lang>

J

Use getHTTP from Web Scraping

<lang j> findUnimpTasks=: 'Programming_Tasks' /:~@([ #~ -.@e.)&getTasks ]

NB. Utility verbs require 'strings' safe=. (33}.127{.a.)-.'=&%+' encode=: [: toupper ('%',(I.'6'=,3!:3'f') {&, 3!:3) urlencode=: [: ; encode^:(safe -.@e.~ ])&.>

NB. RosettaCode Utilities parseTaskNames=: '","' splitstring _2 }. 2 }. ]

getTasks=: monad define

 makeuri=. 'http://rosettacode.org/json/isb/', ,&'.json'
 uri=. makeuri urlencode y
 parseTaskNames getHTTP uri

) </lang>

Example Usage: <lang j>

  4{. findUnimpTasks 'J'     NB. get first 4 unimplemented tasks for J

+-------------+--------------+---------------+----------------+ |Active_object|Atomic_updates|Basic_Animation|Basic_input_loop| +-------------+--------------+---------------+----------------+ </lang>

Perl

Using JSON (not parsed, just Regex.)

<lang perl>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;</lang>

See also: User:ImplSearchBot/Code

Python

Using XML.

<lang python>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</lang>

R

Library: XML (R)

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

  1. Usage

find.unimplemented.tasks(lang="Python") langs <- c("R","python","perl") sapply(langs, find.unimplemented.tasks) # fetching data for multiple languages </lang>

Ruby

Uses the RosettaCode module from Count programming examples#Ruby <lang ruby>require 'rosettacode'

module RosettaCode

 def RosettaCode.rc_unimplemented(lang)
   programming_tasks = []
   rc_tasks("Programming_Tasks") {|task| programming_tasks << task}
   lang_tasks = []
   rc_tasks(lang) {|task| lang_tasks << task}
   programming_tasks - lang_tasks
 end

end

lang = "Ruby" unimplemented = RosettaCode.rc_unimplemented(lang) puts "#{lang} has #{unimplemented.length} unimplemented tasks:" puts unimplemented.join("\n")</lang>

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.

This uses the json and struct::set packages from

Library: tcllib

<lang tcl>package require Tcl 8.5 package require http package require json package require struct::set

fconfigure stdout -buffering none

  1. 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 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 doneTasks [get_tasks $lang]
   set omittedTasks [get_tasks $lang/Omit]
   set ts [struct::set difference $tasks $doneTasks]
   set ts [struct::set difference $ts $omittedTasks]
   set unimplemented {}
   foreach t $ts {

# No elegant way to detect

Rosetta Code/Find unimplemented tasks is part of [[{{{1}}}]]. You may find other members of {{{1}}} at [[:Category:{{{1}}}]].

[[Category:{{{1}}}|Find unimplemented tasks]] template right now

if {[string match Category:RC* $t]} { set t [string range $t 9 end]/$lang if {$t in $doneTasks} { continue } } lappend unimplemented $t

   }
   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

}</lang>