Willian Fernandes

Como usar jQuery para remover um item de um Array JS

Comente »

Quem trabalha com JavaScript sabe que para remover um item de um array basta utilizar o método splice. Como o código abaixo:

frutas = ['maçã', 'banana', 'pera', 'uva'];
frutas.splice(1,1);

O código acima retira a banana do array frutas. Isso porque no 1º parâmetro do método splice informamos qual a posição do item no array que queremos remover. O 2º parâmetro indica quantos itens, contando do item que informamos, queremos remover. Sendo assim, se quisermos remover a banana e a pera basta fazer assim:

frutas = ['maçã', 'banana', 'pera', 'uva'];
frutas.splice(1,2);

Mas em muitos casos não sabemos qual a posição do item que queremos remover e sim qual o valor do item. Uma abordagem é procurar qual a posição do item percorrendo o Array e comparando os valores com o valor que temos. Um tanto quanto chato, concorda?

jQuery para todas as horas!

Como é mais que comum termos jQuery em projetos web, realizar o trabalho acima fica fácil. Pra isso precisaremos da função $.grep. Está função encontra todos os elementos de um array de acordo com uma expressão. Vamos aplicar nosso exemplo removendo a fruta banana do nosso array, mas agora não sabemos qual a posição que essa fruta se encontra no array. Nosso código ficará assim:

frutas = ['maçã', 'banana', 'pera', 'uva'];
frutas = $.grep(frutas, function(val, index) {
	return val != 'banana';
});

Com a funcão $.grep podemos ir muito além. Por exemplo, ter um array com somente os elementos que forém pares:

numeros = [1, 2, 3, 4, 5, 6, 7, 8];
pares = $.grep(numeros, function(v) {
	return v % 2 == 0;
});
 
// Valor do array pares: [2, 4, 6, 8]

A função $.grep recebe 2 parâmetros obrigatórios: o array original e uma função callback. Esse callback recebe, por sua vez, 2 parâmetros: o valor do item atual e o índice (posição) desse valor no array.
Existe um terceiro parâmetro (não obrigatório) da função $.grep chamado inverse, que por padrão tem o valor false. Esse parâmetro inverte a condição dentro do callback, fazendo exatamente o contrário que mandamos ela fazer. Se adicionarmos o parâmetro inverse no exemplo acima, teremos:

numeros = [1, 2, 3, 4, 5, 6, 7, 8];
pares = $.grep(numeros, function(v) {
	return v % 2 == 0;
}, true); // Perceba que adicionamos um novo parâmetro
 
// Valor do array pares: [1, 3, 5, 7]
// pares agora só contém os valores ímpares

Perceba que a função $.grep não altera o array original. Nos exemplos acima o array numeros continuará tendo todos os elementos.

Bom, é isso. Espero que agora remover itens de um array JavaScript utilizando o valor seja mais fácil no seu dia-a-dia.

[ATUALIZADO]

Algumas pessoas se manifestaram no Twitter dizendo que isso é errado. Realmente, existe uma forma bem simples de remover um item de um Array em JavaScript sem saber a posição desse item e sem usar jQuery. Segue abaixo:

frutas = ['maçã', 'banana', 'pera', 'uva'];
index = frutas.indexOf('banana');
frutas.splice(index, 1);

Utilizamos o indexOf para descobrir qual a posição do valor que queremos remover e depois conseguiremos utilizar o splice normalmente.

Agora, sobre a parte de retornar somente os números pares, o Nando Vieira deu uma dica boa:

[1, 2, 3, 4, 5, 6, 7, 8].filter(function(item) {
	return item % 2 == 0;
});

OBS.: Navegadores antigos não suportam a função filter(). Use por sua conta e risco.

Contrate o Willian Fernandes

Comente »

Como alguns sabem, eu estou trabalhando com a equipe da idopter em um novo produto, o Lancelote. Porém a parceria durou pouco. Com algumas decisões empresariais, o alto custo de manter uma equipe com 5 pessoas para um produto e por ser o membro com menos tempo de casa na equipe chegou a hora de procurar novos desafios.

Como a vida continua, estou disponível para projetos em período integral. Se você tem algum projeto interessante e precisa de um profissional de alto nível em sua equipe, entre em contato através do e-mail/Google Talk maurowil@gmail.com. Aos que puderem encaminhar este post para pessoas que possam ter interesse em ter-me em suas equipes, um muito obrigado.

Outras formas de contato:

PS: O segundo parágrafo é uma cópia descarada que o Nando fez e sem autorização prévia
PS2: O PS1 é uma cópia descarada que o Tino Gomes fez e sem autorização prévia

Faye – Como eu criei um simples chat usando Rails

Comente »

Recentemente precisei criar um chat para integrar com a aplicação da empresa que trabalho. Sim, mais um desenvolvimento de chat. Como dizem por ai, chat é o novo Hello World.

Já tinha ouvido falar do Faye, até o Ryan Bates fez um Railscasts sobre o assunto.

O Faye tem módulos para Ruby e Node.js.

Minha primeira tentativa foi utilizar a versão ruby do Faye. Essa versão nada mais é que uma aplicação Rack. Funcionou muito bem, até chegar em produção. O servidor que ele utiliza é o thin, e para a quantidade de requests que minha aplicação faz ao chat o servidor não durava 3 minutos em pé.

Depois de muito quebrar a cabeça resolvi partir para a versão em Node.js do Faye que resolveu perfeitamente esse problema. Vou mostrar abaixo como fiz para utilizando Faye, Node.js e Rails:

Vamos ao código

Primeiro você precisa ter o Node.js e o NPM instalados.

Na raiz da aplicação, instale o faye utilizando o npm:

$ npm install faye

Logo em seguida, também na raiz da aplicação, criei o arquivo abaixo:
faye_server.js

var http = require('http')
  , faye = require('faye');
 
var Logger = {
	incoming: function(message, callback) {
		console.log(message);
		console.log('====================');
 
		callback(message);
	}
};
 
var bayeux = new faye.NodeAdapter({mount: '/faye', timeout: 60});
bayeux.addExtension(Logger);
bayeux.listen(9292);
 

Para testar se o faye está corretamente instalado e funcionando, rode o servidor:

$ node faye_server.js

E abra no seu nevegador a URL http://localhost:9292/faye.js. Se um arquivo JavaScript for carregar, então o Faye está funcionando corretamente. #WIN

Client-side

No seu arquivo de layouts (ex.: application.html.erb) você precisa adicionar o JavaScript do Faye:

<%= javascript_include_tag "http://localhost:9292/faye.js" %>

Agora basta criar uma instância para o Client do Faye e o canal que receberá as mensagens do nosso chat:
application.js

$(function() {
	var faye_client = new Faye.Client('http://localhost:9292/faye');
	faye_client.subscribe('/chat' , function(data) {
		eval(data);
	});
});
 

Back-end

Criei um simples formulário que faz um POST para MessagesController::create utilizando AJAX:
app/views/messages/index.html.erb

<h1>Messages</h1>
 
<div id="messages">
	<ol></ol>
</div>
 
<%= form_for @message, remote: true do |f| %>
	<%= f.label :content %>
	<%= f.text_field :content %>
	<%= f.submit "Send" %>
<% end %>
 

E no controller MessagesController:

class MessagesController < ApplicationController
  def index
    @message = Message.new
  end
 
  def create
    @message = Message.create(params[:message])
  end
end
 

Simples, certo?

O segredo está na view app/views/messages/create.js.erb:

<% broadcast "/chat" do %>
	$("#messages ol").append($("<li><%= @message.content %></li>"));
<% end %>
$("#message_content").val('');
 

Seguindo a dica do Ryan Bates, criei um helper para facilitar o envio das mensagens para o Faye Server. Ele será responsável em fazer o broadcast para todos os usuários conectados no chat.

app/helpers/messages_helper.rb

module MessagesHelper
  def broadcast(channel, &block)
    message = { channel: channel, data: capture(&block) }
    uri     = URI.parse("http://localhost:9292/faye")
    Net::HTTP.post_form(uri, message: message.to_json)
  end
end
 

Como este helper está usando o Net::HTTP, precisamos adicioná-lo na nossa aplicação. Eu normalmente faço o require dessa lib no arquivo config/application.rb:

# ...
 
require 'rails/all'
require 'net/http'
 
# ...

Com isso nosso chat está pronto!

Lógico que na minha aplicação existem processos um pouco mais complexos, lidando com chat privado (estilo Facebook) e autenticação de usuários. Mas para exemplo, esse caso mais simples vale.

Você pode baixar a aplicação completa diretamente do meu GitHub:
https://github.com/willian/faye_chat_example

Fácil, não!? :)

Desabilitando Asset Pipeline no Rails 3.1

Comente »

Se você é como eu e não gostou do assets pipeline que vem habilitado nativamente no rails 3.1, saiba que você pode desabilitá-lo. Para isso, basta editar o arquivo application.rb:

# Enable the asset pipeline
config.assets.enabled = false

Essa notícia não é nova, porém poucos sabem que ao desabilitar este recurso os arquivos controller_name.js e controller_name.css continuam sendo gerados no diretório app/assets/. Veja:

$ rails g controller users
  create  app/controllers/users_controller.rb
  invoke  erb
  create    app/views/users
  invoke  rspec
  create    spec/controllers/users_controller_spec.rb
  invoke  helper
  create    app/helpers/users_helper.rb
  invoke    rspec
  create      spec/helpers/users_helper_spec.rb
  invoke  assets
  invoke    js
  create      app/assets/javascripts/users.js
  invoke    css
  create      app/assets/stylesheets/users.css

Para evitar que isso aconteça basta fazer a configuração abaixo também no arquivo application.rb:

config.generators do |g|
  g.assets false
end

Com isso ao rodar o generator de controller teremos:

$ rails g controller users
  create  app/controllers/users_controller.rb
  invoke  erb
  create    app/views/users
  invoke  rspec
  create    spec/controllers/users_controller_spec.rb
  invoke  helper
  create    app/helpers/users_helper.rb
  invoke    rspec
  create      spec/helpers/users_helper_spec.rb

Fica então a dica.

Dica rápida: RVM 1.8.1

Comente »

Pelo o que parece, a versão atual (1.8.1) do RVM não está funcionando para usuários Mac.

Se você tentar instalar qualquer versão do ruby com essa versão do RVM terá o erro:

Trying http:// URL instead.
curl: (3) malformed

Para funcionar corretamente tive que instalar a versão anterior, a 1.8.0:

curl -s https://rvm.beginrescueend.com/install/rvm -o rvm-installer ; chmod +x rvm-installer ; ./rvm-installer --version 1.8.0

Agora é esperar que eles lancem a correção na versão 1.8.2 para que os usuários Mac possam atualizar o RVM.

#fikdik

RailsConf 2011

Comente »

Para quem não sabe dia 16 de maio acontecerá o RailsConf 2011. O evento será novamente em Baltimore e vai até o dia 19.

Eu nunca viajei para fora do país e minha primeira experiência será um tanto quanto interessante. Embarco dia 13 e chego dia 14, de madrugada, em Washington D.C, vou para Baltimore de carro no dia 15 e dia 20 volto para Washington onde fico até o dia 22. Dia 22 mesmo chego no Brasil.

Enfim, quero saber quem mais do Brasil estará por lá para marcar um #horaextra em Baltimore, ou em Washington.

Postarei no blog e no twitter a experiência de participar desse grande evento e de estar nos States.

Até lá!

Meu ambiente de desenvolvimento

Comente »

Fui convidado pelo Jésus Lopes (post) para falar um pouco sobre meu ambiente. Então segue abaixo o que eu uso no dia-a-dia.

Macs

Desde fevereiro de 2008 trabalho exclusivamente com Mac OS X. No trabalho tenho um iMac Core 2 Duo 2.4 GHz com 4 GB de memória com Snow Leopard rodando.
Em casa uso meu bom e velho (ok, nem tão bom assim) MacBook preto, também com Snow Leopard mas com apenas 2 GB de memória. :(

Editor

Quando trabalhava exclusivamente com Linux (Ubuntu) usava somente o Vim, mas nunca parei para realmente aprender a usá-lo. E quando migrei para o Mac conheci o TextMate e nunca mais troquei.

Com o mate me sinto em casa. Aprendi rapidamente seus atalhos, conheci e instalei alguns Bundles para me ajudar no dia-a-dia e sei que não preciso de mais nada para programar feliz.

Ainda uso o Vim para coisas nos servidores e de vez em quando para brincar e aprender um pouco mais sobre ele. Não, não pretendo trocar de editor. Mas pode ser que um dia precise e se precisar vou usar feliz da vida.

Terminal

A freqüência com que uso o terminal é igual ou até mesmo maior do que com o TextMate. E nele fiz algumas configuração sugeridas pelo Nando Vieira. Meu .bashrc pode ser encontrado em meu GitHub.

Browser

Meu navegador padrão se tornou o Safari assim que adotei a plataforma Mac. Uso Chrome e Firefox apenas para desenvolvimento e olhe lá! ;)

Versionamento

Desde 2008 uso apenas o git para controlar meus projetos. SVN apenas quando preciso fazer checkout de algo.

Linguagens de programação

Uso Ruby a maior parte do dia. Mas também não fico uma semana se quer sem brincar com JavaScript. Node.js tem me chamado muita atenção e JS está voltando a fazer cada vez mais parte dos meus desenvolvimentos.

Outros programas

  1. Safari;
  2. Alfred: abandonei o QuickSilver faz alguns meses;
  3. iTunes: ouço música o tempo todo;
  4. YoruFukurou
  5. Keynote
  6. Pages
  7. Reeder
  8. TextMate
  9. Terminal
  10. iChat
  11. Dropbox
  12. MusicBrainz Picard
  13. Quicktime

Então agora convido @tinogomes e @lucashungaro para contarem do seus ambientes.

Novo layout

Comente »

Depois de quase um ano usando o layout padrão do WordPress, resolvi criar um próprio e ver se assim me animo a escrever com mais frequencia por aqui.
Aproveitei para me aventurar um pouco no HTML 5 e CSS3 e provavelmente algumas coisas ainda quebrem em algum browser até que eu consiga ajeitar tudo por aqui.

Caso você esteja lendo esse post em um leitor de feeds, segue abaixo uma Screen shot de como ficou:
Novo layout

Tem alguma sugestão? Mande no comentário.

Até!

Testando Sinatra com RSpec (dica para quem usa Rails Metal)

Comente »

Após ler o post do Diego Carrion sobre como usar RSpec[bb] para testar uma aplicação Sinatra, lembrei que tive um problema com os testes quando trouxe a aplicação feita em Sinatra para uma outra feita em Rails[bb] usando Rails Metal.

Vou usar o exemplo do Carrion para mostrar o que precisei mudar para os testes rodarem dentro do Rails Metal. Se no Sinatra usamos o spec_helper.rb assim:

require File.join(File.dirname(__FILE__), '..', 'main.rb')
 
require 'spec'
require 'rack/test'
 
Spec::Runner.configure do |conf|
  conf.include Rack::Test::Methods
end
 
def app
  Sinatra::Application
end

No Rails Metal precisamos usar o arquivo spec_helper.rb normal, da forma como ele for gerado pelo RSpec.

A classe Api é um rails metal, mas nesse caso ela deve extender a classe Sinatra::Base (rails_root/app/metal/api.rb):

require 'sinatra'
 
# Allow the metal piece to run in isolation
require(File.dirname(__FILE__) + '/../../config/environment') unless defined?(Rails)
 
class Api < Sinatra::Base
  # Code
end

E no arquivo api_spec.rb definimos o método app assim:

require 'spec_helper'
 
describe "Api" do
  include Rack::Test::Methods
 
  def app
    Api.new
  end
 
  # code
end

No exemplo acima precisei fazer require ‘rack/test’ no spec_helper.rb. Para isso, basta instalar a gem rack-test.

Como você pode ver, com uma simples mudança você pode usar Sinatra com Rails e fazer seus testes com RSpec.

Como gerar validações client-side em projetos Rails usando jQuery Validator com ClientValidations

Comente »

Estou fazendo uma nova aplicação aqui na empresa e teremos muitos formulários. Para não precisar criar um script de validação para cada formulário, fui atrás de um plugin que gerasse as validação JavaScript automáticamente, com base nas validações do modelo.

Sem maiores problemas, encontrei o plugin Live Validations. Ele faz tudo o que preciso, quer dizer, quase tudo. :(

Alguns dos formulários dessa aplicação são Nested Model Form e o Live Validations não suporta esse tipo de formulário.

Sendo assim, resolvi fazer meu próprio plugin, chamado Client Validations. O que ele faz é basicamente ler as validações definidas no Model e traduzi-las para JavaScript usando jQuery Validator.

Instalação

script/plugin install git://github.com/willian/client_validations.git

Como o Client Validations depende do plugin Validation Reflection, preciaremos instalar ele também:

script/plugin install git://github.com/redinger/validation_reflection.git

E por último basta instalar o jQuery e o jQuery Validator:

Não esqueça de carregar o jquery e o validator no seu HTML:

<%= javascript_include_tag 'jquery-latest.min.js', 'jquery.validate.min.js' %>

Supondo que temos o modelo abaixo:

class Task < ActiveRecord::Base
  validates_presence_of :name
end
 

E o formulário desse modelo:

<% form_for(@task) do |f| %>
  <%= f.error_messages %>
 
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

Tudo o que precisamos fazer para a validação client-side funcionar é adicionar o helper client_validations no formulário. Ficará assim:

<% form_for(@task) do |f| %>
  <%= f.error_messages %>
 
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
  <%= f.client_validations %>
<% end %>

Provavelmente você receberá a seguinte mensagem de validação:

translation missing: en, activerecord, attributes, task, name can't be blank

Para resolver esse problema, basta criar o arquivo de internacionalização em config/locales.

O plugin ainda está na versão 0.1.0 e muita coisa pode ser feita para melhorá-lo. Se tiver alguma sugestão, crie um comentário ou use a página do GitHub: http://github.com/willian/client_validations