Ruby on Rails/Grunnleggende Ruby
Objekter
redigerSå godt som alt i Ruby er et objekt. Mange har forsøkt å forklare hva et objekt er, men de aller fleste ender opp med å bli innlagt på et mentalsykehus. Kort sagt: poenget med objekter er å modellere virkeligheten. Dersom et objekt har en lengde, ligger informasjonen om lengden i selve objektet. Man trenger ikke en ekstern funksjon for å vite hvor langt det er. (Dette trenger sårt en bedre forklaring.)
Alle objekter har en klasse, og klassen definerer hva slags objekt det er.
5.class
=> Integer #(En Integer er et tall uten desimaler)
"Dette er en tekst".class
=> String #(en String er en samling tekst, symboler tall etc.
["Fiolin", "Gitar", "Tuba"].class
=> Array #(et Array er en samling av objekter)
#Og alt etter '#' blir ansett som en kommentar, og vil ikke bli
#lest som Ruby-kode.
Alle «tingene» (som 5
, Dette er en tekst
etc) har en klasse. Eksempler på klasser er Integer
(tall uten desimaler) og String
(tekstsbiter med tall, symboler etc). Klassen til objektet definerer hva slags type objekt det er, og hva du kan gjøre med det.
Med ett Integer
-objekt kan man gjøre typiske numeriske kalkulasjoner.
1 + 2
=> 3
6 - 1
=> 5
8 / 2
=> 4
Ett String
-objekt oppfører seg annerledes, siden det er av en annen klasse.
"Hei på deg".upcase
=> "HEI PÅ DEG"
"Snakke baklengs".reverse
=>"sgnelkab ekkanS"
"Legg meg" + " til deg."
=> "Legg meg til deg."
"5" + "2"
=> "52"
Metoder
redigerMetoder er beskjeder man sender til objekter.
Det finnes to ulike typer metoder. Klassemetoder og instansmetoder. Klassemetoder kaller man direkte på en klasse, som String
, mens instansemetoder kalles på en instans av noe. new
er en klassemetode av String
, mens upcase
er en instansmetode av String
.
Logikken er at klassemetoder gir funksjonalitet som går direkte på klassen.
Lag klasser
redigerKlassene String
og Integer
er innebygd i Ruby. I Ruby kan man også lage nye klasser, og gi dem egenskaper.
class Vehicle
def move_forward
"moving forward"
end
def stop
"stopped"
end
end
def
er et nøkkelord (end
og class
er også nøkkelord) for å definere en metode. Det som står etter def
er navnet på metoden, i dette tilfellet move_forward
og stop
.
Slik virker den nye klassen:
#Lag en instans av Vehicle
vehicle = Vehicle.new
vehicle.class
=> Vehicle
vehicle.move_forward
=> "moving forward"
Arving av egenskaper
redigerEn klasse kan være en underklasse av en annen klasse. En underklasse vil arve alle egenskapene til klassen den er underklasse av.
class Bicycle < Vehicle
def ring_bell
"pling plong"
end
def pedal
"pedaling"
end
end
Det kan brukes på denne måten.
bicycle = Bicycle.new
bicycle.ring_bell
=> "pling plong"
# arver metoder fra over-klassen
bicycle.stop
=> "stopped"
bicycle.tullball
=> NoMethodError: "undefined method ‘tullball’ for Vehicle"
Metoden stop
ble ikke definert i klassen Bicycle
. Den metoden arvet Bicycle
fra Vehicle
.
Ruby har et helt sett med innebygde klasser. Kernel
ligger på topp, og definerer nøkkelordene som def
, return
, class
. Kernel
sin underklasse Object
definerer metoder som ettellerannet.class
, og andre liknende «globale» metoder, som ettellerannent.object_id
, ettellerannet.send
, ettelerannet.inspect
osv.
I stedet for å skrive ettellerannet.metode
for å referere til en instansmetode, er det vanlig å bruke Klasse#metode
. Så, dersom den forestilte klassen Queue
har instansemetoden move_forward
og klassemetoden find_all
, kan man referere til dette som Queue#move_forward
og Queue.find_all
. Dette kan ikke brukes på denne måten i selve språket, da #
definerer en kommentar i koden. Det man ville skrevet som Queue#move_forward
vil i virkeligheten bli skrevet slik:
queue_item = Queue.new
queue_item.move_forward
Lagring av data
redigerEt objekt kan settes opp slik at det inneholder data.
class Vehicle
def initialize(brand, horse_power)
@brand = brand
@horse_power = horse_power
end
def brand
@brand
end
def horse_power
@horse_power
end
end
initialize
-metoden har Vehicle
arvet fra Object
-klassen. Den brukes til å definere hva som skal skje når man lager en ny instans av klassen man definerer den i.
Variabler som @ser_ut_som_dette
er instansvariabler. De er tilgjengelige i den instansen av klassen de er satt i.
not_working = Vehicle.new
=> ArgumentError: "wrong number of arguments (0 for 2)"
my_car = Vehicle.new("Volvo", 192)
my_car.horse_power
=> 192
Logisk nok deles ikke verdiene på tvers av instanser.
v1 = Vehicle.new("Subaru", 110)
v2 = Vehicle.new("Fiat", 97)
v1.horse_power
=> 110
v2.horse_power
=> 97
Det finnes også funksjonalitet for å redigere data etter instansen er laget.
class Vehicle
def initialize(brand, horse_power)
@brand = brand
@horse_power = horse_power
end
def brand
@brand
end
def horse_power
@horse_power
end
def set_brand(brand)
@brand = brand
end
def set_horse_power(horse_power)
@horse_power = horse_power
end
end
Dette kan brukes på følgende måte:
my_bmw = Vehicle.new("BMW", 182)
my_bmw.horse_power
=> 182
my_bmw.set_horse_power(212)
my_bmw.horse_power
=> 212
I de aller fleste tilfeller ønsker man å gjøre my_bmw.horse_power = 138
. For å sette opp dette, definer metonede på følgende måte:
class Vehicle
def horse_power=(horse_power)
@horse_power = horse_power
end
end
my_saab = Vehicle.new("saab", 177)
my_saab.horse_power = 172
my_saab.horse_power
=> 172
Siden det er ganske tungvint å skrive alle disse metodene - særlig hvis man har mange attributter - finnes det snarveier for å sette opp en klasse på denne måten med attr_reader
, attr_writer
og attr_accessor
.
class Vehicle
# definerer Vehicle#brand og Vehicle#horse_power
attr_reader :brand, :horse_power
# definerer Vehicle#max_speed=
attr_writer :max_speed
# defivener Vehicle#weight og Vehicle#weight=
attr_accessor :weight
def initialize(brand, horse_power)
@brand = brand
@horse_power = horse_power
end
# Siden @max_speed bare er satt med attr_writer, defineres
# denne metoden for å vise verdien av @max_speed
def max_speed
@max_speed
end
end
a_truck = Vehicle.new("Scania", 496)
a_truck.horse_power
=> 496
a_truck.max_speed
=> nil
a_truck.max_speed = 120
a_truck.max_speed
=> 120
a_truck.weight = 8000
a_truck.weight
=> 8000