Dugga 1 i TDP007 torsdag 11 februari 2016 kl 13.15-15.15 -------------------------------------------------------- Duggan startar kl. 13.15 och pågår till 15:15. Ni kommer att få köra på i vår begränsade datortentamiljö, som ni säkert redan känner till. Instruktioner för att logga in lämnas i salen. Alla filer som ni behöver för att lösa uppgifterna finns i hemkatalogen, under given_files, när ni har loggat in. Där finns också en PDF-version av en tidig utgåva av kursboken som ni gärna får använda er av. Öppna den med kommandot xpdf. Svar på frågor skrivs i vanliga textfiler och programkod skrivs i rb-filer. En fil per huvuduppgift ska produceras, totalt alltså fyra filer. Ingen särskild inlämning behöver göras. När man är färdig loggar man ut och lämnar salen. Duggan består av fyra uppgifter (några indelade i deluppgifter) som totalt kan ge 25 poäng. Dessa poäng summeras ihop med poängen från den andra duggan. Rättelser --------- För framtida läsare av den här duggan införs här ett par rättelser: - I uppgift 2 hänvisades till klassen MyClass, men vi avser klassen Apelsin som finns i filen myclass.rb. - I uppgift 4c var körexemplet fel. Det borde vara ytterligare en krock i Vt2. Lösningsförslaget och körexemplet är uppdaterat för att hantera detta. Uppgift 1 (7p) -------------- a) (1p) Konstruera ett reguljärt uttryck som kan matcha ett svenskt telefonummer. Ett telefonnummer består av ett riktnummer, som alltid börjar med 0, följt av ett bindestreck. Numret som kommer därefter kan, men behöver inte, vara uppdelat med mellanslag. Strängar som inte är telefonnummer ska inte matchas. b) (1p) Vilka fördelar kan man hoppas uppnå genom att arbeta systematiskt med enhetstestning? c) (2p) I Ruby kan man utöka ett enskilt objekt med nya metoder (som alltså inte är tillgängliga för andra objekt av samma klass). Vilka för- och nackdelar kan finnas med den möjligheten? d) (2p) Vad är det för skillnad på strömparsning och trädparsning av XML-dokument? e) (1p) Förklara kortfattat vad en DTD är och vad den har för roll relativt ett XML-dokument! Uppgift 2 (4p) -------------- I den bifogade filen myclass.rb finns en klass MyClass. Här är ett exempel på hur den kan användas: >> a = Apelsin.new => # >> a.citron(7) => nil >> a.citron(8) => nil >> a.banan => [7, 8] a) (2p) Förklara vad klassen MyClass gör (d.v.s. vad poängen skulle kunna vara med en sådan klass) samt föreslå bättre och mer förklarande namn på klassen, dess attribut och metoder, inklusive parametrar. b) (2p) Utforma därefter en uppsättning lämpliga enhetstester för klassen MyClass, eller vad den nu borde heta. Uppgift 3 (6p) -------------- I filen application.txt finns en tabell över antalet sökande till de nationella högskoleförberedande gymnasieprogrammen de senaste åren. Din uppgift är att läsa in tabellen på lämpligt sätt, behandla informationen och skriva ut en ny tabell. Uppgifterna kommer från Skolverkets webbplats. För varje program ska du slå ihop antalet kvinnliga respektive manliga sökande för alla de läsår som finns i tabellen. Därefter ska du beräkna en kvot som består av den mindre av dessa två summor genom den större. Därmed kommer kvoten alltid att bli mindre än 1. Till sist ska du sortera alla programmen och skriva ut namnen tillsammans med kvoten så att programmet med minst kvot kommer först. Om du räknat rätt ska utskriften se ut så här: >> read_table("application.txt") Teknik (TE) 0.186 Humanistiska (HU) 0.212 Estetiska (ES) 0.526 Samhällsvetenskap (SA) 0.584 International Baccalaureate (IB) 0.672 Naturvetenskap (NA) 0.907 Ekonomi (EK) 0.955 Utskriften ska vara snyggt formatterad enligt ovanstående exempel. TE var alltså det program som hade störst obalans mellan könen, avseende sökande, medan EK hade bäst balans. Som vi har gjort den här beräkningen säger dock kvoten ingenting om åt vilket håll obalansen svänger. Huruvida obalansen i sig är ett problem eller inte lämnar vi åt andra kurser. Uppgift 4 (8p) -------------- I filen courses.xml finns uppgifter om ett antal olika universitetskurser. Innehållet borde vara ganska lätt att tolka, men lite översiktligt kan man säga att varje kurs innehåller grundinformation om kurskod, antal poäng, namn och examinator. Utöver det finns också information om när kursen går (i vilken eller vilka perioder samt i vilket schemablock), för vilka program som kursen går samt vilka andra kurser som är förkunskapskrav. Titta igenom filen för att bekanta dig med innehållet och strukturen. Din uppgift är att skriva olika funktioner för att kunna läsa in och hantera informationen i filerna. Om du vill göra en strömparser-lösning hittar du ett exempel att utgå från i filen sax_example.rb och om du vill göra en trädparser-lösning hittar du lite information om metoderna i klassen REXML::Element samt några exempel på XPath-uttryck i filen rexml.txt. a) (2p) Skriv en funktion put_courses_for som skriver ut en lista över alla kurser som ges för ett viss program. Funktionen ska fungera så här: >> put_courses_for("courses.xml", "IP") ... TDP001 Handhavande av datormiljö TDP002 Imperativ programmering TDP003 Projekt: Egna datormiljön TDP004 Objektorienterad programmering ... För varje kurs ska alltså kurskoden och namnet skrivas ut, inget annat. Ordningen spelar ingen roll, så länge alla kurserna för programmet finns med. Observera att programmen ligger lagrade i en kommaseparerad lista inne i elementet PROGRAM. b) (3p) En del av kurserna har inskrivna förkunskapskrav i taggen PRE. Dessa förkunskapskrav funkar så att om det står tre kurser med komma mellan, t.ex. "TDP001, TDP002, TDP003" så betyder det att man måste ha klarat av alla dessa. Om kurserna står med snedsteck mellan, t.ex. "TDP001/TPD002", betyder det att endast en av kurserna räcker som förkunskapskrav. Man kan också kombinera ihop det, t.ex. "TDP001/TDP002, TDP003", vilket betyder endera av TDP001 eller TDP002 men också TDP003. Man kan se det här som en kortvariant av 'and' och 'or' och vi gör det inte mer komplicerat än dessa exempel. Skriv en funktion allowed som tar en kurs som man vill läsa, samt en lista av kurser som man redan har läst. Funktionen ska returnera true om man uppfyller alla förkunskapskrav, annars false. Dessutom ska funktionen skriva ut vilka förkunskapskrav som inte är uppfyllda. Funktionen ska fungera så här: >> allowed("courses.xml", "TDP007", ["TDP001", "TDP002", "TDP003"]) Saknar TDP004. => false >> allowed("courses.xml", "TDDD73", ["TDDC66", "TATA42"]) => true >> allowed("courses.xml", "TDDD04", []) Saknar en av TDDC91/TDDD71/TDDI16/TDDC30. Saknar en av TDDD78/TDIU20/TDP004/TDDC77. => false Det är inte alla kurser som har förkunskapskrav utskrivna, och de är oftast att betrakta som rekommendationer. (3p) c) (3p) Skriv en funkion check_plan som tar en lista med kurser som man planerat att läsa under nästa år. Funktionen ska gå igenom dessa kurser och kolla om de krockar med varandra, d.v.s. om de ligger i samma period och samma schemablock. Om inga krockar finns ska funktionen returnera true, annars false. Dessutom ska krockarna skrivas ut, så att man vet var man kanske bör planera om. Funktionen ska fungera så här: >> check_plan("courses.xml", ["TDDA69", "TDDB68", "TDDD04", "TDDD05"]) Krock i Vt1:3 ["TDDA69", "TDDB68"] Krock i Vt2:1 ["TDDA69", "TDDD05"] => false >> check_plan("courses.xml", ["TDDA69", "TDDB84", "TDDD04", "TDDD05"]) Krock i Vt2:1 ["TDDA69", "TDDD05"] => false >> check_plan("courses.xml", ["TDDA69", "TDDB84", "TDDD04"]) => true (Observera att originalduggan hade ett fel i körexemplen. Detta är korrigerat ovan.)