Como no texto anterior, hoje vou falar sobre o uso de
pattern matching
em Elixir de uma forma mais detalhada.
Pattern matching é um recurso muito poderoso (quase mágico!). Vou começar demonstrando simples exemplos, até chegar aos mais complexos.
Em Elixir não existe o conceito de variáveis como vemos nas linguagens de programação “convencionais”. Isso occore porque em Elixir não temos estado (na verdade temos, mas é um assunto pra outro post): temos valores que são transformados de função em função.
Quando se cria uma expressão de associação (ex.: x = 10), na verdade o que
ocorre é uma tentativa de “apelidar” um valor a um nome (10 foi apelidado de x).
Essa tentativa é feita através de pattern matching
.
Exemplo:
1 2 3 4 5 6 7 8 9 10 |
|
A linguagem vai tentar sempre “casar” o valor da esquerda com o da direita.
Agora queremos capturar valores dentro de uma lista simples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Como você pode ver, Elixir vai entender que o valor do elemento do meio é igual nos dois lados. Mas caso esse valor seja diferente, não há match.
Exemplo com um erro de match
:
1 2 3 |
|
Os mesmos exemplos podem ser reproduzidos usando tuplas:
1 2 3 4 5 6 7 8 9 10 11 |
|
É possível até repetir o nome da “variável”:
1 2 3 4 5 6 7 |
|
O conceito de head
e tail
é muito usado em linguagens funcionais,
e não é exceção em Elixir. Com ele é possível pegar o primeiro item
da lista e o restante da lista em uma só expressão de associação.
Li pela primeira vez sobre o assunto em um tutorial de haskell, que recomendo!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Seguindo o exemplo anterior, para dar match nos dois primeiros itens de uma lista:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
list comprehensions
Aqui começa a complicar. Quem já programou em Python deve ter usado um recurso bem interessante: list comprehensions.
Em Elixir também temos comprehensions
que podemos usar em listas, tuplas, binaries
e streams.
Primeiro, um exemplo usando associação simples:
1 2 |
|
Agora, um exemplo usando um padrão mais complicado:
1 2 3 4 5 6 7 8 9 10 |
|
Como o exemplo sugere, comprehensions retornam somente os itens que deram match no padrão. Isso possibilita o uso de um filtro sem ter que escrever muito código.
string
em partesÉ comum percorrer uma string (ou binary
) por cada caracter. Podemos fazer isso
usando um match
de binary
, como no exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
É interessante notar que estou especificando o encoding do binary. Isso é necessário para que a linguagem entenda aquele caracter como sendo parte de uma string.
Algo a se notar também é que usei uma vírgula ao invés de um pipe (|) para separar head e tail da string. Para que a representação de h seja a correta, tenho que dizer que aquele binary é UTF8.
Há uma maneira mais simples de dar match em uma string usando um operador de concatenação de
strings/binaries: o <>
.
Sem matches, o usamos da seguinte forma:
1 2 |
|
Agora com o match:
1 2 3 4 5 |
|
É bem simples e útil quando se sabe o conteúdo do início de uma string, e queremos pegar o restante dela que é variável, como estou usando nesse parser e leitor de HTML.
case
Pattern matching é usado com frequência em um bloco case
que serve justamente
para fazer alguma ação de acordo com o padrão de entrada.
É como o case
de C, no sentido de ter vários branches de decisão,
mas ao invés de tomar decisões por condições booleanas, o case
da Elixir toma
decisões baseado em padrões.
Exemplo:
1 2 3 4 5 6 7 |
|
O case
é a provavelmente a estrutura de controle mais usada em Elixir.
Faz parte da filosofia da linguagem escrever os programas levando em conta
situações adversas, como o erro que está sendo considerado no exemplo.
Ao invés de usar um tratamento de exceção, a linguagem propõe que os erros
sejam tratados como caminhos “normais” do programa. Sendo assim, o case
é
bem prático para casar um padrão em situações onde um erro é esperado.
Podemos também usar o casamento de padrão em funções, como demonstrei no post anterior.
É possível ignorar um determinado valor dentro
de um match
usando o underscore
.
Ele serve como um coringa, e é muito útil em determinadas
ocasiões.
Exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Uma das features mais legais de Elixir é o modelo de comunicação entre atores (ou processos). Com ela é possível enviar todo o tipo de mensagem para um processo e processar essa mensagem através de pattern matching. Esse assunto é bem complicado de início, por isso recomendo que leiam um pouco mais sobre isso.
Exemplos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Perceba que o bloco de receive
é bem parecido com o
case
, porém está trabalhando com uma mensagem recebida.
Nesse artigo mostrei alguns exemplos de pattern matching em Elixir. Para entender mais e melhor, recomendo a leitura do livro Programming Elixir do Dave Thomas que é bem completo. Recomendo também dar uma fuçada em projetos abertos e tentar entender o código.
Deixo aqui meu convite à comunidade brasileira de Elixir, que é bem pequena ainda, a escrever mais sobre a linguagem. Em português ou inglês, o importante é trazer o máximo de devs que puder! :)
]]>Patter maching é uma feature, assim como muitas outras, herdada da Erlang, que é a linguagem em que Elixir se basea. Em uma tradução livre, pattern maching quer dizer “casamento de padrão”. O termo é meio exquisito em português, mas vamos a um exemplo:
1
|
|
Nesse exemplo, estamos “casando” o que está do lado direito com um padrão do lado esquerdo. Explico: do lado esquerdo temos uma tupla com o primeiro elemento :ok
e o segundo elemento como uma variável name
.
A linguagem vai tentar fazer bater o tipo e o conteúdo dos dois lados. No caso, o tipo bate:
– é uma tupla;
– o primeiro elemento da tupla bate: :ok
é :ok
;
– o segundo argumento também bate: do lado esquerdo temos uma variável a ser “preenchida”, do lado direito temos um valor para ela.
Agora um exemplo onde o pattern não bate:
1 2 |
|
Por mais que o tipo do segundo elemento seja o mesmo, não há casamento porque os conteúdos das strings são diferentes.
Um dos usos mais poderosos para o pattern maching é na declaração de funções.
Em Elixir, as funções são definidas por três combinações: o seu nome, o número de argumentos, e o “padrão” desses argumentos. Em suma, são definidas pelo nome e argumentos.
Isso quer dizer que uma função somar(numero1, numero2)
é diferente da função somar(numero1, numero2, numero3)
. E as funções check({200, body})
e check({404, body})
são diferentes por conta do padrão de seus argumentos (a diferença do primeiro elemento da tupla).
Uma aplicação muito legal pra isso é na construção de funções recursivas.
O exemplo a seguir mostra como somar números de uma lista através de recursividade. Ele é bem parecido com o encontrado no guia Getting started do site oficial da linguagem, mas considero o meu (IMHO) um pouco mais simples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Como você pode perceber, os nomes das funções são idênticos, mas o que muda são seus argumentos. Todas as três recebem listas, porém cada uma com um padrão diferente:
[2, 3, 4]
será dividida em head = 2
e tail = [3, 4]
. Feito isso, a função ira somar recursivamente o primeiro elemento da lista com o resultado da próxima chamada da função recebendo a lista da calda.Quando há somente um item na lista, head
é igual a esse elemento, e tail
é vazia ([]).
As chamadas recursivas de “sum_list” serão processadas levando em conta o “padrão” dos argumentos passados. A “condição de parada” da terceira função é quando tail
for uma lista com somente um elemento. Neste caso a função que será utilizada é a segunda, que recebe uma lista com um elemento.
Nos exemplos usados aqui vimos um pouco do que é possível fazer com o uso de pattern matching. Essa não é uma característica exclusiva da Elixir, mas para mim ficou muito mais fácil de entender com essa linguagem (já havia tentado com Haskell).
Experimente implementar os exemplos e deixe suas dúvidas e sugestões nos comentários.
Recomendo esses links para mais detalhes da linguagem:
]]>O Zeus pré-carrega (faz um preload) sua aplicação Rails, e tudo que é dependência dela. Você pode instalá-lo com o comando:
1
|
|
É importante lembrar que o Zeus não deve ser declarado no seu Gemfile.
Para executar o Zeus, vá a seu projeto Rails e execute zeus start
. A partir daí, você conseguirá subir seu servidor (zeus s
) ou
executar comandos (zeus rake/generate/etc
) de forma muito rápida!
Para rodar seus testes usando RSpec direto do seu Vim, você pode usar o plugin vim-rspec. Instale-o pela maneira mais recomendada, usando Vundle ou a que você preferir.
Em seguida é necessário configurar o comando que executa os testes.
Adicione a linha abaixo ao seu .vimrc
:
1
|
|
O comando padrão para executar os testes (todos do arquivo) é \\t
(<Leader>t
)
Se quiser executar um teste específico, mova o cursos para ele e execute \\s
(<Leader>s
).
Há também um comando para executar o último teste: \\l
(<Leader>l
)).
Com o rspec-vim
sua produtividade pode aumentar consideravelmente, evitando
a mudança de abas ou terminais para executar seus códigos.
Meu caso foi com um código mais ou menos como o abaixo.
1 2 3 4 5 6 7 8 9 |
|
O código não era tão simples, mas o exemplo ilustra bem como aconteceu. Meu intuito
era trabalhar com o conteúdo “armazenado” em b
e deixar o conteúdo em a
intacto.
Porém quando alterei o valor de b
(adicionando 5), também alterei em a
. Isso causou
um bug que foi corrigido no processo de code review
.
Isso porque em Ruby todas as declarações são feitas através de referências para objetos.
Para resolver possíveis problemas (como alterar acidentalmente o objeto errado), você pode “clonar” ou “duplicar” (veja a diferença nos links abaixo) um objeto quando for referenciá-lo a uma variável.
Exemplo:
1 2 3 4 5 6 7 8 9 |
|
Alguns links do Stack Overflow sobre o assunto:
]]>Percebi que já existiam algumas pequenas aplicações para estatísticas, mas nada que promovesse desafios entre usuários(times). Eu queria unir as duas características. Mas o tempo passou e essa app acabou ficando de lado.
Foi então que decidi lançar o que foi feito, mesmo com alguns bugs.
O site fica no Heroku, e você pode acessar aqui. Não sei se vou continuar desenvolvendo essa aplicação, mas já valeu a pena pois aprendi muito com isso!
]]>Com tmux é possível criar sessões com várias “janelas” (inclusive com separação vertical e horizontal) e usar 256 cores sem problemas.
Seguindo o mesmo esquema do post do Gustavo, separei em “host” e “client”.
Na máquina que servirá como servidor de desenvolvimento será preciso criar uma sessão:
1
|
|
Os parâmetros significam:
Você vai precisar dar permissão no arquivo socket criado:
1
|
|
Feito isso, é só abrir o vim e aguardar o client =)
Para que funcione, o client precisa estar conectado ao host via ssh com um usuário qualquer (o importante é ter acesso ao arquivo socket em /tmp/pair).
Depois de conectado, basta executar o comando:
1
|
|
O parâmetro “attach-session” faz o client se conectar à uma sessão alvo (-t nome-da-sessao)
Para ativar algum comando do tmux, por padrão (é possível mudar)você precisa precionar Ctrl+b
Comandos básicos (assumindo que você esteja no Linux):
É possível fazer muita coisa com o tmux. Para saber mais, sugiro que siga os links:
UPDATE (01/04/2013):
Chris Hunt palestrou na LA Ruby Conf 2013 sobre o Vim e Tmux. Ele faz o que este tutorial apresentou, e muito mais: https://www.youtube.com/watch?v=vHdiXoHKSgU
]]>Além disso, você vai querer inserir e retirar elementos de forma transparente e rápida.
Para isso, recomendo que use o Redis e seus sorted sets! Funciona de maneira bem simples e pode ser implementado em várias linguagens que possuam o cliente do Redis Acredito que seja muito mais rápido e eficiente do que armazenar em uma base convencional, fazer consultas ordenadas por score e salvar posição.
Todos os comandos a seguir estão muito bem(!) documentados no site do redis
Comando: ZADD
Cria o ranking(sorted set), se não existir, e adiciona “membro_um” com 100 pontos de score:
1
|
|
Adiciona “membro_dois” com 422.1 de score e “membro_tres” o 142 de score:
1 2 |
|
Você pode selecionar membros de determinado ranking passando um range:
1
|
|
O comando acima vai devolver 11 elementos, ordenados de forma crescente. Para ordenar de forma decrescente, utilize o ZREVRANGE.
Algumas vezes é preciso saber a posição de um elemento relativo a todo o ranking. Isso se torna um pouco complicado quando se faz utilizando SQL e bancos convencionais. No Redis é muito simples:
1
|
|
Para pegar a posição relativa ao ranking ordenado de forma decrescente, utilize o ZREVRANK:
1
|
|
Comando: ZCARD
O total de membros de um determinado ranking pode ser obtido com:
1
|
|
O Redis foi muito útil em uma historia onde era preciso otimizar a performance de páginas de rankings no Kademi. Especialmente porque usávamos vários rankings na mesma página e fazíamos grandes consultas para saber a posição atual de um membro relativo ao ranking. Utilizamos Ruby e o cliente redis-rb, e foi bem legal ver os resultados(a página em questão carrega em média 10x mais rápido agora)!
Há vários outros comandos disponíveis para Sorted set e outras estruturas de dados. Para saber mais sobre o Redis e testar os comandos em questão, acesse o site do projeto e siga o @antires, seu criador.
]]>Para contornar este “problema” o pessoal do Fedora criou o EPEL(Extra Packages for Enterprise Linux), que disponibiliza milhares de pacotes para seu CentOS, Red Hat Enterprise Linux e Scientific Linux.
Baixe uma das versões disponíveis:
EL 6:
1
|
|
EL 5:
1
|
|
EL 4:
1
|
|
Para instalar:
1
|
|
As primeiras linhas que escrevi em um projeto real foram códigos de teste. Esse foi o primeiro grande conceito que veio junto com a linguagem: o TDD. Logo no início tive contato Scrum e pair programming. Metodologias incríveis e que eu provavelmente não conheceria tão facilmente. Acredito que essa cultura de desenvolvimento ágil e inovação tem muito a ver com a comunidade Ruby. São pessoas geralmente abertas à ideias que possam melhorar o desenvolvimento de software. São desenvolvedores pragmáticos!
Isso tudo certamente -foi- está sendo bom pra mim. Eu já era muito ligado ao -movimento- “universo” open source e gostava bastante de Python, então foi muito legal começar a trabalhar com Ruby!
Conheci pessoas muito espertas que me influenciaram(e influenciam) na busca pelo conhecimento, não necessariamente na linguagem Ruby. Não acho que Ruby é a melhor linguagem do mundo, mas com certeza é uma das melhores para se conhecer. A verdade é que todos que trabalham ou vão conhecer a linguagem terão contato com conceitos muito importantes.
Recomendo a todos que deem uma chance ao Ruby. Para começar: http://www.ruby-lang.org/pt/– Site da linguagem em português http://groups.google.com/group/ruby-sp – Grupo de usuários Ruby de São Paulo http://tryruby.org/ – Try Ruby in your Browser http://rubyonrails.org/ – Ruby on Rails – Framework Web – Você precisa conhecer! =)
]]>Acredito realmente que deve-se buscar alternativas abertas, pois isso pode salvar o seu projeto!
]]>Resumidamente: precisa-se instalar bibliotecas 32 bits, mas a lista é grande, então rode e instale tudo com:
#yum install glibc.i686 glibc-devel.i686 libstdc++.i686 zlib-devel.i686 ncurses-devel.i686 libX11-devel.i686 glibc.i686 ncurses-libs.i686 libgcc.i686 ncurses-libs.i686 libstdc++.i686 libX11.i686 zlib.i686 SDL.i686 libXext.i686 libXv.i686 libXrandr.i686 alsa-lib.i686 alsa-plugins-pulseaudio.i686 Em seguida rode o seu sistema emulado:
$./emulator -audio alsa @nomedasuaAVD
Não abordei a instalação do SDK porque é fácil pra caramba. Na verdade é só baixar e descompactar. Agora vou estudar mais sobre isso… quem sabe eu consiga construir uma boa app!*–*
]]>Outra novidade é que as cores, e inclusive os gradientes, do MSN Plus! já estão disponíveis nesta nova versão(versões de testes). O suporte a webcams está avançando… você já pode visualizar a webcam de seu amigo =D (embora eu não tenha testado). Para testar as versões em desenvolvimento do emesene, você deve instalar o Subversion) que é um “controle de versões”. Para isto, abra seu terminal e digite:
Para quem usa Ubuntu ou Debian, etc:
#apt-get install subversion
Para quem usa Red Hat, Fedora:
#yum install subversion
Para obter obter o emesene-trunk(trunk é o nome dado a versões “não oficiais”) faça:
$svn co https://emesene.svn.sourceforge.net/svnroot/emesene/trunk/emesene/ emesene-trunk
Este comando copiará todo o código fonte do emesene e salvará na pasta
emesene-trunk(criada com o mesmo comando). Em seguida:
$cd emesene-trunk
e $./emesene
Você perceberá que não é
muito conveniente ficar fazendo isso toda vez que for iniciar o
programa. Então crie um lançador apontando para o emesene ;D. Para
manter os códigos atualizados, você deve entrar na pasta emesene-trunk e
digitar o comando svn up. Lembre-se que estas são versões em
desenvolvimento e podem ser muito instáveis! Recomenda-se usar a versão
dos repositórios da sua distro! Quem deseja estudar Python e a
biblioteca PyGTK, vai se deliciar com esta belezura. Para mais
informações sobre o desenvolvimento deste (ótimo) software, acesse:
http://emesene.org/smf/ Até mais.