Você está na página 1de 42

RUBY

Eustáquio “TaQ” Rangel


eustaquiorangel@yahoo.com
http://beam.to/taq
Licenciado sob a Creative Commons
O que
O que é Ruby?
é Ruby?

Ruby é uma linguagem interpretada para programação orientada a objetos


de um modo fácil e rápido. Ela tem vários recursos para processar arquivos
de texto e para fazer tarefas de gerenciamento de sistema (assim como o
Perl). Ela é simples, direto ao ponto, extensível e portável.

Recursos de Ruby

● Ruby tem uma sintaxe simples, parcialmente inspirada por Eiffel e Ada.
● Ruby tem recursos de tratamento de exceções
● Os operadores do Ruby são açucar sintático para os métodos. Você pode
redefini-los facilmente.
● Ruby é uma linguagem completa e puramente orientada á objetos. Isso
significa que todo dado em Ruby é um objeto. Por exemplo, em Ruby, o
numero 1 é uma instância da classe Fixnum.
O que
O que é Ruby?
é Ruby?

● A orientação à objetos do Ruby é desenhada cuidadosamente para ser


completa e aberta à melhorias. Por exemplo, Ruby tem a habilidade de
adicionar métodos em uma classe, ou até mesmo em uma instância
durante o runtime!
● Ruby tem herança única, de propósito. Mas entende o conceito de
módulos, que são coleções de métodos. Toda classe pode importar um
módulo e pegar seus métodos.
● Ruby tem closures verdadeiras.
● Ruby tem blocos em sua sintaxe (código delimitado por {. . . } ou do. . .
end). Esses blocos podem ser passados para os métodos, ou convertidos
em closures.
● Ruby tem um garbage collector que realmente é do tipo marca-e-limpa.
Ele atua em todos os objetos do Ruby. Você não precisa se preocupar em
manter contagem de referências em libraries externas.
Por que
Por que Ruby?
Ruby?

● Por que programar em Ruby é divertido. :-)


● Por que os usuários e desenvolvedores são gente-boa.
● Tipagem dinâmica e forte
● Sintaxe limpa
● Código menor e mais eficiente
● Multiplataforma
● Serve para scripting
● Serve para aplicações gráficas
● Serve para web
● Conecta com vários bancos de dados facilmente e de forma uniforme
Por que
Por que nãonão Ruby?
Ruby?

● Por que talvez ainda não. ;-)


● Por que adora a linguagem X e quer que o mundo seja feito nela.
● Por que você adora bytecode e ainda não tem.
● Por que você quer distribuir suas aplicações compactadas tipo um .jar.
● Por que você quer obfuscar seu código.
● Por que você adora aquelas linguagens que tem que arrastar as coisas
com o mouse. ;-)
● Por que você vai fazer uma aplicação com uso extensivo da parte gráfica
e precisa de respostas ultra-rápidas.
● Por que você não aguenta mais aprender mais outra linguagem. :-)
Conhecendo
Conhecendo o básico
Blocos de código

Blocos de uma linha:

{ |<parametros>| <código>}

Blocos de várias linhas:

do |<parametros>|
<código>
end
Conhecendo
Conhecendo o básico
Blocos de código Iterators

Blocos de uma linha: (0..5).each

(0..5).each
{ {|p| puts
|<parametros>| “o parâmetro vale o#{p}”
<código>} parâmetro
} vale 0
-----------------------------
o parâmetro vale 1
o parâmetro vale 0
-----------------------------
Blocos de várias linhas: o parâmetro
o parâmetro vale
vale1 2
o parâmetro vale 2
-----------------------------
o parâmetro
o parâmetro vale
vale3 3
(0..5).each
do do |p|
|<parametros>| o parâmetro vale 4
puts “o parâmetro vale #{p}” -----------------------------
<código> o parâmetro vale 5 4
o parâmetro vale
endputs “----------------------------------” -----------------------------
end o parâmetro vale 5
-----------------------------
Conhecendo
Conhecendo o básico
Números

Fixnum's

Números de -230 até 230-1. São immediate values, onde os


valores são armazenados internamente em formato binário e
quando atribuídos ou passados como parâmetro, a referência
atual (já com valor) é passada, ao invés de uma referência de
um objeto.

Fixnum's tem a capacidade de uma word nativa da


máquina, menos 1 bit. No caso de processadores de 32 bits,
então, podem representar 2.147.483.647 números, entre
-1.073.741.824 e 1.073.741.823.
Conhecendo
Conhecendo o básico
Números Fixnum
Fixnum's abs
next
n1 = 1 to_s
n2 = 2 n1
n3 = 3 Promoção automática de tipos
n1.class => Fixnum
((2**30)-1).class => Fixnum Identificando
((2**30)-0).class => Bignum
n2.class => Fixnum 3 & 0x1 = 1
n3.class => Fixnum n2 5 & 0x1 = 1
n1.object_id => 3 7 & 0x1 = 1
n2.object_id => 5
n3.object_id => 7
Valores
n3 3 >> 1 = 1
5 >> 1 = 2
7 >> 1 = 3
Conhecendo
Conhecendo o básico
Números

Bignum's e Floats

Bignum Float
b = (2**40) (2**40) 123.45
b.class => Bignum

Garbage Collector
f = 123.45
f.class => Float
Fixnum Float Bignum

n = 123 abs floor abs


n.class => Fixnum next ceil next
to_s to_s to_s
Conhecendo
Conhecendo o básico
Booleanos, nulos e constantes

Const = “constante”
t = true
Const = “constante”
t.class => TrueClass
warning: already initialized constant Const

f = false
f.class => FalseClass

n = nil
n.class => NilClass
Conhecendo
Conhecendo o básico
Strings e símbolos

s1 = “taq” String
“taq”

s2 = s1 String
“taq”

s3 = “taq”
Symbol
taq
s4 = :taq

s5 = :taq s6 = :taq s7 = :taq


Conhecendo
Conhecendo o básico
Ranges, Arrays e Hashes

r = 0..5 a = [1,”dois”,3,”quatro”,5]
r.each {|p| print “#{p},”} a.each {|p| print “e:#{p},”}
0,1,2,3,4,5 e:1,e:dois,e:3,e:quatro,e:5,

r = 0...5
r.each {|p| print “#{p},”}
0,1,2,3,4 h = {20=>”vinte”,30=>30.0}
a.each_key {|p| print “e:#{p},”}
e:30,e:20
a.each_value {|p| print “e:#{p},”}
e:30.0,e:vinte
Conhecendo
Conhecendo o básico
Expressões regulares

er = /[0-9]/
er = Regexp.new(“[0-9]”)

puts “Casou!” if “123” =~ er


Casou!

puts “Casou!” if “abc” =~ er

puts “Não casou!” if “123” !~ er

puts “Não casou!” if “abc” !~ er


Não casou!
Conhecendo
Conhecendo o básico
Classes
nome da classe (maiúscula)
class Carro
@@fabricados = 0
def initialize(cor) váriavel de classe
@cor = cor
@@fabricados += 1
end váriavel de instância
def cor
@cor
end “construtor”
def Carro.fabricados
@@fabricados
end métodos
end

a = []
a << Carro.new("azul") azul
a << Carro.new("branco") ----------------------
a.each do |p| branco
puts p.cor
puts "----------------------"
----------------------
end 2
puts Carro.fabricados
Conhecendo
Conhecendo o básico
Classes
class Carro class Carro
attr_accessor :cor attr_accessor :cor # leitura e escrita
@@fabricados = 0 attr_reader :odometro # leitura
def initialize(cor) attr_writer :senha # escrita
@cor = cor
@@fabricados += 1 def initialize(cor)
end @cor = cor
def Carro.fabricados @odometro = 0
@@fabricados @senha = “123456”
end end
end def to_s
"Carro cor #{@cor}, #{@odometro}km"
a = [] end
a << Carro.new("azul") def incrementa_km
a << Carro.new("branco") @odometro += 1
a.each do |p| end
puts p.cor end
puts "----------------------"
end
puts Carro.fabricados
Conhecendo
Conhecendo o básico
Classes
class Carro class Carro
public public
attr_accessor :cor attr_accessor :cor
private private
attr_reader :odometro attr_reader :odometro
protected protected
attr_writer :senha attr_writer :senha

public public
def initialize(cor) def initialize(cor)
@cor = cor @cor = cor
@odometro = 0 @odometro = 0
@senha = “123456” @senha = “123456”
end end
end private
def metodo_privado
puts “privado”
end
end
Entrada e saída
Entrada e saída
Arquivos
# abrindo o arquivo
f = File.new(“teste.txt”,”r”)
f.close

# abrindo o arquivo e fechando “automagicamente”


File.open(“teste.txt”) do |handle|
handle.each {|row| puts row}
end

# lendo todas as linhas de uma vez


File.readlines(“teste.txt”).each {|row| puts row}

# escrevendo em um arquivo
f = File.new(“teste2.txt”,”w”)
f.write “Oi!”
f.close

f = File.new(“teste2.txt”,”w”)
f << “Oi!”
f.close
Entrada e saída
Entrada e saída
Fluxos TCP

# abrindo o SMTP
require “socket”

smtp = TCPSocket.open(“localhost”,25)
puts stmp.gets
220 taq.server.com.br ESMTP Sendmail

smtp.puts(“EHLO taq.com.br”)
puts stmp.gets
250-taq.server.com.br Hello localhost [127.0.0.1], pleased to meet you\r\n

smtp.close
Entrada e saída
Entrada e saída
Fluxos UDP

# servidor
require 'socket'

porta = 12345
server = UDPSocket.new
server.bind("localhost",porta)
puts "Servidor conectado na porta #{porta}, aguardando ..."
loop do
msg,sender = server.recvfrom(256)
msg.chomp!
host = sender[3]
puts "Host #{host} enviou um pacote UDP: #{msg}"
break unless msg.chomp != "kill"
end
puts "Kill recebido, fechando servidor."
server.close
Entrada e saída
Entrada e saída
Fluxos UDP

# cliente
require 'socket'

porta = 12345
client = UDPSocket.open
client.connect("localhost",porta)
loop do
puts "Digite sua mensagem (quit termina, kill finaliza servidor):"
msg = gets.chomp
client.send(msg,0)
break if "kill,quit".include? msg
end
client.close

# rodando
Digite sua mensagem (quit termina, kill finaliza servidor): oi!
Host 127.0.0.1 enviou um pacote UDP: oi!
Entrada e saída
Entrada e saída
HTTP
require "net/http"

s = Net::HTTP.get("www.kernel.org","/")
puts s

<?xml version="1.0" encoding="utf-8"?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...

require "net/http"

s = Net::HTTP.get("www.kernel.org","/")
s.scan(/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/).uniq.sort.each do |k|
puts "kernel #{k} disponivel"
end
kernel 2.0.40 disponivel
kernel 2.2.26 disponivel
kernel 2.2.27 disponivel
Exceções
Exceções
Begin ... rescue ... ensure ... end
i1 = 1
i2 = “dois”

begin
i1 + i2
rescue => exc
puts “Erro: #{exc} (#{exc.class})”
ensure
puts “Passei aqui!”
end

Erro: String can’t be coerced into Fixnum (TypeError)


Passei aqui!
Módulos
Módulos
Mixin's
module Bipadores t = Telefone.new
def bip c = Celular.new
“bip!” p = Palmtop.new
end
end t.bip
NoMethodError: undefined method
class Telefone 'bip' for #<Telefone:0xb7e3476c>
def disca
“discando” c.bip
end bip!
end
p.bip
class Celular < Telefone bip!
include Bipadores
end

class Palmtop
include Bipadores
end
Módulos
Módulos
Mixin's
class Teste class Teste
attr_reader :valor include Enumerable
include Comparable def initialize(a)
def initialize(v) @array = a
@valor = v end
end def each
def <=>(outra) @array.each do |v|
self.valor <=> outra.valor yield v
end end
end end
end
t1 = Teste.new(1)
t2 = Teste.new(2) t = Teste.new([3,5,1,2,4])
puts t.sort => 1,2,3,4,5
puts t1 > t2 puts t.include?(3) => true
puts t2 < t1 puts t.include?(10) => false
puts t1 == t1 puts t.min => 1
puts t.max => 5
false puts t.sort.map {|v| v*10} => 10,20,30,40,50
false
true
Threads
Threads
Threads
t = Thread.new do thread inicializada
puts "thread inicializada." linha 0
5.times do |n| linha 1
puts "linha #{n}" linha 2
sleep(1) linha 3
end linha 4
end thread finalizada
t.join
puts “thread finalizada”
Threads
Threads
Threads
iniciando Proc 1, 5 loops
p = Proc.new do |n,c| Proc 1/1
puts "iniciando Proc #{n}, #{c} loops" iniciando Proc 2, 4 loops
c.times do |x| Proc 2/1
puts "Proc #{n}/#{x+1}" iniciando Proc 3, 3 loops
sleep(1) Proc 3/1
end iniciando Proc 4, 2 loops
end Proc 4/1
iniciando Proc 5, 1 loops
t1 = Thread.new(1,5,&p) Proc 5/1
t2 = Thread.new(2,4,&p) Proc 4/2
t3 = Thread.new(3,3,&p) Proc 3/2
t4 = Thread.new(4,2,&p) Proc 2/2
t5 = Thread.new(5,1,&p) Proc 1/2
t1.join Proc 3/3
Proc 2/3
Proc 1/3
Proc 2/4
Proc 1/4
Proc 1/5
Threads
Threads
Threads

require "thread" Thread.new do


loop do
items = [] lock.synchronize do
lock = Mutex.new size = items.size
count = 0 for i in (0...size)
puts "consumindo #{items[0]}"
Thread.new do items.shift
loop do end
lock.synchronize do puts "----------------------------" if size > 0
(0..rand(3)).each do end
items << count end
puts "produzindo #{count}" end
count += 1
end sleep(5)
end
sleep(1)
end
end
Threads
Threads
Threads
produzindo 0
consumindo 0
----------------------------
produzindo 1
produzindo 2
consumindo 1
consumindo 2
----------------------------
produzindo 3
produzindo 4
consumindo 3
consumindo 4
----------------------------
produzindo 5
produzindo 6
consumindo 5
consumindo 6
----------------------------
produzindo 7
produzindo 8
produzindo 9
consumindo 7
consumindo 8
consumindo 9
----------------------------
Threads
Threads
Threads

require "thread" Thread.new do


loop do
items = [] lock.synchronize do
lock = Mutex.new size = items.size
cond= ConditionVariable.new for i in (0...size)
count = 0 puts "consumidor: consumindo #{items[0]}"
items.shift
t1 = Thread.new do end
(0..3).each do puts "consumidor: todos os items consumidos."
lock.synchronize do cond.signal
(0..rand(3)).each do end
items << count end
puts "produtor : produzindo #{count}" end
count += 1
end t1.join
cond.wait(lock)
puts "produtor : consumo efetuado."
end
end
end
Threads
Threads
Threads
produtor : produzindo 0
consumidor : consumindo 0
consumidor : todos os items consumidos.
produtor : consumo efetuado.
produtor : produzindo 1
produtor : produzindo 2
consumidor : consumindo 1
consumidor : consumindo 2
consumidor : todos os items consumidos.
produtor : consumo efetuado.
produtor : produzindo 3
consumidor : consumindo 3
consumidor : todos os items consumidos.
produtor : consumo efetuado.
produtor : produzindo 4
consumidor : consumindo 4
consumidor : todos os items consumidos.
produtor : consumo efetuado.
Banco
Banco de de dados
dados
Ruby/DBI – Database Independent Interface
require “dbi”

DBI.connect(“DBI:Mysql:taq:localhost”,”taq”,”minhasenha”) do |con|
con.execute(“select * from pedidos”) do |rst|
rst.fetch do |row|
printf “cliente: %06d produto: %s\n”,row[“cliente”],row[“produto”]
end
end
end

cliente:000001 produto: CD - Anthrax - Greater of Two Evils


cliente:000001 produto: DVD - Slayer - Still Reigning
cliente:000002 produto: CD - Judas Priest - Angel of Retribution
Banco
Banco de de dados
dados
Formatação especializada - tabular
require "dbi"

DBI.connect("DBI:Mysql:taq:localhost","taq","minhasenha") do |con|
con.execute("select cliente,descricao from pedidos") do |rst|
rows = rst.fetch_all
cols = rst.column_names
DBI::Utils::TableFormatter.ascii(cols,rows)
end
end

+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+
| cliente | descricao                                |
+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+
| 1       | CD ­ Anthrax ­ Greater of Two Evils      |
| 1       | DVD ­ Slayer ­ Still Reigning            |
| 2       | CD ­ Judas Priest ­ Angel of Retribution |
+­­­­­­­­­+­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­+
Banco
Banco de de dados
dados
Formatação especializada - XML
require "dbi"

DBI.connect("DBI:Mysql:taq:localhost","taq","minhasenha") do |con|
DBI::Utils::XMLFormatter.table(con.select_all("select cliente,descricao from pedidos"))
end

<?xml version="1.0" encoding="UTF­8"?>
<rows>
<row>
  <cliente>1</cliente>
  <descricao>CD ­ Anthrax ­ Greater of Two Evils</descricao>
</row>
<row>
  <cliente>1</cliente>
  <descricao>DVD ­ Slayer ­ Still Reigning</descricao>
</row>
<row>
  <cliente>2</cliente>
  <descricao>CD ­ Judas Priest ­ Angel of Retribution</descricao>
</row>
</rows>
Web
Web
eruby
<html>
<head>
<title>Teste do eruby</title>
<style>
body { font-family:sans-serif; }
table { border:1px solid blue; }
caption { background:blue; color:white; font-weight:bold; }
th { text-align:left; }
caption, td, th { padding:5px; }
</style>
</head>
<body>
<table><caption>Lista de pedidos</caption>
<%
require "dbi"
DBI.connect("DBI:Mysql:taq:localhost","taq","minhasenha") do |con|
con.execute("select cliente,descricao from pedidos") do |rst|
print "<tr>"+(rst.column_info.map {|col| print "<th>"+col["name"]+"</th>"}).to_s+"</tr>"
rst.fetch do |row|
print "<tr>"+(row.map {|col| "<td>#{col}</td>"}.to_s)+"</tr>"
end
end
end
%></table>
</body>
</html>
Web
Web
eruby

<%
require "dbi"
DBI.connect("DBI:Mysql:taq:localhost","taq","minhasenha") do |con|
con.execute("select cliente,descricao from pedidos") do |rst|
print "<tr>"+(rst.column_info.map {|col| print "<th>"+col["name"]+"</th>"}).to_s+"</tr>"
rst.fetch do |row|
print "<tr>"+(row.map {|col| "<td>#{col}</td>"}.to_s)+"</tr>"
end
end
end
%>
Interface Gráfica
Interface Gráfica
Ruby/GTK2
require "gtk2"

Gtk.init # inicializa
w = Gtk::Window.new # cria uma janela
l = Gtk::Label.new("Oi, mundo GUI!") # cria uma label
w.add(l) # adiciona label
w.border_width = 10 # borda
w.show_all # mostra a janela

w.signal_connect(“destroy”) { # associa bloco ao evento


Gtk.main_quit
}
Gtk.main # aguarda eventos GTK
Interface Gráfica
Interface Gráfica
Ruby/GTK2
Garbage Collector
Garbage Collector
Mark-and-sweep

root root

“1” “4” “6” “1” “4” “6”

“2” “5” “2” “5”

“3” “3”

root root

“1” (2) “4” (1) “6” (1) “1” (1) “4” (1) “6” (1)

“2” (1) “5” (1) “2” (1) “5” (0)

“3” (1) “3” (1)


Garbage Collector
Garbage Collector
Mark-and-sweep
class CustomObject
attr_accessor :val, :next
def initialize(v,n=nil)
@val =v
@next =n
end
def to_s
"Objeto #{@val} (#{self.object_id}) aponta para #{@next.nil? ? 'nada' : @next.val} (#{@next.nil? ?
'':@next.object_id})"
end
end

def list
print "Listando todos os CustomObject's com ObjectSpace\n"
print "#{ObjectSpace.each_object(CustomObject) {|v| puts v}} objetos encontrados\n\n"
end

begin
c1 = CustomObject.new("1",CustomObject.new("2",CustomObject.new("3")))
c4 = CustomObject.new("4",CustomObject.new("5"))
c6 = CustomObject.new("6")
c1.next.next.next = c1
list
c1 = nil
c4.next = nil
end
GC.start
sleep(1)
list
Garbage Collector
Garbage Collector
Mark-and-sweep
Listando todos os CustomObject's com ObjectSpace
Objeto 6 (-604874976) aponta para nada ()
Objeto 4 (-604874956) aponta para 5 (-604874946)
Objeto 5 (-604874946) aponta para nada ()
Objeto 1 (-604874916) aponta para 2 (-604874906)
Objeto 2 (-604874906) aponta para 3 (-604874896)
Objeto 3 (-604874896) aponta para 1 (-604874916)
6 objetos encontrados

Listando todos os CustomObject's com ObjectSpace


Objeto 6 (-604874976) aponta para nada ()
Objeto 4 (-604874956) aponta para nada ()
2 objetos encontrados
Unit Testing
Unit Testing
Unit testing
class Calculadora require ’test/unit’
def soma(a,b) require ’Calculadora’
a+b class TC_Calculadora < Test::Unit::TestCase
end def setup
def subtrai(a,b) @clc = Calculadora.new
a-b end
end def test_soma
def multiplica(a,b) assert_equal(2 ,@clc.soma(1,1),"1 + 1 = 2")
a*b end
end def test_subtrai
def divide(a,b) assert_equal(3 ,@clc.subtrai(7,4),"7 - 4 = 3")
assert_equal(5
a/b assert_equal(-3,@clc.subtrai(4,7),"4 - 7 =-3")
end end
end def teardown
@clc = nil
end
end
Loaded suite TC_Calculadora
Loaded suite
Started TC_Calculadora
... Finished in 0.048385 seconds.
Started
1) .. test_subtrai(TC_Calculadora)
Failure:
Finished in 0.00077 seconds.
[TC_Calculadora.rb:12]: 7 - 4 = 3. 5 expected but was 3.
3 assertions, 0
2 tests, 2 1 failures, 0 errors

Você também pode gostar