HashCode

An organizer of symbols

Archive for the ‘Linguagens’ Category

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 …

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?

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

Shared Object Híbrido, Java e Ruby

Saturday, September 29th, 2007

Pense em dois softwares, ambos monitoram um dispositivo via driver, aparentemente iguais diferindo apenas pela linguagem em que foram concebidos, um em Java e outro em Ruby. Conseqüentemente, duas bibliotecas fazendo interface entre o driver e o ambiente da linguagem de auto nível.
Resolvi me aventurar nessa idéia e criei uma solução híbrida, uma biblioteca compatível com Ruby e Java.
jni_ruby.png
Testei com um SmartCard, como é algo específico(e você não vai comprar um só pra testar isso :)) usarei a função getenv definida em stdlib.h .

Vamos dividir em três estágios:
- Criar um teste jni(java)
- Criar um teste em ruby(Extending)
- Juntar Java e Ruby com C

Ingredientes(debian packages)
- sun-java6-jdk
- ruby1.8
- ruby1.8-dev
- gcc-4.1

Java

Vamos seguir este fluxo

jni_java_flow.png

Crie um diretório “java” para o teste. Entre no diretório.

1. Criar o arquivo fonte java
Primeiramente crie o arquivo EnviromentVariable.java que depois de compilado será o protótipo para implementação em C.

 class EnviromentVariable {  

  public native String get(String varname);  

 }

2. Gerar o bytecode
Compile

 javac EnviromentVariable.java

3. Gerar os headers

 javah -jni EnviromentVariable

O javah criará um arquivo .h com o conteúdo

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class EnviromentVariable */
#ifndef _Included_EnviromentVariable
#define _Included_EnviromentVariable

#ifdef __cplusplus
extern "C" {
#endif
/*

 * Class:     EnviromentVariable
 * Method:    get
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */

JNIEXPORT jstring JNICALL Java_EnviromentVariable_get(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

4. Criar o arquivo fonte C
Agora faremos a lógica da biblioteca, portando é necessário a criação do arquivo enviroment_variable_java.c com o conteúdo


#include  <stdio.h>
#include  <stdlib.h> //getenv vem daqui
#include "EnviromentVariable.h"

JNIEXPORT jstring JNICALL Java_EnviromentVariable_get(JNIEnv *jvm, jobject obj, jstring varname){
  //Convertendo uma String Java em C String
  char * c_varname=(char *) (*jvm)->GetStringUTFChars(jvm, varname,NULL);

  //Obtendo o valor da variável e criando uma string para retorno
  return (*jvm)->NewStringUTF(jvm, getenv(c_varname) );
}

5. Gerar o shared object
O home da JVM na minha máquina está em /usr/lib/jvm/java-6-sun, verifique na sua distro onde foi instalada. Pra facilitar export a variável JAVA_HOME

export JAVA_HOME=/usr/lib/jvm/java-6-sun

Agora vamos gerar o libEnviromentVariable.so

gcc enviroment_variable_java.c \\
-shared -o libEnviromentVariable.so\\
-I. -I$JAVA_HOME/include -I$JAVA_HOME/include/linux

6. Testando
Para testarmos, crie um arquivo Main.java com o conteúdo.

class Main{
 static{
   System.loadLibrary("EnviromentVariable");
 }
 static public void main(String args[]){
  System.out.println(new EnviromentVariable().get("PATH"));
 }
}

Observe a cima vamos pegar o valor da variável PATH do seu sistema. Lembrando que a variável tem que existir.
Compile Main.java

javac Main.java

Execute o programa Main com a opção -Djava.library.path=”O diretório onde está o .so” no nosso caso em ‘.’

java -Djava.library.path=. Main

O output semelhante a

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/local/shairon/bin:/usr/lib/jvm/java-6-sun/bin

Depois teste mudando a variável PATH para uma outra variável válida.

Ruby

Vamos seguir o fluxo
jni_ruby_flowx.png
Crie outro diretório no mesmo nível do java mas com o nome de “ruby”. Entre do diretório.

1. Criar o arquivo fonte ruby

Crie o arquivo enviroment_variable_ruby.c conforme abaixo.

#include  <ruby.h>
#include  <stdlib.h>

static VALUE t_get(VALUE self, VALUE varname){
    //Converte String Ruby em C String
   char *c_varname=STR2CSTR(varname);

   //Obtendo o valor da variável e criando uma string para retorno
   return rb_str_new2( getenv(c_varname)); 

}

VALUE cEnviromentVariable;

//Função de inicialização do arquivo
void Init_libEnviromentVariable() {

  //Cria a classe EnviromentVariable
  cEnviromentVariable = rb_define_class("EnviromentVariable", rb_cObject);

  //Associa o método t_get com EnviromentVariable#get
  rb_define_method(cEnviromentVariable, "get", t_get, 1);
}

2. Criar o arquivo para geração do makefile

Vamos criar o arquivo extconfig.rb para geração do makefile. Abaixo

require "mkmf"
create_makefile("libEnviromentVariable")

Execute

ruby extconfig.rb

3. Compile e instale

make

depois

make install

Abrao irb e digite:

require 'libEnviromentVariable'
puts EnviromentVariable.new.get("PATH")

Java e Ruby estão chamando diretamente o getenv, algo fácil pois é só uma chamada de função. Imagine se fosse algo mais complexo? O desenvolvedor iria reutilizar o código em C via copy-paste, nada elegante.
Daqui em diante vamos fazer Ruby e Java usar uma função comum e gerar apenas um Shared Object.

Solução Híbrida

Antes de mais nada observe que o módulo “mkfm” identifica onde estão os headers necessários para a compilação do .so em ruby, durante a compilação aparece o caminho detectado, no meu caso em /usr/lib/ruby/1.8/i486-linux, portanto declarare um variável de ambiente RUBY_HOME para facilitar o entendimento.

export RUBY_HOME=/usr/lib/ruby/1.8/i486-linux

Agora o arquivo que compartilha a mesma função entre Java e Ruby, o arquivo enviroment_variable.c. Verifique a disposição dos seus arquivos e diretório. A estrutura usada é:
1p.png

O conteúdo de enviroment_variable.c, acompanhe pelos comentários.

#include 
#include "java/EnviromentVariable.h"
#include 
#include 

//Função que será compartilhada

char *var(char *varname){
  return getenv(varname);
}

//JAVA SIDE
JNIEXPORT jstring JNICALL Java_EnviromentVariable_get(JNIEnv *jvm, jobject obj, jstring varname){

  char * c_varname=(char *)(*jvm)->GetStringUTFChars(jvm, varname,NULL);

 //Chama a função var e retorna uma String para JVM
  return (*jvm)->NewStringUTF(jvm, var(c_varname) );
}

//RUBY SIDE

static VALUE t_get(VALUE self, VALUE varname){
  char *c_varname=STR2CSTR(varname);
  //Chama a função var e retorna uma String para JVM
  return rb_str_new2( var(c_varname));
}

VALUE cEnviromentVariable;

void Init_libEnviromentVariable() {
  cEnviromentVariable = rb_define_class("EnviromentVariable", rb_cObject);
  rb_define_method(cEnviromentVariable, "get", t_get, 1);
}

Linkando e Compilando

Lembrando que já definimos as variáveis de ambiente $JAVA_HOME e $RUBY_HOME.

Gerando o objeto

gcc -c enviroment_variable.c \
-fPIC -Wall -g -fno-strict-aliasing -O2 \
-I$RUBY_HOME \
-I$JAVA_HOME/include \
-I$JAVA_HOME/include/linux

depois o Shared Object

gcc -L"/usr/lib" \
-shared -o libEnviromentVariable.so enviroment_variable.o \\
-I$RUBY_HOME \\
-I$JAVA_HOME/include \\
-I$JAVA_HOME/include/linux \\
-lruby1.8 -lpthread -ldl -lcrypt -lm -lc

Pronto! Geramos o bacalhau :) o arquivo libEnviromentVariable.so está pronto para ser usado.
Testando em java

java -Djava.library.path=. -cp ./java Main

em Ruby pelo irb

require 'libEnviromentVariable'
puts  EnviromentVariable.new.get("PATH")

Alguns outputs do irb

rb(main):001:0> require 'libEnviromentVariable'
=> true
irb(main):002:0> envs=EnviromentVariable.new
=> #
irb(main):003:0> envs.get("USERNAME")
=> "shairon"
irb(main):004:0> envs.get("TERM")
=> "xterm"
irb(main):005:0> envs.get("SHELL")
=> "/bin/bash"

obs.: depois troque enviroment por environment. :)

Referências

Extending Ruby
Java Native Interface Specification

Ruby Consumindo Objetos Java via RMI

Wednesday, September 12th, 2007

Demonstrarei uma solução de um programa Ruby consumindo um objeto Java via RMI. Usarei o gem Rjb - Ruby Java Bridge.

Ingredientes
+ debian packages
- sun-java6-jdk
- ruby1.8
- ruby1.8-dev
- gcc-4.1
+ ruby gem
- rjb

Instalação
Instale os pacotes, antes de instalar o gem RJB verifique as variáveis de ambiente JAVA_HOME e LD_LIBRARY_PATH, pois durante instalação do gem será compilado um objeto.

JAVA_HOME apontando para o home da JVM(os paths a seguir são relativos ao Ubuntu, verifique onde está a JVM na sua distro)

export JAVA_HOME=/usr/lib/jvm/java-6-sun

LD_LIBRARY_PATH apontando para os shared objects da JVM

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386/client

Agora o gem
Instalação normale

gem install rjb

O gem perguntará qual versão você gostaria de instalar, estou usando a 1.0.6.

Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i486-linux)
 1. rjb 1.0.6 (ruby)
 2. rjb 1.0.6 (mswin32)
 3. rjb 1.0.4 (ruby)
 4. rjb 1.0.4 (mswin32)
 5. Skip this gem
 6. Cancel installation
> 1
Building native extensions.  This could take a while...
Successfully installed rjb-1.0.6

Montando a estrutura do RMI
No nosso teste vamos ler um arquivo em Java passando o caminho do arquivo. Vamos aos passos.

Criando a interface

import java.rmi.RemoteException;
import java.rmi.Remote;

public interface AbstractAnyFile extends Remote {
    String get(String filePath) throws RemoteException;
}

Depois a implementação da interface com a lógica de leitura do arquivo.

import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
import java.io.*;
public class AnyFile extends UnicastRemoteObject implements AbstractAnyFile {

  public AnyFile() throws RemoteException { }

  public String get(String filePath) {

    try{
      InputStream in = new FileInputStream(new File(filePath));
      StringBuilder ret = new StringBuilder();
      int lidos=0;
      byte b[] = new byte[2048];
      String temp = null;
      while ( (lidos=in.read(b)) != -1){
         temp = new String(b,0,lidos);
         ret.append(temp);
      }
      return ret.toString();
    }catch(Exception e){
       return "Deu pau "+e;
    }
  }

  static void bind(){

    try { 

      Naming.rebind("RemoteFile", new AnyFile() );

    }catch(Exception e){
      System.out.println("Problema ao inicializar " + e.getMessage());
    }
   }

  static public void main(String args[]) {  AnyFile.bind();  }
}

lembranças do passado …
Observe que registramos um objeto AnyFile com o nome de RemoteFile.

Levantando o servidor(Binding)
Copile os .java

javac *.java

Gere o stub

rmic AnyFile

Inicie o rmiregistry(em background)

rmiregistry &

Inicie o servidor

java AnyFile

Do lado Ruby(cliente)
Acompanhe pelos comentários

require 'rubygems'
require 'rjb'

#garantindo a localização da JVM
ENV['JAVA_HOME']='/usr/lib/jvm/java-6-sun'

#Iniciando a JVM
Rjb::load

#Atribuindo a classe Naming a variável naming
naming = Rjb::import('java.rmi.Naming')

#Obtendo o objeto AnyFile pelo nome de RemoteFile(já associado)
myfile = naming.lookup('//127.0.0.1/RemoteFile')

#Obtendo o arquivo remoto '/tmp/teste.txt' através do objeto myfile e imprimindo
puts myfile.get("/tmp/teste.txt")

“Se der tudo certo vai funcionar :)”

Possíveis problemas
Quando for instalar o gem

Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.

ruby extconf.rb install rjb
checking for jni.h... no
*** extconf.rb failed ***

Falta de exportar as variáveis JAVA_HOME e LD_LIBRARY_PATH ou não encontrou a JVM.

Em ruby

-:7:in `load': can't create Java VM (RuntimeError)
	from -:7

Também não achou a JVM

Composição de funções em pilha

Tuesday, September 11th, 2007

Lendo e testando o post do Tom Moerte sobre
Composição de funções em Ruby traduzido pelo Akita e refatorado pelo TaQ, a solução de composição de blocos/funções baseai-se em um operador de composição(em Haskell) para geração de uma nova função, simplificando o cálculo e dividindo o problema em partes.

Já em Postscript é implícita tal composição. Por ser uma Linguagem de Programação Orientada a Pilha com a sintaxe Pós-Fixada (Notação Polonesa Invertida) os argumentos e os operadores ficam em um contexto único(pilha), facilitando a execução de cálculos matemáticos sem a necessidade de criar um operador “que junta as funções e passa os parâmetros”. Muito mais simples. Acompanhe.

Primeiramente observe a função

f(x) = X² + 1

Portando para X= 3, temos

f(3) = 3² + 1
f(3) = 10

a mesma função em notação polonesa com operadores postscript

3 2 exp  1 add

quando é executado 3 2 exp o resultado 9 fica na pilha, o valor 1 também está na pilha então 9 1 add resulta em 10. Veja no ghostscript o passo-a-passo(pstack mostra os valores da pilha)

GS>3
GS<1>2
GS<2>pstack
2
3
GS<2>exp
GS<1>pstack
9.0
GS<1>1
GS<2>pstack
1
9.0
GS<2>add
GS<1>pstack
10.0

Vamos criar as funções

/square { 2 exp} def         % eleva ao quadrado o valor corrente
/inc { 1 add } def         %adiciona 1 no valor corrente

testando

GS>3 square
GS<1>pstack
9.0
GS<1>inc
GS<1>pstack
10.0

A composição
Apenas aninhar as funções

/nova{ square inc } def
GS>3 nova
GS<1>pstack
10.0

Programação em pilha tem lá suas vantagens mas não é nada humano.

Append em arquivo no Postgresql via módulo em C

Friday, August 24th, 2007

Estava desenvolvendo um sistema de distribuição de dados no Postgresql e tive a necessidade de armazenar em um arquivo as inserções caso houvesse erro. Relatarei aqui uma solução desenvolvida um módulo(zinho) em C.

Pacotes necessários para a compilação
Na verdade eu não sei bem se os outros são necessários mais o postgresql-server-dev-8.1 é certeza :)

postgresql-8.1
postgresql-client-8.1
postgresql-contrib-8.1
postgresql-server-dev-8.1

Função

#include <stdio.h>
#include "postgres.h"
#include <string.h>
#include "fmgr.h"

//Registrando a função log_pg no escopo do postgres
PG_FUNCTION_INFO_V1(log_pg);

//Datum é o tipo esperado, cast automático do int de retorno
Datum log_pg(PG_FUNCTION_ARGS){

//PG_GETARG_TEXT_P(0) pega o primeiro argumento
//VARDATA faz cast para char *
  char *filename = VARDATA(PG_GETARG_TEXT_P(0));

  FILE *fp;

  if ((fp = fopen(filename, "a"))==NULL)  {
    printf("Cannot open file \n");
    return 1;
  }else{
   //Pega o segundo argumento já convertido para char *
    fputs(VARDATA(PG_GETARG_TEXT_P(1)),fp);
    fclose(fp);
    return 0;
   }
}

Salve o arquivo como log_pg.c
Compile

gcc -fpic -I/usr/include/postgresql -I/usr/include/postgresql/8.1/server -c log_pg.c

Gere o Shared Object

gcc -shared -o log_pg.so log_pg.o

No meu caso a dynamic_library_path está apontando para /usr/lib/postgresql/8.1/lib/ portanto, o log_pg.so vai pra lá.

install log_pg.so  /usr/lib/postgresql/8.1/lib/log_pg.so

Agora no Postgresql duas funções, uma mapeia o log_pg.so em log_me

CREATE or replace FUNCTION log_me(varchar,varchar) RETURNS int
 AS 'log_pg.so', 'log_pg' LANGUAGE C;

e a outra uma abstração para gerar a data corrente e concatena .log ao fim do nome do arquivo (melhor que usar strcpy).

create or replace function logger(varchar,varchar) returns int as $BODY$

  begin
    return log_me(($1 || current_date::varchar ||'.log')::text,$2::text);
  end
$BODY$ language 'plpgsql';

Testando

select logger('/tmp/teste', 'meu primeiro teste');

Saiba mais … libpq - C Library

(’asterisco’ == 42.chr) != ?* => true

Wednesday, June 27th, 2007

Estava comprando alguns livros e achei um de promoção “O Signo, de Isaac Epstein” foi baratinho, mas também oitenta páginas… O livro em si me despertou um grande interesse pelo assunto de semiótica. Não demorou para que adquirisse o livro “Semiótica, de Charles S. Peirce” que define semiótica como a filosofia científica da linguagem. Linguagem no sentido de algo provê a comunicação entre duas ou mais coias através de elementos, como signos, sons, símbolos, mímicas e outros. A Semiótica é redefinida por vários autores mas a definição de Charles detêm minha atenção mais do os outros que consideram apenas uma disciplina da cadeira de lingüística.

Na graduação de Ciência da Computação a matéria que mais me interessou(e interessa) foi(é) Linguagens Formais e Compiladores, vendo a formação dos componentes de uma gramática, a validação, organização e significado de símbolos e palavras de um determinado código-fonte. Os passo dos analisadores léxicos, sintáticos e semáticos nada mais é do um dos nossos sistemas de interpretação de mensagens.

Desde a infância passamos pelos mesmos processos te entendimento dos signos e vamos adquirindo base de conhecimento capacitando-nos a detecção de padrões dos mais simples aos mais complexos, como: “se há fumaça => há fogo”, “se algo está úmido => é porque tem algo líquido”. Parece fácil mas as vezes ao pensarmos em uma solução nos deparamos com a falta desta comparação do que conhecemos e o que é novo.
Vamos fazer um estudo de caso de um símbolo o asterisco.

O Asterisco

Se perguntarmos o que é * a uma criança que não conhece a palavra asterisco teremos entre outras respostas algo como “é uma estrelinha”, “um pontinho explodido”…. Para um adulto a afirmação é um “asterístico” e para os mais sensatos “asterisco” lexicograficamente correto. Portando entramos na idiossincrasia; que é a forma de percepção individual do símbolo. Por exemplo, cada um tem o asterisco como um símbolo que representa algo de forma distinta.

Qual a função(significado) do símbolo asterisco?

Não sei. Depende da linguagem, do contexto em que se encontra.

Para a língua portuguesa ele não faz parte da gramática e nem do alfabeto. Em anúncios sabemos que ele é o “porem ou o lá-invem!”. Exemplo.: ‘Fale a R$ 0,01*’, nas letras bem pequenas temos ‘promoção válida somente para falar que ama sua sogra no dia 30 de fevereiro’. Em alguns livros o * induz ao leitor ler o rodapé explicativo, etc. Já na informática comum pode ter vários significados. Temos alguns:

- Em um editor de texto moderno tenta detectar que o * é um marcador e troca por uma bolinha.
- Caractere de multiplicação
- Todos arquivos em uma lista de arquivos. Ex: ls *.txt

Veja a cima que o asterisco é também um ‘Caracter de multiplicação’. Agora você lembra da terceira série que o x era o sinal de multiplicação? E mais adiante …

2 x 2 = 4

depois

2 . 2 = 4

e agora no computador

2 * 2 = 4

Calma, não fique louco, já passamos desta fase… mas deu para entender um pouco sobre idiossincrasia. A sua idiossincrasia tem que ser mutável principalmente para usar a linguagens de programação como C e Ruby. Em C temos ponteiro com * para o valor e ** ponteiro para apontador…, comentários e assim vai. Demonstraremos abaixo como o asterisco pode ser genérico em uma linguagem computacional, Ruby.

Asterisco em Ruby
O caracter

42.chr #=> '*'

o valor ASCII do caracter

?*   #=> 42

Em Ruby o asterisco pode ser um método
Multiplicação (Numeric * Numeric)

2 * 2       #=>  	4

Potenciação (Numeric ** Numeric)

2**3	  #=> 8

Classe String(String * Numeric)

'ha! '  * 5	#=> 'ha! ha! ha! ha! ha! '

Classe Array (Array * String)

[20, 30, 40] * ':'   #=> '20:30:40'  o mesmo que join

Observe que o resultado que é a multiplicação de todos os elementos e não uma operação distributiva de matemática. (Array * Fixnum)

[20, 30, 40] * 2 #=> [20, 30, 40, 20, 30, 40] 

mas podemos redefinir o método * para um resultado diferente

a=[20, 30, 40]
def a.*(valor)
  self.map{|v| v*valor}
end
a * 2     #=> [40, 60, 80]

Expressões Regulares, zero ou mais ocorrências

a='asterisco'
a =~ /a*/      #=> 0
a =~ /z*/      #=>0

Atribuição
Atribuição com multiplicação

d=2
d*=2   #=> 4

Atribuição com potenciação

d=2
d**=3  #=> 8

Atribuição paralela

a=[1,2,3,4]
x,y=a      #=> x =1 e y=2
x,*y=a    #=> x=1 e y=[2,3,4]
x,*y=33  #=> x=33 e y=[]

Conversão em Array de um argumento de bloco

a=[1,2,3,4,5]
a.each {|v| puts v}
1
2
3
4
5
a.each {|*v| puts v}
[1]
[2]
[3]
[4]
[5]

Argumentos de linha de comando

ruby -e 'puts $*' teste1 teste2

resultado

teste1
teste2

equivalente ao ARGV

ruby -e 'puts ARGV' teste1 teste2

resultado

teste1
teste2

Utilização em argumentos
Na definição do método

def teste(um_valor, *argumentos)
  puts 'valor = '  + um_valor.to_s
  puts 'args = '  + argumentos.join(', ')
end

utilizando o método teste

teste('A',2,'B',4,5,6,7)

resultado

valor = A
args = 2, B, 4, 5, 6, 7

passando um array

array=[20,'C',40,'D']
teste(array)

resultado

valor = 20C40D
args =

mas com a mágica do *

array=[20,'C',40,'D']
teste(*array)

resultado

valor = 20
args = C, 40, D

o mesmo vale para o case. Case normal

s='teste'
case s
  when Fixnum: puts 'N'
  when String,Symbol: 'S'
 end

resultado

'S'

podemos fazer assim com *

s='teste'
tipos=[String,Symbol]
case s
  when Fixnum: puts 'N'
  when *tipos: 'S'
 end

resultado

'S'

Asterisco em Ruby dá nó na cabeça mas depois começamos a entender a idiossincrasia do Matz.