Tenta i TDP007 fredag 11 juni 2010 kl 8-12 ------------------------------------------ Uppgift 1: Grundläggande Ruby (6p) ---------------------------------- a) Vad är en iterator? Förklara i ord och ge ett belysande kodexempel! (1p) b) Vad är det för skillnad på SAX- och DOM-parsning av XML-dokument? (1p) c) Vad är en continuation? Hur skapas den, vad innehåller den och vad kan man ha den till? Ge ett kort körexempel som illustrerar din förklaring. (2p) d) Den här uppgiften innehåller mycket text, men ska förhoppningsvis inte vara allt för svår. Den testar att du förstår ett antal grundläggande begrepp inom objektorientering i allmänhet och Ruby i synnerhet. Skriv fullständig och körbar kod enligt följande långrandiga specifikation. (2p) - Skapa en klass Publication som har tre instansvariabler: title, author och year. Instansvariablerna ska vara läsbara, men inte skrivbara. Ge klassen en initieringsfunktion som tar tre parametrar motsvarande dessa instansvariabler och som sparar värdena i instansvariablerna. De två första variablerna är tänkta att innehålla strängar, den sista ett heltal. - Skapa en klass Book som utökar klassen Publication. Den ska ha ytterligare en instansvariabel publisher som är läsbar men inte skrivbar. Initieringsfunktionen ska ha totalt fyra parametrar som precis som för Book ska innehålla värden till instansvariablerna. De tre som är gemensamma för Book ska initieras med superklassens initieringsfunktion. Klassen Book ska dessutom ha en överlagrad jämförelseoperator som endast jämför titel och författare, inte de övriga två instansvariablerna. Uppgift 2: Enhetstestning (3p) ------------------------------ I filen test_filled_array.rb finns enhetstester för en tänkt funktion filled_array. Funktionen ska returnera en array med ett visst innehåll som beror av indata. Hur funktionen ska fungera framgår av testfallen. Din uppgift är att skriva en funktion som klarar av alla dessa testfall. Uppgift 3: Textfiler och XML (8p) --------------------------------- Denna uppgift består av tre deluppgifter, där de senare bygger vidare på den första. Läs igenom hela uppgiften innan du börjar. Centrala Spioneringsnämnden (CSN) övervakar olika typer av nätverks- kommunikation. Eftersom det är en oöverstiglig uppgift behöver de olika programvaror som kan analysera stora mängder information och identifiera vad som behöver kollas upp manuellt. Just nu behöver de ett program som kan gå igenom stora mängder e-post och lista ut vilka personer som ska hamna på deras stora svarta lista. I en textfil ordlista.txt finns en lista med bra och dåliga ord. Den börjar så här: terrorism 1 knark 2 cannabis 2 fred -1 kanin -1 Varje e-postmeddelande får poäng beroende på vilka ord det innehåller. För att få poäng räcker det att ordet finns med en gång. Ett meddelande med texten "knark knark knark fred" borde alltså få 1 poäng. Observera att man kan få minuspoäng. Trevliga ord kan uppväga dåliga. a) (2p) Skriv en funktion classify_text som tar en sträng samt en ordlista inläst från filen ovan (i valfritt format). Funktionen ska returnera hur många poäng texten får enligt ovanstående metod. Exempel: >> classify_text("knark knark knark fred",wordlist) => 1 >> classify_text("Jag vill ha fred och bananer!",wordlist) => -3 CSN vill även kunna hålla koll på vilka personer som skriver eller tar emot brev med höga poäng. Deras metod för att göra detta funkar så här: Avsändaren av brevet, liksom alla mottagare, samlar på sig de poäng som brevet har tilldelats. Sedan räknar man för varje person ut en medelpoäng. Säg t.ex. att Kalle har varit sändare eller mottagare för fem brev med följande poäng: Brev nr Poäng ---------------- 1 3p 2 5p 3 0p 4 -1p 5 2p Summerar man ihop dessa poäng och delar med 5 får man 1,8 poäng. Det är alltså Kalles poäng. b) (3p) I filen brev.txt finns ett antal olika e-postmeddelanden. Skriv en funktion process_mail som givet en sådan fil med brev samt en fil med ordlista, kan poängsätta alla personer som står som sändare eller mottagare. Så här ska det se ut: >> process_mail("brev.txt","ordlista.txt") kalle@acme.se 1.8 pelle@acme.se -4.0 stina@acme.se 0.5 lisa@acme.se 0.75 olle@acme.se 3.0 => nil Från den här listan kan CSN lätt lista ut att Olle behöver bevakas extra noga, medan Pelle verkar vara en mycket snäll typ som kanske i framtiden ska rekryteras. Angående filen brev.txt kan det vara bra att känna till att olika e-postmeddelanden separeras från varandra med två blankrader. Brevhuvudet (alla rader med From, To, m.m.) separeras från själva texten i brevet med en blankrad. Det är bara texten i brevet som ska räknas. c) (3p) I filen mailbox.xml finns samma e-postmeddelanden, men nu i XML-format. Skriv en funktion process_mail2 som givet en fil med brev i detta format kan poängsätta alla personer som står som sändare eller mottagare. Resultatet ska vara detsamma som i b). Inskickade lösningar kommer garanterat inte att användas i hemlig signalspaning, så ingen behöver ha några moraliska invändningar mot att lösa uppgiften. Uppgift 4: Mer om XML (4p) -------------------------- I filen animals.xml finns ett litet expertsystem som har kunskap om djur. Strukturen på XML-filen är sådan att den börjar med en -tagg som innehåller en fråga i ren text. Den har flera möjliga alternativ som finns inom -taggar. Varje sådan -tagg kan antingen ha en ny inom sig, ifall mer detaljerade frågor behöver ställas, eller bara en text om systemet anser sig ha kommit fram till ett svar. Genom att skriva ett enkelt program som läser in filen och ställer frågorna till användaren kan man på detta sätt skapa sig en liten datoriserad expert. Detta är ett exempel på hur det kan användas: >> expert("animals.xml") *** Where do you usually find the animal? (1) On land (2) In the sea (3) In the air Choose one alternative: 2 *** What kind of water does the animal live in? (1) Salt water (2) Fresh water Choose one alternative: 2 *** Which alternative matches the animal? (1) It has claws! (2) Long with light stripes or spots (3) Greenish with dark vertical stripes (4) Small silverish with red fins Choose one alternative: 3 It is probably a Perch (abborre). => nil Din uppgift är att skriva funktionen expert som kan läsa in en fil, vilken som helst, som har samma struktur som animals.xml. Frågor ska ställas till användaren, och beroende på svar ska man fortsätta med olika delar av filen. (Filen har vissa likheter med ett exempel från en av föreläsningarna, men med en annan struktur.) Lösningen ska givetvis använda sig av REXML-paketet. Eftersom dokumentationen av REXML-paketet är ganska kortfattad i läroboken finns en kort sammanfattning av de viktigaste metoderna hos klassen REXML::Element i filen rexml.txt. Uppgift 5: Domänspecifika språk (6p) ------------------------------------ Vi vill ha ett mycket litet domänspecifikt språk, inbyggt i Ruby, för att kunna hantera längdenheter. I slutändan vill vi i Ruby-interpretatorn kunna skriva så här: >> 5.cm+14.cm => 19.cm >> 2.cm+3.dm-7.cm => 2.5.dm För att lösa detta behöver vi inte nödvändigtvis tillämpa de tekniker för DSL som vi har tittat på i kursen (som oftast utgår från en textfil med rader på ett påhittat minispråk). Det räcker att använda lite olika objektorienterade egenskaper hos Ruby. För att hjälpa till lite på traven finns några olika frågeställningar som du måste lösa: - Vad ska returneras om man skriver bara 2.cm vid prompten? - Vilket objekts metod + respektive - är det som anropas i exemplen ovan? - Hur får man Ruby att ge returvärdet 19.cm i första exemplet ovan? a) (4p) Skriv programkod som gör att man kan skriva precis som i exemplet ovan. Du har goda chanser att få delpoäng även om du inte löser hela uppgiften. b) (2p) Varför är detta ett domänspecifikt språk? Definiera vad ett DSL är och argumentera för eller emot att detta skulle vara ett DSL. Uppgift 6: Parsning (5p) ------------------------ Klassen DiceRoller definierar ett språk för enkla matematiska uttryck som involverar tärningsslag. Vi vill utöka språket så att vi kan definiera egna tärningar som har särskilda intervall. En tärning som har två till fyra prickar vill vi definiera så här: set a 2..4 Vi vill sedan kunna använda den genom att skriva da vilket slår en tärning av typ a, vilket bör ge ett svar i intervallet två till fyra. Utöka parsern i filen rdparse.rb så att man kan definiera och använda egna tärningar på detta sätt. Det ska även gå att slå tärningen flera gånger genom att sätta ett tal framför. Exempel: [diceroller] set a 2..4 [diceroller] da => 3 [diceroller] da => 2 [diceroller] 3da+1 => 9