MushMad!

MushMad!

Felipe Elias Philipp  //  Desenvolvedor Web, interessado em Javascript, Ruby, Ruby on Rails, Métodos Ágeis, Scrum, XP, Web Design

Mar 1 / 12:15pm

First impressions of Redis

In my spare time (1h per day), I’ll try to study a new thing every day and after that, create a post about it in this blog. The “new” thing of the week is Redis. At the same time, I’ll practice my writing (and english) skills, so if something is unclear, just leave a comment. I’ll appreciate it.

Goals

To not forget why I’m spending this hour, I set some goals before I start. And they are:

What is Redis?

Redis is a key-value store, also known as NoSQL database. Basically it stores data as ‘value’ inside a ‘key’. This data can later be retrieved only if we know the exact key used to store it.

Installation

I don’t want to detail the installation process, but if you’re using a Mac and Homebrew, just type brew install redis and that’s it!

How to use Redis

The basic commands are SET and GET.

SET stores the data into a key. For example:

SET server:name "fido"

will store the value “fido” inside the “server:name” key and we can retrieve that key later with the GET command:

GET server:name
=> "fido"

If you try to retrieve a non existent key, Redis will return null:

GET server:ip
=> null

And the opposite of SET is DEL, that deletes the given key from the database.

Redis also has other cool stuff like Lists, Sets, Hashs and Ordered Sets. You can try this stuff online on http://try.redis-db.com (highly recommended) or check out the documentation online on http://redis.io/documentation.

What can I use Redis for?

Anything? I don’t think so, but there is collection of Redis use cases in this post. Some of them I like the most are URL Shortener Service and Who is online.

Conclusion

I’m still thinking on what will be my Redis use case. Anyway, I see a lot of projects using Redis to manage background tasks, but what I can conclude now is that Redis is fast!!!. Try to run redis-benchmark -q -n 100000 in the command line and you’ll see how fast it is.

And that’s it. The next post will be about Redis as well, probably about resque, or something related.

Filed under  //  redis  

Comments (0)

Jan 3 / 6:17pm

A few terminal tips

Lists

Lists are very useful. Take a look a this example:

$ mv README.txt README.markdown

A better way to do this using lists is:

$ mv README.{txt,markdown}

This will do the same thing as the first example.

Bang-bang

“!!” repeats the last command. This is useful in situations like this:

$ cp some_file.txt /some_directory_you_do_not_have_permission
cp: some_file.txt: Permission denied

Aw crap! Instead of typing everything again or type combos like up-arrow + crtl-A + sudo, just type:

$ sudo !!

Bang-bang! Problem solved.

Another bang-like thing is the !$. This repeats the very last argument of the previous command. For example:

$ touch README.txt
$ mate README.txt

Too much typing. Why not use !$ instead?

$ touch README.txt
$ mate !$

Done.

And you, what are your terminal tricks?

Filed under  //  bang   bash   command   line   lists   terminal   tips  

Comments (2)

Nov 2 / 5:55pm

A better Javascript confirmation message

I really don’t like the way we write normal Javascript confirmation messages, like this:

if ( confirm('Are you sure?') ) {
  // do the stuff
}

So, I was wondering if this could be done in a more ‘functional’ way, like this:

confirmIf('Are you sure?', function() {
  // do the stuff
});

Much better I think. Here is the function:

function confirmIf ( message, callback ) {       
  if ( confirm(message) ) {
    return callback();
  }
  return false;
}

What do you think?

Filed under  //  confirm   confirmation   english   functional   javascript  

Comments (2)

Oct 22 / 4:33pm

I - Jogos em Javascript - Desenhando com canvas

Estou iniciando meus estudos com desenvolivmento de jogos em Javascript e pretendo iniciar uma série de posts relacionados ao que aprendi durante esse tempo.

Para começar, veremos um pouco da API do canvas e de como ela pode nos ajudar a desenvolver jogos em Javascript.

Porque canvas?

Falando em jogos no browser, um elemento fundamental a se entender é o canvas. Ele que vai nos permitir desenhar objetos na tela e também movimentá-los, criar animações e etc…

Além do mais, ele é compatível com os browsers mais modernos (IE9, Firefox, Safari, Chrome), e para os mais antigos, existe uma biblioteca que contorna esse problema.

Desenhos simples

Para desenhar com o canvas, primeiro precisamos do elemento no nosso HTML, como esse aqui:

<!DOCTYPE html>
<html>
  <head>
    <title>Canvas</title>
  </head>
  <body>
    <canvas id="canvas" width="960" height="480">
    </canvas>
    <script type="text/javascript" charset="utf-8">
      // Codigo aqui
    </script>
  </body>
</html>

Feito isso, podemos manipular o canvas através do Javascript, veja esse exemplo:

var canvas = document.getElementById("canvas");
var paper = canvas.getContext("2d");

function draw() {
  paper.fillRect(10, 10, 100, 100);
}

draw();

Algumas coisas que temos que entender aqui. Primeiro, existe o elemento HTML do canvas na primeira linha. Depois, escolhemos um contexto para o nosso canvas (no caso 2d) com o getContext(). Esse contexto 2d que vai definir qual a API a ser utilizada nos nossos desenhos.

Um método dessa API é o fillRect, que basicamente desenha um retângulo na tela. Os dois primeiros parâmetros são a posição na tela, no caso X e Y, e os dois últimos são o tamanho do nosso retângulo (um quadrado, na verdade). Todos os parâmetros são em pixels.

Não vou entrar em detalhes de toda a API de desenho do canvas, mais informações você pode conferir aqui. Mas existe uma em especial que quero dar mais foco. Veja o exemplo abaixo:

function draw() {
  paper.beginPath();
  paper.moveTo(10, 0);
  paper.lineTo(20, 30);
  paper.lineTo(0, 30);
  paper.closePath();
  paper.stroke();
}

draw();

No exemplo acima, estamos criando um desenho mais customizado. O método beginPath() diz ao canvas que vamos começar um desenho usando as APIs do PATH, que podemos associar a um “lápis” na tela.

O moveTo() move nosso “lápis” para o ponto 10,0 (x,y). A partir do ponto 10,0, desenhamos uma linha com o método lineTo() para o ponto 20,30. Neste momento, é como se fosse desenhada uma linha mesmo. O mesmo fazemos depois para o ponto 0,30. O método closePath() fecha automaticamente nosso desenho para o ponto inicial, no caso 10,0.

O método stroke() finaliza o desenho. Se você não chamá-lo ao final, seu desenho não aparecerá na tela. Isso porque o método lineTo() apenas adiciona as coordenadas numa fila, que depois são finalmente desenhadas com o stroke().

Animando

Para darmos mais vida ao nosso player, utilizaremos dois métodos do canvas: translate e rotate.

function draw() {
  paper.translate(30, 30);
  paper.rotate(0.1);
  //...
}

O método translate() move o canvas inteiro para a posição X,Y passada nos argumentos. Já o rotate(), gira o canvas inteiro para o ângulo passado (em radianos). Essas duas chamadas dos métodos devem ser colocadas antes do beginPath(). Se colocarmos as chamadas depois do stroke(), nada vai acontecer, porque as transformações com translate() e rotate() só afetam os próximos desenhos.

Vamos trocar a chamada do draw() no fim do nosso script para isso:

setInterval(draw, 200);

Agora você deve ter visto que nosso player se “move” na tela, mas não do jeito que esperávamos, porque o desenho antigo não é apagado da tela. Isso porque a cada 200 milisegundos estamos criando um novo desenho e não movendo o player de verdade. Para corrigir isso, chamamos o método clearRect(x, y, width, height) no início do método draw(). Esse método limpa todos os pixels dentro do retângulo passado.

O código final você pode ver abaixo:

var canvas = document.getElementById("canvas");
var paper = canvas.getContext("2d");

function draw() {
  paper.clearRect(0, 0, 960, 480);
  paper.translate(30, 30);
  paper.rotate(0.1);
  paper.beginPath();
  paper.moveTo(10, 0);
  paper.lineTo(20, 30);
  paper.lineTo(0, 30);
  paper.closePath();
  paper.stroke();
}

setInterval(draw, 200);

Essa ainda não é a forma ideal de movermos nosso player na tela, principalmente porque estamos movendo o canvas inteiro e não só o player. Se tivermos outros desenhos na tela, você vai ver que eles se moverão junto com o nosso player, e isso não é o ideal. Falarei mais sobre este problema e como evitá-lo no próximo post da série.

Concluindo

Até aqui conseguimos entender um pouco do canvas, e de como sua API nos permite fazer coisas bem interessantes. Também já conseguimos ter uma boa idéia de como vai ser nosso jogo e de como podemos estruturá-lo.

No próximo post continuaremos nossa série, falando mais sobre a estrutura do nosso jogo e de como manipular nosso player com o teclado.

Até lá!

Filed under  //  2d   canvas   drawing   games   html   html5   javascript   jogos  

Comments (1)

Aug 5 / 11:56pm

HTML5 contenteditable + jQuery

O contenteditable é uma das novas funcionalidades do HTML5. Ela permite que o usuário consiga editar o conteúdo do elemento, como se fosse um daquels editores WYSIWYG. Para utilizar, basta adicionar o atributo contenteditable="true" no elemento:

<ul contenteditable="true">
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

Neste exemplo, ao clicar na lista, aparecerá algo parecido com uma textarea, tornando o conteúdo editável, como se fosse um editor de textos.

Adicionando eventos

Como saber o momento que o usuário terminou de editar o texto dentro do nosso conteúdo editável? Simples. Como o elemento se transforma em uma “textarea”, podemos utilizar os mesmos eventos de um input padrão do HTML. Veja este exemplo:

<!DOCTYPE html>
<html>
  <head>
    <title>contenteditable</title>
    <style type="text/css" media="screen">
      *[contenteditable]:hover {
        background-color: #F9F9F9;
      }
    </style>
  </head>
  <body>
    <div contenteditable="true">Edit me!</div>
    <ul contenteditable="true">
      <li>Item 1</li>
      <li>Item 2</li>
    </ul>
    <div id="log"></div>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript" charset="utf-8">
      $(function() {
        $("[contenteditable]").bind('focus', function() {
          $(this).data('original-text', $(this).text());
          log(this, 'focus');
        });

        $("[contenteditable]").bind('blur', function() {
          log(this, 'texto alterado de "' + $(this).data('original-text') + '" para "' + $(this).text());
        });
      });

      function log (el, msg) {
        console.log(el, msg);
        $("#log").append("-> " + msg + "<br/>");
      }
    </script>
  </body>
</html>

Ao clicar na div com o atributo contenteditable por exemplo, é disparado o evento onfocus. Se logo após clicarmos em outra área do HTML (fora da nossa div), é disparado o evento onblur. Isso você pode acompanhar no log logo abaixo.

No Javascript logo no fim do arquivo, estamos adicionando eventos (com jQuery) a todos os elementos que tiverem o atributo contenteditable. Os eventos são focus e blur, respectivamente relacionados aos eventos nativos do Javascript onfocus e onblur. Um outro exemplo pode ser visto aqui.

Um curiosidade é que esta funcionalidade existe desde o IE 5.5, inclusive foi a Microsoft que padronizou e implementou esta funcionalidade. Mas como a documentação era apenas superficial, só agora esta funcionalidade está sendo padronizada pelo W3C.

Outro detalhe é que é possível executar coisas como execCommand dentro de elementos com contenteditable. Essass funções são utilizadas pelos editores WYSIWYG, para adicionar negrito, itálico, etc… essas coisas.

Mais detalhes sobre o atributo podem ser conferidos neste post.

Update: O Juan Maiz deu uma dica legal de um editor WYSIWYG totalmente em HTML5, segue o link: http://aloha-editor.com/

Filed under  //  WYSIWYG   contenteditable   html5   jquery   rich-text  

Comments (2)

Aug 3 / 11:06pm

Notas sobre Struct

Existem duas formas de se criar uma Struct em Ruby. Uma delas é simplesmente atribuindo a uma constante:

Color = Struct.new(:color, :hex) do
  def metodo
  end
end

E a outra seria com herança:

class ComplexColor < Struct.new(:color, :hex)
  def metodo
  end
end

Notei que muita gente ou fazia de um jeito, ou fazia de outro, e fui atrás pra ver se realmente tinha alguma diferença, ou se era apenas uma questão de “sintax sugar”. E tem diferença!

A diferença principal é que, quando criamos uma struct com herança, estamos colocando uma struct anônima na hierarquia de ancestrais do nosso objeto:

>> Color.ancestors
=> [Color, Struct, Enumerable, Object, Kernel] # herança normal

>> ComplexColor.ancestors
=> [ComplexColor, #<Class:0x100cb7838>, Struct, Enumerable, Object, Kernel] # ahá!

E isso faz também com que os membros (métodos getters e setters) da struct fiquem na classe pai:

>> Color.instance_methods(false)
=> ["color", "hex", "color=", "hex=", "description"] # normal

>> ComplexColor.instance_methods(false)
=> ["description"] # ops?

>> ComplexColor.superclass.instance_methods(false)
=> ["color", "hex", "color=", "hex="] # ahá!

Claro que isso não faz muita diferença, afinal ao chamar qualquer método dos membros da struct, o Ruby vai subir um nível na hierarquia se ele não achar o método na classe atual.

Agora se você gosta de fazer micro-otimizações, talvez isso faça algum sentido, já que estamos economizando alguns pentelhésimos de segundo nas execuções sem herança.

Filed under  //  ruby   struct  

Comments (1)

Aug 2 / 2:33am

Atualizando o ZSH no OS X com homebrew

Recentemente tive que atualizar a versão do meu zsh com o homebrew, e não foi tão fácil como eu imaginei. Isso porque a versão instalada pelo homebrew, não é instalada no diretório padrão /bin.

Encontrei a solução e fiz um tutorial rápido, caso você também encontre esse problema.

Instale o zsh com o homebrew

brew install zsh

Depois de tudo compilado e instalado (thanks homebrew), você terá que alterar o shell padrão para usar o novo zsh com o comando:

chsh -s /usr/local/bin/zsh

Neste momento aparece a mensagem “chsh: /usr/local/bin/zsh: non-standard shell”. Isso acontece porque a versão do homebrew não está habilitada para ser usada como shell. Para habilitar, adicione a seguinte linha no fim do arquivo /etc/shells:

# /etc/shells
/usr/local/bin/zsh

Feito isso, altere o shell padrão com:

chsh -s /usr/local/bin/zsh

Feche e abra novamente o terminal e o zsh está instalado.

Filed under  //  chsh   homebrew   mac   osx   shell   zhs  

Comments (2)

Jun 10 / 4:27am

Métricas no Rails com metric_fu

Update: Parece que a gem Saikuro original não funciona bem com a metric_fu, por isso é necessário instalar o fork do devver e também atualizar a configuração do metric_fu na linha 10. Confira logo abaixo.

Update2: Atualizado para a versão 1.4.0 da gem metric_fu.

metric_fu é uma gem que serve pra analisar o código da sua aplicação. Ela faz a análise utilizando diversas métricas conhecidas, como por exemplo, cobertura de testes, complexidade ciclomática, code smells e etc…

Essa gem é um conjunto de outras gems, em que cada uma delas é responsável por um tipo de métrica. O que a metric_fu faz, é agrupar todas em um lugar só, provendo um html único para acessar as métricas geradas.

Instalando

Para instalar a gem e suas dependências, basta rodar o comando gem install.

gem install metric_fu
=> Successfully installed metric_fu-1.4.0
=> 1 gem installed

Depois de alguns testes, descobri que a gem Saikuro original não funciona bem com o metric_fu (sequer rodou as análises do código), para corrigir isso, instale o fork do devver (link no github):

gem install devver-Saikuro
=> Successfully installed devver-Saikuro-1.2.0

Na versão 1.4, foi adicionado suporte a gem rails_best_practices, que verifica a qualidade do código da sua aplicação de acordo com as melhores práticas. Mais informações nessa apresentação.

gem install rails_best_practices
=> Successfully installed rails_best_practices

Gerando as métricas

A metric_fu utiliza o Rake para gerar as métricas e por isso, recomendo criar o arquivo metric_fu.rakefile dentro de lib/tasks com o seguinte conteúdo (gist aqui):

require 'metric_fu'

MetricFu::Configuration.run do |config|
  config.metrics  = [:churn, :saikuro, :stats, :flog, :flay, :reek, :roodi, :rcov, :rails_best_practices]
  config.graphs   = [:flog, :flay, :reek, :roodi, :rcov, :stats, :rails_best_practices]
  config.flay     = { :dirs_to_flay => ['app', 'lib', 'spec'], :minimum_score => 10, :filetypes => ['rb'] } 
  config.flog     = { :dirs_to_flog => ['app', 'lib']  }
  config.reek     = { :dirs_to_reek => ['app', 'lib']  }
  config.roodi    = { :dirs_to_roodi => ['app', 'lib'] }
  config.saikuro  = { :output_directory => 'tmp/metric_fu/scratch/saikuro', 
                      :input_directory => ['app', 'lib'],
                      :cyclo => "",
                      :filter_cyclo => "0",
                      :warn_cyclo => "5",
                      :error_cyclo => "7",
                      :formater => "text"
                    }
  config.churn    = { :start_date => "1 year ago", :minimum_churn_count => 10 }
  config.rcov     = { :environment => 'test',
                      :test_files => ['test/**/*_test.rb', 'spec/**/*_spec.rb'],
                      :rcov_opts => ["--sort coverage", 
                                     "--no-html", 
                                     "--text-coverage",
                                     "--no-color",
                                     "--profile",
                                     "--rails",
                                     "-Itest:spec",
                                     "--exclude /gems/,/Library/,spec"],
                       :external => nil
                    }
  config.graph_engine = :bluff
end

Feito isso, basta rodar o comando rake metrics:all.

rake metrics:all

O comando Rake irá abrir automaticamete o browser depois de rodar as métricas, e você pode encontrá-las dentro do diretório temp/metric_fu/output/index.html.

Vale ressaltar que as configurações estão utilizando o Rspec e o Test::Unit. Caso não existam algum deles, basta remover do config.rcov (linhas 20 e 27) as referências ao framework de testes que você não está utilizando. Mais configurações podem ser encontradas aqui.

Concluindo

Pelo que notei, as métricas só são armazenadas uma vez por dia, não tenho certeza se isso é configurável (se você conhece alguma configuração que mude isso, por favor poste nos comentários).

Vale a pena dar uma olhada nas gems que a metric_fu engloba (Saikuro, Flog, Flay, Rcov, Reek, Roodi, Churn e rails_best_practices) para entender mais o que é cada métrica e se quiser, rodá-las em separado.

Métricas geralmente são boas, mas não se deve usá-las como regra, apenas como referência. Muitas métricas podem acabar não sendo totalmente verdade (como 100% de cobertura de testes, por exemplo), por isso devem ser usadas apenas como um aviso.

Para mais informações sobre a gem, acesse o site aqui.

Links

  • Configuração utilizada no artigo: link
  • Artigo sobre complexidade ciclomática: link
Filed under  //  gem   metric_fu   metricas   rails   ruby  

Comments (0)

Jun 8 / 2:09pm

jQuery Plugin - replaceClass

Já me peguei várias vezes fazendo algo parecido com isso:

$('td').removeClass('normal');
$('td').addClass('selecionado');

Então, para facilitar, criei um plugin:

jQuery.fn.extend({
  replaceClass: function(original, replace) {
    return this.each(function() {
      jQuery(this).removeClass(original);
      jQuery(this).addClass(replace);
    });
  }
});

Agora consigo fazer:

$('td').replaceClass('normal', 'selecionado');

Espero que sejá útil.

Filed under  //  class   jquery   plugin   replace  

Comments (1)

May 12 / 3:26am

jQuery Iterators - Simples como deve ser

O jQuery possui algumas formas para iterar sobre coleções (arrays, objetos e elementos) utilizando os métodos $.each, $.map e $.grep. Esses métodos são bem parecidos, porém cada um tem um uso específico.

$.each

O método $.each serve para passar (iterar) por cada elemento de um objeto e fazer uma determinada ação. Essa ação é feita com um callback (função anônima), que é chamada em cada elemento. O $.each espera dois parâmetros: o primeiro é o objeto e o segundo é o callback, este que, fornece dois parâmetros, o primeiro é o índice (se for um array) ou propriedade (se for objeto), e o segundo o próprio elemento:

// Iterando em um array
$.each(['a','b','c'], function(index, element) { 
    console.log(index, element);
});
=> 0, 'a'
=> 1, 'b'
=> 2, 'c'

// Da mesma forma com objetos
$.each({ 'nome': 'Edward Hill', 'musica': 'Trolololo' }, function(key, value) { 
    console.log(key, value);
});
=> 'nome', 'Edward Hill'
=> 'musica', 'Trolololo'

Duas dicas: para parar em qualquer momento a execução do $.each, o callback deve retornar false, já se for preciso apenas "pular" um elemento e continuar a execução, o callback deve retornar true:

// Para a execução se encontrou um 'b' no array
$.each(['a','b','c'], function(index, element) { 
    if(element === 'b') { 
        return false; 
    }
    console.log(element) 
});
=> 'a'

// Já aqui, ele 'pula' a execução se encontrou um 'b', e continua para os outros elementos do array
$.each(['a','b','c'], function(index, element) { 
    if(element === 'b') { 
        return true; // observe o true aqui
    }
    console.log(element) 
});
=> 'a'
=> 'c'

Uma forma de usar o $.each (talvez a mais utilizada), é com elementos do DOM, e aqui que a coisa fica mais interessante. A estrutura e o funcionamento são os mesmos, a diferença é que o $.each é executado a partir de uma coleção de elementos do jQuery:

// Itera sobre todos os elementos forms encontrados
$('form').each(function(index, element) { 
    console.log(this);
};
=> <form ...>
=> <form ...>
=> <form ...>

$.map

O método $.map tem um objetivo diferente do $.each. Ele também executa um callback para cada elemento, porém só retorna o que for especificado no retorno. Se não for preciso retornar alguma coisa, o callback deve retornar null:

// Retorna somente os elementos pares
$.map([4, 5, 6], function(element, index) { 
    return element + 4;
});
=> [8, 9, 10]

// Retorna somente os elementos pares. Funciona como um 'filtro' no array
$.map([4, 5, 6], function(element, index) { 
    return element % 2 === 0 ? element : null;
});
=> [4, 6]

Assim como o $.each, o $.map pode ser usado com elementos do DOM. Aqui as possibilidades são infinitas, vai da criatividade de cada programador. Algumas formas de uso:

// Cria um array com todos os atributos "method" dos formulários
$('form').map(function() { 
    return $(this).attr("method"); 
});
=> ["get", "post", "post", "get"]

// Retorna todos os forms que o método form igual a GET
$('form').map(function() { 
    return $(this).attr("method").toLowerCase() === "get" ? this : null; 
});
=> [<form method="get">, <form method="get">]

Resumindo, qualquer coisa diferente de null, será retornada pelo método $.map.

$.grep

O método $.grep é praticamente um $.map, porém mais específico. A idéia do $.grep é utilizar o callback como um filtro para o array, mais ou menos como o $.map faz, porém tem duas diferenças: a) só funciona com arrays; b) só retorna os elementos que passarem em uma determinada condição. Em outras palavaras, o callback deve retornar true ou false, e se o retorno for true, o elemento do array é retornado:

$.grep([1, 2, 3, 4], function(elemento) { 
  return elemento > 2;
});
=> [3, 4]

Uma forma de fazer isso com elementos do DOM é com o método filter do jQuery:

// HTML
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
</ul>

// o filter funciona como um $.grep, só que para elementos do DOM
$('li').filter(function() {
  return $(this).text() === "Item 2";
}).addClass('red');

// HTML depois
<ul>
  <li>Item 1</li>
  <li class="red">Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
</ul>

Conclusão

Para não se confundir em quando usar cada método, tenha em mente isso:

  • O $.each executa um callback em cada elemento (array, objeto, ou elemento do DOM), e sempre retornará todos os elementos;
  • O $.map funciona da mesma forma que o $.each, com a diferença que você pode especificar o que será retornado;
  • O $.grep só funciona com arrays, e para retornar um elemento do array, o callback deve retornar true;
  • Para usar algo similar ao $.grep, mas como elementos do DOM, o jQuery disponibiliza o método filter;

Documentação

Filed under  //  each   grep   iterators   javascript   jquery   map  

Comments (0)