HashCode

An organizer of symbols

Archive for the ‘Ruby’ Category

IRB com reverse search no Apple Terminal

Saturday, January 3rd, 2009

Após muitas tentativa achei uma solução plausível, agora o meu irb aceita Ctrl+R. Solução simples
Edite o ~/.editrc e cole

bind "^R" em-inc-search-prev

Que saudade do gnome-terminal …

Firulando código em ruby para wordpress

Monday, December 29th, 2008

Ultimamente estou recebendo emails me perguntando qual o plugin do WordPress eu uso para deixar o código do meu blog ‘bonitinho’. Já enviei uns 6 emails para pessoas diferentes, já que o pessoal está gostando vou postar a minha solução.

Criei um programinha que chamei de compile_post.rb ele recebe um arquivo texto e formata as tags code para html.

O programa requer as gems hpricot e syntax, para instalar basta

sudo gem install hpricot
sudo gem install syntax

O conteúdo é esse

#!/usr/bin/ruby
require 'rubygems'
require 'hpricot'
require 'syntax/convertors/html'

convertor = Syntax::Convertors::HTML.for_syntax "ruby"
source=ARGV[0]

abort "usage: ruby compile_post.rb filename.txt" unless source

doc = Hpricot.parse(File.readlines(source).join)
(doc/"code").each do |c|
   c.inner_html=convertor.convert(c.to_s.gsub(/<code>|<\/code>/,''),true)
end
File.open("#{source}.post",'w'){|f| f.puts doc.to_s.gsub(/<code>|<\/code>/,'') }

O programa gerará um arquivo .post é só copiar e colar no post editor do WordPress

Criei também um estilo meia-boca TextMate-like. Não se esqueça de

<link href="http://yoursite.com/mate.css" rel="stylesheet" type="text/css" media="all" />

Ops! RailsTree, de novo?

Monday, November 10th, 2008

Puts! Foi mal Akita e Carlos esse projeto é de mil novecentos e Titanic mas obrigado por mencionar. Eu repostei ele sem querer.

O post real está aqui

class_variable_defined? NoMethodError: Ruby 1.8.5

Tuesday, October 7th, 2008

Se você usa metaprogramação em Ruby fique atento com os servidores desatualizados por aí. O método Object.class_variable_defined? não existe na versão 1.8.5 apenas nas mais versões novas.

Usando Ruby 1.8.5 (2006-08-25) [i486-linux]

 Object.class_variable_defined? :@@coisa #=> NoMethodError: undefined method 

Usando Ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]

 Object.class_variable_defined? :@@coisa #=> false

Solução rápida

Adicionar o método na classe Object que faça o mesmo papel.

def Object.class_variable_defined?(pseudo_var)
  Object.class_variables.include?(pseudo_var.to_s)
end

Compatibilizando o código sem alterar o core

def Object.class_variable_defined?(pseudo_var)
  Object.class_variables.include?(pseudo_var.to_s)
end unless Object.respond_to? :class_variable_defined?

Não deixe que isso consuma 3 horas do seu trabalho como acabou de acontecer comigo :)

RESTful - Parent Load, com método preload

Friday, August 29th, 2008

Para quem usa RESTful e Nested Resources existe uma ação de carregamento do objeto pai na maioria dos controllers filho.

Se você não entendeu nada do que eu falei, dê uma lida em
RESTful Rails Development, by Ralf Wirdemann & Thomas Baustert

Por exemplo tenho dois models um Person e o outro Personality sendo que Person tem uma Personality e Personality pertence a Person.
Ficando assim o relacionamento no AR

#app/models/person.rb
class Person < ActiveRecord::Base
  has_one :personality
end
#app/models/personality.rb
class Personality < ActiveRecord::Base
  belongs_to :person
end

e as rotas desta forma

ActionController::Routing::Routes.draw do |map|
  map.resources :personalities, :belongs_to => :people, :singular => "personality"
  map.resources :people, :has_one => :personality
end

Ok até agora. “Feitisso” podemos criar um registro Person via /people/new e depois criar um registro Personality via /people/1/personality/new
Quando for criado o novo registro Personality o id do pai(Person) vai como parametro

params[:person_id]

Então você já deve ter visto muito a estrategia de carregamento do objeto pai em uma variável de instância via filtro, em um construção do tipo abaixo:

class PersonalitiesController < ApplicationController
  before_filter :get_person

  private
  def get_person
    @person = Person.find(params[:person_id])
  end

end

Portando antes de executar a action o pai é carregado via filtro.

Para evitar está estrategia que estava repetindo em quase todos meus controllers crie o método preload.
Com preload posso ter uma contrução mais clara e com o mesmo efeito. Então agora posso fazer assim

class PersonalitiesController < ApplicationController
  preload :person
end

Podemos também utilizar include, order, limit, etc

class PersonalitiesController < ApplicationController
  preload :person, :include => :personality
end

Ou até especificar em quais actions o preload será utilizado

class PersonalitiesController < ApplicationController
  preload :person, {:include => :personality}, {:only => [:create]}
end

Olha a origem da mágica

class ApplicationController < ActionController::Base
  def self.preload_object(name,options,filter_options={} )
    before_filter(filter_options) do |controller|
      controller.instance_variable_set("@#{name}", name.to_s.camelize.constantize.find(controller.params["#{name}_id"], options))
    end
  end
end

Apenas um método de classe dentro do ApplicationController e um pouco de meta programação.
Agora vou tentar explicar o médodo preload.

Começando por

  name.to_s.camelize.constantize

o name vem como Symbol no nosso caso :person, então temos

name.to_s  		#=> "person"

O método camelize analiza o conteúdo da String e adapta ao padrão de nome de classes utilizadas em Ruby, exemplo “foo_bar” camelizado passa a ser “FooBar”.

name.to_s.camelize #=> "Person"

Invocando a constante

name.to_s.camelize.constantize #=> Person

ou poderia utilizar

Object.const_get name.to_s.camelize

Já que tenho a classe Person utilizo o find passando o padrão pai_id.

O bloco do before_filter passa um yield do controller, precisamos do controller neste escopo pois estamos em um contexto estático, por conseguinte apenas params[:pai_id] não é visível então utilizei controller.params[:pai_id]

E por último criar a instância @pai apontando para o retorno do Person.find, vou dar um zoom no código :)

class ApplicationController < ActionController::Base
  def self.preload_object(name,options,filter_options={} )
    before_filter(filter_options) do |controller|
		  parent_id = controller.params["#{name}_id"]
			find_return = name.to_s.camelize.constantize.find(parent_id)
			controller.instance_variable_set("@#{name}", find_return)
    end
  end
end

Ou você prefere a versão One-Line-Brain-Fucker?

class ApplicationController < ActionController::Base

  def self.preload_object(name,options,filter_options={} )
    before_filter(filter_options) { |controller| controller.instance_variable_set("@#{name}", name.to_s.camelize.constantize.find(controller.params["#{name}_id"], options)) }
  end

end

Mais DRY, mais DRY …

RGhost on Mac OSX

Monday, August 25th, 2008

Abaixo instruções de instalação do RGhost no MacOS

Requirimentos:
- Ruby
- RubyGems
- Xcode
- Mac Port

Primeiro instale o Ghostscript via macport

sudo port install ghostscript

Agora RGhost

sudo gem install rghost

Agora precisamos saber onde o executável do Ghostscript foi instalado para isso execute

hashcode:tmp shairon$ type gs
gs is /opt/local/bin/gs

Observe que na minha instalação o path ficou /opt/local/bin/gs.
Vamos configurar e testar em um arquivo .rb ou via IRB

require 'rubygems'
require 'rghost'

#use o path do seu gs aqui
RGhost::Config::GS[:path]="/opt/local/bin/gs"
RGhost::Config.is_ok?.render :pdf, :filename => "/tmp/is_ok.pdf"

Uma página será gerada como essa
You environment is done.

Em breve no manual em English.

Pare um pouco e revise seus conhecimentos sobre Ruby

Saturday, July 26th, 2008

Referência rápida com exemplos claros sobre os objetos do Ruby Core, acesse aqui.
Algumas coisas como

require 'socket'
require 'timeout'
begin
    timeout(1) do #the server has one second to answer
        client = TCPSocket.new('www.host.com', 'www')
    end
rescue
    puts "error: #{$!}"
end

você conhecia o timeout?

RGhost 0.8 e RGhost Barcode publicado

Thursday, June 19th, 2008

Rubeiros,

Publiquei hoje um nova versão do RGhost http://rghost.rubyforge.org totalmente refatorada.
Bati forte em desempenho e na doçura da sintaxe, ficando mais fácil programar em Ruby e gerar códigos em Postscript.
Fiz um teste estuprador até 10K páginas com template e passou legal.

Abaixo algumas das mudanças.

  • Namespace RGhost adicionado e algumas nomes de classes/módulos mudaram.
  • Teste de ambiente e de fonts como RGhost::Config.is_ok?.render :pdf, :filename => “/tmp/test.pdf” e environment_fonts.
  • Retirado o suporte aos 4 códigos de barras GNU Barcode.
  • Criado o projeto rghost_barcode http://rghost-barcode.rubyforge.org que suporta 32 tipos de códigos de barras incluindo uns doidão.
  • Suporte a qualquer fonte TTF e Type 1.
  • Possibilita agora a cópia da API para a memória de impressoras de alto volume.
  • Tag scope para personalização de fontes.
  • Reformulação de vetores e adicionado: canto arredondados, polígono, etc.
  • Melhora do uso de templates registrando-os do dicionário interno da pilha PS.
  • As classes TextArea e Text foram reformuladas, suporte a alinhamento do texto, tags, e outros.
  • Virtual page.
  • Reestruturado o suporte ao ActiveRecord, agora podemos usar n Grid::Rails em um doc.
  • Alguns callbacks mudaram de posição como o before_page_create e o odd_pages.
  • Documentação em Inglês
  • o resto eu esqueci :)

Se alguém se interessar por traduzir o manual em português é só enviar um email para mim em pvt que eu mando o odt.

Agradeço a todos que reportaram bugs e me ajudaram a testar.

Desculpem a demora. Espero que gostem.

Distribuição com PL/Ruby e DbLink no Postgresql

Saturday, January 12th, 2008

Depois de uma escravização no fim do ano passado e no inicio deste, estou de volta para “espalhar a maldade”!

Vou falar sobre PL/Ruby ou melhor fazer funcionar.

PL/Ruby é uma linguagem procedural acoplada dentro do Postgresql. Entre as linguagem do Postgres é a mais flexível e fácil.
Demonstrarei inicialmente “o jeitão da coisa” e depois uma implementação distribuída.

Instalação
Instale o banco e o módulo plruby, se o postres já estiver instalado, instale apenas o módulo(claro!)

apt-get install postgresql-8.1 postgresql-8.1-plruby

Agora conecte via psql

psql template1

Criaremos um banco novo para todos os testes deste tutorial, o banco “ruby_test”, então vamos lá

template1=# create database ruby_test;

conecte no banco novo

template1=# \c ruby_test

Crie a função/linguagem via o script plruby.sql que faz parte do pacote postgresql-8.1-plruby, se a sua distro difere de ubuntu, verifique onde o arquivo plruby.sql está e invoque com \i semelhante ao exemplo abaixo.

ruby_test=# \i /usr/share/postgresql-8.1-plruby/plruby.sql

Jeitão
Para familiarizarmos um pouco vamos criar uma função que produz uma seqüencia de números separados por espaço.
Portanto a função abaixo cria um Range do primeiro argumento(args[0]) até o segundo argumento(args[1]), converte o range para Array e depois para String separando os elementos por espaço.

create or replace function string_array(int,int) returns text as $RUBY$


  (args[0]..args[1]).to_a.join " "

$RUBY$ language plruby;

Executando

ruby_test=# select string_array(10,20);

Produzindo

"10 11 12 13 14 15 16 17 18 19 20"

Agora uma função que procura um padrão dentro do um texto, se o padrão for encontrado, o mesmo ficará entre tags <b>.

create or replace function find(varchar,text) returns text as $RUBY$


  args[1].gsub(/(#{args[0]})/,'<b>\1</b>')

$RUBY$ language plruby;
ruby_test=# select find('[tT]he','The method PL#context and PL#context= give the possibility to store information between the call')

Produto

"<b>The</b> method PL#context and PL#context= give <b>the</b> possibility to store information between <b>the</b> call"

Até agora demonstramos duas funções, faz uma lógica e retorna apenas uma tupla.
Ficou bem elegante essa implementação do PL/Ruby para vários registros(setof) sendo que cada registro é um objeto lançado pelo operador yield do Ruby.
Uma função em PL/Ruby para resolver a função(x ao quadrado vezes a raíz de 2)

f(x) = x^2 * raiz(2)

sendo x inteiro variando de x1 a x2.

create or replace function fx(int,int) returns setof float as $RUBY$


  (args[0]..args[1]).each {|x|  yield x.to_i**2 * Math.sqrt(2) }

$RUBY$ language plruby;

Executando com * from pois estamos pegando vários registros

ruby_test=# select * from fx(1,10);

Resultando em

1.4142135623731
5.65685424949238
12.7279220613579
22.6274169979695
35.3553390593274
50.9116882454314
69.2964645562817
90.5096679918781
114.551298552221
141.42135623731

Manipulando dados
Vamos criar uma tabela denominada “users” para povoarmos de dados para os testes.

ruby_test=# CREATE TABLE users(
  id serial not null primary key,
  name varchar(255) not null ,
  login varchar(80),
  email varchar(80),
  password varchar(80)
) ;

Inserindo alguns registros

ruby_test=# insert into users(name,login,email,password) values ('Fulano de tal','fulano','fulano@server.com','fulanopwd');
ruby_test=# insert into users(name,login,email,password) values ('Maria da Silva','maria','maria.silva@server.com','mariapwd');
ruby_test=# insert into users(name,login,email,password) values ('Sem nome','semnome','semnome@server.com','semnomepwd');

Daqui a pouco faremos a distribuição dos dados via trigger para bancos remotos, portanto criaremos uma função para criação dos inserts.
A função make_insert faz engenharia reversa na ddl e nos dados utilizando o módulo PL disponível no plruby

CREATE OR REPLACE FUNCTION make_insert(users) RETURNS text AS $RUBY$

    row=args[0]
    tn=PL.args_type.to_s
    cn=row.keys.join(',')
    values= row.values.map{|m| (m)?"'#{m}'":'NULL' }.join(',')
    "INSERT INTO #{tn}(#{cn}) values (#{values})"

$RUBY$ language plruby;

Veja o exemplo da execução

ruby_test=# select make_insert(users) from users;

Resultado

INSERT INTO users(name,id,password,login,email) values ('Fulano de tal','1','fulanopwd','fulano','fulano@server.com')
INSERT INTO users(name,id,password,login,email) values ('Maria da Silva','2','mariapwd','maria','maria.silva@server.com')
INSERT INTO users(name,id,password,login,email) values ('Sem nome','3','semnomepwd','semnome','semnome@server.com')

Sem aquela concatenação demasiada do plpgsql usando pipes e aspas para todo lado. Ah! a função make_insert é genérica para qualquer tabela mas no argumento de criação a sua tabela. Tipo

CREATE OR REPLACE FUNCTION make_insert(sua_tabela) RETURNS text AS $RUBY$
...

Semelhante aos parâmentos tabela%rowtype do postgres.

Distribuindo os dados
Já vou dizendo logo, isso não é comparável ao Slony-I, isso é uma simples utilização do dblink do postgresql.
As funções de dblink ficam no pacote contrib do postgres, a instalação com apt-get

apt-get install postgresql-contrib-8.1

Crie as funções com \i onde o argumento é o arquivo dblink.sql

ruby_test=#  \i /usr/share/postgresql/8.1/contrib/dblink.sql

Lembrando a assinatura da função dblink_exec é

select dblink_exec("connection string","query")

Exemplo

select dblink_exec('hostaddr=127.0.0.1 dbname=mydb user=shairon password=senha','insert into...');

Partiremos da seguinte extrategia: criaremos uma tabela chamada nodes onde armazenaremos os dados dos bancos de dados, selecionaremos apenas os nodes ativos e enviaremos os registros para os mesmos através da trigger replica_plruby(T) no evento after insert na tabela users master(A).
Veja o diagrama abaixo.
replica_plruby.png

Então temos a tabela nodes.

create table nodes(id serial not null primary key, host varchar(80), username varchar(80), password varchar(80), active boolean )

Dados para teste

insert into nodes(host,dbname,username,password,active) values ('127.0.0.1','mydb1','foo','bar',true);
insert into nodes(host,dbname,username,password,active) values ('192.168.0.7','mydb2','foo','bar',true);
insert into nodes(host,dbname,username,password,active) values ('10.0.0.38','mydb3','foo','bar',true);

Criando a trigger replica_plruby, acompanhe pelos comentários

CREATE OR REPLACE FUNCTION replica_plruby() RETURNS trigger AS  $RUBY$

  #obtendo a quantidade de nós ativos
  count=PL::exec("select count(*) from nodes where active=true",1,"value").to_s.to_i
  if count > 0
     #obtendo os nós ativos
     PL::Plan.new("select * from nodes where active=true").each do |row|
       #montando a conexão
       #cada row é um hash  tipo {"dbname"=>"delme", "username"=>"shairon" ...}
       conn="hostaddr=#{row['host']} dbname=#{row['dbname']} user=#{row['username']} password=#{row['password']}"
       #Nome das culunas via metadata
       keys  = new.keys.join(",")
       #Os valores com tratamento de nulo
       values = new.values.map{|m| (m)?"''#{m}''":'NULL' }.join(',')
       #Query final
       query = "INSERT INTO #{tg['relname']}(#{keys}) values (#{values})"
       #Disparo
       PL.exec("select dblink_exec('#{conn}','#{query}')")
     end
  end
  new
$RUBY$ LANGUAGE plruby;

Pronto! Insira novos dados na tabela users para ver o resultado.

Referências
Nos arquivos de documentação dos pacotes

ruby1.8
postgresql-8.1
postgresql-8.1-plruby
postgresql-contrib-8.1

Executive IT Meeting em Goiânia

Friday, October 26th, 2007


Gostaria de Convidar a todos a participarem do Executive IT Meeting l em Goiânia, 29..31 de outubro de 2007.
Vou representar a comunidade(espero ser capaz) :)
O meu amigo Alexandro Lima fez uma Charge para o evento.

palestra_rubi_contec.jpg

Nossa participação será no dia 31 na parte da tarde:

Palestra: Linguagem Ruby - Minerando e Lapidando.
Filosofia, idiossincrasia e pragmática da linguagem.

Tutorial: Ruby on Rails - Overview sobre o Framework do Ano.
Desenvolvendo um aplicação MVC em Rails.

Espero vcs lá hein! :)