9. Standaard libraries
9.1 Wat geeft instance_methods(nil)
terug?
De methode instance_methods
geeft een array met de
namen van de methodes waarop de receiver reageert terug . Het array
bevat ook methodes uit super klassen en mixin modules.
instance_methods(nil)
geeft uitsluitend de namen van de
methodes die in de klasse van het object zijn gedefinieerd.
9.2 Hoe werken random number seeds?
Dat hangt ervan af. In Ruby versies voor 1.5.2, had de random number
generator (default) een vast seed, en zou zodoende iedere keer dat het
programma gedraaid werd dezelfde serie getallen produceren. Als je iest
minder voorspelbaar wilde zijn riep je srand
aan om een
ander seed op te geven.
Latere Ruby versies werken anders. Als rand
word
aangeroepen zonder dat daarvoor een aanroep van srand is gedaan
,
zal Ruby een (min of meer) willekeurig seed genereren. Opeenvolgende
sessies van een programma dat srand
niet gebruikt leidt
nu
tot verschillende nummer reeksen. Om het vroegere voorspelbare gedrag
terug te krijgen (bijvoorbeeld om te testen) roep je srand
aan met een vast seed.
9.3 Wat is het verschil tussen een directe waarde en een referentie?
Fixnum
, true
, nil
, en false
zijn geimplementeerd als directe waardes. Bij directe waardes bevatten
de variabelen de objecten zelf in plaats van referenties naar die
objecten.
Singleton methodes kunnen voor dit soort objecten niet gedefinieerd
worden. Twee Fixnum
s met de zelfde waarde verwijzen
altijd
naar dezelfde instantie van een object. Dus instance variabelen voor de
Fixnum
met de waarde "een" worden gedeeld met alle andere "enen" in het
systeem. Daarom kan er geen sprake zijn van een singleton methode voor
een bepaalde instantie.
9.4 Wat is het verschil
tussen nil
and false
?
Eerst de overeenkomst. nil
en false
zijn
de enige twee waarden die als onwaar gelden in een booleaanse context.
Echter, het zijn instanties van verschillende klassen (NilClass
en FalseClass
), en ze vertonen in een niet-booleaanse
context ander gedrag.
Wij raden aann dat predicaat methodes (dat zijn die wiens naam
eindigd met een vraagteken) true
or false
teruggeven
.
Andere methodes die het falen van een bewerking moeten signaleren
zouden nil
moeten teruggeven.
9.5 Ik lees een bestand in en verander het, maar het bestand op schijf is niet veranderd!
open("example", "r+").readlines.each_with_index{|l, i| |
Dit programma voegt geen regelnummers toe aan het bestand "example". Het leest de inhoud van het bestand en zet het regelnummer voor iedere regel, maar de gegevens worden nooit teruggeschreven naar schijf. De code hierna veranderd het bestand op schijf wel (op een wat gevaarlijke manier omdat er geen backup gemaakt word voor de update start):
io = open("example", "r+") |
9.6 Hoe kan ik een bestand verwerken en de inhoud bijwerken?
Gebruik de command-line optie -i
, of de ingebouwde
variabele $-i
, daarmee leest je een bestand in en
overschrijf je het.
De code van de vorige vraag, die regelnummers toevoegt aan een bestand, kan waarschijnlijk het best worden geschreven met de volgende techniek:
$ ruby -i -ne 'print "#$.: #$_"' example |
Als je het oorspronkelijke bestand wil bewaren kan je -i.bak
gebruiken om een backup te maken.
9.7 Ik heb een bestand weggeschreven en gekopieerd maar het einde van de kopie is weg!
Deze code werkt niet goed:
open('file', 'w').print "This is a file.\n" |
Omdat de I/O gebufferd is, wordt het bestand gekopieerd
voordat
de inhoud naar de schijf is weggeschreven.
newfile
zal
waarschijnlijk leeg zijn. Als het programma stopt worden de buffers
geleegd en zal file
de verwachte inhoud hebben.
Het probleem doet zich niet voor als je file
sluit
voor
je het kopieerd.
f = open('file', 'w') |
9.8 Hoe vind ik het regelnummer van het actieve invoer bestand?
Als je uit een bestand leest houd Ruby het regelnummer bij in de
globale variabele $.
. Deze is ook beschikbaar via het lineno
attribuut van het File
object.
De speciale constante ARGF
is een bestand-achtig
object
dat gebruikt kan worden om alle invoer bestanden die gespecificeerd
zijn
op de command-line te lezen (of de standaard input zls er geen
bestanden
zijn opgegeven). ARGF word implicietm gebruikt in code zoals deze::
while gets |
In dit geval bevat $.
het cummulatieve aantal
gelezen regels van alle invoer bestanden. Om het regelnummer van het
actieve bestand te achterhalen gebruik je:
ARGF.file.lineno |
De naam van het actieve bestand vind je door middel van ARGF.file.path
.
9.9 Hoe kan ik less
gebruiken om de
uitvoer van mijn programma te tonen?
Ik heb dit geprobeerd maar dat werkte niet:
f = open '|less', 'w' |
Dat komt omdat het programma direct stopt en less
dus
nooit de kans krijgt om de output te zien. Gebruik close
om
te wachten tot less
klaar is.
f = open '|less', 'w' |
9.10 Wat gebeurd er met een File
object waar niet langer naar word verwezen?
A File
object waar niet langer naar wordt verwezen is
komt in aanmerking voor garbage collection. Het bestand word
automatisch
gesloten als het object door de garbadge collector word
opgeruimd.
9.11 Ik voel me ongemakkelijk als ik een bestand niet sluit.
Er zijn minstens vier goede manieren om ervoor te zorgen dat je een bestand sluit:
(1) f = open "file" |
9.12 Hoe sorteer ik bestanden op hun tijdstip van laatste wijziging?
Dir.glob("*").sort{|a,b| File.mtime(b) <=> File.mtime(a)} |
Dit werkt (het geeft een lijst terug in omgekeerde chronologische volgorde) maar is niet erg efficient omdat het de wijzigingstijden bij iedere vergelijking opvraagt bij het operating system.
Met wat meer complexiteit kunnen we efficienter te werk gaan:
Dir.glob("*").collect! {|f| [File.mtime(f), f]}. |
9.13 Hoe tel ik het aantal keren dat een woord voorkomt in een bestand?
freq = Hash.new(0) |
9.14 Waarom is een lege string niet gelijk aan false
?
Q: Een lege string ("") geeft true
terug in een
conditionele expressie! In Perl is dat false
.
A: In Ruby zijn alleen nil
en false
onwaar in een conditionele context. Op deze manier word aan snelheid
gewonnen -- nil
en false
hebben directe
waarden zodat ze kunnen worden getest zonder een referentie te hoeven
volgen.
Je kan empty?
gebruiken, de string met "" vergelijken
of de lengte van de string met 0 vergelijken om er achter te komen of
een string leeg is.
9.15 Hoe sorteer ik strings op alfabetische volgorde?
Als je strings wil sorteren als 'AAA', 'BBB', ..., 'ZZZ', 'aaa', 'bbb' dan voldoet de ingebouwde vergelijkingsfunctionaliteit.
Als je geen rekening wil houden met het verschil tussen hoofd- en kleine letters moet je in het sorteerblock de strings in kleine letters vergelijken:
array = %w( z bB Bb BB bb Aa aA AA aa a ) |
Als je zodanig wil sorteren dat de 'A's en de 'a's bij elkaar staan maar dat 'a' een hogere waarde heeft dan 'A' (dus 'Aa' komt na 'AA' maar voor 'AB'), moet je dit gebruiken:
puts array.sort { |a,b| |
9.16 Wat geeft "abcd"[0]
terug?
Dit geeft de character code voor ``a'' terug: 97(Fixnum).Je kan de
character code weergeven als een integer constante door het tken te
prefixen met een vraagteken dus ?a
is ook 97(Fixnum).
9.17 Hoe zet ik tabs om naar spaties?
Als a
de string bevat die moet worden omgezet zou je
een van de volgende mogelijkheden kunnen gebruiken:
1 while a.sub!(/(^[^\t]*)\t(\t*)/){$1+' '*(8-$1.size%8+8*$2.size)} |
9.18 Hoe kan ik een backslash in een reguliere expressie opnemen?
Regexp.quote('\\')
escaped een backslash.
Het wordt moeilijker als je sub
en gsub
gebruikt.
Stel dat je gsub(/\\/, '\\\\') schrijft om iedere backslash door
twee backslashes te vervangen.
Het tweede argument word tijdens
de
syntax analyse omgezet in '\\'. Als de substitutie plaatsvind zet de
reguliere expressie engine dit om naar '\', dus iedere backslash wordt
vervangen door een andere en er gebeurd du niets. Je had gsub(/\\/,
'\\\\\\')
moeten gebruiken!
Omdat \& de gematchte string bevat kan je ook gsub(/\\/,
'\&\&')
schrijven.
Als je de block vorm van gsub gebruikt,
gsub(/\\/){'\\\\'}
,
wordt de te substitueren string maar een keer (tijdens de syntax
analyse) geanalyseerd en is het resultaat dat wat je bedoelde.
9.19 Wat is het verschil tussen sub
and sub!
?
In sub
, word een kopie van de receiver gegenereerd,
gesubstitueerd en teruggegeven.
In sub!
, wordt de receiver gewijzigd en teruggegeven
als er een match word gevondenthe receiver is altered and returned if
any match was found. Word er geen match gevonden dan word nil
teruggegeven.
Methodes zoals sub!
worden destructieve
methodes genoemd die de attributen van de receiver wijzigen. Als er
twee methodes zijn waarvan er een destructief is eindigd de naam van de
destructieve methode met de suffix !.
def foo(str) |
9.20 Waar matcht \Z?
\Z matcht precies voor de laatste \n als de string eindigd met een \n, anders matcht het 't einde van de string.
9.21 Wat is het verschil tussen "..
"
en "...
"?
..
neemt het rechtse argument mee in de range, ...
doet dat niet.
9.22 Heeft Ruby functie pointers?
Naar een Proc object gegenereed door Proc.new
, proc
,
of lambda
kan verwezen worden door een variabele zodat je
zou kunnen zeggen dat die variabele een functiepointer is. je kan ook
refereren aan de methodes van een bepaald object door de Object.method
notatie te gebruiken.
9.23 Wat is het verschil tussen thread
and fork
?
Ruby threads zijn geimplementeerd binnen de interpreter tewijl fork
het operating system gebruikt om een apart subprocess te starten.
Thread
and fork
hebben de volgende
eigenschappen:
fork
is langzaam,thread
is dat niet.fork
deelt zijn geheugenruimte niet.thread
veroorzaakt geen "thrashing".thread
werkt onder DOS.- wanneer
thread
in een deadlock raakt wordt het hele proces gestopt. fork
kan gebruikmaken van pauzes die veroorzaakt worden door het wachten op I/O,thread
doet dat niet (althans niet zonder wat aansporing).
Het is niet verstandig om fork
en thread
door elkaar te gebruiken.
9.24 Hoe gebruik ik Marshal?
Marshal word gebruikt om een object op te slaan in een bestand of een string om deze op en later tijdstip weer op te bouwen. Objecte kunnen worden opgeslagen door:
Marshal.dump obj [, io ] [, lev] |
io
is een scrijfbaar IO object, lev
bepaald
het niveau tot waarop aan objecten word gerefereerd om te worden
opgeslagen. Als er lev
niveau's objecten worden
gerefereerd en er bestaan nog steeds object referenties dan slaat
dump
alleen de referentie en niet het object waarnaar gerefereerd word op.
Dit moet je niet willen omdat de objecten waarnaar gerefereerd word
later niet meer kunnen worden opgebouwd.
Als io
word wegggelaten worden de ge-marshalde
objecten
teruggegeven als string.
Objecten laadt je door:
obj = Marshal.load io |
Hier is io
een leesbaar IO object, str
is
de weggeschreven string.
9.25 Heeft Ruby exception handling?
Ruby heeft een flexibele exception handling mogelijkheden:
begin |
als er een exception plaats vind in de begin
clause,
word de rescue
clause met de bijbehorende exception naam
uitgevoerd. De ensure
clause word altijd uitgevoerd
ongeacht of er een exception optreed. De rescue
and ensure
clauses mogen worden weggelaten.
Word er geen exception class opgegeven voor de rescue
clause, dan geld ze voor de StandardError
exception en
voor
exceptions die een is_a? relatie met StandardError
hebben.
Deze expressie geeft de waarde van de begin clause terug.
De laatst opgetreden exception word opgeslagen in de globale
variabele $!
(dus het type ervan kan worden opgevraagd
door $!.type
).
9.26 Hoe gebruik ik trap
?
trap
associeerd code blocks with externe events
(signals).
trap("PIPE") {raise "SIGPIPE"} |