Novidades Rails E Mootools

julho, 4 - 2008

Pessoal, está muito dificil continuar mantendo o blog, estou totalmente sem tempo, as postagens já diminuiram consideravelmente. Peço desculpas e paciência a todos que lêem (liam) o blog, um dia voltarei ao ritmo de antes. Mas para não deixar passar, vou deixar links para dois assuntos sobre os quais eu queria falar mas não consegui:


Efeitos Na Mootools

março, 12 - 2008

Voltei pessoal! E falando da Mootools, que andei estudando recentemente, mais especificamente sobre efeitos, uma parte muito divertida e legal.
Os efeitos na Mootools são divididos em algumas classes, que estão dentro de Fx, cada uma delas com um objetivo diferente. Falarei hoje nesse post da Fx.Style, Fx.Styles e inevitávelmente da Fx.Transitions, as duas primeiras basicamente mudam uma propriedade de estilo CSS gradualmente ao longo de um tempo de acordo com uma determinada transição, que está contida dentro da última classe referida. A principal diferença entre as duas classes é que a primeira só aplica efeito sobre uma propriedade e a segunda sobre mais de uma propriedade, as duas relacionadas a um elemento.

Transições

A classe Fx.Transitions nos fornece uma lista de transições, que alterarão a animação, para serem usadas em nossos efeitos. Transições são responsáveis por modificar os valores intermediarios entre o inicio e o fim de uma animação. Por exemplo, quando se quer modificar a largura de um elemento de 10 a 15 pixels, a transição será responsável por definir que, por exemplo, no 300º milissegundo da animação a largura terá 12 pixels. Cada transição, exceto a linear, contem 3 opções de easing:

  • easeIn: o efeito é mais intenso no ínicio da animação
  • easeOut: o efeito é mais intenso no final da animação
  • easeInOut: o efeito é mais intenso no ínicio e no final

Escolhida a transição e o método easing, você pode obte-lá desse modo:

// Fx.Transitions.[tipo de transição].[método easing]
Fx.Transitions.Sine.easeInOut

A dica pra escolher a combinação certa é testando, verifique cada transição nesse demo de transições.

Alterando Uma Única Propriedade CSS Com Fx.Style

Primeiro nos precisamos decidir o elemento que receberá o efeito, depois disso temos dois meios de criar o efeito. O primeiro, clássico, usando o construtor, que aceita três argumentos: o primeiro o elemento em si, o segundo a propriedade CSS que será modificada e o terceiro uma lista de opções:

var obj = $("box");
var fx = new Fx.Style(obj, "height", {
	"transition": Fx.Transitions.Sine.easeInOut, // Transição a ser usada na animação
	"duration": 1000, // Duração em milissegundos
	"unit": "px", // Unidade usada para alterar a propriedade
	"wait": true, // Aguardar ou não a animação anterior de mesma instância para começar
	"fps": 50 // Quadros por segundo da animação, quanto maior melhor e mais lento
});

O segundo meio, que eu prefiro, é um atalho no próprio objeto (instância de Element), o método effect, que recebe os argumentos 2 e 3 iguais do construtor acima:

var obj = $("box");
var fx = obj.effect("height", {
	// Mesmas opções
});

Terminada a criação do efeito, temos que iniciá-lo efetivamente, para isso temos o método start. Ele aceita 1 ou 2 argumentos, no primeiro caso o primeiro argumento é o valor final da propriedade, o inicial será o valor atual:

fx.start(350); // O objeto terá a largura igual a 350 pixels no final

Já no segundo caso, o primeiro argumento é o valor inicial e o segundo o final:

fx.start(10, 350); // O objeto terá 10 pixels no ínicio do efeito e 350 depois de terminado

Dica: Se você for alterar a mesma propriedade várias vezes não crie uma nova instância a cada vez, use a que já foi criada e chame o método start pra cada efeito.
Pronto, bem mais legal do que mudar propriedades sem efeito, né?!

Alterando Várias Propriedades CSS Com Fx.Styles

Quase a mesma coisa que a classe Fx.Style, porém algumas diferenças. Continuamos com 2 meios de se obter a instância, ou pelo construtor, que aceita 2 argumentos iguais ao anterior: o elemento e as opções, a exeção é o nome da propriedade que será modificada, já que são mais de uma propriedades elas serão definidas na hora de iniciar o efeito:

var obj = $("box");
var fx = new Fx.Styles(obj, {
	// Mesmas opções
});

Ou pelo método effects do objeto:

var obj = $("box");
var fx = obj.effects({
	// Mesmas opções
});

Agora vamos iniciar o efeito, a diferença principal para Fx.Style é que é aqui que serão definidos os valroes das propriedades atrávez de um objeto (JSON):

fx.start({
	"height": 350, // Efeito iniciará com altura atual e terminará com 350 pixels
	"width": [10, 350], // Efeito iniciará com largura 10 pixels e terminará com 350 pixels
	"background-color": ["#FF0000", "#0000FF"], // Cor de fundo vermelha no início e azul no final
	"color": "#FFFFFF" // Cor do texto atual no início e branca no final
});

Como se pode perceber, se você fornecer um Array como valor da propriedade, o primeiro elemento será o valor para ser usado no início do efeito e o segundo no final, ou se fornecer somente um valor, esse será o valor final e o inicial será o valor atual da propriedade.
A mesma dica anterior também vale aqui, porém como aqui se modificam várias propriedades, a regra é: se você tiver que aplicar vários efeitos a um elemento várias vezes, use a mesma instância e chame o método start.

Viu como não é difícil brincar com a Mootools, gostei muito do suporte a efeitos, animações, esse tipo de coisa, é muito transparente, quem já implementou (ou tentou implementar) algo assim sabe como é difícil fazer um trabalho bem feito e ao mesmo tempo simples de se usar. Esse é um ponto forte da Mootools.

Flws pessoal, até a próxima!


Javascript, Ruby On Rails E O Blog

agosto, 27 - 2007

Pessoal,

O tempo tá meio apertado (ok, sempre a mesma desculpa), por isso a falta dos posts mais frequentes. Vou reiniciar falando de duas coisas, ou melhor, frameworks.

Quem acompanha o blog sabe que, há um tempo, eu estava desenvolvendo um framework Javascript que partiu de diversos códigos usados nos meus projetos. Então, a idéia foi pro ralo, um dos motivos da desistência foi o fato do único mantedor ter sido eu, além dos outros frameworks terem crescido em qualidade e funcionalidades, não dava pra acompanhar. Apesar de parecer um total fracasso, não foi, com esse framework que estava desenvolvendo, realmente aprendi Javascript, diversos conceitos, práticas, técnicas, integração com CSS, DOM, etc. Aprendi o que os frameworks atuais fazem por baixo dos panos, aprendi a usar melhor essa linguagem simples, e usa-la sem comprometer a acessibilidade. Depois disso passei um tempo sem mexer mais com Javascript. Voltei! E percebi que realmente há a necessidade de usar um framework ativo, testei (não intensamente) alguns deles, jQuery, Prototype (junto ao Scriptaculous), e Mootools. Sei que a maioria ama jQuery, fui ver, achei realmente muito simples, mas não gostei, é simples demais para o que quero. Prototype, já imaginava ser a minha escolhida, mas achei grande demais, com a Scriptaculous então, parecia um monstro, e sem muitas das facilidades dos novos frameworks. Mootools, pra mim a menos cotada, nem testaria não fosse o Júlio ter postado sobre ela, fui ver mais de perto, perfeita! Não é um monstro, é fácil, flexível, e o que mais me impressionou foram as animações (Fx!), muito bem acabadas, eventos próprios, o básico que as outras libs tinham e poder selecionar só o que preciso para baixar. Foi o bastante para tomar a decisão. Usarei Mootools de agora em diante. Sei muito pouco (quase nada) sobre ela ainda, terei que estudá-la, mas infelizmente não será imediatamente agora. É minha escolha por enquanto.

Agora sobre framework web, já faz algum tempo que venho estudando Ruby e Rails, mas só agora parece que adquiri o mínimo de conhecimento, me sentia muito inseguro nele, e grande parte por causa do PHP, ou melhor do modo como eu usava o PHP, scripts com consulta ao BD junto de HTML, códigos sujos, etc. Cheguei no Ruby com algum conhecimento de orientação a objetos grande parte por causa do Javascript (Objetos, Closures, etc.), mas ainda num território muito novo, eram muitas coisas novas, e o pior foi que parti direto pro Rails sem nem estudar Ruby antes, aí que me sentia perdido mesmo. Percebi que precisava aprender Ruby puro antes, comecei a fazer códigos Ruby, e me familiarizar, gostei bastante. Parti pro Rails e comecei a entender como as coisas funcionavam, fiz projetos de teste, etc. Agora já estou “contaminado”, pretendo estudar mais e usar bastante Rails de agora em diante.

Portanto o meu blog vai continuar sendo o que sempre foi, o bom e velho XHTML, CSS, Javascript (tradicionais scripts, Mootools e tentarei melhorar o Dynamic History) e tentarei postar mais um pouco de RoR.

Abraço pessoal! Flwss….

Powered by ScribeFire.


Recuperando E Substituindo Texto Selecionado

agosto, 9 - 2007

Galera, vou passar rápido pra postar esta função que recupera e substitui um texto selecionado em um objeto (textarea ou input).

O primeiro parâmetro é o objeto (String com id ou objeto DOM) aonde você quer manipular o texto selecionado, o segundo um booleano, que define se o método para substituir o texto do objeto retornado somente adicionará o texto caso não haja seleção. A função retorna um objeto simples com uma propriedade text que contem a String com o texto selecionado e o método setText() que aceita um parametro que é o texto a ser colocado no lugar do texto selecionado. Abaixo a função:

function selection(obj, set_text_default){
	/* @author Bernardo Rufino
	 * @license Creative Commons Developing Nations: http://creativecommons.org/licenses/devnations/2.0/
	 * @description Function to manipulate the actual selection
	 * @returns It returns an object with an attribute *text* with the current selection text and
	 *		  a method *setText()* that receives one argument, the text to be set in the selection.
	 * @parameters The first is the object where you want the selection (DOM or String with id), and
	 *			 the second (optional), a boolean, if is true then the *setText()* method will
	 *			 append the text if there's no way to replace the selection.
	 *
	 *	   !Nao retire essas informacoes!
	 *	   !Do not drop this information!
	*/
	if(obj.constructor == String){obj = document.getElementById(obj);}
	var set_text = (set_text_default) ? function(text){obj.value += text;} : function(){return false;};
	var selection = {text: "", setText: set_text};
	if(document.selection){
		var range = document.selection.createRange();
		if(range.text){
			selection.text = range.text;
			selection.setText = function(text){
				range.text = text.replace(/\r?\n/g, "\r\n");
			}
    }
	} else if(typeof(obj.selectionStart) != "undefined"){
		selection.text = obj.value.substring(obj.selectionStart, obj.selectionEnd);
		selection.setText = function(text){
			obj.value = obj.value.substring(0, obj.selectionStart) + text + obj.value.substring(obj.selectionEnd);
		}
	} else if(window.getSelection){
		selection.text = window.getSelection().toString();
	}
	return selection;
}

Exemplo abaixo usado muito em editores de fóruns para inserir tags BBCode:

var selected = selection("text", true); //Objeto input ou textarea com id "text"
selected.setText("[b]" + selected.text + "[/b]");

Dê uma olhada no exemplo com tags.
Falows pessoal!


Dynamic History – Implementando

junho, 8 - 2007

Antes de usar o Dynamic History é aconselhável que você leia uma introdução às páginas web primeiro, é rápido. Antes de continuarmos vou descrever como funciona. Para ver os exemplos vá até o final da página.

Para implementar o histórico dinâmico em seu site, são necessários 2 arquivos, o primeiro é um HTML contendo o código do iFrame (control.htm) que é usado para registrar os eventos no IE e o segundo é o código do script (dynamic_history.js), este se quiser pode ser colado em conjunto com outros códigos ou salvo em um arquivo separado e chamado nas páginas que o utilizarão. Agora que você já sabe como funciona, vamos à implementação.

Download

Você pode copiar e colar os códigos ou baixar o arquivo ZIP contendo os 2 arquivos necessários.

Salvando os arquivos

Agora que você já tem os arquivos em mão coloque o dynamic_history.js em qualquer subdiretório (ou coloque seu conteúdo junto de outro script como dito) de seu site e chame-o na página colocando o seguinte código dentro de <head>:

<script src="dynamic_history.js" type="text/javascript"></script>

Especifique no atributo src o diretório onde ele estiver. Agora coloque também o arquivo control.htm no seu site. Os dois podem ficar em qualquer lugar na estrutura de arquivos, mas vale lembrar que se o control.htm for colocado em algum diretório diferente do qual a página, que utilizará o script, está será necessário configurar seu endereço absoluto depois, nada demais.

Configurando

Você pode pular essa etapa, as configurações padrões já servem, ou se preferir especifique o diretório do iFrame e outras configurações. Abra o arquivo dynamic_history.js e edite o código entre as linhas 29 e 31.

28     settings: {
29         interval: 100, //The interval which the verification for new data will be done (in miliseconds)
30         helper: true, //Specify if the onnavigate function will return the helper
31         iframe_src: "control.htm" //The location of the file control.htm, absolute path please
32     },

Na linha 29 você coloca um numero que será o intervalo de tempo que o script verificará novas mudanças no conteúdo em milisegundos, ou deixe 100 como esta. Na linha 30 não mude, é esse valor (true ou false) que decidirá se a cada chamada à função onnavigate retornará um helper, deixe em true como está. Na linha 31, que é a única que talvez precise ser mudada, você colocará uma string indicando o local onde o arquivo control.htm está localizado, se for mudar aconselho especificar um endereço absoluto.

Usando

Já foi explicado no outro post que mencionei no inicio, mas falarei de novo. O que você terá de fazer é chamar a função onnavigate (antes da janela ser carregado) passando como primeiro parâmetro uma string indicando o id desse evento (sem caracteres especiais) e em seguida a função que será executada quando o usuário avançar, voltar e quando você chamar o helper recebido por ela. Esse helper tem que ser armazenado em uma variável que eu aconselho que tenha o mesmo nome do id do evento. No exemplo abaixo a função que será chamada atualizará o conteúdo de uma <div> via Ajax e atualizaro contador de chamadas:

 1 request_source = onnavigate("request_source", function(data){
 2     //Function from my library, not necessary
 3     var source = $("source")
 4     source.innerHTML = "<p style=\"text-align:center;\">Carregando... Aguarde</p>"
 5     //Another method, it just make an ajax request into the element
 6     source.load(data)
 7     //Refreshing the counter
 8     var counter = $("counter")
 9     counter.innerHTML = document.navigators.history.length + 1
10 });

O código fornecido pela função passada no segundo parâmetros será executado à cada interação do usuário (voltar, avançar, atualizar etc.) e quando o helper for chamado, essa função receberá um parâmetro (data, no caso, que é a url para a chamada Ajax) que será o conteúdo diferente a cada interação. A variável request_source armazena o helper que será chamado para registrar o evento no histórico dinâmico e executar a função passada. Você deverá chamá-lo com o primeiro argumento, a string contendo o conteúdo que será recebido pela função passada, essa string servirá para diferenciar cada estado no histórico. E o segundo (opcional, se não fornecido atuará como false) argumento um boleano (true ou false) indicando se a requisição poderá ser chamada seguidamente, registrando assim várias entradas no histórico. Olhe o exemplo do link chamando esse helper (coloquei o evento dentro do atributo href para vizualizar melhor na página, isso não deve ser feito) para armazenar o evento no historio e executar aquela função passada que faz a requisição Ajax.

<a href="javascript: request_source('sources/control.php')">control.htm</a>

Você ainda ganha o objeto document.navigators, onde você pode consultar a propriedade history, um array com os eventos registrados, a propriedade data_buffer que contém o último evento registrado, e acessar cada evento pela sua string id como propriedade, no exemplo acima eu poderia acessar document.navigators.request_source e ganhar duas propriedades, são elas helper e callback, helper é a mesma função recebida pela variável request_source quando a função onnavigate foi chamada e callback é a função que você forneceu.

Observações finais

Os códigos acima foram retirados da página dos códigos. Pronto, acho que já deu para entender como funciona e como utilizar, para poder entender melhor olhe os exemplos: página com os códigos e scroll com texto, ou o monitor (prefere com fundo verde ou vermelho? hehe), que te dará uma visal geral do que acontece em registro de eventos mútiplos. Abaixo listo as pessoas cujos códigos foram tomados por base e outras me ajudaram a descobrir bugs e dicas, se seu nome não estiver aí comenta!

  • Júlio Greff: Código inicial dos hashes.
  • Cau Guanabara: Código consertado para o IE com iFrame.
  • Mike Stenhouse: Idéia original acima.
  • Dekassegui: Adaptações do script do Júlio.
  • Vicente Souza: Ajuda com dicas
  • Rangel Almeida: Bugs consertados
  • Geraldo Abreu: Ajuda com dicas também.

É isso pessoal, não teria feito nem metade sem a ajuda do pessoal aí de cima (do Micox com divulgação também, hauhau). Antes de lançar ele no ar, eu li diversos artigos sobre diversas implementações para consertar esses problemas (voltar, avançar, atualizar, bookmark, etc.), mas não tomei todos por base, somente os do pessoal acima. Abaixo listo os artigos que li e até os que não li, mas consegui o link, hehe, em português primeiro:

O código está longe de estar perfeito, versão 0.8 ainda, qualquer bug posta aí. Depois pretendo fazer um post detalhando e explicando o código, mas já está bem comentado (in bad english hehe).


Dynamic History – Introdução

junho, 7 - 2007

Olá pessoal, já viram posts como esse várias vezes em muitos blogs e até aqui mesmo, nós sempre buscando uma alternativa para fazer o “botão voltar do Ajax” funcionar. Quando desenvolvi e adaptei aquele script baseado em idéias de outras pessoas, eu ainda não tinha entendido o conceito de navegação atual em páginas web, há algum tempo é que percebi diversas redundâncias no meu código e a dificuldade de adaptação por parte de diversas pessoas, além do meu script ter sido difícil de adaptar para além do que somente requisições Ajax, a grande dificuldade do pessoal era entender como funciona uma página web dinâmica. Apesar de diversos avisos de que às vezes usar Ajax é desnecessário, sempre tenho vontade de dar aquele gosto de uma aplicação para uma página web, mesmo não sendo obstrusivo (sempre faço minhas páginas rodarem sem nenhum Javascript primeiro e depois vou adicionando eventos em um arquivo separado do HTML) a principal dificuldade é a adaptação dos usuários. Se você fizer uma interface realmente convincente com javascript e CSS sem mexer no HTML o usuário passará a se comportar diferente na sua aplicação, diversos fatores que falarei depois tem que mudar quando fazer uma aplicação ao invés de página. Mas apesar disso tudo a janela do navegador sempre acaba com você! Voltar, Avançar, Atualizar, Favoritos e etc. sempre estarão presentes nele e você não quer colocar um aviso do tipo “Não use os comandos do seu navegador na minha aplicação” para seu usuário, não é? Pensando nisso que a Tabajara Organizations fez especialmente para você o novíssimo…. hehe, brincadeira, não resisti. Então para “resistir” ao browser existem muitas soluções, mas o ideal é que você entenda como funciona uma página HTML com Javascript.

Uma página web dinâmica é baseada em eventos, ações que reagem às interações do usuário, e muitos desses eventos são essenciais para a aplicação, fornecem conteúdo ou modificam a interface etc. Um exemplo é o Ajax que executa uma requisição respondendo a ação do usuário, que muitas vezes é clicar em algum link, essas requisições são essenciais para a aplicação, e modificam o conteúdo. Mas como estamos em uma página web e não em um aplicativo desktop, o usuário pode tentar “favoritar” sua página ao invés de copiar e colar o conteúdo, e como sua aplicação é constituída de uma única página que faz requisições assíncronas exibindo o resultado em alguma <div>, quando o usuário acessar sua página pelos favoritos a única coisa que irá ver é a página em seu estado inicial, sem o evento da requisição Ajax, o mesmo acontece com o botão voltar, avançar etc. que somente mudarão para outras páginas já que sua aplicação é constituída de uma única página. Esse só foi um exemplo em páginas com requisições assíncronas, mas outros eventos também precisam se comportar como sendo páginas e que precisam ser registrados. As tentativas de resolver esse problema foram muitas como citei no inicio.

Agora que vocês já devem ter entendido como funcionam eventos de uma aplicação e páginas web, mostrarei a vocês como usar o novo script que criei que serve para registrar eventos do usuário, é fácil e simples. Ele se baseia nas técnicas já existentes para registrar os eventos que são os Hashes e o iFrame. Basicamente o que ele faz é usar uma função fornecida por você e devolver um helper, outra função, que quando for usada, não importa quem chamará pode ser em links ou em linha de código etc., executará a sua função fornecida e registrará a ação em um histórico dinâmico sendo assim possível avançar, voltar, favoritar sua aplicação. Dentre os parâmetros desse helper, um será uma string chave que servirá para diferenciar um evento do outro, a função fornecida receberá esse parâmetro. Com o script você pode ter mais de uma ação associada ao histórico dinâmico, sendo elas definidas e diferenciadas por uma string identificadora (não é a string chave). No próximo post mostrarei como implementar, mas para exemplificar e mostrar os códigos você pode ir até a página de códigos que contém uma aplicação funcionando em Ajax com ele (um ótimo exemplo) e os códigos em si, ou também outro exemplo que salva o estado das páginas de um scroll com texto.

Leia agora Dynamic History – Implementando

Edit: O Júlio falou justamente isso no blog dele, agora que ví, o trecho aí em baixo:

Vale lembrar também que estou escrevendo códigos para cuidar do histórico para JavaScript, e não só Ajax (aliás, todas as soluções anteriores faziam isso, mas pouca gente se tocou).

Powered by ScribeFire.


Básico From Javascript To Ruby

junho, 3 - 2007

Como prometido, irei mostrar as diferenças e semelhanças entre Javascript e Ruby. Nada melhor do que começar com o básico, estruturas, variáveis, objetos, tipos, etc. Quem conhece Javascript vai gostar, espero hehe. Para testar os códigos, é necessário que você tenha o Ruby instalado com o IRB ou vá até o Try Ruby e um console do Firebug com o Firefox de preferência. Ou se preferir aqui mesmo, neste mini console meia boca que acabei de fazer: Como eu odeio o WordPress

Introdução

Uma pequena introdução ao Ruby: Ruby é uma linguagem puramente orientada a objetos, tudo em Ruby é objeto, números, strings, arrays etc, Javascript é quase isso, alguns tipos ainda são primitivos. Em Ruby temos classes e módulos ao invés de protótipos. Você pode estender qualquer classe ou objeto a qualquer momento, a maioria dos operadores são na realidade métodos. Ruby tem tipagem forte e dinâmica, o que significa que não precisa ficar declarando tipos, mas não pode tentar somar um número com uma string que resultará em erro. Em Ruby "funções" são métodos de Kernel.

Variáveis

Assim como em Javascript, em Ruby não precisa ficar declarando o tipo das variáveis, mas não tente somar uma string com um número que nem em Js, resultará em erro:

>>> numero = 2
2
>>> string = "2"
"2"
>>> string + numero
"22"

Agora em Ruby:


irb(main):001:0> numero = 2
=> 2
irb(main):002:0> string = "2"
=> "2"
irb(main):003:0> string + numero
TypeError: can't convert Fixnum into String
	from (irb):3:in `+'
	from (irb):3
	from :0

Os exemplos acima mostram que Ruby tem tipagem forte. Um detalhe: assim como em Js, em Ruby não precisa ficar usando ponto-e-vírgula no final das expressões, a não ser que seja feita mais de uma em linha.

Agora vamos falar sobre o escopo das variáveis (só local e global, mais tarde falaremos sobre variáveis de instância, de classe etc.). Em Javascript para que uma variável seja local ela precisa ser definida acompanhada da palavra chave var, se não for ela é interpretada como sendo global.

>>> function teste(){global = "teste"}
>>> global = "fora"
"fora"
>>> global
"fora"
>>> teste()
>>> global
"teste"

No código acima a função teste modificou o valor da variável global, para que não modificasse era só colocar um var antes de sua definição. Agora em Ruby, para declarar uma variável global é só seguir as convenções e colocar um $ na frente da variável, se a variavel começar com letras ou _ (não é permitido variáveis que iniciem com números) ela é considerada local.

irb(main):001:0> def teste; $global = "teste"; end
=> nil
irb(main):002:0> $global = "fora"
=> "fora"
irb(main):003:0> $global
=> "fora"
irb(main):004:0> teste
=> "teste"
irb(main):005:0> $global
=> "teste"

Funcionou do mesmo modo que o exemplo de Javascript porque definimos a variável com um $ na frente, se não tivessemos usado esse $ dentro do método a variável $global continuaria com o valor "fora". Algumas observações: Métodos são definidos usando a palavra chave def seguida do nome do método e seus argumentos. Não precisamos colocar parêntesis nem na chamada do método nem na definição dele, já em Js quando chamamos alguma função sem parêntesis, não estamos chamando e sim recebendo a função em si como uma closure, explicarei isso depois. Na 4 linha quando executamos o método teste recebemos uma string "teste", mas como se não retornamos nada? Simples, em Ruby não precisamos colocar explicitamente a palavra-chave return para retornar alguma coisa, o valor da última expressão avaliada é automaticamente retornada, e no caso a última expressão foi a atribuição de "teste".

Tipos

Mostrarei os tipos padrão da linguagem, assim como em outras linguagens Ruby tem diversos tipos.

String, Numeric e Array – Comum

Em Ruby também temos diversos tipos como String, Numeric (Fixnum ou Float) e Array. Eles podem ser definidos assim como em Javascript:


irb(main):001:0> string = "Uma String"
=> "Uma String"
irb(main):002:0> fixnum = 64
=> 64
irb(main):003:0> float = 3.141585
=> 3.141585
irb(main):004:0> array = [0, "Outra String", string, fixnum, float]
=> [0, "Outra String", "Uma String", 64, 3.141585]
irb(main):005:0> puts "string - #{string.class}\\nfixnum - #{fixnum.class}\\nfloat  - #{float.class}\\narray  - #{array.class}"
string - String
fixnum - Fixnum
float  - Float
array  - Array
=> nil

Definimos uma String, Fixnum, Float e um Array. Agora chamamos o método puts do Kernel com uma String de parâmetro, dentro dessa string usamos #{..} para executar código Ruby, o valor retornado será concatenado com a String. Strings podem ser definidas com " ou , lembrando que neste último não são permitidos caracteres de escape como \n e nem aquelas chaves lá em cima para colocar código Ruby. Olhe este exemplo aí embaixo, lembrando que << serve para concatenar uma string, assim como +=:

irb(main):001:0> string = "Bernardo"
=> "Bernardo"
irb(main):002:0> string2 = string
=> "Bernardo"
irb(main):003:0> string &lt;< " Rufino"
=> "Bernardo Rufino"
irb(main):004:0> "string = #{string}; string2 = #{string2}"
=> "string = Bernardo Rufino; string2 = Bernardo Rufino"

Ué! Mas como?! Quando definimos string2 na linha 2, estamos fazendo uma referência a string e não uma cópia, depois quando usamos o método << ele concatena na string, não cria um novo objeto string, e como string2 apontava para string, ela também muda. Usando += não teremos esse problema, porém é mais lento já que estamos criando um novo objeto. Uma dica: use o <<, mas com cuidado.

irb(main):001:0> string = "Bernardo"
=> "Bernardo"
irb(main):002:0> string2 = string
=> "Bernardo"
irb(main):003:0> string += " Rufino"
=> "Bernardo Rufino"
irb(main):004:0> "string = #{string}; string2 = #{string2}"
=> "string = Bernardo Rufino; string2 = Bernardo"

Funcionou como esperávamos, outro meio de evitar esse tipo de problema é na hora de atribuir string2 fazer uma cópia de string usando o método dup que copia o objeto, a linha 2 ficaria assim string2 = string.dup, e funcionária também.

Hash e Symbol – Arrays com chaves e mini Strings

Vou mostrar a vocês Hashes e Symbols, que nada mais são que Arrays com chaves e Strings imutáveis. Symbols são definidos usando : na frente, são como Strings mais pequenas, disse que eles são imutáveis pois sempre representam o mesmo objeto.


irb(main):001:0> symbol = :simbolo
=> :simbolo
irb(main):002:0> string = 'simbolo'
=> "simbolo"
irb(main):003:0> symbol == string
=> false
irb(main):004:0> symbol == :simbolo
=> true
irb(main):005:0> "symbol id = #{symbol.object_id}; :simbolo id = #{:simbolo.object_id}"
=> "symbol id = 1018338; :simbolo id = 1018338"
irb(main):006:0> "string id = #{string.object_id}; 'simbolo' id = #{'simbolo'.object_id}"
=> "string id = 37415690; 'simbolo' id = 37328150"

Primeiro definimos um Symbol e uma String, comparamos o Symbol com a String, usando == assim como em Js, e verificamos que não eram iguais, comparamos aquele Symbol a :simbolo e verificamos que são iguais. Mostramos o id, chamando o método object_id, de cada objeto String e vimos que cada String nova mesmo com o mesmo conteúdo representa um objeto novo, e depois fazemos o mesmo com Symbols porém cada Symbol novo com o mesmo conteúdo representa o mesmo objeto.

Agora veremos os Hashes, Arrays com chaves. São parecidissimos com os objetos literais em Javascript (JSON). Geralmente usamos os Symbols como chaves de um Hash.

>>> json = {"nome": "Bernardo Rufino", email: "bermonruf@gmail.com"}
Object nome=Bernardo Rufino email=bermonruf@gmail.com
>>> json["nome"]
"Bernardo Rufino"
>>> json.nome
"Bernardo Rufino"
>>> json["email"]
"bermonruf@gmail.com"
>>> json.email
"bermonruf@gmail.com"

JSON é geralmente usado para troca de dados e para criação de classes alterando o prototype. Como vimos pode-se ter uma chave definida com ou sem aspas, e para acessar se usa colchetes ou com um ponto. Em Ruby com hashes temos:

irb(main):001:0> hash = {:nome => "Bernardo Rufino", "email" => "bermonruf@gmail.com"}
=> {:nome=>"Bernardo Rufino", "email"=>"bermonruf@gmail.com"}
irb(main):002:0> hash[:nome]
=> "Bernardo Rufino"
irb(main):003:0> hash["nome"]
=> nil
irb(main):004:0> hash["email"]
=> "bermonruf@gmail.com"
irb(main):005:0> hash[:email]
=> nil
irb(main):006:0> hash.nome
NoMethodError: undefined method `nome' for {:nome=>"Bernardo Rufino", "email"=>"bermonruf@gmail.com"}:Hash
	from (irb):6
	from :0

Repare que tentamos acessar uma propriedade com uma chave Symbol usando String e não deu certo (retornou nil, que é como se fosse null em Js, é um objeto também), ocorre o mesmo ao contrário e depois tentamos acessar como se estivéssemos chamando um método, como o método não existe um erro é gerado (Obs: dá pra fazer o hash ser acessado por métodos com method_missing, falaremos disso depois). O conselho é usar Symbols, já que são imutáveis, ocuparão menos espaço na memória.

true, false e nil – Booleanos e Nulo

Em Ruby até os booleans são objetos, até nulo (nil)é objeto! Diferentemente de Javascript e outras linguagens, Arrays vazios, Strings vazias, zeros etc. são considerados verdadeiros, somente false e nil são realmente falsos.

irb(main):001:0> true.class
=> TrueClass
irb(main):002:0> true.nil?
=> false
irb(main):003:0> false.class
=> FalseClass
irb(main):004:0> false.nil?
=> false
irb(main):005:0> nil.class
=> NilClass
irb(main):006:0> nil.nil?
=> true
irb(main):007:0> nil.methods.join(" ")
=> "inspect send display &amp; clone public_methods __send__ to_yaml equal? freeze object_id require_gem require to_f instance_eval methods pretty_print_inspect dup gem instance_variables instance_of? extend eql? | to_yaml_style id hash singleton_methods taint instance_variable_get frozen? kind_of? ^ to_a to_yaml_properties pretty_print_instance_variables type pretty_print_cycle protected_methods == === instance_variable_set is_a? respond_to? taguri to_s pretty_inspect class method pretty_print private_methods =~ tainted? taguri= __id__ untaint nil? to_i"

Pedimos a classe de cada valor e foi devolvida, testamos se cada valor é nulo com o método nil? e só o nil é nil (nossa! hehe), depois invocamos o método methods que devolve um Array com o nome dos métodos e juntamos os valores com um espaço. Observação: Os métodos que terminam em ? são métodos predicados, ou seja, retornam true ou false, o resto para indicar valor nenhum, ou alguma falha é recomendado retornar nil.

Regexp e Match Data – Expressões Regulares

Ruby também tem ótimo suporte às ERs. Expressões regulares são Regexps, são parecidíssimas com Javascript, se não iguais, podem ser criadas usando / ou o construtor padrão. Strings tem o método match, assim como as Regexp, mas eu acho muito mas lógico usar a partir da String. Temos também os operadores =~ e !~ para testar as ERs.

irb(main):001:0> regexp = /I Love (.+)/
=> /I Love (.+)/
irb(main):002:0> string = "I Love Ruby"
=> "I Love Ruby"
irb(main):003:0> string =~ regexp
=> 0
irb(main):004:0> match = string.match(regexp)
=> #<MatchData:0x477ea08>
irb(main):005:0> "match[1] = #{match[1]}; $1 = #{$1}"
=> "match[1] = Ruby; $1 = Ruby"
irb(main):006:0> regexp2 = Regexp.new("(.+) (.+) Ruby")
=> /(.+) (.+) Ruby/
irb(main):007:0> string =~ regexp2
=> 0
irb(main):008:0> "$1 = #{$1}; $2 = #{$2}"
=> "$1 = I; $2 = Love"
irb(main):009:0> string =~ /um padrao louco/
=> nil
irb(main):010:0> string.match(/um outro padrao louco/)
=> nil

O exemplo acima ilustra bem o que quis dizer, quando executamos o operador =~ se a string casar nós ganhamos a variável global $1 que representa o valor do 1º grupo da ER casado, com 2 grupos se casasse iríamos ter $1 e $2 assim em diante. Quando usamos o método match recebemos um objeto tipo MatchData se casar ou nil se não casar, os grupos casados podem ser acessados pelo objeto usando match[n] onde n é o número do grupo partindo de 1 e match é um MatchData.

Para procurar e substituir temos os métodos sub e gsub de Strings, que procuram por um padrão em uma String uma vez e mais de uma vez respectivamente. Eles recebem uma Regexp, também podem receber uma String nesse caso a string será substituída, e depois uma String que substituirá o valor casado, pode conter os valores dos grupos casdos usando \\n onde n é o número do grupo. Veja o exemplo

irb(main):001:0> string = "Um exemplo de <b>String</b> com formatacao <b>HTML</b> em <b>negrito</b>."
=> "Um exemplo de <b>String</b> com formatacao <b>HTML</b> em <b>negrito</b>."
irb(main):002:0> regexp = /<b>([^<]+)<\/b>/
=> /<b>([^<]+)<\/b>/
irb(main):003:0> string.sub(regexp, "*\\1*")
=> "Um exemplo de *String* com formatacao <b>HTML</b> em <b>negrito</b>."
irb(main):004:0> string.gsub(regexp, "*\\1*")
=> "Um exemplo de *String* com formatacao *HTML* em *negrito*."

Como podemos ver é parecidíssimo com Javascript. Qualquer erro no código comente, pode elogiar, criticar etc. mas comente hehe…