Archive for Setembro 2008
Slides da minha palestra sobre Ruby
Estou disponibilizando abaixo o link para os slides que usei na minha palestra sobre ruby hoje na Universidade de Taubaté.
Caso alguma pessoa que assistiu à palestra ainda tenha ficado com dúvidas e queira me perguntar
alguma coisa, fique à vontade para me mandar um email (cassiommc@gmail.com).
Eu filmei a palestra, mas achei que a qualidade não ficou das melhores… Vou ver se dá pra disponibilizar ainda assim e coloco aqui, ou então uso apenas o audio e crio um “slidecast” com o áudio + os slides.
Link para o slideshare http://www.slideshare.net/cassiomarques/palestra-ruby-presentation/
Ou baixe o arquivo diretamente clicando aqui.
Palestra sobre Ruby na Universidade de Taubaté
Nessa segunda-feira, dia 29/09, estarei palestrando sobre a linguagem Ruby na Universidade de Taubaté (Unitau). Como o auditório do Departamento de Informática é pequeno e haverá mais uma palestra no dia, o pessoal da organização decidiu utilizar mais uma sala e criar uma “dobradinha”: cada palestra será realizada duas vezes. Dessa forma, eu deverei fazer minha apresentação as 19:00h e as 20:30h.
O evento é aberto para não-alunos e faz parte da SECOMP – Semana da Computação, um evento realizado anualmente pelo departamento.
Alguns dos tópicos que abordarei são:
● Origens e motivações da linguagem Ruby
● Características básicas
● Exemplos simples de código comparando Ruby com outras linguagens
● Possíveis aplicações para resolução de problemas
● Integração com outras linguagens
● Práticas e paradigmas de programação favorecidos pelo Ruby
● Implementações alternativas do interpretador Ruby – JRuby, Rubinius, etc
● Ruby e o mercado de trabalho atual
● A comunidade Ruby
● Casos de sucesso
Endereço: Av. Marechal Deodoro, 605 – Jardim Sta. Clara – Taubaté – SP Cep: 12080-000
Contato: (12) 3625-4256
Brazilian Rails agora com suporte a CPF e CNPJ
Terminei há pouco tempo uma pequena aplicação financeira escrita em Rails e usei o Brazilian Rails para diversas funcionalidades. Uma das coisas que o Brazilian Rails não tinha e que acabei tendo que criar foi um suporte a CPF e CNPJ, com validações do formato das strings e do seu conteúdo numérico (utilizando módulo 11).
Achei que a solução ficou boa e tive a idéia de adicionar esta funcionalidade ao Brazilian Rails. Depois que o plugin foi adaptado para funcionar como um conjunto de gems ficou realmente simples integrar o que eu havia escrito. E assim surgiu a gem brcpfcnpj!
Com o brcpfcnpj, você pode criar campos que funcionem como um CPF ou um CNPJ de forma totalmente automática, de maneira semelhante ao que já é feito com a classe Dinheiro do Brazilian Rails.
As classes Cpf e Cnpj formatam e validam strings no formato xxx.xxx.xxx-xx (para os CPFs) e xx.xxx.xxx/xxxx-xx (para os CNPJs), onde x pode ser qualquer digito de 0 a 9. Os caracteres ‘.’, ‘/’ e ‘-’ são totalmente opcionais. Caso um atributo do seu model seja declarado para que funcione como Cpf ou Cnpj e você tente salvar um objeto deste model contendo uma string inválida para o cpf ou o cnpj, um novo erro será inserido em errors e o objeto passará a ser inválido.
Além disso, caso associe um valor não formatado a este atributo, seu conteúdo será automaticamente formatado.
A forma de usar é praticamente a mesma tanto para o CPF quanto para o CNPJ.
Como usar o Cpf:
Suponha que temos um model Pessoa, com um atributo ‘cpf’ que voce quer usar como um numero de documento para cpf. Basta usar o metodo usar_como_cpf, assim:
class Pessoa < ActiveRecord::Base usar_como_cpf :cpf end
O atributo que sera usado como cpf pode ter qualquer nome e nao apenas ‘cpf’. Agora voce pode usar o atributo para cpf da seguinte forma:
p = Pessoa.new
p.cpf = "11144477735"
puts p.cpf # ==> 111.444.777-35
p.cpf.valido? # ==> true
p.cpf_valido? # ==> true
p = Pessoa.new(:cpf => "111.444.777-35")
puts p.cpf # ==> 111.444.777-35
p = Pessoa.new
p.cpf = Cpf.new("111444777-35")
puts p.cpf # ==> 111.444.777-35
p = Pessoa.new
p.cpf = "12345" # ==> um cpf invalido
puts p.valid? # ==> false
p.save # ==> false
p.errors.on(:cpf) # ==> 'numero invalido'
c = Cpf.new("11144477735")
p.cpf = "111.444.777-35"
c == p.cpf # ==> true
Como usar o Cnpj
Suponha que temos um model Empresa, com um atributo ‘cnpj’ que voce quer usar como um numero de documento para cnpj. Basta usar o metodo usar_como_cnpj, assim:
class Empresa < ActiveRecord::Base usar_como_cnpj :cnpj end
O atributo que sera usado como cnpj pode ter qualquer nome e nao apenas ‘cnpj’. Agora voce pode usar o atributo para cnpj da seguinte forma:
e = Empresa.new
e.cnpj = "69103604000160"
puts e.cnpj # ==> 69.103.604/0001-60
e.cnpj.valido? # ==> true
e.cnpj_valido? # ==> true
e = Empresa.new(:cnpj => "69.103.604/0001-60")
puts e.cnpj # ==> 69.103.604/0001-60
e = Empresa.new
e.cnpj = Cnpj.new("691036040001-60")
puts e.cnpj # ==> 69.103.604/0001-60
e = Empresa.new
e.cnpj = "12343" # ==> um cnpj invalido
puts e.valid? # ==> false
e.save # ==> false
e.errors.on(:cnpj) # ==> 'numero invalido'
c = Cnpj.new("69103604000160")
e.cnpj = "69.103.604/0001-60"
c == e.cnpj # ==> true
As novas alterações já foram integradas ao projeto principal. Você pode instalar o projeto utilizando o GitHub. Mais informações em http://www.improveit.com.br/software_livre/brazilian_rails
Espero que seja útil!
named_scope – combinando buscas
Não há dúvidas de que o named_scope é um dos recursos mais úteis dentre todas as novas funcionalidades do Rails 2.1. O que nem todo mundo sabe é que o named_scope serve para muito mais do que simplesmente criar finders mais “bonitinhos”. A opção mais utilizada dentro do named_scope continua sendo :conditions, mas com um pouco de criatividade podemos criar named_scopes que, quando combinados, nos permitem fazer buscas bastante complexas.
A princípal funcionalidade do named_scope é possibilitar que você concatene seus métodos e vá refinando sua busca através de uma cadeia de chamadas aos scopes. Funciona como se você estivesse sempre chamando o scope sobre a própria classe que define o model. Um exemplo:
class Camiseta < ActiveRecord::Base named_scope :vermelhas, :conditions => ["cor = 'vermelha'"] end
E podemos usar isso assim:
v = Camiseta.vermelhas
Podemos melhorar isso e criar um named_scope que retorna camisetas de uma cor específica
named_scope :da_cor, lambda { |cor| { :conditions => ["cor = ?", cor] } }
Porque agora precisamos do lambda? Porque os named_scopes são definidos no momento em que a classe é carregada pelo interpretador Ruby. Se você não usar um lambda, não será possível definir o valor de retorno do bloco em tempo de execução e o scope acabará sendo sempre o mesmo, estático. Agora podemos fazer assim:
azuis = Camiseta.da_cor('azul')
E se quisermos pesquisar todas as camisetas e ordenar os resultados pela ordem alfabética das cores? Podemos criar um named_scope para isso também
named_scope :ordenado_por_cor, :order => 'cor'
E podemos usar assim:
camisetas = Camiseta.ordenado_por_cor
Vamos avançar mais um pouco. Quero agora poder escolher o campo pelo qual os resultados devem ser ordenados.
named_scope :ordenado_por, lambda { |coluna| { :order => coluna } }
E podemos usar assim
camisetas = Camiseta.ordenado_por(:cor)
Se agora no model Camiseta eu tiver também uma coluna para o preço, podemos combinar nossos named_scopes para fazer uma busca por camisetas de uma cor específica, ordenadas por preço.
amarelas = Camisetas.da_cor('amarela').ordenado_por(:preco)
Praticamente todos os parâmetros que você pode usar em um ActiveRecord::Base.find você pode usar também nos named_scopes, sendo possível gerar diversas buscas combinadas como a descrita acima.
Factory Girl para models com has_many
A idéia de usar fixtures para os testes no Rails parece muito boa em um primeiro momento, porém quando começamos a querer testar models com relacionamentos muito complexos manter essas fixtures se transforma em um verdadeiro inferno. Para cada fixture você acaba tendo que abrir vários arquivos e verificar na raça os valores dos ids referenciados nas demais fixtures associadas. É muito fácil se perder. Pior ainda, é totalmente improdutivo.
Para testar controllers esse problema pode e deve ser solucionado através do uso de algum framework para mocking, como o Mocha ou os recursos nativos de mocking do RSpec. Assim diminui-se a dependência dos models nos testes dos controllers e os testes executam mais rápido. Mas para os models nem sempre “mockar” todo o comportamento é uma boa solução. Muitas vezes você vai querer testar tudo que ocorre entre seus objetos e o banco de dados, incluindo os relacionamentos anteriormente citados.
Para os testes dos models tenho substituído as velhas fixtures pela utilização do factory_girl.
O que o factory_girl faz é possibilitar a criação de fábricas de objetos. Com essas fábricas, você pode gerar objetos de forma simplificada durante seus testes, elimando complemente a necessidade de utilização das fixtures. E com diversas vantagens.
Bom, eu não vou ficar falando sobre como usar o factory_girl, porque isso é realmente MUITO simples. Caso você ainda não conheça o factory_girl, basta olhar a documentação no site do projeto que com certeza você vai se virar bem.
O que eu gostaria de falar aqui é sobre como criar associações quando temos declaração do tipo :has_many em um dos nossos models. Eu tive que fuçar um pouquinho na net para conseguir encontrar essa informação, então talvez seja útil para mais alguém.
O fato é que cada vez que fazemos algo como
Factory.define :post do |p|
p.title "Blabla"
p.author { |author| author.association(:user) }
end
estamos apenas usando um proxy que usa uma espécie de “lazy loading” para instanciar objetos a partir da fábrica de Users. Logo, se você possui um model User com uma declaração do tipo belongs_to :post, a coisa vai funcionar e pronto. Mas e quando tenho algo como
class Post < ActiveRecord::Base has_many :comments end
como podemos “fabricar” uma instância de Post já com uma lista de comentários?
Assim (supondo que já exista a factory para o model Comment):
Factory.define :post do |p|
p.title "Blabla"
p.author { |author| author.association(:user) }
p.comments do |c|
[c.association(:comment), c.association(:comment)]
end
end
Perceberam? Cada vez que chamo o método association e passo o parâmetro :comment estou fazendo com que o factory_girl use a factory criada para o model Comment e gere uma nova instância desta classe, a qual é retornada como um elemento dentro de um array. Está feita minha fábrica com um relacionamento do tipo um-para-muitos.
gedit-snippets
Para quem usa Ubuntu e por consequência não pode usar o TextMate, uma boa solução é usar o Gedit com vários plugins. Não vou ficar aqui explicando como fazer isso porque link na net é o que não falta. Pesquisem por “gedit rails”, o gugól lhe trará muita coisa.
De todos os plugins do Gedit, o que mais me ajuda é o Snippets. Este plugin possue trechos de código semelhantes aos bundles do TextMate, que realmente facilitam muito minha vida. Além dos snippets que já vêm com o plugin, estou sempre criando novos, principalmente para uso com Rails e com o RSpec.
Os snippets estão aqui, junto com um pequeno README.
Resolvi disponibilizar os snippets que venho usando atualmente no GitHub. Basta fazer:
$ git clone git://github.com/cassiomarques/gedit-snippets.git
$ cp gedit-snippets/snippets/*.xml ~/.gnome2/gedit/snippets
E reiniciar seu gedit.
Atenção: Cuidado, caso você já tenha algum snippet cujo nome coincida com os snippets que eu criei, o mesmo será sobrescrito.
À medida que eu for criando novos snippets, vou atualizando o repositório :-)
Apagar os diretórios ocultos do SVN ao migrar para GIT
Qualquer um que já tenha utilizado o Subversion sabe como enche o saco o monte de diretório oculto que ele cria dentro do seu projeto. É .svn para todo lado.
Pior foi quando eu quis deixar de usar Subversion em alguns projetos e migrar pro Git. Como os commits anteriores não eram muito importantes, achei melhor simplesmente passar a usar o Git do que migrar tudo com alguma solução tipo git-svn. O problema é o mar de lixo que o Subversion cria. Simplesmente não dá pra ficar entrando em pastas e subpastas caçando estes caras. Como tinha vários projetos para migrar e sou preguiçoso, resolvi escrever um script ridículo em Ruby para resolver meu problema. Melhor do que ficar caçando pasta e dando rm -r em tudo que tivesse .svn na mão… E você pode até mesmo executar para toda sua pasta de trabalho!
Para usar, o de sempre: ruby remove_svn_dirs.rb caminho_para_o_seu_projeto
ou
$chmod +x remove_svn_dirs.rb
$./remove_svn_dirs.rb caminho_para_o_seu_projeto
#!/usr/bin/ruby
require 'find'
require 'fileutils'
if ARGV.empty?
puts "passe o caminho para o projeto, sua mula!"
exit(1)
end
Find.find(ARGV[0]) do |f|
if f =~ /\.svn/
puts "Removendo #{f}..."
FileUtils.rm_r f
end
end


