===== Liczby i wyrazenia =====
Liczby w Rubym, w odroznieniu od Javy, to obiekty!
==== Podstawowe wyrazenia ====
=== if ===
# wow_life.rb
print "Ile masz postaci na poziomie 85 w WoWie? "
number_of_lvl_85s = gets.to_i
puts "Powinienes czesciej wychodzic." if number_of_lvl_85s > 1 && number_of_lvl_85s <= 5
puts "Sprzedaj konto i zacznij zyc, na milosc boska!" if number_of_lvl_85s > 5
=== unless ===
# facebook_friends.rb
print "Ilu masz znajomych na facebooku? "
fb_friends = gets.to_i
puts "W sam raz." unless fb_friends < 10 || fb_friends > 20
=== between ===
# between.rb
print "Czesc, podaj mi twoje HRrest: "
hrrest = gets.to_i
puts "Ooo, duzo biegamy?:-)" if hrrest.between?(40, 50)
=== x <=> y ===
# comparison.rb
print "Ile masz lat? "
age = gets.to_i
my_age = 26
reaction = age <=> my_age
puts "Czesc." if reaction == -1
puts "Dzien dobry." if reaction == 1
puts "Haii!" if reaction == 0
=== .times ===
# loops.rb
5.times do
puts "Bede sie pilnie uczyl, obiecuje!"
puts "I juz nigdy nie wejde na ta strone. /blushes"
end
Zamiast ''do'' i ''end'' mozna wykorzystac nawiasy klamrowe. Preferowane jest uzywanie klamer dla jednoliniowych blokow a ''do'' i ''end'' dla wieloliniowych.
# curly_loops.rb
5.times {
puts "Bede sie pilnie uczyl, obiecuje!"
puts "I juz nigdy nie wejde na ta strone. /blushes"
}
=== upto, downto, step ===
# iterators.rb
# upto
puts "== upto =="
1.upto(5) {
|number| puts number
}
# downto
puts "== downto =="
10.downto(5) {
|number| puts number
}
# step
puts "== step =="
0.step(50, 15) {
|number| puts number
}
Output:
== upto ==
1
2
3
4
5
== downto ==
10
9
8
7
6
5
== step ==
0
15
30
45
=== to_f, to_i ===
# floating.rb
x = 10
x_float = 10.0
y = 3
print "10 / 3: \t\t\t", x / y, "\n"
print "10.0 / 3: \t\t\t", x_float / y, "\n"
print "10.to_f / 3.to_f: \t\t", x.to_f / y.to_f, "\n"
print "(x.to_f / y.to_f).to_i: \t", (x.to_f / y.to_f).to_i, "\n"
Output:
10 / 3: 3
10.0 / 3: 3.3333333333333335
10.to_f / 3.to_f: 3.3333333333333335
(x.to_f / y.to_f).to_i: 3
=== stale ===
Stale w Rubym to zmienne zaczynajace sie od duzej litery.
# constants.rb
# O, solitude...
Have_girlfriend = 0
# ... how I hate thee...
Have_girlfriend = 1
print "... but our paths, it seems, are forever to be intertwined.\n" if Have_girlfriend == 0
print "... but there is a hope! Keep your chin up.\n" if Have_girlfriend == 1
Output:
constants.rb:7: warning: already initialized constant Have_girlfriend
... but there is a hope! Keep your chin up.
?! How can this be? **Stale moga byc zmieniane**, ich zmiana generuje ''warning'' ale to wszystko. Nazwy klasy takze sa pisane wielka litera i rowniez sa traktowane jak stale.
===== Tekst i lancuchy znakow =====
Lancuchy znakow (''string''i), jak w Javie, sa obiektami. Lancuch wpisany w kod, za pomoca cudzyslowow nazywany jest jako literał łańcuchowy (''string literal'').
# string_literals.rb
x = %q{Test zmiennej
wielo
liniowej.
}
y = %q!Zamiast
klamer mozna
wykorzystac inne delimitery.
!
# heredoc
z = <
Dobrze jest wybrac taki delimiter, zeby nie kolidowal ze znakami w cytowanym tekscie.
==== Operacje na lancuchach ====
# string_expr.rb
# konkatenacja
season = "summer"
puts "Shall I compare thee to a " + season + "'s day..."
# mnozenie
puts "I hate you. " * 5
# porownywanie
puts "x" > "y"
# ?x
print "?x = ", ?x, "\n"
print "?y = ", ?y, "\n"
print "120.chr = ", 120.chr, "\n"
Output:
Shall I compare thee to a summer's day...
I hate you. I hate you. I hate you. I hate you. I hate you.
false
?x = x
?y = y
120.chr = x
?x nie dziala w wersji 1.9.2 - **investigate**.
=== Interpolacja ===
# interpolation.rb
x = 10
y = 20
puts "#{x} + #{y} = #{x + y}"
Output:
10 + 20 = 30
Mozna umieszczac wyrazenia lub nawet logike w lancuchach. Taki proces, tj. proces wstawiania wyniku wyrazenia do lancucha literalowego, nazywamy interpolacja. Robi sie to, umieszczajac wyrazenie pomiedzy ''#{'' a ''}''.
=== .sub(), .gsub() ===
.sub() zastepuje pierwsze wystapienie tekstu innym, .gsub() zastepuje wszystkie wystapienia.
# sub_stitution.rb
sentence = "sqbell rings a bell"
puts sentence.sub('bell', 'ueal')
puts sentence.gsub('bell', 'ueal')
Output:
squeal rings a bell
squeal rings a ueal
=== Krotkie wprowadzenie do wyrazen regularnych ===
^ Znak ^ Znaczenie ^
| ''/'' | poczatek i koniec wyrazenia regularnego |
| ''^'' | kotwica (''anchor''), znacznik poczatku linii |
| ''$'' | kotwica, znacznik konca linii |
| ''\A'' | absolutny poczatek ciagu |
| ''\Z'' | absolutny koniec ciagu |
| ''.'' | dowolny znak |
| ''\w'' | dowolna cyfra, litera badz podkreslenie |
| ''\W'' | wszystko, czego nie obejmuje ''\w'' |
| ''\d'' | dowolna cyfra |
| ''\D'' | odwrotnosc ''\d'' |
| ''\s'' | whitespace (spacje, tabulacje, nowe linie, etc)|
| ''\S'' | j/w |
^ Modyfikator ^ Znaczenie ^
| ''*'' | zero lub wiecej, poprzedzajacych modyfikator, znakow; dopasuj najwiecej ile sie da |
| ''+'' | jeden lub wiecej... |
| ''*?'' | zero lub wiecej, dopasuj najmniej jak sie tylko da |
| ''+?'' | jeden lub wiecej... |
| ''?'' | jeden lub zero |
| ''{x}'' | dopasuj dokladnie x wystapien |
| ''{x, y}'' | dopasuj conajmniej x i conajwyzej y wystapien |
Wiecej: http://net.tutsplus.com/tutorials/ruby/ruby-for-newbies-regular-expressions/
# regexp_01.rb
x = "sqbell likes his beer like he likes his women: stout and bitter.\nAnd yes, he IS a World of Warcraft player."
# zastepujemy pierwsze (^) dwa dowolne znaki (.) pierwszej (.sub()) linii
puts x.sub(/^../, 'Mr '), "\n"
# zastepujemy ostatnie ($) szesc dowolnych znakow pierwszej linii
puts x.sub(/......$/, 'etter.'), "\n"
# zastepujemy ostatnie (\Z) szesc znakow (calego) ciagu
puts x.sub(/......\Z/, 'etter.'), "\n"
Output:
Mr bell likes his beer like he likes his women: stout and bitter.
And yes, he IS a World of Warcraft player.
sqbell likes his beer like he likes his women: stout and better.
And yes, he IS a World of Warcraft player.
sqbell likes his beer like he likes his women: stout and bitter.
And yes, he IS a World of Warcraft petter.
=== .scan() ===
# scan.rb
x = "sqbell likes his beer like he likes his women: stout and bitter.\n"
# wyswietlamy po trzy znaki
x.scan(/.../) {
|letters| puts letters
}
puts "=========="
# nie chcemy whitespace'ow!
x.scan(/\w\w\w/) {
|x| puts x
}
puts "=========="
# slowa
x.scan(/\w+/) {
|x| puts x
}
puts "=========="
# slowa czteroliterowe
x.scan(/\w{4}/) {
|x| puts x
}
Output:
sqb
ell
li
kes
hi
s b
eer
li
ke
he
lik
es
his
wo
men
: s
tou
t a
nd
bit
ter
==========
sqb
ell
lik
his
bee
lik
lik
his
wom
sto
and
bit
ter
==========
sqbell
likes
his
beer
like
he
likes
his
women
stout
and
bitter
==========
sqbe
like
beer
like
like
wome
stou
bitt
=== Dopasowywanie (matching) ===
''=~'', podobnie jak w perlu, sluzy nam jako operator dopasowywania.
# matching.rb
x = "O democracy, near at hand to you my throat
is inflating itself and joyfully singing"
# czy jest na pokladzie jakas samogloska?
puts "Mamy samogloski!" if x =~ /[aeiou]/
# to samo co powyzej
puts "Mamy samogloski, inaczej!" if x.match(/[aeiou]/)
# nawiasy w regexp umozliwiaja nam dostep do matchowanych danych
y = x.match(/(\w+) (\w+)/)
# match zwraca nam obiekt MatchData, z ktorego mozna korzystac jak
# z tablicy
puts y[0] # zerowy element zawiera dane dopasowane przez cale wyrazenie
puts y[1] # kolejne elementy zawieraja dane dopasowane przez kolejne
puts y[2] # wyrazenia ujete w nawiasy
Output:
Mamy samogloski!
Mamy samogloski, inaczej!
O democracy
O
democracy
===== Tablice i listy =====
# arrays.rb
x = [1, 2, 3, 4]
puts x[2]
# wstawianie elementow do tablicy
y = [] # definicja pustej tablicy, to samo co y = Array.new
y << "I rulezZz." # to to samo co
y.push("You suck.")
y << "kk?"
# pop pobiera i usuwa ostatni element tablicy
puts y.pop
puts y.length
# join laczy wszystkie elementy tablicy;
# opcjonalny parametr wskazuje delimiter
puts x.join(', ')
puts y.join(' ')
Output:
3
kk?
2
1, 2, 3, 4
I rulezZz. You suck.
==== .inspect() i p ====
Obydwie metody doskonale sprawdzaja sie w podgladaniu obiektow, tablic i tak dalej. ''inspect'' przedstawia tekstowa reprezentacje obiektu. ''p'' dziala na podobnej zasadzie. Cos jak print_r w PHP.
# str_to_array.rb
p "Jestes jak melodia tkliwa, slodko z najczystszych grana nut.".scan(/\w+/)
puts "To be a ruler of life, not a slave!".split(/ /).inspect
["Jestes", "jak", "melodia", "tkliwa", "slodko", "z", "najczystszych", "grana", "nut"]
["To", "be", "a", "ruler", "of", "life,", "not", "a", "slave!"]
==== Iteratory .each i .collect ====
http://stackoverflow.com/questions/3630670/ruby-on-rails-distinct-difference-between-collection-and-each
Roznica jest taka, ze .collect (oraz, jak sie okazuje, .map) zwracaja nowa tablice, podczas gdy .each modyfikuje stara.
# array_iteration.rb
# each
x = [1, 2, 3, 4]
x.each {
|element| element * 2
}
p x
puts "========"
# collect
y = [1, 2, 3, 4]
z = y.collect {
|element| element * 2
}
p y
p z
Output:
[1, 2, 3, 4]
========
[1, 2, 3, 4]
[2, 4, 6, 8]
==== Dodawanie, odejmowanie tablic, empty? ====
# combine_array.rb
x = ["Ala", "ma"]
y = ["kota", "a", "kot"]
z = ["ma", "Ale"]
a = x + y + z
p a
# odejmowanie tablic
x = [1, 2, 3, 4, 5]
y = [1, 2, 3]
z = x - y
p z
# .empty?
x = []
puts "x jest pusta" if x.empty?
Output:
["Ala", "ma", "kota", "a", "kot", "ma", "Ale"]
[4, 5]
x jest pusta
==== .include? ====
# array_include.rb
x = ["sqbell", "lubi", "koszule", "w", "kratke"]
p x.include?("w")
p x.include?("dziewczyny")
Output:
true
false
==== .first, .last ====
Jako parametr, mozna podac liczbe zwracanych elementow od poczatku (lub konca) tablicy.
# array_fl.rb
x = "Lubie duze, ciezkie i stare zolwie".scan(/\w+/)
print "#{x.first} #{x.last}.\n"
print "#{x.first(2).join(" ")} #{x.last(3).join(" ")}.\n"
Output:
Lubie zolwie.
Lubie duze i stare zolwie.
==== .reverse ====
# array_reverse.rb
x = ["December.", "bleak", "a", "in", "was", "It"]
puts x.reverse.join(" ")
Output:
It was in a bleak December.
===== Hashe =====
W odroznieniu do tablic, gdzie kazdemu elementowi przyporzadkowany jest indeks, pozycja na liscie, w przypadku hashy, jest to klucz (''key''), ktory na element wskazuje. Nie ma tu zagwarantowanej kolejnosci. W wersji 1.9 Rubiego jednakowoz, kolejnosc, z jaka elementy byly wstawiane do hasha jest zapamietywana i ''each'' zwroci je w tej kolejnosci.
# hash_basics.rb
hash_pipe = { 'band' => 'Weezer', 'status' => 'sucky' }
==== Iterowanie poprzez hasha ====
# hash_iterating.rb
x = { "a" => 1, "b" => 2 }
x.each {
|key, value| puts "#{key} equals #{value}"
}
==== .keys, .values ====
# hash_kv.rb
hsh = { "first" => "Belegost", "second" => "Aiginn", "third" => "Misette"}
p hsh.keys
p hsh.values
Output:
["first", "second", "third"]
["Belegost", "Aiginn", "Misette"]
==== .delete, .delete_if ====
# hash_delete.rb
x = { "a" => 1, "b" => 2 }
x.delete("a")
# hash_delete_if.rb
x = { "a" => 100, "b" => 20 }
x.delete_if {
|key, value| value < 25
}
==== Hashe w hashach ====
# hash_in_hash.rb
people = {
'fred' => {
'name' => 'Fred Elliott',
'age' => 63,
'gender' => 'male',
'favorite painters' => ['Monet', 'Constable', 'Da Vinci']
},
'janet' => {
'name' => 'Janet S Porter',
'age' => 55,
'gender' => 'female'
}
}
puts people['fred']['age']
puts people['janet']['gender']
===== Sterowanie przebiegiem programu =====
==== elsif, case ====
W przypadku ''case/when'', nie trzeba przerywac wykonywania (''break'' w PHP).
# elsif_case.rb
fruit = "orange"
if fruit == "orange"
color = "orange"
elsif fruit == "apple"
color = "green"
else
color = "unknown"
end
fruit = "orange"
case fruit
when "orange"
color = "orange"
when "apple"
color = "green"
else
color = "unknown"
end
==== Bloki kodu ====
# code_blocks.rb
x = [1, 2, 3]
x.each { |y| puts y}
W powyzszym przypadku kod bloku znajduje sie pomiedzy klamrami (moze tez znajdowac sie pomiedzy delimiterami ''do'' i ''end''). Kod ten to anonimowa metoda lub funkcja. Jest on podawany do metody ''each'', ktora z kolei uruchamia ten kod dla kazdego elementu tablicy.
Metoda, ktora przyjmuje takie bloki kodu wygladac moze nastepujaco:
# code_blocks_method.rb
def each_vowel(&code_block)
%w{a e i o u}.each { |vowel| code_block.call(vowel) }
end
each_vowel { |vowel| puts vowel}
Pierwsze trzy linie to metoda, ktora przyjmuje blok kodu jako parametr(?), co jest okreslane za pomoca znaku ''&''. W tej metodzie, iterujemy po elementach specjalnej tablicy ''%w'' (omowionej w dalszej czesci), dla kazdego wywolujac blok kodu podany jako parametr za pomoca metody ''code_block.call''.
To samo mozna osiagnac za pomoca metody ''yield''.
# code_blocks_yield.rb
def each_vowel
%w{a e i o u}.each { |vowel| yield vowel }
end
each_vowel { |vowel| puts vowel}
Tylko jeden blok kodu moze byc podawany metodzie. Bloki kodu natomiast, moga przyjmowac parametry.
Mozna przechowywac bloki kodu w zmiennych za pomoca metody ''lambda''.
# code_blocks_lambda.rb
print_parameter_to_screen = lambda { |x| puts x }
print_parameter_to_screen.call(100)
Wiecej przykladow:
* http://blog.codahale.com/2005/11/24/a-ruby-howto-writing-a-method-that-uses-code-blocks/
* http://en.wikipedia.org/wiki/Ruby_%28programming_language%29#Blocks_and_iterators
* http://blog.rubybestpractices.com/posts/gregory/009-beautiful-blocks.html
=== % ===
TODO rozszerzyc!
Przyklady:
* http://old.blog.jimhoskins.com/?p=8
* http://stackoverflow.com/questions/5751831/percent-notation-in-ruby
===== Inne przydatne rzeczy =====
==== Daty i czas ====
Sprytni programisci, aby ulatwic sobie sprawe z operacjami na datach, rozszerzaja klase Fixnum o nastepujace metody. Dzieki temu, kod jest duzo bardziej czytelny i zrozumialy.
# date_fixnum.rb
class Fixnum
def seconds
self
end
def minutes
self * 60
end
def hours
self * 60 * 60
end
def days
self * 60 * 60 * 24
end
end
puts Time.now
puts Time.now + 10.minutes
puts Time.now + 16.hours
puts Time.now + 7.days
^ Metoda ^ info ^
| ''Time.local(year, month, day, hour, min, sec, msec)'' | Kod tworzy instancje obiektu ''Time'' na podstawie lokalnej strefy czasowej |
| ''Time.gm(...)'' | GMT/UTC |
| ''Time.utc(...)'' | dokladnie jak powyzej |
Aby zamienic obiekt ''Time'' na liczbe sekund od epoku UNIXa (lub z powrotem)
# time_to_unix.rb
puts Time.local(2011, 05).to_i
puts Time.at(Time.local(2011, 05).to_i).year
==== Duze liczby ====
W rubym nie trzeba sie martwic duzymi liczbami. Sa one obslugiwane przez klase ''Bignum'' niemalze bez wiedzy uzytkownika. Granica pomiedzy ''Fixnum'' a ''Bignum'' zalezna jest od architektury systemu. (mozna to sprawdzic, testujac liczby: ''puts 1073741824.class'').
==== Przedzialy ====
Opcje -Ku wlaczaja obsluge UTF-8.
#!/home/sqbell/.rvm/rubies/ruby-1.9.2-p180/bin/ruby -Ku
# utf_8.rb
(0x0000 .. 0x7f).each {
|letter| puts "0x#{letter.to_s(16)}: #{letter.chr} "
}
Output:
[...]
0x6d: m
0x6e: n
0x6f: o
0x70: p
0x71: q
0x72: r
0x73: s
[...]
# ranges.rb
puts ('a' .. 'z').include?('r')
a = [2, 4, 6, 8, 10, 12]
p a[1 .. 3]
a[1 .. 3] = ["a", "b", "c"]
p a
Output:
true
[4, 6, 8]
[2, "a", "b", "c", 10, 12]
==== Symbole ====
Symbole nie posiadaja wartosci czy obiektu, jak zmienne. Sa uzywane jako stale nazwy w kodzie. Poprzedzamy je dwukropkiem ('':'').
# symbols.rb
current_situation = :good
puts "Everything is fine." if current_situation == :good
puts "PANIC! Run for your life!" if current_situation == :bad
Mozna by zamiast symboli uzyc lancuchow znakow (''"good"'', ''"bad"''), ale jest to mniej wydajne (lancuch znakow to obiekt a symbol to zwykla referencja do wartosci, ktora jest inicjowana tylko raz).