# Tässä yhden rivin kommentti=begin
Tässä usean rivin kommentti
Näitä ei kylläkään käytetä
Joten käytetään vastedes vain yksirivisiä
=end# Tärkeintä on muistaa, että Rubyssa kaikki pohjautuu olioihin.# Luvutkin ovat olioita:3.class#=> Fixnum3.to_s#=> "3"# Peruslaskutoimituksia:1+1#=> 28-1#=> 710*2#=> 2035/5#=> 72**5#=> 325%3#=> 2# Bittioperaatioita:3&5#=> 13|5#=> 73^5#=> 6# Laskutoimitukset ovat vain syntaksisokeria lukuolion laskumetodin kutsulle:1.+(3)#=> 410.*5#=> 50# Erityisarvotkin ovat olioita:nil# vastaa joidenkin kielten "null"-arvoatrue# tosifalse# epätosinil.class#=> NilClasstrue.class#=> TrueClassfalse.class#=> FalseClass# Samanvertaisuuden testaus:1==1#=> true2==1#=> false# ...ja sama eriarvoisuudelle:1!=1#=> false2!=1#=> true# "nil" ja "false" ovat ainoat epätodet arvot; kaikki muu ymmärretään todeksi:!nil#=> true!false#=> true!0#=> false# Lisää vertailuoperaatioita:1<10#=> true1>10#=> false2<=2#=> true2>=2#=> true# Kahdensuuntainen vertailuoperaattori:1<=>10#=> -110<=>1#=> 11<=>1#=> 0# Logiikkaoperaattorit:true&&false#=> falsetrue||false#=> true!true#=> false# Merkkipohjaisten logiikkaoperaattorien vaihtoehtona on sanalliset muodot,# joilla on hyvin matala presedenssi. Niillä voi muokata ohjelman kulkua# esimerkiksi väitelausekkeita ketjuttaen.# Metodia `do_something_else` kutsutaan vain, jos `do_something` onnistuu:do_something()anddo_something_else()# Metodia `log_error` kutsutaan vain, jos `do_something` epäonnistuu:do_something()orlog_error()# Merkkijonot ovat olioita:'Tässä on merkkijono'.class#=> String"Rajaavat lainausmerkit voivat olla yksin- tai kaksinkertaisia".class#=> Stringtäyte='sisällyttää muita merkkijonoja'"Kaksinkertaisilla lainausmerkeillä voi #{täyte}"#=> "Kaksinkertaisilla lainausmerkeillä voi sisällyttää muita merkkijonoja"# Yksinkertaisia lainausmerkkejä kannattaa silti suosia, sillä kaksinkertaiset# merkit saattavat aiheuttaa turhia kielensisäisiä tarkistuksia.# Merkkijonoja voi yhdistellä toisiinsa:'hello '+'world'#=> "hello world"# ...mutta luvut vaativat ensin tyyppimuunnoksen:'hello '+3#=> TypeError: can't convert Fixnum into String'hello '+3.to_s#=> "hello 3"# Merkkijonoja voi soveltaa laskutoimituksiin... odotettavin seurauksin:'hello '*3#=> "hello hello hello "# Merkkijonoa voi jatkaa toisella:'hello'<<' world'#=> "hello world"# Tulosteen luonti kera rivinvaihdon:puts"I'm printing!"#=> I'm printing!#=> nil# ...ja ilman rivinvaihtoa:print"I'm printing!"#=> I'm printing! => nil# Muuttujien määrittely:x=25#=> 25x#=> 25# Arvon asettaminen palauttaa arvon itsensä, joten usean muuttujan arvon# yhtäaikainen määrittely käy vaivatta:x=y=10#=> 10x#=> 10y#=> 10# Muuttujien sanaerottimena käytetään alaviivaa:snake_case=true# Lisäksi Rubyssa suositaan ytimekkäitä nimiä:path_to_project_root='/good/name/'path='/bad/name/'# Symbolit# Symbolit ovat muuttumattomia, uudelleenkäytettäviä vakioita.# Niitä käytetään merkkijonojen sijaan, kun tarkoitus on viitata arvoon,# jolla on tietty, pysyvä merkitys::pending.class#=> Symbolstatus=:pendingstatus==:pending#=> truestatus=='pending'#=> falsestatus==:approved#=> false# Taulukot# Tässä taulukko:array=[1,2,3,4,5]#=> [1, 2, 3, 4, 5]# Taulukko saa koostua erityyppisistä arvoista:[1,'hello',false]#=> [1, "hello", false]# Taulukon alkioihin voi viitata järjestysnumerolla nollasta alkaen:array[0]#=> 1array.first#=> 1array[12]#=> nil# Kuten laskutoimituksissa nähty syntaksisokeri on myös taulukon alkioiden haku# pohjimmiltaan vain taulukko-olioon kuuluvan "[]"-metodin kutsu:array.[]0#=> 1array.[]12#=> nil# Haku käy myös lopustapäin:array[-1]#=> 5array.last#=> 5# Alitaulukon haku käy indeksiparilla...array[2,3]#=> [3, 4, 5]# ...tai määrittelemällä väli:array[1..3]#=> [2, 3, 4]# Taulukon voi kääntää:a=[1,2,3]a.reverse!#=> [3,2,1]# Ja sitä voi jatkaa näin...array<<6#=> [1, 2, 3, 4, 5, 6]# ...tai näin:array.push(6)#=> [1, 2, 3, 4, 5, 6]# Alkion olemassaolon tarkistus:array.include?(1)#=> true# Hashit eli assosiaatiotaulut ovat Rubyn tärkein avain-/arvoparirakenne.# Hash luodaan aaltosulkeilla:hash={'color'=>'green','number'=>5}hash.keys#=> ['color', 'number']# Hash toimii erityisen nopeasti, kun haetaan arvoa avaimen perusteella:hash['color']#=> 'green'hash['number']#=> 5# Jos hashistä ei löyty avainta vastaavaa arvoa, palautetaan nil-arvo:hash['nothing here']#=> nil# Symbolihashin määrittelylle on oma syntaksinsa (alkaen Rubyn versiosta 1.9):new_hash={defcon:3,action:true}new_hash.keys#=> [:defcon, :action]# Hashin avaimen ja arvon olemassaolon tarkistus:new_hash.key?(:defcon)#=> truenew_hash.value?(3)#=> true# Vinkki! Sekä taulukot että hashit sisältävät Enumerable-moduulin,# johon kuuluu useita hyödyllisiä iterointimetodeja kuten .each, .map,# .reduce ja .count# Rakenteitaiftrue'if statement'elsiffalse'else if, optional'else'else, also optional'endforcounterin1..5puts"iteration #{counter}"end#=> iteration 1#=> iteration 2#=> iteration 3#=> iteration 4#=> iteration 5# HUOMAA, että for-rakennetta kannattaa välttää, sillä Rubyssa suosittu# each-metodi ajaa saman asian idiomaattisemmin. Each-metodi ottaa ainoana# argumenttinaan lohkon. Lohkot toimivat pitkälti samoin kuin muiden kielten# anonyymit funktiot, lambdat tai sulkeumat.# Lukuvälit vastaavat each-metodiin, jolloin sille annettu lohko ajetaan# kerran jokaiselle välin kokonaisluvulle.# Lukuvälin each-rakenne lohkoineen näyttää tältä:(1..5).eachdo|counter|puts"iteration #{counter}"end#=> iteration 1#=> iteration 2#=> iteration 3#=> iteration 4#=> iteration 5# Lohkoa ympäröivät do/end-avainsanat voi korvata myös aaltosulkeilla:(1..5).each{|counter|puts"iteration #{counter}"}# Lukuvälien lisäksi myös tietorakenteita voidaan iteroida each-metodilla:array.eachdo|element|puts"#{element} is part of the array"endhash.eachdo|key,value|puts"#{key} is #{value}"end# Taulukoita voi iteroida metodilla each_with_index, jolloin lohko saa# argumenteikseen sekä alkion että indeksin:array.each_with_indexdo|element,index|puts"#{element} is number #{index} in the array"endcounter=1whilecounter<=5doputs"iteration #{counter}"counter+=1end#=> iteration 1#=> iteration 2#=> iteration 3#=> iteration 4#=> iteration 5# Each-metodin lisäksi Rubyssa on useita muita iterointimetodeja kuten# "map" ja "reduce". Näistä "map" kutsuttuna taulukolla ottaa argumentikseen# lohkon, suorittaa sen kerran jokaiselle rakenteen jäsenelle, ja lopuksi# palauttaa uuden taulukon, jonka jäsenet ovat lohkon suorituksen tuloksia.array=[1,2,3,4,5]doubled=array.mapdo|element|element*2endputsdoubled#=> [2,4,6,8,10]putsarray#=> [1,2,3,4,5]# Case-rakenne siirtää ohjelman kulun yhdelle monista määritellyistä poluista:grade='B'casegradewhen'A'puts'Way to go kiddo'when'B'puts'Better luck next time'when'C'puts'You can do better'when'D'puts'Scraping through'when'F'puts'You failed!'elseputs'Alternative grading system, eh?'end#=> "Better luck next time"# Case-rakenteessa voidaan hyödyntää lukuvälejä:grade=82casegradewhen90..100puts'Hooray!'when80...90puts'OK job'elseputs'You failed!'end#=> "OK job"# Virheidenkäsittely:begin# Seuraava koodinpätkä aiheuttaa NoMemoryError-poikkeuksenraiseNoMemoryError,'You ran out of memory.'rescueNoMemoryError=>exception_variableputs'NoMemoryError was raised',exception_variablerescueRuntimeError=>other_exception_variableputs'RuntimeError was raised now'elseputs'This runs if no exceptions were thrown at all'ensureputs'This code always runs no matter what'end# Ylimmän näkyvyysalueen metodi näyttää itsenäiseltä funktiolta:defdouble(x)x*2end# Funktiot (ja lohkot) palauttavat implisiittisesti# viimeiseksi ajamansa lausekkeen arvon:double(2)#=> 4# Metodikutsun argumentteja ympäröivät kaarisulkeet voi jättää pois,# kunhan koodi ei muutu monitulkintaiseksi:double3#=> 6doubledouble3#=> 12defsum(x,y)x+yend# Argumentit erotetaan pilkuilla:sum3,4#=> 7sumsum(3,4),5#=> 12# Kaikilla metodeilla on implisiittinen lohkoparametri,# joka voidaan suorittaa yield-avainsanalla:defsurroundputs'{'yieldputs'}'endsurround{puts'hello world'}# {# hello world# }# Metodille annetun lohkon voi nimetä parametrilistassa &-merkin avulla,# minkä jälkeen se suoritetaan call-metodilla:defguests(&block)block.call'some_argument'end# Metodille voi antaa vaihtelevan määrän muuttujia. Ne siirretään taulukkoon,# jolle annetaan parametrilistassa nimi \*-merkin avulladefguests(*array)array.each{|guest|putsguest}end# Luokan määritys aloitetaan class-avainsanalla:classHuman# Tässä luokkamuuttuja, joka on yhteinen kaikille luokan olioille:@@species='H. sapiens'# Alustusmetodin määrittely:definitialize(name,age=0)# name-oliomuuttujan arvon asetus metodille annetun name-muuttujan mukaan:@name=name# Jos tätä metodia kutsuessa jätetään toinen argumentti (age) antamatta,# saa se parametriluettelossa määritetyn arvon 0:@age=ageend# Tyypillinen oliomuuttujan arvon asettava metodi:defname=(name)@name=nameend# Tyypillinen oliomuuttujan arvon palauttava metodi:defname@nameend# Edelliset kaksi metodia voi ilmaista idiomaattisemmin myös näin:attr_accessor:name# Lisäksi arvon palauttavan ja asettavan metodin voi määritellä erikseen:attr_reader:nameattr_writer:name# Luokkametodeissa käytetään avainsanaa self erotuksena oliometodeista.# Luokkametodia voi kutsua vain luokalla itsellään, ei olioilla:defself.say(msg)putsmsgenddefspecies@@speciesendend# Olion luonti:jim=Human.new('Jim Halpert')dwight=Human.new('Dwight K. Schrute')# Olion metodien kutsuja:jim.species#=> "H. sapiens"jim.name#=> "Jim Halpert"jim.name="Jim Halpert II"#=> "Jim Halpert II"jim.name#=> "Jim Halpert II"dwight.species#=> "H. sapiens"dwight.name#=> "Dwight K. Schrute"# Luokkametodin kutsu:Human.say('Hi')#=> "Hi"# Muuttujan näkyvyysalueen voi määritellä etuliitteellä.# $-alkuiset muuttujat ovat globaaleja:$var="I'm a global var"defined?$var#=> "global-variable"# @-alkuiset muuttujat kuuluvat oliolle,# jonka näkyvyysalueella määrittely tehdään:@var="I'm an instance var"defined?@var#=> "instance-variable"# @@-alkuiset muuttujat kuuluvat vastaavasti näkyvyysalueensa luokalle:@@var="I'm a class var"defined?@@var#=> "class variable"# Isolla alkukirjaimella nimetyt muuttujat ovatkin vakioita:Var="I'm a constant"defined?Var#=> "constant"# Kuten odottaa saattaa, myös luokat itsessään ovat olioita.# Siksi niille voi määritellä muuttujia, jotka ovat yhteisiä kaikille# luokan ilmentymille ja perillisille.# Tavallisen luokan määrittely:classHuman@@foo=0defself.foo@@fooenddefself.foo=(value)@@foo=valueendend# Perillisluokan määrittely:classWorker<HumanendHuman.foo# 0Worker.foo# 0Human.foo=2# 2Worker.foo# 2# Oliomuuttuja on kuitenkin olion oma eikä periydy:classHuman@bar=0defself.bar@barenddefself.bar=(value)@bar=valueendendclassDoctor<HumanendHuman.bar# 0Doctor.bar# nilmoduleModuleExampledeffoo'foo'endend# Moduulien lisääminen luokkaan "include"-avainsanalla siirtää moduulin metodit# luokan ilmentymille, kun taas "extend" avainsana siirtää metodit# luokalle itselleen:classPersonincludeModuleExampleendclassBookextendModuleExampleendPerson.foo# => NoMethodError: undefined method `foo' for Person:ClassPerson.new.foo# => 'foo'Book.foo# => 'foo'Book.new.foo# => NoMethodError: undefined method `foo'# Callback-tyyppiset metodit suoritetaan moduulia sisällyttäessä:moduleConcernExampledefself.included(base)base.extend(ClassMethods)base.send(:include,InstanceMethods)endmoduleClassMethodsdefbar'bar'endendmoduleInstanceMethodsdefqux'qux'endendendclassSomethingincludeConcernExampleendSomething.bar# => 'bar'Something.qux# => NoMethodError: undefined method `qux'Something.new.bar# => NoMethodError: undefined method `bar'Something.new.qux# => 'qux'