Velocity – incluindo diversos arquivos através de um loop

O Chris já publicou aqui um tutorial de Velocity, uma linguagem de templates que estou usando diariamente no trabalho.

Como eu não conhecia a linguagem até começar a trabalhar aqui, existem várias coisas que são são novidades para mim – e os blogs e docmentações estão ajudando a aumentar a produtividade.

Para compartilhar o que aprendi (e servir para minhas consultas futuras), fiz algumas contribuições com posts aqui no O Desenvolvedor, e entre as relacionadas ao Velocity (e Java) destaco duas:

  1. Formatação de datas em Java
  2. Loop no Velocity com limite numérico (foreach)

 

Velocity – Loop de includes usando variáveis

Estava estudando métodos para dar include (parse) em arquivos com o Velocity, e em um caso específico queria incluir diversos arquivos através de um loop: código enxuto, ao invés de adicionar uma linha para cada parse.

Se você não sabe como funciona o parse no Velocity, veja este exemplo de código.

 

 

Para ilustrar este post, criei um "problema" e abaixo explico a solução.

 

Problema
Necessário fazer diversos includes a partir de uma lista de arquivos (string).

Solução
Pegar a lista, transformar em array e usar o parse para cada elemento do array

 

Supondo que você tem a string: "include1,include2,include5" e estes são os nomes de arquivos que você precisa incluir, o primeiro passo é dar um split pelas vírgulas e transformar isso em um array.

 

 

Primeiro setamos uma variável ($inc) com a lista de includes que serão feitos

#set($inc = "include3,include4,include9")

Abaixo utilizo o método split (ler documentação) na variável $inc gerada anteriormente, separado os elementos pela vírgula e criando um array com os nomes dos arquivos (o array poderia ser criado diretamente, porém usei o string para enriquecer mais o exemplo).

#set($arr = $stringUtils.split($inc,","))

Pronto, agora temos um array com o nome dos arquivos e é aqui que a "mágica" começa. Criamos um loop (foreach) para o array, e dentro dele definimos uma variável com o caminho do arquivo que será incluído e chamamos o parse para a variável do caminho ($dir).

#foreach($o in $arr)
   #set($dir = "includes/vm/"+$o+".vm")
   #parse($dir)
#end

 

Tentei concatenar o nome do arquivo (elemento do array) com o caminho direto na linha do parse e não funcionou. O workarround de definir a variável antes resolve o problema!

Espero que seja útil, esse script pode ser bastante útil para o controle de includes!

Formatação de datas – Java

Ontem eu estava apanhando para fazer formatação de data no Velocity (leia o que é Velocity?) para um template e antes de implementar uma POG com vários elseif´s, pedi uma ajuda para o Chris para saber se já existia alguma classe ou função disponível para formatação de datas em texto (em número já estava funcionando).

Danger!

Antecipo que qualquer coisa relacionada a Java ainda é uma novidade para mim, escrevi este post baseado na documentação da Sun (de uma classe) mas mesmo assim caso tenha alguma bobagem no conteúdo comentem, a internet está aí para possibilidades de correção e melhoria do conteúdo! 😉

O Chris me enviou um ótimo link de referência sobre a classe SimpleDateFormat do Java (me corrijam se estiver errado), que como o nome diz é para formatação de datas.

Não acho necessário a tradução da tabela, o funcionamento é simples: ao chamar a função para formatar data você segue os padrões indicado pela primeira coluna, que irá retornar o elemento indicado pela segunda coluna.

 

Letter Date or Time Component Examples
G Era designator AD
y Year 1996; 96
M Month in year July; Jul; 07
w Week in year 27
W Week in month 2
D Day in year 189
d Day in month 10
F Day of week in month 2
E Day in week Tuesday; Tue
a Am/pm marker PM
H Hour in day (0-23) 0
k Hour in day (1-24) 24
K Hour in am/pm (0-11) 0
h Hour in am/pm (1-12) 12
m Minute in hour 30
s Second in minute 55
S Millisecond 978
z Time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone -0800

 Tabela  da classe SimpleDateFormat (site da Sun)

 

Dicas para formatação e exibição das datas

Ainda existe algumas dicas para selecionar como será exibido o resultado, por extenso, número ou texto. Segue uma explicação rápida e algumas dicas para formatar e exibir a data:

Texto

Para formatar o texto, se a letra do padrão se repetir 4 vezes ou mais, a forma completa é utilizada, caso contrário a forma abreviada é exibida (se existir).

Número

Para a formatação, o número de repetição da letra padrão (primeira coluna da tabela) indica o número mínimo de dígitos do número, as casas que "faltaram" são preenchidas com zeros.

Year (ano)

Para a formatação, 2 repetições da letra truncam o ano para 2 dígitos.

Mês

Se a letra repetir por 3 vezes ou mais é exibido como texto, caso contrário como número.

 

 

Exemplos

Acho que a formatação de data é complicada de explicar, mas com exemplos -> resultados prontos fica masi fácil, então segue uma tabelinha que utiliza os padrões SimpleDateFormat.

Date and Time Pattern Result
"yyyy.MM.dd G "at" HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ""yy" Wed, Jul 4, "01
"h:mm a" 12:08 PM
"hh "o""clock" a, zzzz" 12 o"clock PM, Pacific Daylight Time
"K:mm a, z" 0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ" 010704120856-0700

 Tabela  da classe SimpleDateFormat (site da Sun)

 

É isso, espero ter ajudado! Para mais informações sobre formatação de data no Java leia a documentação completa da classe citada neste post.

Como contar arquivos em uma pasta usando ASP (FSO)

Na intranet de um cliente existe um módulo para distribuição de arquivos para os clientes dele, para isso eu utilizo o File System Object (FSO), que navega pelas pastas especificadas do sistema (onde meu cliente sobe diversos arquivos por FTP), identifica os arquivos e distribui cada arquivo para o respectivo usuário final (o cliente do meu cliente).

Com poucos arquivos a distribuição acontece tranquilamente, os arquivos são movidos para a pasta de cada usuário, cada usuário recebe uma notificação por e-mail com o link para a área de login do sistema com acesso aos arquivos. Porém todo o servidor tem um limite para execução de scripts e muitas vezes simplesmente aumentar esse limite de tempo de execução não é recomendável, pois se alguma coisa der errado (como um loop infinito) vai ficar sobrecarregndo o servidor.

New Folder

Isso sim é organizar os documentos em pastas

 

Começaram a acontecer problemas quando existiam muitos arquivos para mover, pois além da listagem de todos os arquivos o sistema segue uma lógica para identificar de qual usuário é cada arquivo para que a distribução seja feita de forma correta.

A solução para não retornar o erro de limite de tempo excedido e não aumentar loucamente este limite (o usuário certamente vai achar que deu erro quando uma página demorar demais para carregar) foi limitar o número de arquivos movimentados por vez, isso permite dar um feedback entre a "paginação" evitando que o usuário pense que o aplicativo travou ou deu erro e clique repetidamente em botões da interface. Eles gostam disso.

Segue uma parte da solução que adotei.

 

Como contar quantos arquivos tem em uma pasta utilizando o FSO?

Quando procurei informações de como contar quantos arquivos existiam em uma pasta a maioria envolvia um loop por todos os arquivos, e isso me lembrou minha experiência com POG: Não programe isso!

Twittei para ver se alguém conhecia uma solução melhor do que um loop, @chrisloki@cleiverrr e @alinedecampos responderam com idéias/sugestões, não achei nenhuma documentação completa do FSO (ok, só dei uma googleada básica) mas resolvi testar algumas coisas como UBound (para pegar o índica mais alto de uma array) e depois um count.

O UBound não funciona, o array de arquivos não pode ser tratado como um normal, mas existe o comando COUNT no FSO, segue abaixo o script para contar quantos arquivos existem em uma pasta:

 

dirtowalk = "../web_users/gssolutions/arquivos/"

Set fs = CreateObject("Scripting.FileSystemObject")

Set f = fs.GetFolder(server.mappath(dirtowalk))

Set fc = f.Files

total = fc.count

response.write "Total de arquivos na pasta " & dirtowalk & ": " & total

 

É isso aí, um simples .count no "array" de arquivos retorna o número de arquivos dentro da pasta. Caso existam subpastas, você teria que criar um loop para ir navegando e somando os arquivos dentro de cada subpasta…

Mais funcional e elegante do que um "For Each arquivo In fc"!

Obrigado a todos os que ajudaram e responderam meus pedidos de socorro no twitter, espero ter ajdado também! 🙂

Boas práticas com form

Estou a algum tempo com um post do blog do Cleiver no Read it Later e aproveitei agora que estou aqui no Campus Party matando um tempo (estou finalizando a nova versão do And After aqui, mas não esqueci de postar, né? 🙂 resolvi repassar essa apresentação que tem dicas bem interessantes de "boas maneiras" para formulários, é grande mas vale a pena (em inglês):

 

Não tenho muito a acrescentar as dicas do formulário, apenas que cada caso é um caso e cada usuário é um usuário, bom senso sempre está valendo, né?

Indexando todas as imagens de um texto – jQuery

Como vocês já devem estar cansados de ler, estou desenvolvendo algumas novidades para o And After mas isso está rendendo ótimos frutos, principalmente com jQuery (e ultimamente com SQL).

Para uma das novas features eu precisava indexar todas as imagens utilizadas nos posts do site. Resolvi cadastrar tudo no banco de dados, mas a dúvida era… como automatizar isso tudo?

Como estava estudando jQuery resolvi deixar de lado o server-side, utilizando apenas quando necessário: para inserir os dados no banco. Quase todo o resto foi feito com javascript, especificamente com jQuery.

Dica de leitura: Excelentes truques e dicas para jQuery

Objetivo do script
Encontrar todas as imagens de um texto e inserir estas imagens no banco de dados guardando as informações: url (src), descrição (alt) e qual o texto utilizou a imagem (definido por server-side). Ao final, passar para o próximo post do banco de dados e repetir o processo até que as imagens de todos os posts tenham sido indexadas.

 

Etapas de funcionamento

Explicarei em passos simples o funcionamento do script:

  1. O script server-side seleciona o post no Banco de Dados
  2. Através o jQuery o script "lê" o texto e busca pelas imagens
  3. Para cada imagem encontrada é executado um script server-side (post por ajax) que insere a imagem no banco de dados
  4. Ao final da indexação das imagens daquele post o script redireciona a página para o próximo post

 

Irei publicar aqui apenas a programação client-side, que é o foco deste post para facilitar o entendimento, deixando o script resumido. Também ocultei as funções de redirect (para passar os itens "post" do banco de dados) para o script ficar mais amplo.

O objetivo aqui é mostrar como funciona e estimular idéias 🙂

 

Indexando todas as imagens de um post

/*
 * Finding images in a div and list (or execute any action) with all images
 *
 * Copyright (c) 2009 Guilherme Serrano
 * Dual licensed under the MIT
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://www.guilhermeserrano.com.br
 * https://andafter.org
 *
 */
$(function (){
	var imag = $(´#finder´).find(´img´); //find all images
	var i = 0
	if(imag.length==0){
		item.html(´
  • Nenhuma imagem neste texto
  • ´) } imag.each(function(){ var url = $(this).attr(´src´); //get img url var titulo = $(this).attr(´alt´); //get img description (alt) var item = $(´
  •  
  • ´) //create item list $.post(´server-side.asp?a=add´, { url: url, titulo: titulo, id_post: id_post}, //POST data to server side script function(data){ i = i+1 item.html(data) $(´#imagens´).animate({opacity: 1}, 5000).append(item) //print data and pause 5s }); }) })

     

    No arquivo server-side.asp eu tenho um script que verifica se a imagem já está cadastrada no banco de dados, se ela não está cadastrada então cadastro e retorno um html "Imagem X cadastrada com sucesso no banco" ou "A imagem X já existe no banco". Esta mensagem é a variável data, que é printada pelo jQuery   no meu elemento #imagens.

     

    [update] Depois do comentário do Anderson Baldner resolvi tornar mais intuitivo, adicionando o html de forma "completa", chamando o jQuery e também chamando o arquivo de javascript. [/update]

    Html

    
    
    
    Aqui vai o texto que contém as imagens que você deseja indexar.

     

    Utilizando server-side e algumas alterações neste script criei um "mini-crawler" que percorreu todos os posts do meu banco de dados indexando as imagens e suas informações em um banco de dados, independente as imagens estarem hospedadas no meu servidor ou não.

     

    Curiosidade

    Esse script foi desenvolvido para aplicação "interna", utilizando um delay de 2 segundos por post o script levou 1 hora e 30 minutos para percorrer de forma automática 800 posts do And After e indexar 2.659 imagens no banco de dados. Poderia ser feito de forma reduzindo um pouco o delay, mas como não estava com pressa e não queria "consumir" o banco (sou cagão e não sou programador, então melhor previnir né?) deixei ele light.

     

    É apenas um exemplo do que é possível, dá pra fazer muita coisa com um pouco de criatividade, espero ter ajudado a despertar alguma idéia nestas cabeças geniais que leio por aí! 🙂

    Indexar feeds dos blogs que você gosta, para selecionar posts pelas imagens por exemplo é só umas das idéias possíveis… haha 😉

    Lembre-se que Programar é Grátis, exercite-se!