Codemountain, Paulo Suzart's Blog

Posts Tagged ‘clojure

Flowchart de apoio a escolha de tipos em Clojure

with 4 comments

Muitas vezes fiquei em dúvida sobre qual forma de definição de tipos em Clojure utilizar. As opçõe são muitas: deftype, defrecord, reify, proxy, e gen-class e é fundamental um bom entendimento de cada uma delas para fazer a melhor escolha sua implementação.

Foi aí que encontrei este post de Chas Emerick, um dos autores de Clojure Programming: Rough Cuts Version. Este livro promete muito e não vejo a hora de tê-lo em mãos.

No post, Chas fala a respeito da tarefa de escolher o tipo certo e mostra um fluxo que ajuda e muito, não só entender os tipos, mas como fazer a melhor escolha. Depois de OGINO Masanori oferecer uma versão em Japonês, me ofereci para fazer uma tradução para português, e Chas aceitou. Assim você pode usar como Wall paper ou fazer impressão bem grande para deixar na parede mais próxima. Clique na imagem para ampliar.

Usando as próprias palavras do autor, a Zona de Interoperabilidade (ou “The ‘Interop Zone'”) do chart, agrega os seguintes casos:

“The ‘Interop Zone’” demarcates use cases (e.g. needing to define multiple constructors) and forms (proxy and gen-class) that are exclusively the domain of Clojure’s JVM interoperability support. Using these forms is fine, but be aware that by doing so, you are stepping outside of Clojure’s “native” abstractions; unless you are defining a type for the express purpose of meeting interoperability requirements, one of Clojure’s simpler type-definition forms may suit your needs better. (Chas Emerick)

Eu já precisei usar um misto de Protocols, types e Proxy como você pode ver aqui. Era justamente um caso de interoperabilidade com classe puramente Java, e obtive um ótimo resultado.

Espero que o flowchart seja útil para você também.

Update 2011-11-17 07:46 pm UTC: Chas teve uma grande ideia! Ele criou um repositório no Github onde é possível contribuir com traduções para este chart, que é dos mais úteis que já vi. Ele me acionou pelo twitter e tive o prazer em fazer a versão em Português para colocar no repo. O chart original estará publicado em seu livro Clojure Programming – que sai no final deste ano.

Written by paulosuzart

agosto 22, 2011 at 6:34 pm

Publicado em clojure, coding

Tagged with , ,

Stream Server com Clojure e Aleph

with one comment

Hoje vou ser objetivo e já começo com o código:

(ns NewStream.core
	(:use [aleph.http])
	(:require [lamina.core :as l]
	          [beanstalk.core :as b]))

	(def beans (b/new-beanstalk "192.168.0.105" 11300))

	(defn init
		[ch]
		(l/receive-all ch (fn[_]))
		(future
			(loop [job (b/reserve beans)]
				(l/enqueue ch (:payload job))
				(b/delete beans (:id job))
				(recur (b/reserve beans)))))

	(defn handler
		[ch requet]
		(let [stream (l/named-channel :news-stream init)]
			(l/enqueue ch
				{:status 200
				 :headers {"content-type" "text/html"}
				 :body (l/fork stream)})))

	(defn -main[& args]
		(start-http-server handler {:port 8089}))

E mais objetivo ainda eu digo: O Aleph é simplesmente sensacional! É um framework de comunicação assíncrona feito com o excelente JBoss Netty e um framework muito completo para programações baseada em eventos do mesmo autor do Aleph, o Lamina.

O Lamina usa canais como cidadãos de primeiro nível e compartilha o mesmo princípio de canais em Go. Mas é muuuuuuito mais poderoso.

O código acima nasceu de um desafio lançado para @abraaoisvi, @lucastex, @rafaelfelini e eu (@paulosuzart). O desafio era fazer um servidor de stream de notícias de um dado evento sem usar websocket e algumas outras restrições que não vem ao caso.

Na minha solução, tenho um servidor beanstalkd rodando num linux. Este servidor recebe mensagens de uma aplicação usada por um editor de notícias fictícia (na verdade um código tosco em python meu mesmo). E cada cliente que conecta no Aleph, vai passar então a receber as notícias uma vez emitidas pelo editor.

O código acima tem handler como a função que recebe as requisições de um browser, por exemplo. Veja que nela, stream é um canal que recebe todas as mensagens vindas do beanstalkd. O detalhe é:news-stream que é o nome dado ao canal de mensagens. Isto é, existirá apenas um canal com este nome no servidor.

init é a função que inicializa o canal stream (recebido como parâmetro ch). Como a função reserve da lib beanstalk é blocking, executo ela em outra thread usando future, e a cada nova mensagem recebida, faço o enqueue no canal stream.

O http handler responde imediatamente para o Browser com status 200 OK, mas o body é um channel que sofreu um fork do canal stream. O fork permite que cada cliente receba uma cópia das mensagens de stream a partir do momento em que fez o fork. O Lamina se encarrega de repassar todas as mensages de stream para os canais gerados a partir do fork.

Com um body sendo um channel, o Aleph vai responder a requisição usando uma resposta Chunked.

Ao acessar http://localhost:8089, o Browser vai manter a conexão aberta. Cada nova mensagem emitida será então enviada imediatamente para cada browser pendurado no server. Simples assim 🙂

Aleph + Lamina, ta aí uma boa combinação para tirar o máximo do seus processadores! Até a próxima.

Update: Algumas pessoas me perguntaram como rodar este pequeno programa. Você pode usar o Leiningen com o seguinte project.clj:


(defproject NewStream "1.0.0-SNAPSHOT"
  :description "Simple news stream server"
  :dependencies [[org.clojure/clojure "1.2.1"]
                 [lamina "0.4.0-beta2-SNAPSHOT"]
                 [aleph "0.2.0-beta2-SNAPSHOT"]
                 [org.clojars.bengl3rt/beanstalk "1.0.2"]]
  :main NewStream.core)

Depois é só executar lein deps e então lein run. Ah, não esquece de ter um Servidor beanstalkd rodando.

Written by paulosuzart

agosto 15, 2011 at 12:19 am

Publicado em clojure

Tagged with ,

OO Funcional: Clojure, Coherence e JavaScript

with 2 comments

Nossa! Estou escrevendo cada vez menos. Isso me deixa um pouco triste. Mas é consequencia de algumas mudanças, até agora positivas.

Durante o carnaval decidi implementar uma ideia que havia comentado com @danielamadei. É uma idea simples: Criar uma fina camada REST em cima do Coherence, expandindo assim sua aplicabilidade para além do Java, .Net e C. Bom, o objetivo mesmo é estudar e aplicar o que tenho aprendido em algum caso que eventualmente pode se tornar útil. A mistura de Coherence com Clojure e Javascript motivou a elaboração do post e o título dele.

O resultado foi: Clojure, Ring, Rhino e Moustache. As libs contrib usadas foram: Duck-streams, json e string.

Mas, antes tentei fazer uma coisa mais louca com Aleph e Lamina. Aleph é um framework de comunicação  assíncrono escrito sobre lamina e JBoss Netty criado pelo mesmo autor do Lamina. É interessante, mas o Aleph acabou se mostrando com um nível de maturidade insuficiente para o que queria fazer, embora fosse simples.

Na lib que dei o nome de CoheREST, fiz a parte de inserção e busca pela chave. A parte mais interessante foi usar o Rhino pra executar funções Javascript submetidas via http para o servidor Ring. Bom, a abstração para acesso ao Coherence ficou assim:

    (with-cache "My-Cache"
        (put-val 1 {"name" "Paulo" "age" 20}))

É isso mesmo, basta esse código para iniciar, criar e inserir um Map com a chave 1 no cache de nome “My-Cache”. Analogamente, pare obter o valor, basta usar uma função chamada get-val. Mas isso foi só pra ilustrar como ficou a simples abstração.

Ok! O Coherence tem uma feature muito interessante. Ao invés de pesquisar no cache uma certa quantidade de entradas, efetuar algum tipo de operação e depois submeter as mudanças ao cache, ele permite que o processamento seja emitido por todo o cache (EntryProcessor). Isto faz com que o processamento ocorra localmente – no nó do grid em que a entrada reside – sem onerar o nó emissor do processamento. Isto é obtido emitindo para o cache uma implementação de AbstractProcessor.

Para emitir um Entry Processor, é possível fazer como se faz para por ou resgatar uma entrada no cache:

    (with-cache "My-Cache"
        (process 1 (coherest.processor.JSProcessor. some-js)))

Só uma observação, nesta versão implementei a emissão de um EntryProcessor para uma única entrada, aqui com a chave 1. E agora começa a parte interessante. coherest.processor.JSProcessor é executado por um EntryProcessor (apresentado mais abaixo), e é ele quem executa javascript no cluster, desde que o javascript tenha o seguinte formato:

    function(e) {//e é a entrada no cache
         e.age = e.age + 1;
         return e;
     }

Isto é, caso a entrada seja encontrada, ela será passada no formato JSON para a função que pode alterar a entrada e retornar o resultado do processamento. Aqui o exemplo é um  simples incremento da propriedade age da entrada. A função é a string some-js passada na construção do JSProcessor. E é aqui que o OO funcional começa.

JSProcessor é um type que implementa um Protocol (leia-se interface em clojure) que define apenas uma função: process. O Protocol e o type ficam assim:

    (defprotocol PProcessor
        (process [this entry]))

    (deftype JSProcessor
		[^String script] java.io.Serializable PProcessor
		(process [this entry]
                       ;; Implementation went here))

Simples, o Coherence vai invocar apenas o método process(entry) na Implementação de AbstractProcessor. Como o processor é espalhado pelo cluster, ele também precisa implementar Serializable. Mas no início do post falei que um EntryProcessor deve implementar AbstractProcessor, mas esta classe não apareceu em lugar nenhum aqui até agora. Acontece que por questões de design, meu Protocol PProcessor é na verdade invocado por uma implementação anonima de AbstractProcess. Esta implementação anonima é que contem a implementação do método process, que por sua vez se encarrega em a função process do JSProcessor, passando como argumento a entrada encontrada no cache. Veja como ficou:

(defn make-processor
	"Create a valid Coherence EntryProcessor from the PProcessor passed
	 as agurment"
	[processor]
	(proxy [AbstractProcessor] []
	    (process [entry]
		(process processor entry))))

Ufa! make-processor é uma função que recebe a instância de JSProcessor, cria um proxy de AbstractProcessor, onde sua implementação é justamente a invocação da função process nele passando a entrada encontrada. A implementação de AbstractProcessor não passa de uma porta de entrada para a invocação das funções definidas pelo PProcessor. E usar um Protocol para o carro chefe na execução de funções no cluster permite que criemos instâncias deste protocol que façam o que desejarmos. O JSProcessor no caso, usa o Rhino pra executar funões no grid.

O CoheREST foi feito sem nenhuma intenção comercial, tão pouco para uso em ambiente corporativo. Isto por que ainda preciso verificar algumas questões de licença. Aí posso liberar o fonte no meu github. O post já foi bastante longo e não pude entrar em detalhes sobre o CoheREST ou sobre o Ring e o Rhino sendo usado direto em Clojure. Mas fica uma deixa pra próximos posts.

Bom, e aqui tivemos herança, programação com interfaces, etc, tudo em clojure, uma linguagem não orientada a objetos, mas que não nos limita em nada a usar conceitos OO. Obrigado e lembre-se: @paulosuzart.

Written by paulosuzart

março 14, 2011 at 1:07 pm

Publicado em clojure, coherence

Tagged with ,

clojure + xml com saxon e xstandard

leave a comment »

Outro dia no trabalho estava definindo alguns padrões de como um XSD deveria ser escrito. Coisas simples como formato de nomes de elements, complexTypes, se o XSD deveria ter targetNamespace e attributeFormDefault.

Foi aí que surgiu a ideia de fazer um script em clojure que validasse isso em um dado XML e indicasse o que está fora destes padrões. Claro, algo assim existe por aí. Mas não dá pra perder a oportunidade. Juntei algumas funções auxiliares em cima do Saxon, um wrapper clojure do Saxon XSLT and XQuery Processor. A ideia foi pegar a base do Saxon e usar de tal forma que eu pudesse aplicar algumas asserções a um documento XML.

Queria trabalhar com a idea de assertions. Elas, além do nome, seriam compostas por uma expressão xPath, uma mensagem de falha, uma segunda expressão xPath para localizar que atributo do nó sendo avaliado seria considerado como display-name e uma função de validação que receberá o nó sendo avaliado e simplesmente retornaria true ou false. O resultado foi uma pequena lib commitada no meu github: xstandard.

Por questão de praticidade, escolhi uma estrutura de map par armazenar as informações de uma assertion. Ah, e pra tornar ainda mais prático, criei uma macro que ajuda a definir uma assertion assim:

(defassertion element-name "//xsd:element[@name]"
  :msg "element %s does not match [a-z].*."
  :validator (attr-matches "name" #"[a-z].*")
  :display-name "data(./@name)")

Esta assertion fará análise – através do validator –  de todo elemento do meu XSD cujo atributo name esteja presente. Ok, mas decidi agrupar as assertions, eu poderia eventualmente tratar grupos diferentes de formas diferentes ou usar  a saída delas de forma diferente. Por isso existe uma outra macro que me permite fazer assim:


(defassertions *default-assertions*

  (defassertion element-name "//xsd:element[@name]"
    :msg "element %s does not match [a-z].*."
    :validator (attr-matches "name" #"[a-z].*")
    :display-name "data(./@name)")

  (defassertion type-name "//xsd:complexType[@name]"
    :msg "type %s does not match [A-Z].*Type."
    :validator (attr-matches "name" #"[A-Z].*Type")
    :display-name "data(./@name)")

  (defassertion element-form-default "/xsd:schema"
    :msg "schema hasn't attr elementFormDefault=\"qualified\""
    :validator (attr-eq "elementFormDefault" "qualified"))

  (defassertion target-ns "/xsd:schema"
    :msg "schema hasn't targetNamespace attr"
    :validator (attr-present "targetNamespace")))

Legal, agora temos um grupo de assertions. Mas como executá-las? Simples, basta passar o conjunto de assertions aqui chamado *default-assertions* para a função run provida pela lib. O que fica mais ou menos assim:

  (xs/run *default-assertions* xs/*nss* xmldoc)
  ;; *nss* is provided by the lib with a default namespace prefixe for xml schema.

Por padrão a lib vai retornar o resultado do processamento em um map contendo o nome de cada assertion, o caminho para o nó analisado no xml, a linha no arquivo:

{:assertion :element-name, :status false, :display-name Item,
 :details {:result-msg element Item does not match [a-z].*.,
           :line 25,
           :path /xs:schema/xs:element[1]/xs:complexType[1]/xs:sequence[1]/xs:element[3]}}

Note no código onde declarei todas as asserções, a função attr-matches sendo usada na assertion type-name. Ela recebe como parâmetro o nome do atributo do nó analisado e uma regex para verificar o formato do atributo. Note também que a função é executada no momento da montagem da assertion, pois ela retorna uma segunda função, que esta sim, receberá o nó analisado e fará a checkagem do formato. O código de attr-matches é:

(defn attr-matches
  "Validates the format of a given node `n` against `regex`."
  [attr regex]
  (fn [n]
    (not (nil? (re-matches regex (get-attr n attr))))))

Lindo, não? Bom, para se divertir mais no código basta acessar meu github.

Pra fechar, durante a criação desse projetinho tive a oportunidade de usar a IntelliJ IDEA. Surpreendente! Muito boa e estável, sem falar do plugin clojure e leiningen muito bons. Ah, pra somar ao aprendizado, utilizei o Marginalia pra gerar a documentação do xcode, veja aqui. Basta salvar o html e ver a doc do projeto de uma forma bem interessante. O Marginalia é um projeto do @fogus.

Não esqueça de me seguir no twitter: @paulosuzart.

Written by paulosuzart

fevereiro 7, 2011 at 12:00 pm

Publicado em clojure

Tagged with ,

5 coisas para tornar o seu cérebro funcional

leave a comment »

Desde janeiro de 2009, no meu primeiro post sobre Scala, venho na verdade falando de um paradigma desafortunadamente não ensinado na maioria das universidades brasileiras: Programação Funcional. Se alguém tem/teve aulas de programação funcional na universidade por favor deixe o nome da instituição nos comments.

O que percebi nestes dois anos de posts sobre programação funcional e duas (Scala e Clojure) das linguages que suportam este paradigma, é que muitos leitores sentem uma dificuldade em se livrar das suas raizes imperativas, e a syntax destas linguagems acabam ficando até como uma dificuldade em segundo plano.

Por isso resolvi escrever este post compacto que serve mais como direcionamento para tornar o seu cérebro funcional. Aqui vão 5 coisas que vão ajudar o programador a atingir seu momento de iluminação funcional:

1. Lambda Calculus

Estude essa coisa. Lambda Calculos, em muito alto nível, é a raiz da programação funcional. Neste cálculo, tudo é uma função, inclusive os números naturais, as operações algébricas, etc. Este sistema formal, possui uma série de colorários e propriedades que vão embasar as linguagens de programação funcional. E não, eu não sou especialista em Lambda Calculus e estou longe de ter fôlego intelectual pra isso. Mas ver a introdução é um bom começo pra se sentir confortável.

2. Diga ‘o quê’, não ‘como’

Isto está bastante ligado a funções de alto nível (High-order functions). São aquelas funções que recebem funções como argumento e até mesmo retornam alguma função. Fortes exemplos de funções de alto nível são funções de mapeamento em listas. Ou seja, você tira da sua responsabilidade a iteração de uma sequencia e informa para a função de mapeamento, qual função você quer aplicar nos elementos da sequencia. Exemplo:

(def numbers (range 5))
(map #(* % %) numbers);; obtem o quadrado de cada ítem da lista de 0 a 4.

Aqui podemos ver a funções de alto nível map em ação, esta é provavelmente a função mais utilizada e mais exemplificada na internet. Mas é realmente prática e fácil de entender a coisa. Simplesmente pedimos que seja aplicada a função anônima que multiplica cada ítem por ele mesmo. Esta: #(* % %). Não vemos um for, iterações ou coisas do gênero.

3. Entenda funções parcialmente aplicadas

Elas são úteis. Você pode computar somente entradas pra uma função, mas ao invés de aguarda que você obtenha todas as entradas para ela, você pode começar a aplicar (invocá-la) com os parâmetros que você possue em mãos e passá-la a diante. Veja um exemplo: Usando o mesmo numbers acima, vamos computar a multipliação de cada ítem de 0 a 4 por algum número que ainda não conhecemos.

(def partials (map #(partial * %) numbers)))
(map #(% 2) partials);; = (0 2 4 6 8 )

partial também é uma função que recebe uma função (a função de multiplicação *) e um parâmetro para ser aplicado a esta função, no caso cada ítem da sequencia. partials é a minha lista de funções parcialmente aplicadas. Algo como: ((* 0 ?) (* 1 ?) (* 2 ?) (* 3 ?) (* 4 ?)). Wow! Interessante. A segunda funão no código acima aplica a função gerada na lista de partials ao 2. 2 é o número que gostariamos de multiplicar cada elemento de 0 a 4 inicialmente, lembra? Acredite, isso é útil demais e existem muitos frameworks usando fortemente funções parcialmente aplicadas.

4. Imutabilidade é natural

Este é o tópico que talvez tenha gerado o maior hype nesta história de programação funcional. O resultado foi um monte de final nas variáveis em java, na esperança de isso ser suficiente para programar funcional ou garantir alguma imutabilidade. Na verdade de nada adianta colocar final na variável da classe, digamos, Pessoa e todos os seus atributos não serem final. E aí vem: Mas clonar a cada set vai custar memória? Vai. Clojure resolve essa questões com estruturas de dados persistêntes. Aqui você encontra uma boa explicação sobre estas estruturas. Vamos a um exemplo: Pegue a lista numbers e faça um prepend do valor 5 nesta lista:

(cons 5 numbers);; o REPL mostrará (5 0 1 2 3 4)
numbers;; e o REPL mostrará novamente (0 1 2 3 4)

Isso deixa claro como numbers não vai mudar. A menos que você use algum artifício da sua linguagem (clojure: atoms, refs, vars, agents e pods brevemente) para acesso aos valores de uma identidade ao longo do tempo. Ainda assim, o que vai mudar é o para onde no tempo a sua identidade aponta, mas os valores nunca irão mudar. Assim como seu passado não mudará. Profundo. Mas não fica proibido o uso de alguma variável completamente mutável.

5. Recursividade não deve ser estranho

Funções recursivas por incrível que parece ainda causam confusão na cabeça da grandíssima maioria dos programadores. Este post de Michael Kohl (@citizen428) fala especificamente de Y Combinator que é implementado com um conjunto de funções recursivas, lambdas e high-order functions ao mesmo tempo. Entender este post é obrigatório se você quer seu cérebro afiado.

Além disso…

Na verdade existem conceitos mais profundos no universo funcional. Coisas que sinceramente são capazes de torcer o cérebro de qualquer um. Existem também outras linguagens que não estas que mais estudo como Erlang, Haskell (talvez a mais impressionante em termos conceituais e expressividade funcional), Scheme, Lisp, Racket (sensacional), e outras.

Programação funcional não é sobre moda, ou sobre “passar um método como argumento”, ou “sobre escrever um programa inteiro em uma linha só”. FP (Functional Programming) é sobre elaborar soluções focadas no problema, e de forma elegante e muito concisa. Ainda que não use no seu dia-a-dia, é de grande utilidade para suas próximas construções mesmo numa linguagem imperativa. 🙂

É isso e não esqueça de me seguir no twitter: @paulosuzart.

Ah, este post deveria ter 10 itens. Estou buscando os demais itens no exterior. Espero conseguí-los. Este post teve apoio de @jneira.

Written by paulosuzart

janeiro 1, 2011 at 3:58 pm

Publicado em clojure

Tagged with ,

Clojure macros

leave a comment »

É um pouco contraditório falar do básico de uma linguagem e já envolver um framework tão rebuscado quanto o Enlive. Não vou falar muito deste framewok, só o suficiente para deixarmos nosso exemplo mais interessante.

Um amigo me perguntou qual era o meu público alvo depois de ler o último post. Ele falou sobre ter feito uma série de posts sobre scala de forma suave, e de repente cheguei como um trem falando de clojure.

Pra compensar, neste post vamos ver uma pequeníssima introdução a algo muito poderoso da linguagem: Macros. Vejamos uma enxuta definição do Eric Rochester:

“A macro is a function that accepts Clojure code—represented as lists, vectors, symbols, strings, numbers, and other Clojure data types—and returns another list, vector, etc., that represents Clojure code.”

O que passa é que o código clojure é exatamente composto por suas próprias estruturas de dados como vetors, listas, mapas, conjuntos, etc. Esta é uma característica das linguagens de programação Homoiconicas. No fim das contas o que temos é a possibilidade de manipular o código (literalmente) antes que este seja compilado e executado. Pode ser absurdo, mas em *algumas situações* uma macro age como um wrapper ou decorador de uma função lembrando até mesmo o padrão de projeto – guardadas as devidas proporções – do GOF, Decorator.

Mas com macros, não criamos um objeto, extendemos aquele outro ou implementamos alguma interface. O que fazemos é alterar o código inserindo antes, depois ou ao redor dele, algum outro código. O uso de macro pode ser tão complexo ou alto nível quanto queiramos. Mas acho que pra as minhas possibilidades, um exemplo simples é o adequado.

Enquanto estudava a linguagem me perguntava quando usar uma macro, e acredito ter arrumado um bom exemplo. Os nossos amigo da Caelum fizeram um site legal apoiando uma iniciativa que apoio há algum tempo: seja um programador poliglota. E pra os que pensam que programar é coisa de peão, vejam este excelente artigo intitulado: LA RAÍZ DE LA PRECARIEDAD EN LA INFORMÁTICA, onde o autor descreve um cenário que se aplica perfeitamente ao brasil e certamente a muitas partes do mundo: o descaso com o desenvolvimento de software por parte das consultorias, dos pseudo-engenheiros de software, etc.

Vamos ao ponto! O script a seguir usa o poder do Enlive para pesquisar nas tags HTML retornada pela requisição ao site programadorpoliglota, o conteúdo onde aparecem as citações lá listadas. Examinando o fonte HTML, vemos que os tweets são colocados num span de classe tweet_text (isso significa que este script será válido enquanto este for o css usado no site).

O Gist http://gist.github.com/617497 mostra a evolução desta ideia até chegarmos no código abaixo:

(ns enlive
   (:use [net.cgrand.enlive-html])
   (import java.net.URL))

(def target "http://www.programadorpoliglota.com.br")

(defn citations    "check if the given twitter user u was cited."
    [u]
    (let [tweets (-> target URL. html-resource
                    (select [:span.tweet_text]))
          progs (select tweets [:a content])]
        (count (filter #(= % u) progs))))

(defmacro every
    "wraps a serie of functions f to be called every t seconds."
    [t & f]
    `(let [t# (* 1000 ~t)]
         (loop []
             (do ~@f)
             (. Thread (sleep t#)))
             (recur)))

(defn run []
    (future
        (every 10
            (println "Number of citations is: " (citations "your-user-here")))))

Colei o código completo, mas vamos analisar por partes. O foco aqui é a macro every. Ela recebe como parâmetro 2 argumentos t e f. O & é semelhante ao varargs java, com a diferença de receber qualquer tipo de argumento.
Como você deve ter notado, para definir funções em clojure, usamos defn e para macros, defmacro. o argumento t representa o tempo que precisamos colocar nossa thread para dormir entre cada execução de f. E f são todas as funções passadas como parâmetro para every.

Começamos nossa macro pedindo que ela gere o código de let, que vai avaliar a multiplicação de 1000 por ~t e atribuir a t#. Aqui a coisa pode começar a ficar estranha enquanto você não se acostuma.

~t pede ao reader para fazer um evaluate do argumento t da macro, retornando (para o exemplo) o valor 10. O resultado será atribuído a uma variável cujo nome único gerado não sabemos, mas usamos t# para referenciá-la no restante do código (veja o sleep t#).

Outro ítem novo é o ~@, que não tem segredo, podemos ver esta forma especial como um ~ para cada elemento dentro do vetor (do varagrs) que f é.

Por último temos uma função auxiliar de nome run. Usei um future para liberar a thread do REPL clojure e permitir o recarregamento do código enquanto fazia os testes. Ela não é mandatória na linguagem e é uma função como outra qualquer.

O que ganhamos até aqui? Ao de fixar que a função citations (definida mais acima) possua no seu código o comportamento de executar a cada 10 segundos, ou até mesmo usar uma função auxiliar pra isso, o que fizemos foi mudar o nosso próprio código a ser gerado “inserindo” (println “Number of …) onde você vê ~@f. Essa é uma visão simplificada de macros, um instrumento poderoso que permite você construir programas que modifiquem ou mesmo produzam outros completamente diferentes. E se quiser vermos o resultado de código gerado ao executar a macro? basta fazer um:

user=> (macroexpand-1 '(every 10 (println "Number of citations is: " (citations "your-user-here")))

(clojure.core/let [t__1790__auto__ (clojure.core/* 1000 10)]
     (clojure.core/loop []
        (do (println "Number of citations is: " (citations "your-user-here")))
        (. java.lang.Thread (enlive/sleep t__1790__auto__)))
        (recur))

Num código de uma aplicação não há diferença entre invocar uma macro ou uma função, as duas tem a mesma estrutura e o Clojure Reader vai se preocupar em fazer iso por você. Acima, o macroexpand-1 vai retornar a nossa função depois de passar pela macro. Note que o código gerado foi exatamente o que descervemos acima e a variável t# que assume o nome t__1790__auto__.

O que acabamos empacotando numa execução a cada 10 segundos não foi exatamente a função citations, foi a invocação desta função que acontece dentro da função print. Assim podemos manter “a lógica” de imprimir a consulta fora da função citations e da nossa belíssima macro every.

E é só. O uso do Envile fica como apoio para permitir fazermos alguns selectors no HTML retornado pelo site. Espero ter ajudado a fundamentar a linguagem e é claro não esqueça de me seguir no twitter: @paulosuzart.

Written by paulosuzart

outubro 9, 2010 at 3:30 pm

Publicado em clojure

Tagged with ,

Clojure na web – Compojure/Hiccup/Sandbar/Leiningen

with one comment

Quanta coisa aconteceu desde o último post! Umas boas, outras ruins. Uma das boas é que agora você pode ler artigos meus em scala-br.org. O primeiro post na verdade é um repost de um texto já publicado aqui no Codemountain.

Desde o último post fiquei bastante ocupado com a pós, até passei a estudar menos as coisas que gosto por conta disso. ¬¬ Mas arrumei um tempo pra parar de apenas dar RT no twitter sobre clojure e resolvi fazer uma micro app para web usando esta fabulosa linguagem e alguns dos frameworks disponíveis.

O post não contém nada extraordinário ou que não seja possível encontrar nas documentações dos frameworks, a intenção mesmo é fazer uma introdução – em português – do que pode ser seu ferramental de amanhã.

Anote a receita:

  • Um pouco de Ring. Algo com WSGI para Clojure, abstraindo o HTTP numa DSL concisa. Aqui vamos usar seu adaptador para Jetty.
  • Uma pitada de  Compojure. Um webframework simples onde o foco aqui  é o uso dos seus routes para construir o que o Ring chama de handlers.
  • Uma boa dose de Hiccup. Isto é, vamos representar nosso html em Clojure. Não é fantástico?
  • Uma forma em Sandbar. Na verdade é possível construir html forms com Compojure + Hiccup. Mas acredite, construção de forms com Sandbar é mais sexy.
  • E pra selar tudo, nossa ferramenta de build expressa na linguagem: o Leiningen. Este nome vem de um personagem que luta contra formigas na Amazônia. As formigas que esta ferramenta luta contra são os antigos builds.xml usando Ant. Nome criativo.

Me referi a receita, por que criar software é uma arte como cozinhar, já dizia Terrence Parr, ele é só o autor do ANTLR.

A aplicação: Moyure

Muito simples. Uma página principal – sem autenticação ou belezas visuais – com um link para a página de criação de um registro do seus Meet Ups! O nome Moyure não tem uma história tão interessante quanto a do Leiningen 😦

Após incluir o registro, a aplicação deve voltar à página principal e mostrar a listagem do registro existentes com um link para edição em cada um deles.

O Banco de Dados: STM

STM (Software Transactional Memory) é, a grosso modo, transações em memória. Isso mesmo, sem uso de locks explícitos podemos efetuar transações em memória usando Clojure Refs. A linguagem oferece outras formas de isolamento/concorrência, mas me pareceu suficiente usar Refs. O objetivo de ter feito um pequeno conjunto de funções é permitir que você faça um clone da aplicação no git (link mais abaixo) e possa executa-la sem se preocupar em gerar schemas/massa de dados ou mesmo instalar uma base. Nosso banco se resume a:

(ns moyure.db)
(def id (ref 0))

(def db (ref {}))

(defn nextval [] (dosync (alter id inc)))

(defn insert-meet
    "Insert a new meet."
    [d] (dosync  (let [nid (nextval)]
          (alter db assoc nid (assoc d :id nid))  nid)))

(defn find
    "If id present, returns the given entry.  Otherwise, returnts all
    entries (the actual map of db)"
    ([] @db)
    ([id] (get @db id)))

Não desanime. O post está só começando. Resumindo, temos aqui duas Refs. Veja id e db sendo definidas com (ref), isto é, para “alterar estes valores” precisamos faze-lo dentro de uma transação. Para isso usamos (dosync) para estabelecer um escopo transacional e (alter) para efetuar a alteração. É possível envolver mais de uma variável em uma transação, e é o que temos aqui. As variáveis id e db estão envolvidas na mesma transação e serão alteradas com sucesso juntas, ou retornarão ao seu estado original se necessário.

Dito isto, precisei garantir que esse banco de dados de última geração 🙂 se comportaria como desenhei. Pra isso usei o pacote clojure.test disponível na própria linguagem. Os testes são simples e autodescritivos. Eles tem mesmo a cara do RSpec. Veja:

(ns moyure.test.db
    (:use [moyure.db])
    (:use [clojure.test]))

(deftest db-t
    (testing "db"

         (testing "should return 1 in the first insertion and 2 in the second."
            (is (= (inc @id) (insert-meet {:title "test" :when "today"})))
            (is (= (inc @id) (insert-meet {:title "doc" :when "saturday"})))

            (testing "And and then nextval should return 2."
                (is (= (inc @id) (nextval)))))

         (testing "Should return all entries (2) with unspecified id."
            (is (not= 0 (count (find))))
         (testing "But should return one entry using id as argument."
            (is (not= nil (find (dec @id))))))))

Testes desse tipo fazem a diferença, numa linguagem dinãmica, ainda mais. Por que basta você ficar sem mexer numa parte do código por uma semana e já não vai lembrar tão bem das coisas. Os testes vão garantir a evolução do seu código sem medos.

Existem libs mais apropriadas para BDD como o Lazytest apontada pelo @alandipert. Vale conferir.

O Projeto

Quase esqueço! Precisamos configurar o nosso novo projeto (sei que você vai fazer um clone do github, mas fica a dica). Para criar um novo projeto com o Leiningen, precisamos de um project.clj com a descrição do projeto. Uma versão simples seria:


(defproject moyure "1.0.0-SNAPSHOT"  :description "Save your meet ups in the speed of clojure"
    :dependencies [[org.clojure/clojure "1.2.0"]
                            [org.clojure/clojure-contrib "1.2.0"]
                            [compojure "0.5.2"]
                            [ring/ring-jetty-adapter "0.3.1"]
                            [hiccup "0.2.7"]
                            [sandbar/sandbar "0.3.0-SNAPSHOT"]])

A aplicação foi construída com este super Banco de dados em db.clj (acima) e core.clj que contém tudo: layout, forms, rotas de requisição http, etc. Mas sempre será boa prática separar melhor as coisas. Pra efeito de exemplo, acho que é suficiente.

A primeira coisa a definir na nossa aplicação pode ser o conjunto de rotas, isto é, quais urls serão acessíveis pelo usuário e para que função cada url será mapeada. defroutes é a macro responsável por gerar nossas rotas:

 (defroutes app-routes
     (GET "/" [] (home))
     (meetup-form (fn [request form] (layout form)))
     (route/not-found (layout [:h2 "Page not found dude!"])))
 

Observe a macro GET, ela mapeia o verbo GET Http na url / sem parâmetros para a invocação da função home. Em seguida vemos meetup-form, não necessitamos gerar explicitamente uma rota com verbo e url pois estes dois elementos definidos no próprio form com a macro defform. Esta macro é quem faz toda mágica do Sandbar, e entender vai demandar um pouco de intimidade com clojure e macros.

Nossa última rota é a rota para tudo que não seja “/” nem “/meetup” – a url para a página de cadastro. Usamos not-found, uma rota que retorna 404 para o browser.

Parece um monte de coisa até aqui pra fazer algo tão simples assim. É, parece, mas é questão de costume.

Agora vamos à função home ela é quem vai fazer a consulta por todos os registros no banco de dados e exibir uma tabela com os resultados.

(defn show-all
    "Generates a html snipet for entries"
    [a]
    (for [[k v] a]
        (let [id (:id v)
             title (:title v)]
             [:tr
                [:td id] [:td title]
                [:td (link-to (str "/meetup/" id) "Edit")]])))

(defn home
    "The welcome screen"
     []
     (layout [:div
                    [:b "Hello Visitor"]
                    [:p (link-to "/meetup" "New MeetUp")]
                    (if-let [a (db/find)]
                       [:table (show-all a)])]))

Aqui entra o Hiccup, de fato as tags aqui não passam de vetores com uma :chave e um valor nativos Clojure, o tratamento disso acontece na função layout (a seguir). É possível passar atributos para o elemento html em quesão, css, eventos js, etc. Tudo direto do clojure. Note a função find do nosso banco sendo invocada. E pra facilitar a modularização, a geração das tr/td html é feita a função show-all. Esta última recebe algo como {1 {:id 1 :title “Consulting” :when “Saturday” :subject “Check some code!”}}. Note o link para a página de edição, que é: /meetup/{id}. Simples! Ah, outra coisa fabulosa é que você abre a tag e o fechamento do vetor dela já basta, o Hiccup faz a geração correta para você. Me lembra até HAML ou SCAML.

Agora vamos para a melhor parte. O form com Sandbar. Eu espero algum dia construir algo assim. Vejam:


(def m-label
      {:title "Title"
       :when "When"
       :subject "Subject"})

(forms/defform meetup-form "/meetup"
:fields [(forms/hidden :id)
                (forms/textfield :title)
                (forms/textfield :when {:size 10})
                (forms/textarea :subject)]
:load #(db/find %)
: on-cancel "/"
: on-success #(do (db/insert-meet  % )
                 (flash-put! :user-message [:p "Meet up saved, go tell your friends!"])
                 "/")
:properties m-label)

A grande sacada do Sandbar é através de :chaves fazer a definição do que o nosso form precisa. Vale a pena ver esta macro. Nosso forme de nome meetup-form é bem explicativo, creio. Basta ressaltar as chaves :load  e :on-sucess, que são quase intuitivas, você só precisa saber o que é este % nelas.

Estas chaves representarão funções que recebem um argumento. :load representa uma função anônima (lembre-se do #) contendo o id da requisição em caso de edição. Ou seja, o valor de % é mapeado automaticamente para 1 na url “/meetup/1” . Então, passamos este valor para a função find do nosso banco. Esta função retorna um map com chaves de mesmo nome dos campos, permitindo que o formulário seja preenchido automaticamente. WOW!

E quanto a : on-success? Neste caso o % representa o mapa de campos preenchidos (estes campos podem ser validados com o próprio Sandbar, mas acho que já deu no post). Veja que a função anônima de : on-success  invoca a função de inseção com o mapa de valores, em seguida salva no scopo flash da requisição uma mensagem, e por último retorna para onde a navegação deve seguir após o dado ser persistido. Isso mesmo, tão simples quanto isso.

Não tem nada de ocultismo no %, esta á a forma curta de referenciar o primeiro argumento de uma função anônima em clojure. E o valor que ele recebe pode ser facilmente verificável na documentação da lib Sandbar.

Se você chegou até aqui, obrigado. Confesso que as vezes me sinto só nessa mundo Scala, Clojure, etc. Então não deixe de me seguir no twitter (@paulosuzart).

Por último, e tão importante quanto tudo. Está nossa função layout, ela é quem invoca a função html do Hiccup e gera o nosso correto HTML


(defn layout
    "Acts as a template wrapping all the content (cont) in the
base structure"
    [con]
    (html [:html
             [:head
                 [:title "Organize your meet ups with Moyure"]
                 (stylesheet "sandbar-forms.css")
                 (stylesheet "sandbar.css")]
             [:body
                 [:h2 "MOYURE"]
                 (if-let [m (flash-get :user-message)]
                     [:div m])
                  con]]))

Sempre que alguém invocar layout aqueles vectors contendo :chaves serão passados como parâmetro, e aqui acontece a mágica do HTML. Nesta função vemos o uso de .css – que peguei emprestado do pessoal do Sandbar (Não foram alterados e os créditos são deles). Existe uma pasta chamada public/css no projeto, e lá estão os css usados.

E como testar isso tudo? Vá até o meu repositório no GitHub e faça um clone: http://github.com/paulosuzart/moyure. Supondo que você tem o Leiningen instalado, basta fazer:


lein repl
#Deve aparecer algo como:
"REPL started; server listening on localhost:54837."
user=>
# e você faz uso do moyure.core:
user=> (use 'moyure.core)
user=> (run)

Basta acessar http://localhost:8080 e pronto. Jetty rodando com sua aplicação Web em Clojure. Você pode baixar a aplicação e modificar ela para deployar no Google App Engine como exercício, ou mesmo corrigir a função db/insert que insere duas vezes um registro ao invés de atualizá-lo.

A aplicação no GitHub tem algumas coisas não comentadas no post para tentar simplificar. Pretendo explorar mais Clojure na Web e quem sabe mostrar mais detalhes e ir mais a fundo em cada um destes frameworks/libs separadamente. Vamos ver o que consigo.

Conclusão

Clojure é uma linguagem que já ganhou espaço. Só que fora do Brasil. Existem empresas muito focadas nela para os mais variados tipos de problema como a Relevance. A insatisfação razoável com – a linguagem e não a plataforma java – para internet é algo que pode ser observado nos últimos anos, e boas alternativas já existem como Rails, Grails, Play, Django, etc. Mas nenhuma delas tem Clojure, uma linguagem puramente funcional que permite construir soluções elegantes e concisas. Esta virou sem dúvida primeira opção pra mim junto com Scala e Python. Espero ver um pouco de Clojure nos próximos grandes eventos no Brasil.

Pra matar a curiosidade de alguns e preguiça de outros, segue o print das telas (observe as urls no browser):

Update: Os testes sofreram uma pequena modificação para funcionar com a JVM persistente do Cake. Ao invés de identificadores hard coded, passei a usar o último valor do id do banco para a escrita dos testes (veja @id nos testes).

Written by paulosuzart

outubro 8, 2010 at 5:49 am

Publicado em clojure

Tagged with ,