Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

01 Sep 09 Vimpress – Escrevendo posts para o wordpress com o melhor editor de todos os tempos

Encontrei hoje um plugin espetacular para o VIM, e claro, tive que testar ele, o resultado é este post que vocês estão lendo agora, que foi escrito utilizando o VIM :D
O Vimpress é um plugin para o VIM que adiciona alguns comandos divertidos para interagir direto com o WordPress …

  • :BlogList – lista todos os posts
  • :BlogNew – cria uma página para que você escrava um novo post
  • :BlogOpen id – abre um post especifico para edição
  • :BlogSend – publica o artigo sendo editado

Agora vou testar o último comando, se vocês estão vendo este post no meu blog é por que funcionou, e eu sou uma pessoa mais feliz por que posso escrever os posts para o blog no VIM :D

Tags: , , , ,

31 Aug 09 Rs On Rails 2009 – Ótimo evento, espero que aconteça novamente em 2010

RS On Rails

O Rs On Rails que aconteceu no fim de semana passado estava excelente, palestras muito boas, a organização estava show debola também.
Tinha mais gente no evento do que eu achei que teria …
Acho que só temos a agradecer ao pessoal da Softa pela realização deste evento …
Infelizmente eu pude ficar pouco tempo por lá, meu filho esta com 3 meses agora e eu só tenho os fins de semana pra babar um pouco com ele acordado, e pra poder ajudar a Aline a cuidar dele (Não basta ser pai, tem que participar) :D
Mas este post tem 5 objetivos:

  1. Agradecer ao pessoal da organização pelo ótimo evento, que ja fiz
  2. Avisar que os slides da minha palestra já estão no SlideShare (embedded abaixo), e que o código esta no GitHub (clique aqui)
  3. Perguntar aos leitores do blog o que acharam da minha palestra, o que preciso melhorar para a próxima :D
  4. Tirar um pouco da poeira do blog, já que não tenho tido muito tempo de escrever por aqui
  5. Lembrar vocês que quem quiser comprar o meu livro com 30% desconto, pode utilizar o código URUBATAN no site da Novatec

Bom, acho que era isto, seguem os slides …

Quaisquer dúvidas é só deixar um comentário por aqui …

PS.: fiz o upload errado como um usuário guest no slideshare também, mas o oficial é o acima que esta na minha conta do slideshare :D

Tags: , , , , , , ,

14 Feb 08 Escrevendo plugins para o Rails – dicas e truques – plugins com generators

Seguindo a seqüencia que eu iniciei aqui, mas alterando a ordem proposta, Vamos conversar um pouco sobre os Geradores de código do Rails.

Generators são uma das coisas mais legais do Rails!
Sim, você ja viu eles, lembra do primeiro screencast sobre rails que você viu? Sim, aquele mesmo em que um cara cria um CRUD em 1 minuto …

Generators são a “forma rails” de gerar código[bb] :D

Mas o código gerado não precisa ser apenas aquele CRUD, ele pode ser o que você quiser, e o Rails ja tem um suporte excelente para isto, pois este mesmo suporte ja é utilizado na base do Rails.

Beleza, mas por que eu iria querer escrever um gerador de código?
Pense sobre o projeto que você estaria começando hoje, lembre de todos aqueles formulários para CRUD que você precisara criar, ou aquela parte quase igual de todas as páginas da aplicação …
Agora pense em todas as aplicações da empresa que você trabalho …
Entendeu agora?

Sim, eu concordo que utilizar o “scaffold” padrão não é realmente útil, mas se esta geração de código inicial for feita seguindo os padrões da sua empresa, ela pode aumentar muito a velocidade de desenvolvimento inicial das aplicações …

Agora eu imagino que você esteja pensando: Legal, generators são show de bola, mas para de falar besteira e me mostre o código!

Então, vamos brincar um pouco[bb]
Vamos iniciar criando um novo projeto rails: rails plugins102
agora de dentro do diretório do projeto execute: script\generate plugin my_generator
(Se você esta pensando que você ja viu isto antes, provavelmente você leu o post anterior sobre escrita de plugins para o rails :D )

Agora que você a criou a estrutura para um novo plugin, vamos escrever algum código!
Para criar um novo generator, você precisa criar um diretório de nome “generators” dentro do diretório do plugin, um diretório com o nome do seu generator dentro deste, e um diretório de nome “templates” dentro do diretório do seu generator, por exemplo a minha estrutura ficou assim:

  • my_generator
    • lib
    • tasks
    • test
    • generators
      • test_gen
        • templates

Na verdade, você não precisa de um plugin para criar um generator, você pode colocar o seu novo generator dentro de qualquer um dos seguintes diretórios:

  • RAILS_ROOT/lib/generators
  • RAILS_ROOT/vendor/generators
  • RAILS_ROOT/vendor/plugins/plugin_name/generators
  • USER_HOME/.rails/generators
  • gems com nome terminado em _generator

Mas eu acho que um plugin é a orma mais fácil de começar, e vai ser mais fácil de utilizar nas suas aplicações também, mas claro que se você for utilizar isto em diversas aplicações um GEM seria melhor pois você teria apenas uma cópia do código para todo o servidor, mas como eu nunca criei um GEM vou continuar com o plugin pelo menos para este exemplo …

para o código do generator nos vamos criar um arquivo no diretório do generator de nome [nome_do_generator]_generator.rb, no meu caso o nome do arquivo ficou: my_generator/generators/test_gen/test_gen_generator.rb

Agora dentro deste arquivo precisamos criar a classe que define o generator, esta classe deve ter o nome de acordo com o nome do arquivo (seguindo os padrões do ruby), no meu caso o nome da classe precisa ser TestGenGenerator, e ela precisa extender uma das classes padrão para generators do rails (na verdade eu poderia não extender nada e implementar um monte de métodos, mas assim é bem mais fácil :D ), estas classes são:
Rails::Generator::Base ou Rails::Generator::NamedBase, eu vou utilizar NamedBase (A base para o controller generator do Rails), e vou criar um modelo de generator para uma migration apenas para mostrar como isto funciona …

NamedBase é uma ótima base para geradores que esperam parametros no formato: Nome [parametro1] [parametro2] …
Para todos os outros Base é uma melhor pedida …

O nosso código inicial é este:

1
2
3
4
5
6
7
class TestGenGenerator < Rails::Generator::NamedBase
  def manifest
    record do |m|
 
    end
  end
end

Nesta classe precisamos configurar o manifesto do generator e configurar quaisquer variáveis locais que utilizemos nos templates.

Mas com o código que nos temos, você ja pode executar: ruby script\generate test_gen asdas_dasda asd:ash (letras aleatórias como parâmetros por hora).
NamedBase ja vai configurar algumas variáveis para nós quando executarmos este comando:

  • class_name -> AsdasDasda
  • class_nesting ->
  • class_nesting_depth -> 0
  • class_path ->
  • file_path -> asdas_dasda
  • name -> asdas_dasda
  • plural_name -> asdas_dasdas
  • singular_name -> asdas_dasda
  • table_name -> asdas_dasdas
  • attributes -> #<Rails::Generator::GeneratedAttribute:0×3716418>
  • args -> asd:ash

Claro que por enquanto não estamos gerando absolutamente nada, por que o manifesto do gerador esta em branco, então vamos criar um exemplo simples para ver como isto realmente funciona …
Vamos criar um diretório de nome “dummy” dentro do diretório “template” e um arquivo em branco de nome “log.log” dentro deste, e vamos fazer as seguintes alterações no manifesto:

1
2
3
4
5
  def manifest
    record do |m|
      m.file 'dummy/log.log', "log/#{file_path}.log"
    end
  end

Este código vai dizer para o gerador copiar o nosso arquivo em branco para $APP_ROOT/log/asdas_dasda.log se executarmos o gerador com os mesmos parâmetros que antes …
Mas apenas copiar arquivos de um lugar para outro não é uma coisa muito divertida, então vamos brincar um pouco com o ERB, e vamos criar uma migration para o nosso plugin, para isto vamos alterar novamente o manifesto como no seguinte exemplo:

1
2
3
4
5
6
7
8
  def manifest
    @migration_name = "Create#{class_name}"
    @migration_action = "add"
    record do |m|
      m.file 'dummy/log.log', "log/#{file_path}.log"
      m.migration_template 'lib/mymigration.rb',"db/migrate", :migration_file_name => "create_#{file_path}"
    end
  end

Como você pode ver no código, estou informando ao gerador que eu tenho um arquivo de nome mymigration.rb dentro do diretório templates/lib, este template vai ser processado pelo ERB e o código gerado vai ser colocado no diretório “db/migrate”e vai ser chamado XXX_create_asdas_dasda.rb (XXX vai ser o número da migration gerado automaticamente pelo rails)

O conteúdo do arquivo mymigration.rb é o seguinte:

1
2
3
4
5
6
7
8
9
10
11
class <%= migration_name.underscore.camelize %> < ActiveRecord::Migration
  def self.up<% attributes.each do |attribute| %>
    <%= migration_action %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'add' %>, :<%= attribute.type %><% end -%>
  <%- end %>
  end
 
  def self.down<% attributes.reverse.each do |attribute| %>
    <%= migration_action == 'add' ? 'remove' : 'add' %>_column :<%= table_name %>, :<%= attribute.name %><% if migration_action == 'remove' %>, :<%= attribute.type %><% end -%>
  <%- end %>
  end
end

este é um template ERB que vai gerar código ruby.

Agora que ja temos um plugin razoavelmente útil , vamos ver o que mais é possível fazer …
para responder esta pergunta, vou copiar parte da documentação da classe Rails::Generator::Commands::Create, ou seja, todas as possibilidades de comandos para o manifesto do gerador:

  • class_collisions – Check whether the given class names are already taken by Ruby or Rails. In the future, expand to check other namespaces such as the rest of the user‘s app.
  • directory – Create a directory including any missing parent directories. Always directories which exist.
  • file – Copy a file from source to destination with collision checking.
  • identical? – Checks if the source and the destination file are identical. If passed a block then the source file is a template that needs to first be evaluated before being compared to the destination.
  • migration_template – When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
  • readme – Display a README.
  • route_resources – add a route to the routes.rb
  • template – Generate a file for a Rails application using an ERuby template. Looks up and evaluates a template by name and writes the result.

Acho que era isto, você pode fazer perguntas nos comentários se quiser, vou tentar responder todas (se é que alguem vai perguntar :D )

Para mais documentação sobre generators do rails siga os seguintes links:
http://wiki.rubyonrails.org/rails/pages/UnderstandingGenerators
http://www.aidanf.net/node/33
http://api.rubyonrails.org/classes/Rails/Generator/Base.html
http://api.rubyonrails.org/classes/Rails/Generator/NamedBase.html
http://api.rubyonrails.org/classes/Rails/Generator/Commands/Create.html

Espero que este passo a passo ajude alguem!
O próximo vai ser sobre testar o seu plugin! e o quarto eu ainda não pensei sobre o que vai ser, sugestões são bem vindas :D

Tags: , , , , , ,

16 Jan 08 Escrevendo plugins para o Rails – dicas e truques – plugins com view helpers

Uma das coisas mais legais no Rails[bb] é o suporte a Plugins …
O Ruby On Rails em si já é um excelente framework, mas a combinação dos Plugins do Rails com as classes abertas do Ruby é uma combinação explosiva!
Esta combinação é o que permite a criação de “tags” customizadas para utilizar nas suas aplicações RoR nas views e nos layouts.
E é realmente fácil de criar estes “view helpers” no Rails.

A forma padrão (sem plugins) de se criar estas “tags” é simplesmente criar um método em uma das classes Helper (as que ficam em app/helpers), por exemplo, se todos os forms na sua aplicação ficam dentro de tabelas, com uma coluna para o label e uma para o campo real, você pode criar um método helper para diminuir bastante a quantidade de código a ser digitada seguindo estes passos:

  1. rails plugins101
  2. cd plugins101
  3. ./script/generate scaffold example name:string url:string

O formulário padrão, bastante simples e feio, para o model “Example” que criamos, nesta aplicação seria algo parecido com:

1
2
3
4
5
6
7
<% form_for(@example) do |f| %>
  <table>
    <tr><td><label for="example_name">Name</label></td><td><%= f.text_field :name %></td></tr>
    <tr><td><label for="example_name">Url</label></td><td><%= f.text_field :url %></td></tr>
    <tr><td colspan="2"><%= f.submit "Update" %></td></tr>
  </table>
<% end %>

mas se editarmos o arquivo app/helpers/application_helper.rb e adicionarmos o seguinte método:

1
2
3
   def textfield label, object, property, options = {}
    %Q{<tr><td><label for="#{object.to_s}_#{property.to_s}">#{label}</label></td><td>#{text_field object, property, options}</td></tr>}
  end

o código da view ficaria muito mais simples como podemos ver abaixo.

1
2
3
4
5
6
7
<% form_for(@example) do |f| %>
  <table>
    <%= textfield "Name", :example, :name %>
    <%= textfield "Url", :example, :url %>
    <tr><td colspan="2"><%= f.submit "Update" %></td></tr>
  </table>
<% end %>

Se você pensar apenas neste pequeno formulário, pode parecer muita complicação para pouca coisa, mas pensando na aplicação inteira isto poupa bastante trabalho :D

Agora pensando um pouco maior, imagine que este padrão de layout (bem feio por sinal) que eu defini para esta aplicação, seja o padrão de todas as aplicações de toda a empresa!

e todos os desenvolvedores estão trabalhando da primeira forma que eu descrevi, codificando o HTML direto em todas as páginas.
Um belo dia, um designer novo, contratado pelo dono da empresa, diz que em todos os TR de todos os forms, é necessário adicionar uma classe CSS.
Nesta situação, o negócio é sentar e chorar …

Mas se você escolheu trabalhar da segunda forma, utilizando um helper, no máximo você precisara alterar uma linha de código por aplicação!
Você pode se considerar um herói! Certo?

Mas considere a opção de você ser ainda mais esperto do que isto! Que tal criar um plugin que vai conter estas tags para facilitar o trabalho, e utilizar este plugin em todas as aplicações da empresa?
Desta forma você precisaria alterar apenas uma linha de código, testar apenas uma vez, e todas as aplicações da empresa ja estariam corrigidas!

E como sempre, com o Rails, esta é uma tarefa muito fácil de ser completada :D
Apenas siga estes passos simples:

  1. ./script/generate plugin life_saver
  2. Edite o arquivo vendor/plugins/life_saver/lib/life_saver.rb e adicione o seguinte código nele:
    1
    2
    3
    4
    5
    6
    
    # LifeSaver
    module LifeSaver
      def textfield label, object, property, options = {}
        %Q{<tr><td><label for=#{object.to_s}_#{property.to_s}>#{label}</label></td><td>#{text_field object, property, options}</td></tr>}
      end
    end
  3. Edite o arquivo vendor/plugins/life_saver/init.rb e inclua o seguinte código:
    1
    2
    
    # Include hook code here
    ActionView::Base.send :include, LifeSaver
  4. Remova o método helper que adicionamos no arquivo app/helpers/application_helper.rb

Ok, você acabou de criar o seu primeiro plugin para o Rails[bb]!
E sim, o código é exatamente o mesmo utilizado no application_helper.rb, o único truque esta no init.rb, aquela linha de código, inclui todos os métodos do module “LifeSaver” na classe base de todas as views do Rails, a ActionView::Base.

Agora, se você escolheu esta terceira opção, va falar com o seu chefe, conte uma historia parecida com a que eu contei aqui, e peça um aumento, por que você merece, você acabou de poupar diversas horas de trabalho de umas 3 pessoas pelo menos :D

Espero que este pequeno passo a passo ajude alguem :D

Este é o primeiro post de uma série sobre escrita de plugins para RoR, o próximo vai ser sobre testes unitários para o código dos seus plugins, o terceiro vai falar de plugins com generators, e o quarto vocês vão ter que voltar aqui para descobrir sobre o que vai ser :D

Tags: , , , , ,