PNG transparente no Internet Explorer com PainlessPNG

Estou ouvindo neste exato momento o episódio #5 do Rails Podcast Brasil, com o Carlos Brando e com o Fábio Akita. Eles estão tratando de um assunto muito importante que são os bugs do Internet Explorer e a falta de padrão do mesmo, e disseram sobre o ie7-js, que é uma biblioteca em javascript que tenta amenizar os problemas do IE7 (e das versões anteriores).

O Carlos Brando comentou que resolve inclusive o problema de renderização da camada alfa do PNG (o famoso fundo transparente) nas versões anteriores ao IE7, o problema desses plugins em JS que eles tornam a aplicação muito pesada, o que muitas vezes pode ser desnecessário, dependendo do tamanho do projeto.

Então me lembrei de um plugin do Rails interessantíssimo, que de forma simples resolve este problema, é o PainlessPNG. Ele cria um helper que mostra as imagens PNG de forma normal se o seu browser for qualquer um, exceto no IE5 e no IE6, onde ele utiliza o filtro AlphaImageLoader, método recomendado pela Microsoft.

Para utilizar seu plugin, basta instalá-lo e reiniciar o server. Pronto, a solução já está funcionando para todas as imagens de sua aplicação.

ruby script/plugin install http://svn.wheremydogs.at/painless_png/tags/painless_png

Upload de arquivos com AJAX em Ruby on Rails

Um dos maiores problemas para quem desenvolve sistemas utilizando AJAX é o upload de arquivos. Se você ouviu dizer que não era possível fazer upload de arquivos em AJAX, acredite, utilizando AJAX simplesmente não dá mesmo, porém existem maneiras de simular um upload assíncrono, como uma que eu achei no site do Khamsouk Souvanlasy, o code_fu. Este tutorial é uma adaptação do tutorial AJAX file uploads in Rails using attachment_fu and responds_to_parent do blog do Khamsouk Souvanlasy.

Passo 1: Escolha um plugin de upload de arquivos

Sim, é possível que você utilize seu próprio sistema de arquivos, mas sempre é bom utilizar plugins completos como os que citarei abaixo, pois lhe darão mais recursos. Os plugins recomendados são:

  1. File_column
  2. acts_as_attachment
  3. attachment_fu

Neste caso, usarei attachment_fu, que é o plugin que eu utilizo para as minhas aplicações e que coincidentemente no tutorial é utilizado. Mas você pode utilizar qualquer um deles.

Passo 2: Escolha o processador de imagens que irá utilizar

Como neste caso, o upload de arquivos realizado é de imagens e este irá gerar uma thumb, é necessário utilizar um rocessador de imagens que reduzirá as imagens. É possível utilizar os seguintes processadores de imagens:

  1. image_science
  2. RMagick
  3. minimagick

Eu utilizo o RMagick, mas como foi um saco conseguir instalá-lo no Ubuntu, recomendo que sigam os passos do tutorial, que utiliza o minimagick.

Passo 3: Instalando minimagick e o plugin attachment_fu

Dependendo do seu sistema operacional, a instalação do processador de imagens pode ser longa e complicada, como para mim foi. No meu caso, há problemas nos pacotes oferecidos pelo repositório do ubuntu e do gem. Eu instalei o RMagick em uma versão anterior a ofericida no pacote do Ubuntu. Atenção: No pacote de softwares do Ubuntu, o nome do processador está sem o k, ou seja, RMagic.

$ sudo gem install mini_magick

Para instalar o plugin no attachment_fu:

script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/

Passo 4: Adicione o upload ao seu código:

No tutorial ele utiliza RESTful, e como eu também utilizo, recomendo que siga a dica e comece a implementar RESTful em suas aplicações. No tutorial ele recomenda esta leitura, mas eu vou recomendar também este screencast do Fábio Akita.

Para gerar um Scaffold RESTful, utilize o comando:

ruby script/generate scaffold_resource asset filename:string content_type:string size:integer width:integer height:integer parent_id:integer thumbnail:string created_at:datetime

Este comando irá criar um controller, um model, as views e a migration de um Scaffold RESTful. Além disso, é possível observar que ele já informa quais são os campos da migration, que no caso ficará assim:

class CreateAssets < ActiveRecord::Migration
  def self.up
    create_table :assets do |t|
      t.column :filename, :string
      t.column :content_type, :string
      t.column :size, :integer
      t.column :width, :integer
      t.column :height, :integer
      t.column :parent_id, :integer
      t.column :thumbnail, :string
      t.column :created_at, :datetime
    end
  end

  def self.down
    drop_table :assets
  end
end

No modelo, você deve inserir estes dados para que seja possível enviar arquivos:

class Asset < ActiveRecord::Base
  has_attachment  :storage => :file_system,
                  :max_size => 1.megabytes,
                  :thumbnails => { :thumb => '80x80>', :tiny => '40x40>' },
                                    :processor => :MiniMagick # attachment_fu looks in this order: ImageScience, Rmagick, MiniMagick

  validates_as_attachment # ok two lines if you want to do validation, and why wouldn't you?
end

Sobre o funcionamento do attachment_fu, é algo complicado explicar em poucas linhas, dado o poder do plugin. Mas neste caso, a utilização é somente para o upload de imagem e a geração de uma miniatura dela. Para ter maiores informações sobre as outras opções do plugin, leia o arquivo README do plugin localizado em vendor/plugins/attachment_fu/.

Para que você entenda o funcionamento dos cadastros que o plugin faz no banco, e como utilizar ele, vou tentar explicar rapidamente: O attachment_fu cadastra uma nova imagem no banco de dados que você escolher, fazendo uma query para cada imagem gerada, ou seja, no caso de você utilizar upload de imagem com uma miniatura, serão duas querys, uma com parent_id = nil e outra com o parent_id = id da imagem em tamanho normal. Desta forma é possível identificar que a imagem com parent_id = nil é a imagem original e se você enviar outros dados como nome, email, eles estarão nesta query. Utilize <%= image_tag(image.public_filename(:thumb)) %> para exibir a miniatura de um cadastro.

Agora, faremos com que o form da view new.rhtml, consiga enviar arquivos, para isto, é preciso que o parâmetro do html chamado :multipart seja setado para true, como na view abaixo:

<%= error_messages_for :asset %>
<% form_for(:asset, :url => assets_path, :html => { :multipart => true }) do |form| %>
  <p>
    <label for="uploaded_data">Upload a file:</label>
    <%= form.file_field :uploaded_data %>
  </p>
  <p>
    <%= submit_tag "Create" %>
  </p>
<% end %>

Para o nosso exemplo, queremos ver a imagem (caso seja uma imagem) e o nome desta imagem.

<h1>Listing assets</h1>

<ul id="assets">
<% @assets.each do |asset| %>
<li id="asset_<%= asset.id %>">
<% if asset.image? %>
<%= link_to(image_tag(asset.public_filename(:thumb))) %><br />
<% end %>
<%= link_to(asset.filename, asset_path(asset)) %> (<%= link_to "Delete", asset_path(asset), :method => :delete, :confirm => "are you sure?"%>)
</li>
<% end %>
</ul>

<br />

<%= link_to 'New asset', new_asset_path %>

Faça agora um rake db:migrate para criar a tabela necessária para o upload de arquivos no banco de dados. Com isto, você já pode iniciar o server (script/server) para utilizar o endereço http://localhost:3000/assets/new para testar o seu scaffold em funcionamento juntamente com o plugin. Note que ele ainda não está funcionando em AJAX.

Quando você fizer o upload, você será direcionado para a index de assets, onde serão listados os dados presentes. Note que além da linha que contém o arquivo original, também será mostrada a linha referente a thumb. Podemos modificar o controller para exibir somente os arquivos com os arquivos originais, que na verdade é o que nos interessa, visto que somente nele existirão os dados extras que você usará além do arquivo, como nome e e-mail, por exemplo. Para visualizar a thumb, basta utilizar o seguinte método: <%= image_tag(image.public_filename(:thumb)) %>

  # GET /assets
  # GET /assets.xml
  def index
    @assets = Asset.find(:all, :conditions => {:parent_id => nil},  :o rder => 'created_at DESC')
    respond_to do |format|
      format.html # index.rhtml
      format.xml  { render  :x ml => @assets.to_xml }
    end
  end

Passo 5: AJAX it! Atualmente, o seus sistema funciona da seguinte forma:

  • Você vai à página index
  • Clica no link New Asset
  • Escolhe um arquivo e o envia pelo form
  • Você é direcionado à página index

A partir de agora, nós faremos o upload de arquivo utilizando somente a página index, sem sair dela em nenhum momento do seu upload. Para isto, existem alguns passos básicos, como:

Insira as bibliotecas javascript do prototype/scriptaculous no seu layout:

<%= javascript_include_tag :defaults %>

Modifique a tag form_for para remote_form_for em seu formulário, que no caso é new.rhtml

<% remote_form_for(:asset, :url => assets_path, :html => { :multipart => true }) do |f| %>

Adicione format.js no sua action create no seu controller para permitir requisições AJAX.

  # POST /assets
  # POST /assets.xml
  def create
    @asset = Asset.new(params[:asset])

    respond_to do |format|
      if @asset.save
        flash[:notice] = 'Asset was successfully created.'
        format.html { redirect_to asset_url(@asset) }
        format.xml  { head :created, :location => asset_url(@asset) }
        format.js
      else
        format.html { render :action => "new" }
        format.xml  { render  :x ml => @asset.errors.to_xml }
        format.js
      end
    end
  end

Crie um arquivo create.rjs na pasta app/views/assets, contendo isto:

page.insert_html :bottom, "assets", :partial => 'assets/list_item',  :o bject => @asset
page.visual_effect :highlight, "asset_#{@asset.id}"

Crie uma partial chamada _list_item.rhtml na sua pasta app/views/assets para adicionar a listagem de dados o novo dado inserido.

<li id="asset_<%= list_item.id %>">
<% if list_item.image? %>
<%= link_to(image_tag(list_item.public_filename(:thumb))) %><br />
<% end %>
<%= link_to(list_item.filename, asset_path(list_item))%> (<%= link_to_remote("Delete", {:url => asset_path(list_item), :method => :delete, :confirm => "are you sure?"}) %>)
</li>

Uma parte opcional é a exclusão AJAX, que você pode fazer criando o arquivo destroy.rjs na pasta app/views/assets.

page.remove "asset_#{@asset.id}"

No controller, você deve adicionar o formato format.js na action destroy.

Para que o seu formulário seja utilizado tanto em uma área que é necessário o upload via AJAX, como em index.rhtml, quanto em uma área que o upload pode ser feito da forma convencional, como em new.rhtml, siga os seguintes passos:

_form.rhtml

<p>
  <label for="uploaded_data">Upload a file:</label>
  <%= form.file_field :uploaded_data %>
</p>
<p>
  <%= submit_tag "Create" %>
</p>

new.rhtml

<% form_for(:asset, :url => assets_path, :html => { :multipart => true }) do |form| %>
<%= render(:partial => '/assets/form', :o bject => form)%>
<% end %>

Adicione o formulário na sua action index.rhtml:

<% remote_form_for(:asset, :url => assets_path, :html => { :multipart => true }) do |form| %>
<%= render(:partial => '/assets/form', :o bject => form) %>
<% end %>

Agora, já temos todo o código necessário para realizar o cadastro de dados assíncrono, ou seja, inserção comum de dados em AJAX.

Mas há um problema, onde por razões de segurança não é permitido acesso a arquivos usando javascript (razoável não?). Desta forma, o upload de arquivos não irá funcionar em seu formulário.

Passo 6: Usando iframes e responds_to_parent

É esse o grande segredo de upload assíncrono no rails, ou seja, para burlar esta restrição do javascript, precisamos usar o iframe remoting pattern. Para fazer isto, basta inserir um iframe escondido em sua página e apontar o formulário para este iframe, usando target. O código de seu formulário da index.rhtml deve ser modificado para voltar a usar a tag form_for. Você deve estar se perguntando como será possível fazer upload assíncrono usando esta tag? Basta adicionar a extensão “.js” a action do formulário. Depois deixe o iframe do tamanho 1×1 de forma a não aparecer na sua view.

Atenção: não use display:none pois dependendo do seu browser você esconderá não só do usuário o iframe, mas do browser também, fazendo com que este abra uma nova página.

<% form_for(:asset, :url =>formatted_assets_path(:format => 'js'), :html => { :multipart => true, :target => 'upload_frame'}) do |form| %>
  <%= render(:partial => '/assets/form', :o bject => form) %>
<% end %>
<iframe id='upload_frame' name="upload_frame" style="width:1px;height:1px;border:0px" src="about:blank"></iframe>

Para lidar com o formulário no servidor, utilizaremos o plugin responds_to_parent:

script/plugin install http://responds-to-parent.googlecode.com/svn/trunk/

Este plugin facilita o retorno do javascript à janela pai. Fazendo com que a resposta não ocorra dentro do próprio iframe, como seria o normal.

Para isto, apenas adicione o código abaixo na action create de seu controller:

  # POST /assets
  # POST /assets.xml
  def create
    @asset = Asset.new(params[:asset])
    respond_to do |format|
      if @asset.save
        flash[:notice] = 'Asset was successfully created.'
        format.html { redirect_to asset_url(@asset) }
        format.xml  { head :created, :location => asset_url(@asset) }
        format.js do
          responds_to_parent do
            render :update do |page|
              page.insert_html :bottom, "assets", :partial => 'assets/list_item',  :o bject => @asset
              page.visual_effect :highlight, "asset_#{@asset.id}"
            end
          end
        end
      else
        format.html { render :action => "new" }
        format.xml  { render  :x ml => @asset.errors.to_xml }
        format.js do
          responds_to_parent do
            render :update do |page|
              # update the page with an error message
            end
          end
        end
      end
    end
  end

A partir daqui, o arquivo create.rjs não é mais necessário.

Com estes passos, você já é capaz de fazer upload de arquivo de forma assíncrona, retornando os dados enviados em sua página instantâneamente.

Passo 7: Configurando as respostas necessárias para um ambiente produtivo

Para tornar a sua página pronta para ser utilizada por usuários comuns, é preciso fazer o seguinte:

  • Manusear erros
  • Mostrar mensagem de erro quando o upload falha
  • Mostrar um retorno ao usuário – como um spinner (botão rotativo) – quando o arquivo é enviado e excluído.

Atenção: Este passo é muito importante e não foi muito aprofundado no tutorial original, porém, pretendo pôr aqui as modificações que fiz para que eu obtivesse as respostas como propostas por ele.

Adicione ao lado do botão de submit uma imagem de spinner com display:none:

<%= submit_tag 'Criar', :class => "btn", :o nclick => "Effect.Appear('spinner');" %> <%= image_tag("spinner.gif", :id => 'spinner', :style => 'display:none;') %>

Em cima de toda a marcação na partial _form adicione uma div vazia com o id=”error”:

<div id="error"></div>

Adicione as novas modificações na action create, o que fará com que ao obter sucesso no upload, oculte o spinner que foi ativado ao clicar no submit e esconda os erros que por ventura podem ter surgido. Em caso de erro, o spinner também é ocultado e é inserida uma mensagem de erro na div error.

  # POST /assets
  # POST /assets.xml
  def create
    @asset = Asset.new(params[:asset])
    respond_to do |format|
      if @asset.save
        flash[:notice] = 'Asset was successfully created.'
        format.html { redirect_to asset_url(@asset) }
        format.xml  { head :created, :location => asset_url(@asset) }
        format.js do
          responds_to_parent do
            render :update do |page|
              page.hide          'spinner'
              page.hide          'error'
              page.insert_html :bottom, "assets", :partial => 'assets/list_item',  :o bject => @asset
              page.visual_effect :highlight, "asset_#{@asset.id}"
            end
          end
        end
      else
        format.html { render :action => "new" }
        format.xml  { render  :x ml => @asset.errors.to_xml }
        format.js do
          responds_to_parent do
            render :update do |page|
              page.hide 'spinner'
              page.replace_html 'error', "Houve um erro ao enviar os dados. Tente novamente."
            end
          end
        end
      end
    end
  end

Um bom link para excluir pode ser este, desta forma não é necessário o arquivo destroy.rjs:

<%= link_to_remote("X", :url => asset_path(asset),
                       :success  => " new Effect.Fade('asset-#{asset.id}')",
                       :failure  => "alert('Erro ao deletar.');\n" +
                                    "Element.hide('spinner-#{asset.id}');",
                       :loading  => "Element.show('spinner-#{asset.id}')",
                       :confirm  => "Tem certeza?", :method => :delete) %>
      <%= image_tag("spinner.gif", :id => "spinner-"+asset.id.to_s,
          :style => 'display:none;') %>

Créditos:

Tutorial original criado por Khamsouk Souvanlasy
Adaptado por Vinícius Ebersol

Configurando o ambiente de desenvolvimento ideal

Antes de mais nada, o ambiente de desenvolvimento ideal é no momento, porque daqui a um mês posso mudar de opinião, mas o importante é que com as atuais modificações significaram muito para a minha produção, comecei a produzir com mais prazer e com mais agilidade, devido as novas modificações que eu fiz.

Atualmente tenho falado bastante sobre a minha mudança radical para o emacs. Mas o emacs puro não tem nada que modifique a sua produtividade em ruby e rails como um TextMate ou um Aptana RadRails, pois ele não tem os recursos específicos da linguagem e do framework, como console, MVC e autocomplete de código e marcação, ele só tem a coloração do código e de seus recursos próprios.

Foi então que neste fim de semana passado eu resolvi procurar configurações ideais para o emacs direcionado especificamente ao ruby e rails, bem como código xhtml + erb e css.

Na busca, encontrei este screencast fantástico em que o cara mostra o emacs funcionando como os famosos editores de ruby que já comentei anteriormente. Neste screencast dizia por cima os recursos que ele usou no screencast, foi aí que eu fui buscar de novo, e caí na wiki do rails, em um texto que mostra como deixar o emacs funcionando pra desenvolver em rails com alguns recursos do textmate, como o autocomplete de código, marcação erb e xhtml. Além desses recursos, existe uma integração do emacs com toda a estrutura do rails, como a possibilidade de trabalhar com o console do rails e o irb no emacs, iniciar o server em mongrel ou WEBrick, geradores do rails, entre outros, como é possível ver neste screencast linkado nesta wiki.

Vale lembrar que embora este usuário que está demonstrando utilize muito o mouse, o rails-mode pro emacs como os outros recursos que eu instalei, tem mapeamento de teclado e não é necessário se assustar com isto. O próprio emacs code browser, ou ECB, tem mapeamento de teclado.

Meu ambiente de desenvolvimento após as modificações:

* O importante é saber que o visual é você que faz. Eu utilzei neste caso o tema Gray30, presente no Color Themes do emacs e setei a fonte .emacs. Abaixo o meu arquivo de configuração do emacs.

;Set Font
(set-default-font "lucidasanstypewriter-10")

;Set Theme
(require 'color-theme)
(color-theme-gray30)

(mouse-wheel-mode)
(global-font-lock-mode 1)
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
(require 'php-mode)
'(column-number-mode t)
'(cua-mode t nil (cua-base))
'(ecb-options-version "2.32")
'(message-log-max 150)
'(rails-ws:default-server-type "webrick")
;; Habilitar scroll do mouse
'(scroll-bar-mode (quote right))
'(text-mode-hook (quote (text-mode-hook-identify)))
'(transient-mark-mode t))
'(mouse-wheel-mode t)

(defun up-slightly ()
(interactive)
(scroll-up 5)
)
(defun down-slightly ()
(interactive)
(scroll-down 5)
)

;; Relaciona a rolagem da rodinha com
;; as 2 funções acima

(global-set-key [mouse-4] 'down-slightly)
(global-set-key [mouse-5] 'up-slightly)

;; Show column-number in the mode line
(column-number-mode 1)

;; Line highlight
;; (global-hl-line-mode 1)

(custom-set-faces

;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)

;carrega emacs code browser
(add-to-list 'load-path
"/usr/share/emacs22/site-lisp/ecb/")

;carrega css-mode
setq load-path (cons "~/.emacs.d/css-mode" load-path))
(require 'css-mode)
(autoload 'css-mode "css-mode")
(setq auto-mode-alist
(cons '("\\.css\\'" . css-mode) auto-mode-alist))

;carrega rails-mode
(setq load-path (cons "~/.emacs.d/rails" load-path))
(require 'rails)

;carrega ri-ruby
(setq ri-ruby-script (expand-file-name "~/emacs.d/ri/ri-emacs.rb"))
(autoload 'ri "ri-ruby.el" nil t)

;mmm-mode, suporte para marcacoes erb no html
(setq load-path (cons "~/.emacs.d/mmm-mode" load-path))
(require 'mmm-mode)
(require 'mmm-auto)
(setq mmm-global-mode 'maybe)
(setq mmm-submode-decoration-level 2)
(set-face-background 'mmm-output-submode-face  "Gray25")
(set-face-background 'mmm-code-submode-face    "MediumSlateBlue")
(set-face-background 'mmm-comment-submode-face "DarkOliveGreen")
(mmm-add-classes
  '((erb-code
  :submode ruby-mode
  :match-face (("<%#" . mmm-comment-submode-face)
  ("<%=" . mmm-output-submode-face)
  ("<%"  . mmm-code-submode-face))
  :front "<%[#=]?"
  :back "-?%>"
  :insert ((?% erb-code       nil @ "<%"  @ " " _ " " @ "%>" @)
  (?# erb-comment    nil @ "<%#" @ " " _ " " @ "%>" @)
  (?= erb-expression nil @ "<%=" @ " " _ " " @ "%>" @))
  )))
  (add-hook 'html-mode-hook
  (lambda ()
  (setq mmm-classes '(erb-code))
  (mmm-mode-on)))
  (add-to-list 'auto-mode-alist '("\\.rhtml$" . html-mode))

;Snippet Textmate like, deixar o emacs com os recursos do textmate
  (require 'snippet)

Poupe suas páginas, ponha somente o CSS e o Javascript necessário com Ruby on Rails

Hoje em dia cada byte a mais no seu código pode significar gigabites de tráfego ali na frente, por isso é necessário utilizar em cada página que é renderizada somente o que é preciso para aquela página rodar.

O ideal é pôr o stylesheet_link_tag e o javascript_include_tag dentro de cada view, somente com os arquivos necessários. Porém, surge um problema grave, que é o fato de o elemento <link> não poder ficar fora do elemento <head>, ou seja, se você usar um layout padrão com n views, o seu arquivo que contém as Stylesheets ficará fora do elemento <head>, tornando seu código fora do padrão da w3C, o que para muitos não é importante, para mim é imprescindível.

Mas como o Rails é muito bom, também pensaram nisso. O método de pôr stylesheets e javascripts que estão na view dentro do elemento <head> é muito simples.

app/views/layouts/application.rhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt" lang="pt">
  <head>
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    <meta name="language" content="pt-br" />
    <meta name="generator" content="emacs" />
    <title>Título da sua página</title>

    <%= javascript_include_tag :defaults %>

    <!--  Pega os blocos de CSS e Javascript e exibe nesta região da sua marcação. -->
    <%= yield(:page_javascript) %>
    <%= yield(:page_stylesheet) %>
  </head>
  <body>
    <div id="wrap" >
      <%= yield %>
    </div>
  </body>
</html>

app/views/teste/view.rhtml

<% content_for(:page_stylesheet) do %>
  <%= stylesheet_link_tag 'redboox' %>
<% end %>

<% content_for(:page_javascript) do %>
  <%= javascript_include_tag 'redbox' %>
<% end %>

<div>
  <h4>Seu html aqui...</h4>
  ...
  ...
  ...
</div>

Exportar seu código para HTML com o emacs

Há dias eu tenho buscado uma solução para exportar códigos ou trechos deles para HTML. O objetivo é mostrar posteriormente dicas com o código colorido, para melhor identificar os elementos. Existem alguns javascripts que transformam o código através de varredura por uma marcação com determinada classe, porém este é extremamente lento.

Foi então que vi que com editores como o Vim, conforme mostra o Eustáquio Rangel em seu blog. Desde então fiquei entusiasmado para utilizar o mesmo recurso no emacs, que com certeza não iria perder para o vim neste recurso.

Descobri que existe uma função lisp do emacs que faz isto, é a htmlize, que permite exportar um arquivo inteiro, um trecho do arquivo, vários arquivos entre outros. Para utilizar este recurso é simples: M-x htmlize (ALT + X e digite htmlize) aperte tab para ver todos os recursos disponíveis e selecione o recurso que deseja.

Um exemplo de trecho código de um controller do Ruby on Rails exportado com o tema Gray30 do emacs:

  # PUT /comments/1
  # PUT /comments/1.xml
  def update
    @comment = Comment.find(params[:id])

    respond_to do |format|
      if @comment.update_attributes(params[:comment])
        flash[:notice] = 'Comment was successfully updated.'
        format.html { redirect_to comment_url(@comment) }
        format.xml  { head  :o k }
      else
        format.html { render :action => "edit" }
        format.xml  { render  :x ml => @comment.errors.to_xml }
      end
    end
  end

Esse código acima é um trecho de um controller gerado com o scaffold resource. Em breve vou dar dicas que estava guardando há dias para publicar aqui.

Rails Podcast Brasil – O feedback

Esse post é rapidinho, pois a manhã se aproxima. Hoje eu estava bem belo ouvindo o episodio #3 do Rails Podcast Brasil, com Carlos Brando e Fábio Akita, no final ambos imploraram por um feedback acerca do referido.

Pois então, meu comentário será breve e espero que contribua com alguma coisa. A primeira coisa que eu sinto falta é de um Feed do Podcast pra pôr no meu Rythmbox e receber as atualizacoes direto lá sem precisar salvar o MP3 no computador.

O conteúdo vem se mantendo agradável e bem interessante, exceto a parte que eles insistem em falar em Mac, pra que invejosos como eu se mordam (Tem jabá?), mas é claro, isso é só um brincadeira, o conteúdo tá jóia, consegui ouvir todos os podcasts até hoje por completo, o que é raro.

Uma sugestão pros próximos Podcasts é chamar convidados para debater sobre algum assunto, me lembro de ouvir o Podcast do Gilberto Jr., o [0-] taligado que tinha a ótima participação do Elcio Ferreira. Portanto, creio que participações eventuais são muito boas.

Sobre a teoria da oferta e da demanda do Akita, ele ficou no dilema sobre quem surge primeiro, “o ovo ou a galinha?”. Imagine que no caso que ele citou a afirmação é verdadeira, mas não é a lei.

Ahh! Falta também um player de podcast daqueles em flash que sao bem legais!

 

E a qualidade de áudio está ótima (headphone).

Microformats são uma maravilha, com Mofo melhor ainda!

Acabo de ler um post bem legal no Nome do Jogo, é um screencast mostrando como utilizar Microformats com um gem do Ruby de forma fácil e rápida (como tudo no ruby). O nome deste gem é Mofo, ele é muito útil para chamar dados de um web service, como por exemplo seu perfil no Linkedin. Como o próprio Carlos Brando mencionou no Podcast dele com o Akita - o Rails PodCast Brasil – ele está preparando assuntos bem legais para os screencasts e aprendendo como se faz, então a dica é para algo sério e bem feito!

Eu já postei algumas coisas sobre Microformats na versão 1.0 deste blog, pois eu vi uma palestra do Élcio Ferreira sobre o assunto no 9º ELPI. Eu particularmente achei esta idéia simples e muito produtiva, pois ela já permite que com uma extensão do Firefox chamada Operator, você tenha acesso fácil e rápido aos dados mais importantes do perfil da empresa ou da pessoa.

Como fazer o seu Microformat com marcação XHTML? É Fácil!

Agora se você quer algo mais sofisticado Carlos Brando é a solução.

O emacs funciona no Ubuntu SIM!

Há dias estava num dilema. Eu queria parar de trabalhar com o Aptana Radrails, pois ele me deixava muito dependente do mouse, e em termos de produtividade isto não é nada bom. Quando comecei a trabalhar com Rails, eu vi o Everton utilizando um editor simples, mas que cumpria o principal papel de um editor de texto: colorir e identar o código. Este editor se chama emacs.

O emacs é um editor bem estabelecido, como vocês podem ler no link acima, ele tem nada mais nada menos do que 32 anos. Embora tenha uma interface extremamente simples, o editor é um dos mais poderosos editores que eu já vi. Um dos recursos mais impressionantes é que posso identar uma linha (apertando TAB) de qualquer lugar da linha, não precisa ser necessáriamente do início. Além disso, ele permite que eu abra N frames na mesma janela, como vocês podem ver abaixo:

Pra quem faz download do emacs pelo ubuntu, via apt-get, nota que ele não colore o código, isto não é bug, é falta de configuração.

Então faça o seguinte:

  1. Se ainda não fez, instale o emacs, no terminal digite: sudo apt-get install emacs;
  2. Após instalado, rode o emacs abrindo as próprias configurações dele: emacs /home/seu_login/.emacs & (o & é para liberar o terminal);
  3. Procure no arquivo a seguinte linha: (global-font-lock-mode 0) e troque o valor 0 (zero) para 1 (um);
  4. Salve o arquivo: C-x, C-s (ctrl + x e ctrl + s);
  5. Abra um arquivo em html, .rhtml ou .rb para ver se está ok.

Quer aprender alguns comandos básicos do emacs? Que tal a Wiki do emacs?

Como validar a marcação XHTML de formulários em Ruby on Rails?

Este tópico não é uma explicação de como resolver o problema, mas é uma dúvida que surgiu agora. Quem trabalha com tableless sabe o quanto é importante validar a sua marcação no W3C Validator, a falta de fechamento de uma DIV ou um elemento que faltam atributos pode quebrar toda a página e podemos perder horas procurando o problema no código fonte da página.

O W3C Validator serve para isto, é um atalho para descobrir erros em apenas alguns segundos. No entanto, o tipo de formulário utilizado pelo Rails é diferente, ele utiliza dados armazenados em Hash, o que na verdade é um padrão adotado no Ruby.

Um input gerado com um helper do Rails, fica mais ou menos assim:

<p>
    <label for="company_name">Nome da empresa:</label><br />
    <input id="company_name" class="per" value="Google" size="30" name="company[name]" type="text">
</p>

Essa marcação não passa na validação da W3C, pois o name company[name] não é um padrão da W3C. Não sei o porquê, não encontrei respostas. Sigo em busca de alguma coisa.a