Posts Tagged 'Ruby'

Classes abstratas em Ruby?

Post movido para: http://blog.guilhermegarnier.com/2009/12/04/classes-abstratas-em-ruby/

Como eu estava há algum tempo sem mexer com Ruby, resolvi fazer o ótimo curso online gratuito Core Ruby, do Satish Talim (também conhecido como Indian Guru) para relembrar algumas coisas. Ao chegar no tópico Ruby Overriding Methods, há um item sobre classes abstratas, que diz o seguinte:

Abstract class

In Ruby, we can define an abstract class that invokes certain undefined “abstract” methods, which are left for subclasses to define. For example:

# This class is abstract; it doesn't define hello or name
# No special syntax is required: any class that invokes methods
# that are intended for a subclass to implement is abstract
class AbstractKlass
  def welcome
    puts "#{hello} #{name}"
  end
end

# A concrete class
class ConcreteKlass < AbstractKlass
  def hello; "Hello"; end
  def name; "Ruby students"; end
end

ConcreteKlass.new.welcome # Displays "Hello Ruby students"

Assim que li esse código, fiquei com uma pulga atrás da orelha. Ele mostra como um exemplo de classe abstrata uma classe que faz referência a métodos não definidos, explicando que seria necessário criar uma classe concreta estendendo esta classe e implementando os métodos necessários.

Eu sempre pensei que classes abstratas fossem classes que não poderiam ser instanciadas, o que não é o caso do exemplo. É perfeitamente possível criar objetos da classe AbstractKlass. Só ocorrerá uma exceção se o método welcome do objeto criado for executado:

irb(main):006:0> obj = AbstractKlass.new
=> #<AbstractKlass:0x37d490>
irb(main):007:0> obj.class
=> AbstractKlass
irb(main):008:0> obj.welcome
NameError: undefined local variable or method `hello' for #<AbstractKlass:0x37d490>
        from (irb):9

Resolvi levantar esta questão no forum do curso, e recebi uma resposta de um dos participantes dizendo que em Ruby o conceito de classes abstratas seria diferente daquele que apresentei acima. De acordo com a definição da Wikipedia: “An abstract class, or abstract base class (ABC), is a class that cannot be instantiated”.

Pesquisando sobre o assunto, encontrei referências apresentando algumas sugestões de como implementar classes abstratas em Ruby de diferentes maneiras (herança, módulos e até um gem):

Uma das possibilidades mostradas nos links acima seria desta forma:

class AbstractClass
  class AbstractClassInstiationError < RuntimeError
  end

  def initialize
    raise AbstractClassInstiationError, "Cannot instantiate this class directly"
  end
end

class ConcreteClass < AbstractClass
  def initialize
  end
end

Isso teoricamente resolveria o problema:

irb(main):043:0> obj1 = AbstractClass.new
AbstractClass::AbstractClassInstiationError: Cannot instantiate this class directly
        from (irb):36:in `initialize'
        from (irb):44
irb(main):044:0> obj1.class
=> NilClass
irb(main):045:0> obj2 = ConcreteClass.new
=> #<ConcreteClass:0x309f9f>
irb(main):046:0> obj2.class
=> ConcreteClass

Porém, há um detalhe importantíssimo: em Ruby todas as classes são abertas, ou seja, sempre será possível reimplementar métodos ou adicionar módulos que alteram o comportamento da classe, tornando impossível proibir completamente a instanciação e, consequentemente, a implementação de classes abstratas (pelo menos de acordo com o conceito apresentado aqui).

A linguagem Ruby possui alguns conceitos diferentes dos utilizados em outras linguagens, em função de algumas de suas características, como classes abertas e meta programação. Isso nos força a pensar em maneiras diferentes de implementar soluções para os mesmos problemas, o que é muito bom.

Para concluir, segue um trecho do livro “Programming Ruby” que foi apresentado na discussão sobre este assunto no forum do curso:

The issue of types is actually somewhat deeper than an ongoing debate between strong typing advocates and the hippie-freak dynamic typing crowd. The real issue is the question, what is a type in the first place?

If you’ve been coding in conventional typed languages, you’ve probably been taught that the type of an object is its class—all objects are instances of some class, and that class is the object’s type. The class defines the operations (methods) that the object can support, along with the state (instance variables) on which those methods operate.

In Ruby, the class is never (OK, almost never) the type. Instead, the type of an object is defined more by what that object can do. In Ruby, we call this duck typing. If an object walks like a duck and talks like a duck, then the interpreter is happy to treat it as if it were a duck.

Instant Rails, o ambiente Rails de bolso

Post movido para: http://blog.guilhermegarnier.com/2009/06/18/instant-rails-o-ambiente-rails-de-bolso/

Com a proliferação dos pen drives com alguns GB de capacidade e a preços acessíveis, aplicativos que rodam sem necessitar de instalação tornaram-se igualmente populares. Estes aplicativos “portáteis”, mais conhecidos como Portable Apps, podem ser executados diretamente do pen drive, geralmente com todas as funções dos equivalentes instaláveis. Eles são mais comuns em ambiente Windows (o site mais conhecido é o PortableApps, mas existem outros, como o The Portable Freeware Collection), porém também existem Portable Apps para Mac OS X. Até onde eu sei, não existem Portable Apps para Linux, porém, é possível executar os Portable Apps de Windows via Wine.

Como não poderia deixar de ser, existem também muitos ambientes de desenvolvimento portáteis. Talvez o mais conhecido seja o XAMPP, que inclui um servidor Apache com MySQL, PHP e Perl, entre outras ferramentas. Basta descompactar e executar.

Para Ruby on Rails, também existe um ambiente portátil. É o Instant Rails, infelizmente disponível somente para Windows. A exemplo do XAMPP, basta descompactar um arquivo zip para se ter um ambiente Rails totalmente funcional, com Mongrel, Apache e MySQL. É possível, inclusive, instalar RubyGems e plugins Rails normalmente, como num ambiente Rails comum. O pacote inclui ainda o SQLite, PHP, phpMyAdmin, o editor SciTE e o typo, sobre o qual já escrevi aqui no blog.

A principal desvantagem do Instant Rails é que ele está bastante desatualizado – a versão atual, 2.0, é de dezembro de 2007, e inclui as seguintes versões:

  • Ruby 1.8.6
  • Rails 2.0.2
  • Mongrel 1.1.2
  • RubyGems 1.0.1
  • Rake 0.8.1
  • Apache 1.3.33
  • MySQL 5.0.27
  • SQLite 3.5.4
  • PHP 4.3.10
  • SciTE 1.72
  • phpMyAdmin 2.10.0.2

Segundo o wiki do projeto, há uma petição solicitando o upgrade para a versão 1.9.1 do Ruby.

UPDATE: Só agora vi que o Urubatan escreveu sobre o mesmo assunto no blog dele. Só que ele citou o Ruby on Rails Portable, um projeto muito semelhante ao InstantRails, porém um pouco mais atualizado: a versão do Rails atualmente é 2.1.0 (a do Ruby é 1.8.6).

Outro projeto semelhante que encontrei, mas ainda não testei, é o Flash Rails.

Ruby on Rails search engine

Post movido para: http://blog.guilhermegarnier.com/2009/03/03/ruby-on-rails-search-engine/

O Google se tornou, há muito tempo, a ferramenta padrão para qualquer desenvolvedor procurar ajuda para resolver os problemas que encontra. Porém, os resultados retornados nem sempre são satisfatórios e confiáveis. O objetivo do Custom Ruby on Rails search engine é resolver este tipo de problema: ele filtra os resultados de uma busca no Google para exibir somente os resultados que vêm de uma lista específica de sites que o autor considera como confiáveis – além de links “oficiais”, como o site oficial do Rails, o wiki do Rails, o Ruby Forum e a API do Rails, alguns dos blogs mais conhecidos. O autor também aceita sugestões de sites para incluir nos resultados.

A ferramenta pode ser utilizada através do link direto ou através de um bookmarklet, conforme descrito no blog.

Ferramenta em Rails para criação de blogs

Post movido para: http://blog.guilhermegarnier.com/2008/10/31/ferramenta-em-rails-para-criacao-de-blogs/

Muitos tutoriais de Rails para iniciantes, para demonstrarem na prática como é rápido e simples criar aplicações web com ele, explicam como criar um blog em 15 minutos, baseados no screencast do David Heinemeier Hansson, criador do Rails, para o FISL 6.0. Apesar de ser uma aplicação funcional de blog, com opção para criar posts e adicionar comentários, é bastante limitado.

O Typo é uma aplicação desenvolvida em Rails para criação de blogs bastante completa (inclusive encontrei este blog criado com ele). Ele lembra muito o WordPress, acredito que tenha sido inspirado nele. A interface de administração é muito semelhante à do WordPress, apresentando basicamente as mesmas opções: criar posts e páginas, ver/aprovar/rejeitar comentários, criar usuários, customizar a barra lateral, etc. Há também uma opção para seleção de temas (outros temas podem ser encontrados aqui) e plugins com diversas funcionalidades, como APIs para Delicious, Flickr, Twitter e outros. Só senti falta das opções de estatísticas de acesso que o WordPress oferece.

A instalação pode ser feita através do comando gem (gem install typo), porém, tentei e não consegui instalar desta forma. Instalei a ferramenta pela versão tgz. Neste caso, basta descompactar a aplicação, copiar o arquivo database.yml.example, no diretório config, para database.yml, editá-lo conforme a configuração do banco de dados, e em seguida executar rake db:create para criar a estrutura do banco de dados. Caso você queira ser avisado por email quando receber comentários nos posts, copie também o arquivo config/mail.yml.example para mail.yml no mesmo diretório, e edite as configurações de SMTP.

O Typo também possui um servidor de feeds RSS/Atom. Porém, na versão atual (5.1.3), recebi uma mensagem de erro ao tentar acessar os feeds. Encontrei o erro no arquivo app/models/article.rb e corrigi substituindo o método link_to_author? (linhas 384 a 386) pelo seguinte:

def link_to_author?
  begin
    !user.email.blank? && blog.link_to_author
  rescue NoMethodError
    return false
  end
end

Rails sem banco de dados

Post movido para: http://blog.guilhermegarnier.com/2008/06/17/rails-sem-banco-de-dados/

O Active Record é um dos principais componentes do Rails, pois é exatamente o model do MVC. Ele mapeia automaticamente uma classe numa tabela do banco de dados, criando métodos para acesso a cada atributo. Porém, e se quisermos desenvolver uma aplicação sem banco de dados?

Passei por esta situação recentemente: a aplicação acessa um servidor diretamente, via Atom, e, portanto, não precisa armazenar dados localmente. Porém, não basta comentar todas as linhas do arquivo config/database.yml, pois o Rails mostrará uma mensagem de erro informando que não encontrou o banco de dados correspondente.

Para resolver este problema, resolvi, inicialmente, tentar não utilizar o Active Record. Para isso, primeiramente precisei modificar o model que eu tinha na aplicação, retirando a herança de ActiveRecord::Base. Porém, ao tentar executar o servidor, recebi mensagens de erro informando que o banco de dados não foi encontrado. Isso ocorre porque, apesar de não haver qualquer classe herdando de ActiveRecord::Base no projeto, este módulo estava sendo carregado. Conseqüentemente, o Rails tentava ler o arquivo config/database.yml, que não estava configurado, resultando na mensagem de erro. Para evitar este problema, foi necessário evitar o carregamento do ActiveRecord explicitamente, acrescentando a linha abaixo ao arquivo config/environment.rb:

config.frameworks -= [ :active_record ]

Feito isto, o Rails passa a funcionar sem banco de dados e sem ActiveRecord. Porém, surgiu um outro problema: os testes unitários do Rails pararam de funcionar, pois a classe ActiveSupport::TestCase, que é a classe base para os testes unitários, não funciona sem ActiveRecord. Para resolver, troquei a herança desta classe para Test::Unit::TestCase, que era utilizada como padrão antes da versão 2 do Rails. Não sei exatamente quais são as diferenças entre as duas, mas só consegui resolver este problema desta forma – se alguém descobrir alguma outra solução, me avise!

Também precisei carregar explicitamente o model no arquivo de teste, pois o Rails deixou de fazer a referência automática a esta classe. Feitas as alterações, o arquivo de teste (ex: test/unit/usuario_test.rb) ficou assim:

require 'test/test_helper'
require 'test/unit'
require 'app/models/usuario'

class UsuarioTest < Test::Unit::TestCase
  # Replace this with your real tests.
  def test_truth
    assert true
  end
end

IDEs para Ruby on Rails

Post movido para: http://blog.guilhermegarnier.com/2008/05/27/ides-para-ruby-on-rails/

O uso de IDEs para desenvolvimento em Rails é um assunto bastante controverso. Devido às diversas facilidades no desenvolvimento com este framework, muitas pessoas afirmam que uma IDE não é necessária, basta um editor de textos simples e um terminal. Outros acreditam que, apesar do alto grau de automação do Rails, ainda é vantajoso usar uma IDE. No meio desta discussão, acredito que, no caso do Ruby on Rails, a escolha torna-se um gosto pessoal.

Para os que estão no primeiro caso, a escolha do editor de texto também é uma questão de gosto pessoal. Alguns se sentem confortáveis com o vi, outros com o Emacs. Estes casos são mais comuns quando já há uma intimidade com estes editores – dificilmente alguém vai aprender a usar Emacs para desenvolver em Rails. Para quem prefere um editor mais amigável, há opções para todos os sistemas operacionais: no Linux, o Gedit, quando bem configurado com alguns dos diversos plugins disponíveis, torna-se uma poderosa ferramenta de desenvolvimento, com code completion, por exemplo. No Mac há o TextMate e no Windows o SciTe (também disponível para Linux). Para tarefas como rodar o servidor web, executar migrations e generates, debugar a aplicação ou trabalhar com uma ferramenta de controle de versão (CVS, SVN, GIT, etc), usa-se o terminal.

Para quem prefere usar uma IDE, a principal vantagem é não precisar recorrer ao terminal para executar as tarefas acima. Tudo é integrado, facilitando o trabalho. Realmente algumas dessas tarefas são extremamente simples, como executar migrations. Nestes casos, pouca diferença há entre usar a IDE ou o terminal. Porém, trabalhar com uma ferramenta de controle de versão e executar um debug por linha de comando pode ser trabalhoso. Acredito que estas sejam as principais vantagens de se usar uma IDE. Por outro lado, as IDEs requerem bastante memória do desktop, ao contrário dos editores de texto, e costumam ser mais instáveis.

As opções de IDE para Rails também são variadas, e as duas principais são o Aptana RadRails e o NetBeans. Nos últimos meses trabalhei com ambos alternadamente, e encontrei diversas vantagens e desvantagens em cada um.

Aptana RadRails

O Aptana RadRails pode ser instalado como um plugin do Eclipse ou isoladamente, caso você não o tenha instalado. Na primeira vez que o testei, há alguns meses, achei o plugin bastante instável, e com alguns bugs incômodos. Recentemente, ao verificar que havia uma nova versão disponível, testei novamente, e verifiquei que esta nova versão está bem melhor. Há alguns meses atrás, escrevi neste post que o RadRails não conseguia ler arquivos database.yml usando o formato descrito. Conforme este comentário do Chris Williams, um dos desenvolvedores do RadRails, a nova versão corrigiu este problema e outros que eu havia encontrado. A versão mais recente também possui um Ruby Shell bastante útil, inclusive com autocomplete de comandos e parâmetros, porém instável – já o vi travar algumas vezes. Outras vantagens do RadRails são:

  • Botões para acesso rápido ao Model, View, Controller, Helper e Test equivalentes ao arquivo ativo
  • Problema do DRY no database.yml corrigido
  • Suporte a testes mais completo (permite executar apenas um arquivo de testes de cada vez)

As principais desvantagens do RadRails são:

  • Problemas no autocomplete (não mostra todos os métodos)
  • O console não aceita a tecla para cima para acessar os últimos comandos, como no shell
  • Ruby shell instável (trava com freqüência)
  • Server não permite selecionar um environment diferente dos 3 defaults (development, test e production), mesmo que você tenha algum outro environment definido no arquivo database.yml

NetBeans

O suporte do NetBeans ao Rails tornou-se estável há mais tempo que o RadRails, com um editor para código Ruby bem completo. Atualmente, ambos diferenciam-se nos detalhes. Principais vantagens do NetBeans:

  • Ao selecionar um texto e digitar (, o editor envolve o texto selecionado com parênteses
  • Ao selecionar um texto e digitar #, o editor envolve o texto selecionado com #{ e }
  • Ao colocar o cursor sobre um end, o editor destaca o inicio desse bloco/método/classe
  • O find é mais fácil de usar (estilo Firefox, com highlight automático dos termos conforme você digita)

Principais desvantagens do NetBeans:

  • Problemas no autocomplete (mostra os métodos que não deveriam aparecer)
  • O console não aceita a tecla para cima para acessar os últimos comandos, como no shell
  • Suporte a SVN bastante limitado
  • A execução do server não permite selecionar o environment (sempre utiliza o development)
  • A opção Test executa todos os testes (não há opção para executar apenas um arquivo, ou apenas os testes unitários, por exemplo)

Concluindo, o editor do NetBeans me parece mais completo para tratamento de código Ruby. Porém, o ambiente do RadRails é mais completo para execução de testes, integração com SVN e outras tarefas. Um ponto onde ambos apresentam problemas é o autocomplete – às vezes aparecem métodos de mais, outras vezes de menos. Porém, devemos reconhecer que, por se tratar de uma linguagem dinâmica, onde uma variável não tem tipo fixo, é bastante complicado termos um autocomplete realmente preciso.

O poder do Ruby

Post movido para: http://blog.guilhermegarnier.com/2008/05/08/o-poder-do-ruby/

Muito se fala das vantagens do Ruby sobre muitas das linguagens atuais, por ser uma linguagem de altíssimo nível. Mas muitas vezes não percebemos grandes diferenças entre as linguagens, além das usuais diferenças de sintaxe – se as linhas de comando precisam de ponto-e-vírgula no final, se as variáveis precisam de $ no início do nome, se estas são tipadas ou não, se precisam ser declaradas ou não, etc. Porém, em algumas situações específicas, enxergamos o verdadeiro poder do Ruby.

Hoje precisei implementar uma paginação de resultados de busca. Eu sei que existem plugins para Rails que simplificam esta tarefa, porém como esta busca não é feita no banco de dados, e sim através de um indexador que já retorna resultados paginados, optamos por fazer manualmente a lista de links para as páginas.

Por exemplo: ao realizar uma busca, são exibidos os 10 primeiros resultados, com um link para a próxima página e a lista de links para cada página. Como o número de páginas, teoricamente, não tem limite, fiz o seguinte:

  • caso o resultado tenha até 10 páginas, todas são exibidas
  • caso o resultado tenha mais de 10 páginas, são exibidas apenas 10, sendo que:
    • caso a página atual seja uma das 6 primeiras, exibe os links para as páginas 1 a 10
    • caso a página atual seja maior que 6, exibe da página atual – 5 até a página atual + 4
    • caso a página atual seja uma das 10 últimas, exibe as 10 últimas

Pela descrição acima, percebemos que é uma lógica bem simples, porém meio chata para ser implementada – na maioria das linguagens atuais, isto exigiria um grande número de if’s aninhados, para verificarmos se as condições descritas acima são atendidas. Porém, em Ruby o código ficou muito simples e enxuto:

if (num_pages > 1)
  page_start = [1, page-5].max
  page_end = [num_pages, page+4].min
  if num_pages > 10
    page_start = [page_start, num_pages-9].min
    page_end = [page_end, 10].max
  end
  page_start.upto(page_end) {|p|
    # Exibe os links
  }
end

@guilhermgarnier

Erro: o Twitter não respondeu. Por favor, aguarde alguns minutos e atualize esta página.

Estatísticas

  • 58,340 hits
Linux Counter