Texto original disponível em http://codefury.net/2011/04/why-php-was-a-ghetto/
⁂
Eu estava conversando com o
fundador de uma start-up bem legal em DUMBO outro dia sobre o porquê de o mundo do
desenvolvimento "não-PHP" ter tanto desdém pelo PHP e pela comunidade em volta
dele. Ele trouxe um ponto interessante que ficou na minha cabeça,
principalmente porque nunca o tinha ouvido antes.
Se você não está a par da
antipatia que a maioria dos desenvolvedores tem pelo PHP, ela geralmente gira
em torno de:
- Sintaxe feia
- Falta de alguns
recursos necessários que outras linguagens têm (antes da 5.3, namespacing,
closures)
- Nomeação de
funções, usos e outras peculiaridades inconsistentes
- Mistura de código procedural e orientado a objetos
- O fato de 80-90%
dos projetos PHP serem grandes porcarias
Mas o problema dele com o PHP
era um pouco diferente. Ele não disse que a linguagem em si era pobre – ele
disse que era a cultura geral em volta da linguagem, que é geralmente
reverenciada pelo criador da linguagem, que parece ter encorajado praticas
ruins. Isto é, as bases de código do PHP tendem a ser insustentáveis.
O conceito de que a
comunidade de certa linguagem ou framework carrega a filosofia do autor parece
ser verdade. Ele mencionou Ruby e Matz.
Matz queria que a linguagem fosse simples para ler e escrever, e aumentasse a
produtividade do programador. Os programadores de Ruby não parecem desenvolver um
aplicativo rapidamente e com elegância?
Então o DHH e o Rails surgiram. E depois o Guido e o Python. Aí eu pensei: e o Rasmus?
Rasmus Lerdorf é uma figura
interessante. Ele criou a versão original do PHP, continua a contribuir com
ela, é vastamente considerado um semideus na comunidade e a autoridade em tudo
o que diz respeito a PHP. Ele rouba a atenção de um grande número de
pessoas nas conferências, é contratado por grandes lugares da internet e ganha o respeito de todos, apesar de uma
propriedade ofuscante: Rasmus representa tudo que a maioria dos
desenvolvedores "não-PHP" odeiam no PHP.
Ele geralmente promove a
abstenção de uso de frameworks, e o uso do PHP como uma linguagem de
template. Para ele, isso se traduz em velocidade pura e escalabilidade
(no
que diz respeito ao carregamento). Para todos os outros, isso se traduz
em pilhas de código procedural macarrônico e projetos de manutenção
impossível. Durante os
10 anos difíceis que se seguiram ao nascimento do PHP, em 1995, era
dessa
maneira que os projetos eram escritos.
Mas outro problema surgiu:
durante seus anos adolescentes (antes do 5.0), o PHP ganhou sérios
adeptos
entre os novatos. A linguagem tem uma barreira de entrada muito baixa,
então
qualquer pessoa poderia começar em 2 minutos ao fazer o download de uma
pilha AMP para Windows. Adicionalmente, a aceitação do paradigma MVC
não tinha ainda acontecido no desenvolvimento web. O que você tem quando
mistura n00bs com uma grande falta de práticas boas? Lixo insustentável.
E foi
isso que proliferou.
Não me entenda mal – existiam
alguns desenvolvedores PHP muito bons por aí, mesmo naquele tempo. Mas como eu
disse, n00bs não refinados estavam por aí. Quando desenvolvedores PHP sem
escrúpulos se reuniam para construir um projeto, ele saía parecendo com PHPbb,
PHPNuke ou alguma outra massa deformada de arquivos .php3. Mas podemos culpar
unicamente os desenvolvedores PHP? Não! As outras grandes linguagens web, ASP e
Perl, também eram nojentas e promoviam as mesmas práticas de código macarrônico.
Então por que o PHP ficou com
a má reputação? Por causa do seu legado. A maioria dos desenvolvedores antigos
de PHP que migrou para Python, Ruby, e Java não olhou para trás para ver
que tipo de desenvolvimento aconteceu na linguagem desde a introdução do MVC na
web. Além disso, existiam criticas extremamente sinceras como “o cara Ruby” Zed
Shaw, reclamando de desenvolvedores com “o cérebro infectado com PHP”, e a
distribuição de coisas como essa no RubyInside.
PHP era um gueto.
Mas o desenvolvimento de
frameworks como Zend e CodeIgniter empurrou o desenvolvimento da linguagem
para a direção certa. Na verdade, ela foi empurrada na direção oposta que o
Rasmus gostaria. Dê uma olhada nos frameworks Zend e CodeIgniter e me diga se
não são alguns dos códigos mais bem documentados e bem escritos que você já viu.
Quando a maioria dos
desenvolvedores aprendeu o Ruby, eles estavam aprendendo Rails e MVC ao mesmo
tempo. O PHP estava em uso por longos 10 anos antes disso. Então na verdade não
existiu um período de tempo quando o hediondo Ruby estava sendo escrito por
novatos. Existia um padrão já estabelecido para o Rails, e sua barreira de
entrada era muito maior, mantendo, assim, desenvolvedores menos experientes do
lado de fora.
O fato é que aplicações PHP
podem ser tão bem escritas como aplicações em qualquer outra linguagem, e elas provavelmente
têm a vantagem adicional da velocidade. O vasto uso do desenvolvimento no
estilo MVC no mundo PHP é um fenômeno relativamente recente, e admito que
podemos agradecer o Rails por isso.
Então o que o PHP tem a seu
favor agora?
- Padrões (não universais,
mas geralmente com uma pitada de MVC para a maioria dos projetos, e pouca
porcaria procedural)
- Uma barreira de
entrada muito baixa
- Velocidade &
Escalabilidade (talvez os melhores entre linguagens baseadas em script)
- Um ótimo framework
para unidades de teste
- Tem a melhor
documentação que qualquer linguagem
Além disso, ela está por trás
de alguns dos websites e ferramentas mais influentes de hoje, como Facebook,
Digg, Wikipedia, WordPress, Drupal etc. Aposto que um entendimento sólido
sobre o PHP pode abrir mais portas para um desenvolvedor do que qualquer outra
linguagem.
Se você não concorda com o
que eu disse acima, comente este post – eu gostaria de
ouvir porque você não concorda.
Eu não sou fã do PHP – na
verdade, eu sou bastante agnóstico no que diz respeito a linguagens. Eu
escrevo mais em PHP porque, você adivinhou, as pessoas me pagam para isso. Tudo
se resume a isto: se
você é capaz de tomar decisões inteligentes no que diz respeito a design de
softwares, o PHP é uma ótima escolha para construir sua aplicação.
Falando nisso, se eu te
convenci a escrever sua nova aplicação web em PHP, dê uma olhada no CodeIgniter.
É
um framework leve e super rápido para PHP. No que diz respeito ao CodeIgniter, sou fã.
artigo publicado originalmente no iMasters, por Kenny Katzgrau
|
A cada dia os designers são premiados com novos
recursos de HTML e CSS que visam ampliar as possibilidades do
desenvolvimento front-end. Porém, nem sempre os browsers acompanham o
ritmo do surgimento das novidades – e nem sempre os usuários estão em
dia com as atualizações de seus navegadores.
Esse fato, além de desencorajar o uso de novos recursos que não sejam
completamente crossbrowser, obriga os desenvolvedores a gastar boa
parte do seu tempo procurando alternativas para lidar com a discrepância
de suporte entre os navegadores - quando poderiam estar aplicando seus
esforços em tarefas mais produtivas.
Atualmente a forma mais comum de utilizar funcionalidades avançadas
de HTML e CSS de maneira crossbrowser é através de scripts de detecção
de “userAgent”. Eles detectam o agente do navegador do usuário e aplicam
(ou deixam de aplicar) as novas funcionalidades de acordo com o suporte
fornecido pelo agente.
Esse método, além de tomar tempo e linhas de código, nem sempre é a
maneira mais precisa de implementar uma nova propriedade, já que
navegadores com o mesmo agente podem renderizar conteúdo de forma
diferente.
Uma biblioteca Javascript com abordagens para HTML e CSS
O Modernizr, uma compacta
biblioteca Javascript, oferece uma abordagem diferente para o uso de
novas tecnologias do HTML e CSS. Em vez de basear a renderização de uma
propriedade no que é declarado pelo agente do navegador, ele de fato
testa a presença da propriedade no próprio navegador do usuário (em
questão de milissegundos) e armazena o resultado do teste numa variável
dentro de um script.
Se a funcionalidade está presente, o valor da variável é true; do
contrario, é declarada false. O resultado do teste pode ser manipulado
via CSS, no qual o desenvolvedor tem a chance de prover diferentes
alternativas de acordo com a presença ou ausência de determinada
funcionalidade.
Em sua mais recente versão, o Modernizr é capaz de detectar mais de
20 recursos de última geração, entre eles o suporte a border-radius,
canvas, @font-face, opacidade e backgrounds múltiplos.
Aqui vale abrir um parêntese em relação ao Modernizr: embora seja
capaz de detectar a presença ou a ausência de um recurso, ele não é
capaz de implementá-lo em um agente no qual ele não esteja presente.
Porém, a incapacidade de implementar novos recursos não tira os méritos
da biblioteca - que torna muito mais simples e ágil o uso de novas
tecnologias e eleva o desenvolvimento front-end a um novo patamar.
Exemplos utilizando o Modernizr
A documentação do Modernizr é bastante abrangente e tem exemplos para
a implementação de todas as funcionalidades suportadas pela biblioteca.
Geralmente as propriedades de CSS3 são implementadas a partir de uma
classe especial, que checa a presença ou a ausência de suporte à
propriedade e executa o código para ambas as ocasiões. Neste código, por
exemplo:
.divGradiente {background: #1eff00;}
.cssgradients .divGradiente {background:-webkit-linear-gradient(#00f0ff, #1eff00);}
O elemento de classe .divGradiente tem como valor default de
sua propriedade background uma única cor (padrão aceito por todos os
browsers). A classe do Minimizr, .cssgradients, então checa o
suporte do navegador ao uso de gradientes. Caso ele exista, o background
do navegador passa a ser o gradiente definido como valor da propriedade
em vez da cor única definida anteriormente.
O código acima também pode ser escrito como beautiful degradation, em que o gradiente é definido como o valor default da classe .divGradiente enquanto uma outra classe do Minimizr no .cssgradients fornece um valor alternativo caso não haja suporte para gradientes no navegador:
.divGradiente {background:-webkit-linear-gradient(#00f0ff, #1eff00);}
.no-cssgradients .divGradiente {background: #1eff00;}
Elementos do HTML5 são implementados via Javascript. Este script cria uma canvas e testa a presença da propriedade getContext. Em caso verdadeiro, ele criará um quadrado vermelho dentro de uma div cujo id é “canvasAqui”:
if(Modernizr.canvas) { function draw() { var c = document.createElement("canvas"); var cxt = c.getContext("2d"); cxt.fillStyle="#FF0000"; cxt.fillRect(20,20,150,150); $(c).appendTo("#canvasAqui"); }
window.onload = draw; }
E para providenciar conteúdo alternativo na ausência de suporte a
canvas, basta inserir este conteúdo dentro da div “canvasAqui” e
escondê-lo se o suporte ao elemento canvas for verdadeiro:
/*HTML*/
<div id="canvasAqui"> <p>Este conteúdo requer suporte a HTML 5.</p> </div>
/*CSS*/
.canvas #canvasAqui p { display:none; }
Conclusão
Como demonstrado nos exemplos anteriores, usar o Modernizr é bastante
simples, e a biblioteca ainda pode ser utilizada sem conflitos com
outras bibliotecas como jQuery. Não é à toa que o Minimizr foi adotado
pela equipe de desenvolvedores do Twitter.
A forma como ele oferece ao desenvolvedor controle sobre o uso de
funcionalidades que ainda não são suportadas por todos os browsers é
bastante eficiente, impulsionando o uso dessas novas tecnologias no
desenvolvimento front-end.
artigo publicado originalmente no iMasters, por Heloisa Biagi
|
Texto original disponível em http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/
⁂
Blocks, Procs e Lambdas (definidas
closures
na
Ciência da Computação) são uns dos aspectos mais poderosos do Ruby, e
também os mais incompreendidos. Isso provavelmente acontece porque o
Ruby lida com
closures de uma maneira única. O que deixa as coisas mais complicadas é o
fato
de o Ruby ter quatro maneiras diferentes de usar closures, cada uma
delas um
pouquinho diferente, e às vezes sem sentido. Existe um bom número de
sites com
informações muito boas sobre como trabalhar com closures dentro do Ruby.
Mas eu
ainda tenho que encontrar um guia definitivo por aí. Espero que este
artigo
assuma essa função.
Primeiro, Blocks
O
jeito mais fácil, comum e comprovado de usar closures no Ruby é dentro de
blocks. Eles têm a seguinte sintaxe:
array = [1, 2, 3, 4]
array.collect! do |n| n ** 2 end
puts array.inspect
Então, o que está
acontecendo aqui?
- Primeiro, nós mandamos o método collect! para um Array
com um bloco de código.
- O bloco do código interage com uma variável usada
dentro do método collect! (nesse caso n) e o eleva ao quadrado.
- Cada elemento dentro do Array agora está elevado ao quadrado.
Usar
um block com o método collect! é bem fácil, nós apenas temos que pensar que esse
collect! vai usar o código dado dentro de cada elemento no Array. No entanto, e
se quisermos fazer nosso próprio método collect!? Como ele vai ser? Bem, vamos
construir um método chamado iterate! e vamos ver.
class Array def iterate! self.each_with_index do |n, i| self[i] = yield(n) end end end
array = [1, 2, 3, 4]
array.iterate! do |n| n ** 2 end
puts array.inspect
Para começar, nós
reabrimos a classe do Array e colocamos o método iterate! dentro dela. Nós
vamos continuar com as convenções do Ruby e colocar um "bang" no final, dizendo
aos nossos usuários para tomar cuidado, pois esse método pode ser perigoso!
Então usamos nosso método iterate! da mesma maneira que o Ruby fez no método
collect! No entanto, a melhor parte está bem no meio da nossa definição de método
iterate!.
Diferentemente de
atributos, você não precisa especificar o nome dos blocks dentro dos seus
métodos, você pode usar a palavra-chave yield. Ao chamar essa palavra-chave, ela vai
executar o código dentro do block fornecido ao método. Além disso, note como
estamos passando o n (o número inteiro com que o método each_with_index está trabalhando
no momento) ao yield. Os atributos passados ao yield correspondem às variáveis
especificadas na piped list do block. Esse valor agora está disponível para o
block, e devolvido pelo chamado yield. Para recapitular o que está acontecendo:
- Mande iterate! para o Array de números.
- Quando o yield é chamado com o número n (primeira
vez é 1, segunda vez é 2 etc…), passe o número para o block do
código fornecido.
- O block tem o número disponível (também chamado n) e o eleva
ao quadrado. Como este é o
último valor gerenciado pelo block, ele é devolvido automaticamente.
- O yield devolve o valor retornado pelo bloco e sobreescreve o valor no Array.
- Isso continua para cada elemento no Array.
O
que nós temos agora é uma maneira flexível de interagir com o nosso método.
Entenda os blocks como aqueles que estão dando a seu método uma API,
na qual você pode determinar que cada valor do Array seja elevado ao quadrado, ou
ao cubo, ou converter cada número em uma string e imprimi-los na tela. As
opções são infinitas, deixando seu método bem flexível e, assim, muito
poderoso.
No
entanto, esse é apenas o começo. Utilizar o yield é uma maneira de usar seu block de código, mas existe um
outro, chamado de Proc. Dê uma olhada.
class Array def iterate!(&code) self.each_with_index do |n, i| self[i] = code.call(n) end end end
array = [1, 2, 3, 4]
array.iterate! do |n| n ** 2 end
puts array.inspect
Parece bem similar ao nosso exemplo anterior, no
entanto existem duas diferenças. Primeiro, nós estamos passando um argumento
ampersand chamado &code. Esse argumento é, convenientemente suficiente, o
nosso block. O segundo é o meio da nossa definição de método iterate!, no qual em vez de usar o yield, mandamos um chamado para todos os nossos blocos de
códigos. O resultado é exatamente o mesmo. No entanto, se isso é verdade,
por que então temos essa diferença em sintaxe? Bom, ela nos ensina um pouco mais
sobre o que blocks realmente são. Dê uma olhada:
def what_am_i(&block) block.class end
puts what_am_i {}
Um
block é simplesmente um Proc! Dito
isso, o que é um Proc?
Procedimentos, mais conhecidos como Procs
Blocks
são bastante convenientes e sintaticamente simples, no entanto é melhor termos
vários blocks diferentes à nossa disposição e usá-los múltiplas vezes. Assim,
passar o mesmo block múltiplas vezes faria com que nós nos repetíssemos. Como o
Ruby é completamente orientado ao objeto, isso pode ser contornado de uma
maneira tranquila, ao salvar o código reutilizável como sendo um objeto. O
objeto reutilizável é chamado Proc (abreviação para procedimento). A única
diferença entre blocks e Procs é que um block é um Proc que não pode ser salvo
e, assim, é uma solução única. Ao trabalhar com Procs, podemos começar a fazer o
seguinte:
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end
array_1 = [1, 2, 3, 4] array_2 = [2, 3, 4, 5]
square = Proc.new do |n| n ** 2 end
array_1.iterate!(square) array_2.iterate!(square)
puts array_1.inspect puts array_2.inspect
Por que block em caixa baixa e Proc em caixa
alta?
Eu
sempre escrevo o Proc em caixa alta como se fosse uma própria classe dentro do
Ruby. No entanto, blocks não têm uma classe (afinal eles são apenas Procs) e
são apenas um tipo de sintaxe dentro do Ruby. Por isso, eu escrevo blocks em
caixa baixa. Mais para frente neste artigo, você verá que eu também escrevo
lambda em caixa baixa. Eu faço isso pelo mesmo motivo.
Note como nós não precedemos com um & o atributo do código no nosso método iterate!. Isso
é porque passar Procs não é diferente de passar qualquer outro tipo de dado.
Como os Procs são criados como qualquer outro objeto, podemos começar a nos
divertir e a forçar o intérprete do Ruby a fazer algumas coisas interessantes. Tente
isto aqui:
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end
array = [1, 2, 3, 4]
array.iterate!(Proc.new do |n| n ** 2 end)
puts array.inspect
Acima temos como a maioria das linguagens lida
com closures, e é exatamente o mesmo que enviar um block. No entanto, se
você
pensou que isso não parece com o “jeito Ruby”, eu vou ter que concordar.
A razão acima é exatamente o porquê de o Ruby ter blocos, e isso é para
permanecer de acordo com a familiar sintaxe de conclusão "end".
Se
esse é o caso, por que não usar somente blocks? Bem, a resposta é simples, e se
nós quisermos passar duas ou mais closures para um método? Se esse é o caso,
blocks rapidamente se tornam muito limitados. No
entanto, ao ter Procs, podemos fazer algo como:
def callbacks(procs) procs[:starting].call
puts "Still going"
procs[:finishing].call end
callbacks(:starting => Proc.new { puts "Starting" }, :finishing => Proc.new { puts "Finishing" })
Então
quando devemos usar blocks no lugar de Procs? Minha lógica é a seguinte:
- Block: Seu método está quebrando um objeto em pedaços
menores, e você quer permitir que seus usuários interajam com esses
pedaços.
- Block: Você quer executar expressões múltiplas
automaticamente, como uma migração de banco de dados.
- Proc: Você quer reutilizar um bloco de código
múltiplas vezes.
- Proc: Seu método vai ter um ou mais callbacks.
Lambdas
Até
agora, você usou Procs de duas maneiras, passando-os diretamente como um
atributo e salvando-ps como uma variável. Esses Procs agem de maneira muito
similar ao que outras linguagens chamam de funções anônimas, ou lambdas. Para
deixar as coisas mais interessantes, lambdas estão disponíveis no Ruby também.
Dê uma olhada:
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end
array = [1, 2, 3, 4]
array.iterate!(lambda { |n| n ** 2 })
puts array.inspect
# => [1, 4, 9, 16]
À primeira vista, lambdas parecem ser exatamente
iguais aos Procs. No entanto, existem duas diferenças sutis. A primeira é que,
diferentemente de Procs, lambdas checam o número de argumentos passados.
def args(code) one, two = 1, 2 code.call(one, two) end
args(Proc.new{|a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}"})
args(lambda{|a, b, c| puts "Give me a #{a} and a #{b} and a #{c.class}"})
Vemos com o exemplo do Proc que variáveis
extras são definidas no nil. No entanto, com lambdas, em vez disso, o Ruby
gera um erro.
A
segunda diferença é que lambdas têm retornos diminutos. O que isso significa é
que, enquanto o retorno de um Proc vai parar um método e retornar o valor
fornecido, lambdas vão retornar o seu valor ao método e deixá-lo continuar.
Confuso? Vamos ver um exemplo:
def proc_return Proc.new { return "Proc.new"}.call return "proc_return method finished" end
def lambda_return lambda { return "lambda" }.call return "lambda_return method finished" end
puts proc_return puts lambda_return
Em proc_return, nosso método aciona a palavra-chave
return, ele pára de processar o resto do método e retorna a string Proc.new.
Por outro lado, nosso método lambda_return aciona nosso lambda - o que retorna o
string lambda –, continua processando, encontra o próximo return e retorna
lambda_return. Por que a diferença?
A
resposta está nas diferenças conceituais entre procedimentos e métodos. No
Ruby, Procs são trechos dentro do código, não métodos. Por causa disso, o
retorno do Proc é o retorno do método proc_return, e ele age adequadamente a isso.
No entanto, lambdas agem como métodos, ao checar o número de argumentos e não
substituir os métodos return. Por esse motivo, é melhor pensar em lambdas
como uma nova maneira de escrever métodos, uma maneira anônima.
Então
quando você deve escrever um método anônimo (lambda) em vez de um Proc? O código
a seguir mostra um exemplo:
def generic_return(code) code.call return "generic_return method finished" end
puts generic_return(Proc.new { return "Proc.new" }) puts generic_return(lambda { return "lambda" })
Parte da sintaxe do Ruby é que argumentos (um
Proc neste exemplo) não podem ter uma palavra-chave return dentro deles. No entanto,
um lambda age da mesma maneira que um método, o que pode ter um retorno
literal, e assim passar ileso por esse requerimento! Essa
diferença em semântica aparece em situações como a do exemplo a seguir:
def generic_return(code) one, two = 1, 2 three, four = code.call(one, two) return "Give me a #{three} and a #{four}" end
puts generic_return(lambda { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| return x + 2, y + 2 })
puts generic_return(Proc.new { |x, y| x + 2; y + 2 })
puts generic_return(Proc.new { |x, y| [x + 2, y + 2] })
Aqui,
nosso método generic_return está esperando a closure para retornar dois
valores. No entanto, fazer isso sem a palavra-chave return se torna arriscado. Com o lambda,
tudo é fácil. No entanto, com o Proc, temos que tirar vantagem do modo que o
Ruby interpreta os Arrays com atribuições.
Então quando usar Proc em vez de lambdas, e
vice-versa? Honestamente, além da checagem de argumentos, a diferença é
simplesmente como você vê as closures. Se você tem a finalidade de passar blocks
de códigos, fique com o Proc. Se mandar um método para outro método que pode
retornar um método faz sentido para você, use lambdas. Mas se lambdas são
apenas métodos em forma de objetos, podemos armazenar métodos existentes e passá-los
como Procs? Para isso, o Ruby tem algo intrigante debaixo da manga.
Métodos dos objetos (Method Objects)
Então
você já tem um método que funciona, mas você quer passá-lo para outro método
como uma closure, e manter seu código. Para fazer isso, você pode tirar
vantagem do método do Ruby:
class Array def iterate!(code) self.each_with_index do |n, i| self[i] = code.call(n) end end end
def square(n) n ** 2 end
array = [1, 2, 3, 4]
array.iterate!(method(:square))
puts array.inspect
Nesse exemplo, nós já temos um método chamado
square (potência de 2) que funcionaria bem para essa tarefa.
Assim, podemos utilizá-lo novamente como um parâmetro ao convertê-lo a um
método do objeto e passando-o para o nosso método iterate!. Mas qual é esse
novo tipo de objeto?
def square(n) n ** 2 end
puts method(:square).class
Bem, como você
adivinhou, o square não é um Proc, mas um Método. A melhor parte é que esse
método do objeto vai agir como um lambda, porque o conceito é o mesmo. Esse
método, no entanto, é denominado método (chamado square), enquanto lambdas são
denominadas métodos anônimos.
Conclusão
Para recapitular,
vimos quatro tipos de closures no Ruby - blocks, Procs, lambdas e Methods. Nós
também sabemos que blocks e Procs agem da mesma maneira que métodos.
Finalmente, através de uma grande quantidade de exemplos de código, você está
pronto para decidir quando usar cada um deles da maneira correta. Agora você
deve ser capaz de começar a utilizar esse interessante e expressivo recurso do
Ruby no seu próprio código, e começar a oferecer métodos flexíveis e poderosos
aos outros desenvolvedores que trabalham com você.
artigo publicado originalmente no iMasters, por Roberto Sosinski
|
O ato de escrever códigos faz com que você seja um cara que programa, mas não necessariamente um programador.
Ok, confesso que “inventei” agora essa diferença entre esses termos.
Digamos que ambos cumprem o papel e resolvem o problema. E a diferença
está na forma de pensar deles.
Existem diversas maneiras de se chegar a um mesmo resultado. Algumas
mais claras, diretas, outras mais bonitas, elegantes, às vezes
nebulosas, cheias de voltas e emaranhados, boas ou ruins. Apesar do peso
de subjetividade que esses termos carregam.
Acredito que um bom código é aquele que, chega onde deve chegar,
sendo este legível aos envolvidos, e aqueles que não sabem do que se
trata.
- Bom em performance;
- Sem rotinas confusas ou desnecessárias(as famosas gorduras);
- Bem indentado e organizado.
Apenas isso. Simples e objetivo. Toda a comunidade, conhece ou
deveria conhecer os conceitos que citei. (Keep It Simple, Faça o Simples
que Funcione, Você não vai precisar disso, Don’t Repeat Yourself…)
Não pretendo estender o assunto sobre cada um deles. O meu ponto é:
“Um CQP [Cara Que Programa], não leva ou nem sempre leva em consideração
estas ‘máximas’.” Já um VP [Verdadeiro Programador], possui esses
conceitos incorporados a ele. Na forma de pensar, na maneira de
codificar. Para um Programador, é natural, para o CQP, ainda não é.
Todos sofremos pressão, temos prazos apertados, e situações difíceis
pra lidar… Este é o nosso mundo. A agência ou a empresa, pode lhe dizer
que é tranquilo, que são pacientes, que os prazos são legais, e tudo
mais.. Porém, faz parte da arte de programar nos deparamos com algo
urgente e impossível, para ontem!
Um programador resolve da melhor forma possível, enxergando na
frente, o outro faz apenas para se ver livre, e entregar logo. O erro
aqui, é que depois aquele monstrinho volta, e nem sempre podemos ou
temos tempo de refazer ou corrigir. E quando surgem as cabeças dos
nossos monstros. Duas, Três, Sete… a tendência é piorar. Começou errado,
por preguiça, falta de conhecimento, mal planejamento, ego…
Um CQP, acha que sabe tudo, ou não se importa de não saber, e nem
tenta. Um VP, tenta saber, sempre busca melhorar, aceita analisando as
críticas recebidas, e gosta do que faz. Fazer bem feito lhe deixa feliz,
o contrário lhe incomoda.
O melhor programador não é aquele que complica mais. Códigos de
linguagens alto nível, devem ser escritos por humanos e para humanos. As
máquinas entendem, tanto códigos bem escritos, quanto códigos ruins,
mas e você no futuro? E o outro programador?
Acho que todos nós já demos continuidade no trabalho de alguém. Já
vimos scripts porcos, e outros bem feitos. Quando alguém pegar um
trabalho nosso, vamos tentar ser aquele que não será xingado, e nem fez o
outro programador perder horas e horas, entendendo as loucuras que
fizemos.
Se faça essa pergunta. O que você é? Qual dos dois?
artigo publicado originalmente no iMasters, por William Bruno
|
Texto original disponível em http://www.zimuel.it/blog/2011/02/encrypt-php-session-data/
⁂
Este artigo apresenta um exemplo de sólida criptografia no
PHP para proteger os dados de sessão.
É uma implementação bastante simples, que pode ser usada para melhorar a
segurança de aplicações PHP, especialmente em ambientes compartilhados, nos quais diferentes
usuários têm acesso aos mesmos recursos. Como você sabe, as sessões de dados PHP
são gerenciadas, por padrão, usando arquivos temporários. Em um ambiente
compartilhado, um usuário malicioso que é capaz de acessar esses arquivos
temporários pode facilmente ler os dados de sessão, uma vez que eles estão
armazenados em plaintext (dados em um arquivo de sessão são a serialização do
array $_SESSION).
Em
teoria, os dados de sessão deveriam ser armazenados em arquivos que são
acessíveis somente ao proprietário do site, mas nunca diga nunca (inclusive,
você pode gerenciar o local dos dados de sessão usando a função session_save_path
ou mudando o session_save_path no the php.ini).
Para
proteger os dados de sessão, eu usei uma sólida criptografia para criptografar
o conteúdo usando a extensão mcrypt do PHP. Eu escolhi a cifra simétrica AES
(Rijandel-256) para criptografar os
dados de sessão e a função openssl_random_pseudo_bytes() para
gerar uma chave randômica do bit 256.
A ideia é
usar um cookie variável para armazenar a chave que será utilizada para
criptografar os dados de sessão. Dessa maneira, a chave é armazenada somente no
cliente (o browser) e somente o cliente é capaz de descriptografar os dados de
sessão no servidor. Cada vez que criptografamos os dados de sessão, nós geramos
mais uma vez o vetor IV de uma maneira randômica usando a função mcrypt_create_iv().
É muito importante gerar um único
IV em cada criptografia. Essa prática aumenta a segurança do algoritmo de
criptografia. É importante notar
que essa implementação não protege contra um ataque de session hijacking. Se alguém for capaz de capturar
o cookie variável de um cliente e ter acesso aos arquivos temporários da
sessão, no servidor, ele ou ela serão capazes de descriptografar os dados de
sessão. Nosso objetivo é proteger os dados de sessão contra ataques em
ambientes compartilhados.
A ideia de criptografar dados de sessão não é
nova, Chris Shiflett por exemplo, propôs uma
implementação em seu livro “Essential
PHP Security” (O’Reilly,
2006). Shiflett usou uma variável $_SERVER para armazenar a chave usada para
criptografar os dados de sessão. Kevin
Schroeder, meu
colega na Zend Technologies, implementou um algoritmo de criptografia da sessão
bem parecido, estendendo a classe Zend_Session class do Zend Framework (você
pode encontrá-lo aqui). Na
minha solução, eu usei algumas das melhores práticas relacionadas à uma sólida
criptografia para implementar um handler de sessão segura.
Abaixo temos o código-fonte para a minha
implementação:
class SecureSession { const CIPHER= MCRYPT_RIJNDAEL_256; const CIPHER_MODE= MCRYPT_MODE_CBC; private static $_key; private static $_path; private static $_name; private static $_ivSize; private static $_keyName; private static function _randomKey($length=32) { if(function_exists('openssl_random_pseudo_bytes')) { $rnd = openssl_random_pseudo_bytes($length, $strong); if($strong === TRUE) return $rnd; } for ($i=0;$i<$length;$i++) { $sha= sha1(mt_rand()); $char= mt_rand(0,30); $rnd.= chr(hexdec($sha[$char].$sha[$char+1])); } return $rnd; } public static function open($save_path, $session_name) { self::$_path= $save_path.'/'; self::$_name= $session_name; self::$_keyName= "KEY_$session_name"; self::$_ivSize= mcrypt_get_iv_size(self::CIPHER, self::CIPHER_MODE);
if (empty($_COOKIE[self::$_keyName])) { $keyLength= mcrypt_get_key_size(self::CIPHER, self::CIPHER_MODE); self::$_key= self::_randomKey($keyLength); $cookie_param = session_get_cookie_params(); setcookie( self::$_keyName, base64_encode(self::$_key), $cookie_param['lifetime'], $cookie_param['path'], $cookie_param['domain'], $cookie_param['secure'], $cookie_param['httponly'] ); } else { self::$_key= base64_decode($_COOKIE[self::$_keyName]); } return true; } public static function close() { return true; } public static function read($id) { $sess_file = self::$_path.self::$_name."_$id"; $data= @file_get_contents($sess_file); if (empty($data)) { return false; } $iv= substr($data,0,self::$_ivSize); $encrypted= substr($data,self::$_ivSize); $decrypt = mcrypt_decrypt( self::CIPHER, self::$_key, $encrypted, self::CIPHER_MODE, $iv ); return rtrim($decrypt, ""); } public static function write($id, $data) { $sess_file = self::$_path.self::$_name."_$id"; $iv= mcrypt_create_iv(self::$_ivSize, MCRYPT_RAND); if ($fp = @fopen($sess_file, "w")) { $encrypted= mcrypt_encrypt( self::CIPHER, self::$_key, $data, self::CIPHER_MODE, $iv ); $return = fwrite($fp, $iv.$encrypted); fclose($fp); return $return; } else { return false; } } public static function destroy($id) { $sess_file = self::$_path.self::$_name."_$id"; setcookie (self::$_keyName, '', time() - 3600); return(@unlink($sess_file)); } public static function gc($max) { foreach (glob(self::$_path.self::$_name.'_*') as $filename) { if (filemtime($filename) + $max < time()) { @unlink($filename); } } return true; } }
ini_set('session.save_handler', 'user'); session_set_save_handler(array('SecureSession', 'open'), array('SecureSession', 'close'), array('SecureSession', 'read'), array('SecureSession', 'write'), array('SecureSession', 'destroy'), array('SecureSession', 'gc') );
Você pode
fazer o donwload da classe SecureSession aqui.
Para
poder usar a classe SecureSession, você tem que incluí-la no seu projeto PHP
antes da função session_start.
Depois disso
você pode usar a sessão PHP como de costume.
artigo publicado originalmente no iMasters, por Enrico Zimuel
|
Olá, pessoal!
Vou aproveitar o espaço deste artigo para compartilhar um recurso que acho muito interessante no .NET, a Partial Class.
Partial Class é uma forma de dividir a definição de uma class em mais
de um único arquivo físico. Porém ao compilar nossa class, o compilador
irá interpretar como se fosse uma única class.
Antes de explicar a utilização de Partial Class com Entity Framework,
vou explicar o que é Partial Class na prática. Vamos criar um projeto
no Visual Studio do tipo Console Application, então vou colocar o nome
de ConsolePartialClass no projeto.
Crie uma class, chame o arquivo de Pessoa e coloque as seguintes propriedades:
public class Pessoa {
public int intCodigoPessoa { get; set; }
public string strNomePessoa { get; set; }
}
Crie uma segunda class, chame o arquivo de PessoaJuridica, mas a class chame de pessoa conforme podemos ver abaixo:
public partial class Pessoa {
public string strNomeFantasia { get; set; }
}
Veja que no código acima utilizamos a palavra partial antes da palavra class para informar ao compilador que essa class faz uma união com a class Pessoa.
Acesse o arquivo Program e instancie a class Pessoa, então você poderá ter acesso as três propriedades que criamos. Veja a imagem abaixo:

Esse foi apenas um exemplo simples de como utilizar. Uma forma legal é
criar dois arquivos físicos, separar as propriedades em um arquivo e os
métodos em outro arquivo.
Existem algumas regras a serem observadas:
- As classes partial não podem ter modificadores de acesso diferentes;
- A classe principal e as que recebem o partial têm que estar na mesma namespace;
- Quando algo estiver definido em uma das classes, essa definição estará disponível para as demais classes.
Acredito que você tenha entendido o que é partial class, mas, caso tenha alguma dúvida ou queira aumentar seu conhecimento, acesse esse artigo no site do MSDN.
Agora vamos utilizar Partial Class com Entity Framework. Para esse
exemplo, criei três tabelas em uma base de dados SQL Server, o script
está logo abaixo:
CREATE TABLE [dbo].[UF]( [CD_UF] [nchar](2) NOT NULL, [DS_UF] [nchar](10) NULL, CONSTRAINT [PK_UF] PRIMARY KEY CLUSTERED( [CD_UF] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] GO CREATE TABLE [dbo].[MUNICIPIO]( [CD_MUNICIPIO] [numeric](10, 0) NOT NULL, [NM_MUNICIPIO] [varchar](100) NULL, [CD_UF] [nchar](2) NULL, CONSTRAINT [PK_MUNICIPIO] PRIMARY KEY CLUSTERED( [CD_MUNICIPIO] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] GO SET ANSI_PADDING OFFGO ALTER TABLE [dbo].[MUNICIPIO] WITH CHECK ADD CONSTRAINT [FK_MUNICIPIO_UF] FOREIGN KEY([CD_UF])REFERENCES [dbo].[UF] ([CD_UF]) GO ALTER TABLE [dbo].[MUNICIPIO] CHECK CONSTRAINT [FK_MUNICIPIO_UF] GO CREATE TABLE [dbo].[PESSOA]( [CD_PESSOA] [numeric](10, 0) NOT NULL, [NM_PESSOA] [varchar](100) NULL, [CD_MUNICIPIO] [numeric](10, 0) NULL, CONSTRAINT [PESSOA_PK] PRIMARY KEY CLUSTERED( [CD_PESSOA] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY] GO SET ANSI_PADDING OFFGO ALTER TABLE [dbo].[PESSOA] WITH CHECK ADD CONSTRAINT [PESSOA_MUNICIPIO_FK] FOREIGN KEY([CD_MUNICIPIO])REFERENCES [dbo].[MUNICIPIO] ([CD_MUNICIPIO]) GO ALTER TABLE [dbo].[PESSOA] CHECK CONSTRAINT [PESSOA_MUNICIPIO_FK] GO
Insira alguns valores nessa tabela para utilizarmos em nosso exemplo.
Com valores preenchidos, abra o Visual Studio e crie um projeto do tipo Library Class em C#. Coloquei o nome do projeto de PartialClassWithEntity. Clique com o botão direito sobre o projeto em Add New Item e selecione ADO.NET Entity Data Model. Chamei o arquivo de Partial.edmx.
Em Entity Data Model, selecione Generate from database e
clique em next. Na próxima tela, você precisa selecionar a conexão com a
base de dados que criamos nossas tabelas anteriormente. Talvez seja
necessário que você crie a conexão.
Com a conexão criada, marque a opção Yes, include the sensitive data in the connection string e a opção Save entity connection settings in App.Config as, então coloque um nome para sua conexão entity - no meu caso está PartialEntity, e clique em next.
Na próxima tela, selecione as três tabelas que criamos anteriormente e
clique em Finish para que as entidades sejam criadas conforme a imagem
abaixo:

Com o projeto Library pronto, vamos adicionar outro projeto à solução. Clique na Solution e em Add New Project.
Selecione um projeto do Tipo Console em C# com o nome de ConsolePartial. Com o projeto criado, clique com o botão direito sobre ele e em Add Reference, selecione a guia Projects e o projeto PartialClassWithEntity que possui o Entity Framework.
Volte em Add New Reference, porém selecione a guia NET e selecione a biblioteca System.Data.Entity. Também copie o arquivo App.config do projeto PartialClassWithFramework para o projeto ConsolePartial. Lembre-se de copiar e não recortar.
No arquivo Program.cs, escreva o seguinte código:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using PartialClassWithEntity;
namespace ConsolePartial { class Program
{
static void Main(string[] args) { using (PartialEntity ef = new PartialEntity()) { IQueryable iqbPessoa = from p in ef.PESSOA select p;
foreach (PESSOA p in iqbPessoa) { Console.WriteLine(string.Format("Nome Pessoa: {0} - Município/UF: {1}", p.NM_PESSOA, p.MUNICIPIO.NM_MUNICIPIO)); } }
Console.Read(); } } }
Executando o código será possível visualizar os dados que inserimos
na tabela PESSOA, porém veja que não conseguimos trazer a descrição da
UNIDADE FEDERATIVA (UF). É claro que podemos concatenar a descrição da
unidade federativa como no exemplo abaixo:
Console.WriteLine(string.Format("Nome Pessoa: {0} - Município/UF: {1} - {2}", p.NM_PESSOA, p.MUNICIPIO.NM_MUNICIPIO, p.MUNICIPIO.UF.DS_UF));
Mas e se a entidade PESSOA já tivesse uma propriedade com o nome do município relacionado com o nome da unidade federativa?
Volte ao projeto PartialClassWithEntity (nosso projeto Library) e crie uma nova class chamada PESSOA. A classe deve ser criada conforme abaixo:
ususing System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace PartialClassWithEntity { public partial class PESSOA { public string NM_MUNICIPOUF { get { return MUNICIPIO.NM_MUNICIPIO + " - " + MUNICIPIO.UF.DS_UF; } } } }
Veja que criamos uma propriedade chamada NM_MUNICIPIOUF, que quando
realizamos o get, ele concatena os campos NM_MUNICIPIO E DS_UF. Compile o
projeto class e altere o projeto console com a linha abaixo:
Console.WriteLine(string.Format("Nome Pessoa: {0} - Município/UF: {1}", p.NM_PESSOA, p.NM_MUNICIPOUF));
Pronto, através da Partial Class criamos uma nova propriedade para
nossa class do Entity Framework, sendo que essa propriedade não faz
relação com nenhuma coluna da tabela PESSOA. Podemos criar outras
propriedades que podem ser úteis, utilizando Partial em várias vezes do
projeto com EF.
Lembre que a Class Partial deve estar na mesma namespace da classe principal, senão o compilador vai entender como sendo duas classes diferentes.
Outro detalhe importante, veja que o foreach está dentro do
Using. Isso porque para que nossa propriedade NM_MUNICIPOUF seja
populada, o Entity precisa estar aberto; caso ele esteja fechado, um
exception irá acontecer. Veja abaixo a maneira de como o código não irá
funcionar.
static void Main(string[] args) { IQueryable<PESSOA> iqbPessoa = null;
using (PartialEntity ef = new PartialEntity()) {
iqbPessoa = from p in ef.PESSOA select p;
}
foreach (PESSOA p in iqbPessoa) { Console.WriteLine(string.Format("Nome Pessoa: {0} - Município/UF: {1}", p.NM_PESSOA, p.NM_MUNICIPOUF)); }
Console.Read(); }
Executando o código acima, uma exception (The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.) será exibida.
Espero que esse exemplo seja útil para você. Compartilhe seus experimentos e deixe seu recado abaixo nos comentários.
Obrigado pela atenção e até a próxima!
artigo publicado originalmente no iMasters, por Marcos Aguiar Jr.
|
Texto
original disponível em http://davidwalsh.name/mootools-history
⁂
Uma das razões pelas quais
gosto da tecnologia AJAX é porque ela permite evitar que páginas desnecessárias
sejam carregadas. Por que carregar o cabeçalho, o rodapé, e outros dados
estáticos múltiplas vezes se eles não mudam? É um desperdício de tempo,
processamento e conexão. Infelizmente, até o momento, atualizações constantes
são a norma na internet – mas elas não precisam ser.
Christoph Pojer, um desenvolvedor MooTools,
adicionou o plugin para gerenciamento de histórico à sua biblioteca
Power Tools. Ele substitui o carregamento de URLs do mesmo site
fornecendo um
método para capturar cliques de links, carregar o conteúdo das páginas
via AJAX
(Mootools' Request.HTML class),
modificar o objeto que guarda endereço da página para manter registros
de histórico, e reavaliar conteúdos de links para
permitir que os desenvolvedores criem websites de uma página rápidos e
eficientes.
Ver Demo
O método tradicional de um sistema de histórico dinâmico com suporte
do "botão voltar" sempre foi baseado no uso de JavaScript com endereços
de âncora hash. Tecnologias mais novas, incluindo métodos HTML5's window.onpopstate and history.pushState permitem opções mais confiáveis de
administrar o histórico. O plugin Moo Tools para gerenciamento de histórico suporta métodos
modernos para administração do histórico. Deixe-me mostrar como implementá-lo
rapidamente.
Estrutura HTML
O plugin para gerenciamento de histórico não necessita de nenhum ajuste
da estrutura HTML, mas pelo menos um conteúdo designado deve ser identificado;
você pode, naturalmente, ter quantas áreas de conteúdo quiser, mas
precisará de solicitações múltiplas ao AJAX para acessá-las, a menos que você
use uma solicitação Request.JSON para acessar o conteúdo de múltiplas áreas da
página. Para essa simples demonstração, definiremos um cabeçalho, um rodapé e
uma área de conteúdo:
<div id="body">
<header> <a href="/" data-noxhr>David Walsh Blog</a> <div>MooTools History Plugin Demo</div> <div>This is a simple example of the MooTools History plugin created by Christoph Pojer</div>
</header>
<ul id="demoMenu"> <li><a href="mootools-history.php">Home</a></li> <li><a href="mootools-history-david.php">About David Walsh</a></li> <li><a href="mootools-history-mootools.php">About MooTools</a></li> <li><a href="mootools-history-christoph">About Christoph Pojer</a></li> </ul>
<article id="contentHolder">
</article>
<footer>
</footer> </div>
A área de conteúdo é a única
parte que terá mudanças. A página deverá carregar como de costume.
O JavaScript MooTools
Considerando que o plugin MooTools para gerenciamento de histórico foi
incluído na página, há algumas poucas funções que devem ser criadas no
domready. O primeiro é um método que executará a solicitação de conteúdo quando
um link é clicado:
var contentHolder = document.id("contentHolder");
var request = new Request.HTML({ onSuccess: function(nodeTree,elements,html) { contentHolder.set("html",html); onPageUpdate(); } });
var loadPage = function(url) { request.send({ url: url }); };
O
próximo passo é a criação de um método (teoricamente opcional, mas você normalmente
vai querer fazer alguma coisa uma vez que o conteúdo tenha sido carregado) que
rodará toda vez que um conteúdo seja recebido:
var onPageUpdate = function() {
};
O plugin MooTools para gerenciamento de histórico não solicita que
você faça qualquer coisa quando um conteúdo é recebido, mas provavelmente você
vai querer fazer alguma coisa. Por que gravar manualmente a visualização da página dentro do Google
Analytics?
O próximo pedaço é importante em deixar os links das páginas
estáticas passarem pelo armazenador de histórico baseado em ajax. Uma
única linha do Element.Delegation
já consegue realizar o trabalho - não só para o carregando da página
inicial, mas para todo carregamento que será executado depois disso:
var listener = function(evt){ evt.preventDefault(); History.push(this.get('href')); };
document.body.addEvent("click:relay(a:not([href=#],[href^=http://],[data-noxhr]))",listener);
Quando qualquer link que aponta para outra página é clicado, o método listener pára o evento e envia a
nova URL para o plugin, mudando a barra de endereços, administrando o clique do
botão back/forward.
Uma função back também é criada de forma que
possamos providenciar um link “back” e um link “forward”, para andar para trás
e para frente no histórico da página, se escolhermos usá-lo:
var back = function(evt){ evt.preventDefault(); History.back(); };
var forward = function(evt){ evt.preventDefault(); History.forward(); };
document.id("backLink").addEvent("click",back); document.id("forwardLink").addEvent("click",forward);
O
próximo passo é adicionar um evento change no próprio plugin para gerenciamento de histórico para rodar
nossa função loadPage quando a URL da página muda:
// When the history changes, update the content History.addEvent('change',loadPage);
Se
o cliente não suporta o método history.pushState, o plugin avalia o hash e
carrega a página como necessário:
if(!History.hasPushState()) { var hash = document.location.hash.substr(1); if (!hash) return;
var path = document.location.pathname.split('/'); path = path[path.length - 1]; if (hash == path) return;
loadPage(hash); }
Finalmente,
rodar onPageUpdate no carregamento domready não dói, uma vez que os eventos são adicionados uma
vez na onPageUpdate:
// Update the page onPageUpdate();
Agora a página está pronta
para suportar permutas de conteúdo baseadas no plugin para gerenciamento de histórico e operadas pelo
AJAX. Graças à função onPageUptade,
links são adicionados a eventos na medida em que chegam, de modo que até os
conteúdos recuperados pelo AJAX podem ser administrados pelo plugin.
Dicas e estratégias para websites que mantêm histórico com hash
Plugins como o do MooTools para gerenciamento de histórico, a obra
prima de Christoph, são muito úteis no enriquecimento da experiência do
usuário, mas necessitam de um pouco do conhecimento da lógica do
desenvolvedor:
- Uso
do
Event Delegation
– Lembre-se de que num sistema do estilo do plugin MooTools para
gerenciamento de histórico, designar eventos a
elementos diretamente pode não ser a melhor solução, porque tais
elementos
podem desaparecer no próximo clique de um link. Usar event
delegation em vez de tradicionalmente delegar eventos aos elementos pode
lhe poupar de um
monte de problemas. Leia o topico MooTools
Element.Delegation se não
estiver familizarizado com event delegation.
- Não assuma suporte
para JavaScript – Tenha
em mente de que o cliente pode não suportar JavaScript. Mecanismos de busca
adicionaram suporte para JavaScript, mas é importante usar URLs que trabalhem
tanto em sites gerenciados pelo plugin MooTools para gerenciamento de histórico quanto em websites sem JavaScript.
- Use detecão para AJAX – O MooTools proporciona um cabeçalho
específico para AJAX na requisição chamada HTTP_X_REQUESTED_WITH. Clique aqui para aprender como usá-lo para detectar
solicitações de AJAX. Você vai querer ser capaz de detectar o AJAX de forma que
tais solicitações simplesmente retornem o conteúdo, e não o cabeçalho ou o rodapé
(etc) juntamente com ele. Você pode escrever um client-side script/regex para
analisar o conteúdo, mas isso é muito ineficiente. Meu demo usa PHP para
armazenar o conteúdo da página em variáveis, como segue:
// Load pages based on querystring $qstring = $_SERVER['QUERY_STRING']; if($qstring == 'home' || $qstring == '') { $content.= '<h1>Welcome Home!</h1>'; $content.= '<p>History Management via popstate or hashchange. Replaces the URL of the page without a reload and falls back to Hashchange on older browsers.</p><p>This demo page aims to teach you how you can use Christoph Pojer's outstanding History widget to load only the content you need, dynamically and reliably.</p>'; } elseif($qstring == 'about-david') { $content.= '<h1>About David Walsh</h1>'; $content.= '<p>My name is David Walsh. I'm a 27 year old Web Developer from Madison, Wisconsin. In the web world, I am:</p> <ul> <li>Founder and Lead Developer for Wynq Web Labs.</li> <li>Software Engineer for SitePen.</li> <li>Core Developer for the MooTools JavaScript framework.</li> <li>Co-Founder of Script & Style, a website aimed at making web developers and designers better.</li> </ul> <p>I don't design the websites - I make them work.</p> <p>I am also an admirer of the great <a href="?about-christoph">Christoph Pojer!</a>.</p>'; } // and more.... // Page not found else { $content.= '<h1>Page Not Found</h1>'; $content.= '<p>The page you were attempting to find could not be found.</p>'; }
// If request was via AJAX, push it out. if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { echo $content; exit(); }
Obviamente
seu sistema estará buscando conteúdo de um banco de dados ou outros
arquivos
estáticos, mas você entende o ponto – carregar o conteúdo antes de
qualquer saída de página, aspirar para o AJAX e distribuir o conteúdo
condizente. Se
não for uma solicitação AJAX, você deve distribuir o conteúdo dentro das
áreas
de conteúdo do HTML, via métodos tradicionais.
Essas dicas devem bastar para
colocá-lo em condições de usar um sistema baseado no plugin MooTools para gerenciamento de histórico. Lembre-se de que o
JavaScript visa a melhorias – tenha em mente de que seu usuário (ou mecanismo de
busca) pode não suportar JavaScript e, sendo assim, certifique-se testando seu
website extensivamente!
Teste o exemplo. Clique de
página em página, use o back button, dê refresh na página etc. O plugin MooTools para gerenciamento de histórico é
sólido como uma rocha!
artigo publicado originalmente no iMasters, por David Walsh
|
Texto original disponível em http://programmingzen.com/2011/03/28/what-programming-language-should-i-learn-first/
⁂
Existem
centenas de linguagens de programação diferentes por aí. Se você for um novato,
pode ignorar o fato que a maioria delas existe. No entanto, mesmo se
restringirmos a lista para apenas uma dúzia das linguagens mais importantes,
decidir qual linguagem de programação aprender primeiro pode ser uma tarefa
desafiadora. Você pode se perguntar: devo aprender primeiro C, C++, Java, C#, ou PHP? Se você fizer essa
pergunta para 10 programadores, você provavelmente irá escutar 10 respostas
diferentes. Aqui está a minha.
Da
mesma maneira que as linguagens humanas, as linguagens de programação são
utilizadas para comunicar. Curiosamente, elas também envolvem a
comunicação entre pessoas, uma vez que outros programadores irão acabar
lendo/modificando/melhorando seu código ou você fará isso em algum momento.
Diferentemente das linguagens naturais, no entanto, as linguagens de
programação são compreendidas perfeitamente por computadores, graças à ajuda de
intérpretes, de compiladores e de outros tipos similares de software.
Dependendo
do tipo de programa que você está tentando escrever, e em que ambiente você
está trabalhando, você descobrirá que algumas linguagens de programação se
encaixam melhor do que outras para certas tarefas, mesmo se as linguagens de
programação mais comuns forem rotuladas como sendo para “uso geral”.
Por
exemplo, se você quiser criar um aplicativo para iPhone e iPad, sua melhor aposta seria usar
Objective-C. Para smartphones Android e tablets, na maioria dos casos, você
precisará aprender tecnologias do lado cliente, como HTML, CSS e JavaScript
(dessas 3, somente o JavaScript é uma linguagem de programação real, mas as
outras duas são importantes do mesmo jeito). Para o lado servidor do seu
aplicativo web, você provavelmente precisará aprender linguagens como PHP,
Ruby, ou Python (todas as três têm frameworks que irão ajudar a deixar as
tarefas web mais fáceis e menos demoradas), em vez de um sistema de
programação favorito como o C. (Claro, é preciso mencionar o SQL se você
estiver criando uma interface com um banco de dados relacional).
Então
você deve começar sua aventura pelo mundo das linguagens de programação com o
JavaScript? Mas e o Objective-C? SQL? Meu conselho é evitar começar sua jornada
de programação com uma linguagem que é atrelada a um ambiente específico. No
início do jogo, seu principal objetivo é aprender como programar – e como
pensar como um programador – em vez de aprender uma linguagem específica. Uma
vez que você estiver craque nos conceitos fundamentais com a ajuda do objetivo
geral da linguagem de programação, você pode facilmente aprender novas
linguagens à medida que a necessidade aparecer, dependendo do tipo de software
que você gostaria de desenvolver.
Esta
é uma profissão em que a maioria das suas habilidades são desenvolvidas e aperfeiçoadas quando você realmente pratica.
Se você titubear nos fundamentos da programação, você pode facilmente escolher
uma linguagem específica e um framework quando precisar construir
aplicativos para iPad ou qualquer outra coisa que você queira criar.
Um
programador bem preparado irá acabar aprendendo várias linguagens de
programação e ferramentas ao longo de sua carreira. Dito isso, se você
está
apenas começando, foque em uma linguagem primeiro. Enquanto isso possa
parecer
um pouco bobo no início, a boa notícia é que, a não ser que você escolha
uma
linguagem de programação verdadeiramente exótica, muito do que você
aprender também poderá ser usado em outras linguagens de programação.
Lembre-se de que
nesse estágio, acima de tudo, você está aprendendo como comunicar seus
pensamentos em afirmações precisas para que outros programadores possam
entender (e para o computador poder executar).
Por
esse motivo, você não pode errar muito com qualquer uma das linguagens de
programação com objetivos gerais (p.e., C, Java, C#, Perl, Ruby, Python, ou
Scheme). Dito isso, se você está aprendendo sozinho, eu te aconselharia a
escolher uma linguagem que irá tornar seu caminho de aprendizado mais fácil. Em
outras palavras, opte por uma linguagem de programação que é vastamente usada,
bem documentada, e amigável para iniciantes. Você está procurando por uma
linguagem que não seja muito burocrática, não precise que você gerencie a
memória diretamente, ou tenha conhecimentos profundos em matemática para
começar.
Assim,
minha sugestão seria começar com o Python, e a use como uma ferramenta para
aprender a arte geral da programação. Aprender Python é divertido, fácil e
útil. Você será capaz de usá-lo para uma vasta gama de projetos em diversos
ambientes (scripting, web, pesquisa científica etc).
Existe
uma variedade de
tutoriais grátis na web, mas se você quiser
instruções mais rigorosas/sistemáticas/acadêmicas, eu recomendo “Python Programming: An
Introduction to Computer Science (2nd Edition)” - “Programação em Python: Uma introdução à Ciência da
Computação (Segunda Edição”) - (USA
| UK | Canada).
Uma
vez que você tiver aprendido os fundamentos da programação, tiver um conhecimento
decente da linguagem Python, e tiver ganho alguma experiência com projetos
práticos no Python, você deverá estar melhor preparado para evoluir e para escolher
outras linguagens e frameworks baseados em projetos em que você tem interesse de
desenvolver ou contribuir no futuro (projetos Open Source são ótimos para esse
objetivo).
artigo publicado originalmente no iMasters, por Antônio Cangiano
|
Neste artigo abordaremos um tema fundamental para
administradores de sistemas GNU/Linux e também para usuários avançados
deste sistema: o gerenciamento de pontos de montagem em modo Shell.
Todas as técnicas explanadas neste artigo são aplicáveis a qualquer
distro GNU/Linux.
Espero que este artigo seja útil ao maior número possível de profissionais e usuários do GNU/Linux.
1. FHS - O padrão hierárquico do sistema de arquivos do GNU/Linux
FHS (Filesystem Hierarchy Standard) é o padrão estabelecido pela LSB (Linux Standard Base)
o qual define a estrutura (hierarquia) de diretórios para sistemas
GNU/Linux certificados por este instituto, bem como a localização de
cada tipo de arquivo dentro desta estrutura. O padrão FHS é originário
do sistema Unix.
Dentre as vantagens proporcionadas pelo FHS para sistemas GNU/Linux, destaco as seguintes:
- Facilitar a administração de sistemas baseados em GNU/Linux,
independente da distro adotada, pois proporciona uma estrutura de
diretórios padronizada.
- Proporcionar segurança ao sistema, pois arquivos binários
específicos e fundamentais à administração do sistema são localizados em
diretórios específicos do FHS cujo acesso e execução são restritos ao
usuário root, impedindo sua utilização ou remoção indevidas.
- Facilitar o desenvolvimento de softwares para a plataforma
GNU/Linux, pois define a localização de arquivos específicos como as
bibliotecas compartilhadas do sistema.
Destas vantagens, a que mais nos interessa para o âmbito deste artigo
é a primeira, referente à administração de sistemas GNU/Linux.
Veja na figura a seguir os diretórios do FHS abaixo do diretório raiz (/) do sistema:

2. Pontos de montagem: diretórios “recipientes”
Para podermos ter acesso a dados em discos e partições
(leitura/gravação) precisamos antes montar tal disco ou partição em um
determinado ponto de montagem previamente criado dentro da estrutura de
diretórios do FHS em um sistema GNU/Linux. As montagens poderão ser
feitas manual ou automaticamente, conforme explanarei mais adiante.
Ponto de montagem é um diretório, preferentemente vazio, que será o
“recipiente” do sistema de arquivos do disco ou partição ao qual
queremos ter acesso.
No FHS há dois diretórios indicados para a criação de pontos de montagem:
A maioria dos administradores de sistemas GNU/Linux prefere utilizar o
diretório /media/ para criar pontos de montagem. E eu também.
Portanto,utilizarei este diretório para a criação de pontos de montagem.
3. Identificando discos e partições para montagem: o utilitário blkid
Agora que você já sabe o que são o FHS e pontos de montagem, é
necessário saber identificar os dispositivos (discos e partições)
detectados pelo GNU/Linux para poder montá-los. Basicamente, o GNU/Linux
detecta estes dispositivos automaticamente nos seguintes momentos:
- Na da inicialização do sistema são detectados os dispositivos já
conectados ao sistema (coldplug: conectados à frio) ou já disponíveis
no próprio hardware do computador, como é o caso de partições existentes
no HD.
- Após o sistema já estar inicializado, serão detectados todos os
dispositivos USB, como pendrives, que forem conectados ao sistema
(hotplug: conectados à quente) ou novas partições que forem criadas no
HD, bem como CD/DVD's que forem inseridos.
Obs.: Note que quando você estiver utilizando um desktop (ambiente
gráfico, como GNOME, KDE, XFCE, dentre outros) no GNU/Linux, a montagem
de dispositivos USB (como pendrives) e CD/DVD's é, geralmente, feita
automaticamente, assim que estes forem conectados ou inseridos no
sistema. Para o âmbito deste artigo, considerarei que esta
característica de montagem automática esteja desabilitada no sistema.
Os dispositivos detectados pelo GNU/Linux são identificados como
arquivos especiais dentro do diretório /dev/ do FHS. Para montagem de um
dispositivo (disco ou partição), precisaremos obter as seguintes
informações sobre o mesmo:
- A identificação atribuída ao dispositivo pelo GNU/Linux dentro do diretório /dev/ do FHS.
- O tipo do sistema de arquivos utilizado pelo dispositivo.
Para obter estas informações, abra um Shell (Terminal) do GNU/Linux,
logue-se como superusuário (su) e digite o seguinte comando:
# /sbin/blkid

No exemplo acima, o utilitário blkid identificou os seguintes dispositivos montáveis em meu sistema
01 - hda: um HD master com cinco partições:
- hda1: primeira partição com o tipo de sistema de arquivos NTFS na qual tenho o MS-Windows instalado.
- hda2: segunda partição com o tipo de sistema de arquivos VFAT (FAT32) a qual é utilizada pelo MS-Windows como memória virtual.
- hda5: quinta partição com o tipo de sistema de arquivos Ext3 na qual tenho o CentOS instalado.
- hda6: sexta partição com o tipo de sistema de arquivos SWAP a qual é utilizada pelo CentOS como memória virtual.
- hda7: sétima partição com o tipo de sistema de arquivos NTFS na qual
mantenho documentos e arquivos compartilhados entre os sistemas CentOS e
MS-Windows
02 - sda: um Pendrive (dispositivo USB) com uma única partição:
- sda1: única partição deste dispositivo com o tipo de sistema de arquivos VFAT (FAT32).
03 - hdc: uma unidade de CD/DVD (tipo de sistema de arquivos iso9660).
4. Montagens manuais de discos e partições: o comando mount
Para a montagem de discos e partições os passos a serem seguidos são:
a) Abrir o Shell (Terminal) do GNU/Linux e logar-se como superusuário (su);
b) Identificar o dispositivo que será montado e o tipo de sistema de arquivos do mesmo utilizando o utilitário blkid:
# /sbin/blkid
c) Criar, caso ainda não exista, o ponto de montagem correspondente dentro do diretório /media/ do FHS com o comando mkdir:
# mkdir /media/<ponto_montagem>, onde:
• <ponto_montagem>: é o ponto de montagem, isto é, o diretório “recipiente” para a montagem do dispositivo.
Ex.: # mkdir /media/Docs
d) Montar o dispositivo com o comando mount cuja sintaxe geral é a seguinte:
# mount -t <tipo_sistema_arquivos> <dispositivo> <ponto_montagem>, onde:
• <tipo_sistema_arquivos>: é o tipo de sistema de arquivos
utilizado pelo dispositivo (disco ou partição) a ser montado; esta
informação é obtida com o comando blkid.
• <dispositivo>: é identificação do dispositivo pelo GNU/Linux, por exemplo, /dev/hda1, /dev/sda1, /dev/hdc.
• <ponto_montagem>: é o ponto de montagem (diretório “recipiente”) no qual o dispositivo será montado.
Ex.: # mount -t ntfs-3g /dev/hda7 /media/Docs
Para que fique bem claro a montagem manual de discos e partições apresentarei os três exemplos a seguir:
Exemplo 1 – Montagem de uma partição NTFS local:
Estando logado como superusuário (su) no Shell para montar a partição
/dev/hda7 identificada pelo GNU/Linux como /dev/hda7, a qual utiliza o
tipo de sistema de arquivos NTFS, em um ponto de montagem chamado Docs
(/media/Docs), a sequência de comandos é a seguinte:
# /sbin/blkid # mkdir /media/Docs # mount -t ntfs-3g /dev/hda7 /media/Docs

Obs.: Note que o tipo de sistema de arquivos utilizado pelo
dispositivo /dev/hda7 informado pelo utilitário blkid é NTFS. Porém,
montei informando o tipo ntfs-3g. A explicação para isso é que o tipo
ntfs padrão do comando mount é correspondente ao tipo NTFS utilizado
pelo MS-Windows 2000. A partição em questão foi formatada utilizando o
MS-Windows 7 o qual utiliza um formato NTFS mais recente.
Exemplo 2 – Montagem de um pendrive (dispositivo USB):
Estando logado como superusuário (su) no Shell, para montar um
pendrive identificado pelo GNU/Linux como /dev/sda1 o qual utiliza o
tipo de sistema de arquivos VFAT (FAT32) em um ponto de montagem chamado
USB (/media/USB), a sequência de comandos é a seguinte:
# /sbin/blkid # mkdir /media/USB # mount -t vfat /dev/sda1 /media/USB

Exemplo 3 – Montagem de uma imagem ISO de DVD armazenada no HD local:
Estando logado como superusuário (su) no Shell, para montar um
arquivo de imagem ISO do DVD do CentOS localizada na partição NTFS
(/media/Docs/SO/CentOS-5.4-i386-bin-DVD.iso) de meu HD em um ponto de
montagem chamado ISO (/media/ISO), a qual já está montada, a sequência
de comandos é a seguinte:
# /sbin/blkid # mkdir /media/ISO # mount -t iso9660 -o loop /media/Docs/SO/CentOS-5.4-i386-bin-DVD.iso /media/ISO

Obs.: Note que o tipo de sistema de arquivos utilizado por CD's e
DVD's é iso9660. Para que seja possível navegar pelos diretórios da
imagem ISO como em um diretório normal no sistema é necessário utilizar o
parâmetro -o loop.
5. Desmontagem de discos e partições: o comando umount
Para desmontar um disco ou partição montado no sistema o comando a
ser utilizado é o umount. Para executá-lo, você deverá estar logado em
um Shell (Terminal) do GNU/Linux como usuário superusuário (su) e o
dispositivo (disco ou partição) a ser desmontado não poderá estar em
uso.
Há duas formas de de desmontar um dispositivo com o comando umount:
01 - Informando o ponto de montagem a ser desmontado:
# umount <ponto_montagem>, onde:
- <ponto_montagem>: é o ponto de montagem (diretório “recipiente”) no qual o dispositivo (disco ou partição) foi montado.
Ex.: # umount /media/Docs

02 - Informando o dispositivo a ser desmontado:
# umount <dispositivo>, onde:
- <dispositivo>: é a identificação do dispositivo (disco ou
partição) atribuída ao mesmo pelo GNU/Linux, a qual pode ser obtida com o
utilitário blkid já explanado neste artigo.
Ex.: # /dev/hda7

Obs.: Antes de desmontar dispositivos USB no qual você tenha feito
alterações nos dados armazenados (gravações de dados), execute o comando
sync para fazer uma desmontagem mais segura do dispositivo, evitando
perdas de dados. O comando sync grava no dispositivo todos os dados
armazenados em buffers. Veja um exemplo na figura a seguir:

É isso!
artigo publicado originalmente no iMasters, por Roberto Rodrigues Junior
|
Houve uma discussão
interessante no JSMentors.com sobre JSONP e como deixá-lo mais
seguro. Foi uma boa experiência,
principalmente porque me forçou a examinar o assunto com profundidade e
a apresentar uma contraproposta própria.
Começaremos com um resumo dos
fundamentos do JSON, incluindo a API EcmaScript5JSON, e depois discutiremos a recuperação de domínio cruzado do JSON via
JSONP. Finalmente, introduzirei um framework JSONP simples e relativamente
seguro e mostrarei como usá-lo para buscar tweets na database do Twitter.
O que é JSON?
JSON (JavaScript Object
Notation) é um formato leve de intercâmbio de dados baseado na representação
literal de Objetos, Arrays, Strings, Números e Booleans do JavaScript. Uma variação do JSON é suportada pela maioria
das linguagens modernas, e agora compete com o XML como
protocolo de dados para serviços web, http e configuração de sistemas.
O JSON foi formalizado e
popularizado por volta de 2001 por Douglas
Crockford. A
especificação é descrita no rfc4627
OK, OK, posso obter
isso na Wikipedia. Queremos exemplos.
OK - aqui estão
alguns cookies (dos bons) expressos em JSON…
{ "cookies": { "oatmeal": { "ingredients": [ "flour", "sugar", "oats", "butter" ], "calories": 430, "eatBy": "2010-12-05", "kosher": true }, "chocolate": { "ingredients": [ "flour", "sugar", "butter", "chocolate" ], "calories": 510, "eatBy": "2010-12-03", "kosher": true } } }
…isso é equivalente à seguinte expressão xml…
<cookies> <oatmeal> <ingredients>flour</ingredients> <ingredients>sugar</ingredients> <ingredients>oats</ingredients> <ingredients>butter</ingredients> <calories>430</calories> <eatBy>2010-12-05</eatBy> <kosher>true</kosher> </oatmeal> <chocolate> <ingredients>flour</ingredients> <ingredients>sugar</ingredients> <ingredients>butter</ingredients> <ingredients>chocolate</ingredients> <calories>510</calories> <eatBy>2010-12-03</eatBy> <kosher>true</kosher> </chocolate> </cookies>
Então JSON é como
JavaScript?
Não exatamente. Embora o JSON
se pareça com o JavaScript, tem as seguintes regras restritivas:
- O JSON
representa seis tipos de valores: objetos, arrays, números, strings,
booleans e o null literal.
- Datas não são
reconhecidas como um tipo de valor único
- O conceito de um
identificador JavaScript não é compreendido pelo JSON. Todos os nomes-chave têm que ser strings JSON
- Strings JSON têm
que estar entre aspas
- Números JSON não
podem ter zeros à esquerda
Além do mais, como o JSON tem
a intenção de ser uma linguagem independente, os objetos JSON devem ser
considerados como strings genéricos, e não objetos JavaScript.
Usando JSON no
JavaScript
JSON é um formato
útil para receber respostas do servidor para solicitações XHR. Aparentemente,
essa resposta será na forma de uma string. Uma forma de converter uma string
JSON em um objeto JavaScript é alimentá-la com um argumento para a função eval:
var myCookies = eval('(' + cookieJSON + ')'); myCookies.cookies.chocolate.ingredients[1]; //"sugar"
(Os parênteses extras são
necessários por causa da ambiguidade com que o JavaScript interpreta uma chave)
Transações XHR comuns estão
sujeitas às mesmas restrições de domínio, de forma que você pode ficar razoavelmente
seguro de que a resposta vem do seu próprio servidor. Entretanto, os paranóicos
entre nós vão se preocupar com as consequências de um erro do servidor, ou um
redirecionamento malicioso, e realmente um eval cego de um gremlin qualquer
enviado por seu servidor pode colocar você em dificuldades um dia.
Felizmente, o ES5 (pdf) está tomando conta de você.
JSON.parse e
JSON.stringify
O ES5 especifica um novo
objeto incorporado chamado JSON com duas funções úteis baseadas em uma API
originalmente desenvolvida por Douglas Crockford.
O JSON.parse realiza um eval seguro de supostas strings
JSON (presumivelmente através de uma expressão regular). Se a string não for um
JSON válido, uma exceção SintaxError é disparada e o eval não é chamado. Há um
segundo argumento opcional, reviver,
uma função com dois parâmetros (key e value). Se fornecida, a função reviver é aplicada a todo par key/value
produzido pelo parse, o que pode fazer com que certos valores sejam modificados
de acordo com a lógica da função. Um uso típico do reviver é na reconstituição de valores de datas de strings (embora
não tenha valor o ES5 também especificar uma função Date.prototype.toJSON).
function dateReviver(key, value) { if (typeof value === 'string') { var a = /^(d{4})-(d{2})-(d{2})$/.exec(value); if (a) { return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3])); } } return value; }; var myCookies = JSON.parse(cookieJSON, dateReviver); myCookies.cookies.oatmeal.eatBy;
O JSON.stringify faz o oposto. O argumento value é requerido e pode ser qualquer objeto
JavaScript (embora tipicamente seja um objeto em um array). O resultado da
invocação do stringify é uma string JSON. Também há dois argumentos opcionais,
replacer e space. Quando replacer é uma função, funciona basicamente como um inverso do reviver; contudo pode ser
também um array, quando funciona como uma lista em branco de propriedades do
objeto a ser serializado.
O argumento space é usado para formatação e seu valor pode
ser tanto um número quanto uma string. Se um número é fornecido, ele
representa o número de espaços em branco
com os quais identar cada nível. Se o argumento é uma string (por
exemplo ‘t’), então o texto é identado utilizando os caracteres
contidos na string.
JSON.stringify(cookies, ['cookies','oatmeal','chocolate','calories'], 't')
Ambas funções são implementadas em todos browsers modernos (mas não no
IE7). Asen Bozhilov compilou uma tabela de compatibilidade
que mostra as diferenças com que os fornecedores interpretam o JSON.parse.
⁂
Texto original disponível em http://javascriptweblog.wordpress.com/2010/11/29/json-and-jsonp/
artigo publicado originalmente no iMasters, por Angus Croll
|
No primeiro artigo, falamos do JSON. Neste, abordaremos o JSONP.
JSONP
Vimos que podemos usar JSON
para transportar dados entre servidor e cliente, e que isso pode ser feito com relativa
segurança. Mas e para buscar dados em outros domínios? Sei que o Twitter tem
uma API poderosa para obter dados históricos de tweets, mas sou limitado pela
política de mesma origem. Ou seja, a menos que meu cliente esteja no domínio
twitter.com, o uso de um XHR get comum me retornará nada mais do que um erro
HTTP.
A forma padrão de
contornar isso é usar o Cross
Origin Resource Sharing (CORS), que agora é implementado pela maioria
dos browsers modernos. No entanto, muitos desenvolvedores acham essa abordagem pesada
e um tanto pedante.
O JSONP (documentado pela
primeira vez por Bob Ippolito em 2005) é uma alternativa simples e
efetiva que usa a capacidade das tags script de obter conteúdo de qualquer
servidor.
Ele funciona assim: uma tag script tem um atributo src que pode ser configurado para qualquer
resource path, como uma URL, e não precisa retornar um arquivo JavaScript.
Assim, posso facilmente criar um fluxo JSON dos dados que alimentam meu
twitter para meu cliente.
var scriptTag = document.createElement('SCRIPT'); scriptTag.src = "http://www.twitter.com/status/user_timeline/angustweets.json?count=5"; document.getElementsByTagName('HEAD')[0].appendChild(scriptTag);
Essas são boas notícias,
exceto pelo fato de não terem absolutamente nenhum efeito em minha página web,
a não ser enchê-la com um monte de JSON
indisponível. Para poder usar dados de tag script, precisamos interagir com
nosso JavaScript existente. É aí que a parte P (ou “padding” – acolchoado) do
JSON se apresenta. Se pudermos fazer o servidor envolver (wrap) sua resposta em
uma de nossas próprias funções, podemos fazer com que ele seja útil.
OK, aí vai:
var logIt = function(data) { window.console && console.log(data[0].text); } var scriptTag = document.createElement('SCRIPT'); scriptTag.src = "http://www.twitter.com/status/user_timeline/angustweets.json?count=5&callback=logIt"; document.getElementsByTagName('HEAD')[0].appendChild(scriptTag);
Uau, como fiz isso? Bem, não
sem muita ajuda do twitter, que juntamente com muitas outras APIs agora
suportam requisições JSONP. Note o parâmetro de solicitação
extra: callback=loglt. Isso informa o servidor (twitter) para envolver sua resposta
em minha função (loglt).
O JSONP parece bem bacana.
Por que toda essa confusão?
OK, finalmente estamos
prontos e em condição de checar a discussão JSMentors.com a que me referi no artigo anterior.
Peter Van der Zee, Kyle Simpson (conhecido como Getify) e outros estão
compreensivelmente preocupados com a segurança do JSONP.
Por quê? Porque sempre que
chamamos o JSONP, invocamos qualquer código que o servidor coloque em nossas
mãos, sem questionamentos, e sem volta. É como ir de olhos vendados a um
restaurante e pedir que coloquem comida na sua boca. Em alguns lugares você
pode confiar, em outros, não.
Peter recomenda tirar a função padding da resposta e implementá-la manualmente somente depois que a
resposta tiver sido confirmada como JSON puro.
A ideia é basicamente sólida,
mas ele acrescenta alguns detalhes de implementação. Ele também lamenta a
exigência atual do fornecimento de uma variável global. A proposta do Kyle é
similar: ele também defende uma verificação pós-resposta, baseada no mime type da tag script – ele sugere a introdução de um novo mime type específico para o JSONP (por exemplo: “application/json-p”), que
dispararia tal validação.
Minha solução JSONP
Concordo com o
espírito dos argumentos tanto do Kyle quanto do Peter. Aqui vai um framework
JSONP leve que considera algumas de suas preocupações. A função evalJSONP é um
callback wrapper que usa uma closure para ligar o custom callback aos dados de
resposta. O custom callback pode ser de qualquer alcance e, como no exemplo a
seguir, pode ser uma função anônima criada dinamicamente. O wrapper evalJSONP
assegura que o callback somente será invocado se a resposta JSON for válida.
var jsonp = { callbackCounter: 0, fetch: function(url, callback) { var fn = 'JSONPCallback_' + this.callbackCounter++; window[fn] = this.evalJSONP(callback); url = url.replace('=JSONPCallback', '=' + fn); var scriptTag = document.createElement('SCRIPT'); scriptTag.src = url; document.getElementsByTagName('HEAD')[0].appendChild(scriptTag); }, evalJSONP: function(callback) { return function(data) { var validJSON = false; if (typeof data == "string") { try {validJSON = JSON.parse(data);} catch (e) { } } else { validJSON = JSON.parse(JSON.stringify(data)); window.console && console.warn( 'response data was not a JSON string'); } if (validJSON) { callback(validJSON); } else { throw("JSONP call returned invalid or empty JSON"); } } } }
(Atualização: com a sugestão
de Brian Grinstead
e Jose Antonio Perez , eu acertei o utilitário para
suportar carregamento concorrente de scripts).
Eis aqui alguns
exemplos de uso...
var obamaTweets = "http://www.twitter.com/status/user_timeline/BARACKOBAMA.json?count=5&callback=JSONPCallback"; jsonp.fetch(obamaTweets, function(data) {console.log(data[0].text)}); var reddits = "http://www.reddit.com/.json?limit=1&jsonp=JSONPCallback"; jsonp.fetch(reddits , function(data) {console.log(data.data.children[0].data.title)});
Note que sites como o
twitter.com na verdade retornam JSON sem aspas, o que faz a tag script carregar um objeto JavaScript. Em tais
casos, é o método JSON.stringify
que na verdade faz a validação, removendo qualquer atributo não
compatível com o JSON. Depois disso, eles com certeza passam no teste
JSON.parse. E isso é
lamentável, porque mesmo que eu possa limpar o objeto de qualquer dado
não
JSON, nunca terei certeza se o servidor estava tentando me enviar
conteúdo
malicioso (sinteticamente, um método horroroso para comparar o objeto
original
recebido com a versão stringfied e
parsed) – o melhor que posso fazer é colocar uma advertência no console.
Esclarecendo, isso é um pouco
mais seguro, mas não é seguro. Se o provedor do servidor simplesmente escolher
ignorar sua solicitação para envolver (wrap) a resposta dele em sua função,
então você estará vulnerável, mas, do contrário, o que apresentei deve fazer do
uso do JSONP algo muito tranquilo.
Também listado aqui. Espero que seja útil.
Leitura complementar
⁂
Texto original disponível em http://javascriptweblog.wordpress.com/2010/11/29/json-and-jsonp/
artigo publicado originalmente no iMasters, por Angus Croll
|
Quando falamos de desenvolvimento ágil, logo
pensamos em programação pareada, quadros de rendimento com tickets e, é
claro, testes unitários com integração contínua.
Neste artigo, falaremos sobre testes unitários. E o PHPUnit será
abordado para fazer testes em cima de navegação web de verdade, com
navegador de verdade, seja ele Safari, Internet Explorer, Firefox ou
qualquer outro. Para isso, integraremos Selenium ao PHPUnit, o que é
mais fácil do que parece.
 Selenium funciona como um servidor que você manda comandos pela sua aplicação e ele redireciona para os navegadores
Estamos
preparando um novo ambiente no portal em que trabalho e decidimos
trabalhar com teste unitários. Particularmente, gosto muito do
SimpleTest, que é uma ferramenta de testes bem simples, não precisa de
nenhum adicional para funcionar e ainda consegue fazer testes de
navegação sobre as ações básicas (como acessar uma página, clicar em um
link, escrever algum dado em campos do formulário, submeter o formulário
e verificar se tudo saiu como o planejado).
Sempre recorro ao SimpleTest, porém, desta vez, optamos por usar
PHPUnit por ser mais integrado às outras bibliotecas do Pear, ou
sistemas que geram relatórios mais completos do que simplesmente
verificar se o código funcionou conforme o esperado. Com o PHPUnit, por
exemplo, conseguimos verificar qual parte do código ainda não foi
testado passando apenas um parâmetro na linha de comando. Isso se chama
code coverage (mas é assunto para outro artigo).
Outra ferramenta interessante integrada no PHPUnit é o Selenium.
Trata-se de um programa/servidor que manipula diversos servidores. Com
ele, podemos abrir um navegador e acessar uma URL, escrever um
determinado valor em um campo de texto ou selecionar determinada opção
em um campo do tipo select e verificar se realmente foi feito conforme o
plano. A diferença para o SimpleTest é que no Selenium temos um
navegador de verdade executando as ações, portanto, conseguimos fazer
testes em cima do que pode ser alterado via JavaScript ou mesmo ver o
resultado tanto no Firefox como no Google Chrome, no Opera ou mesmo no
Internet Explorer.
Sempre relutei para começar a trabalhar com o PHPUnit + Selenium
porque o SimpleTest resolvia todos os meus problemas sem precisar
instalar o módulo Pear e nem sempre tenho como fazer isso em alguns
servidores de clientes. Mas, no caso deste outro portal, temos um
controle total sobre o servidor e podemos nos arriscar e testar
tecnologias, o que nos permite ter uma maior confiança sobre o que
escrevemos no código.
Para instalar e executar o Selenium no meu Linux, é preciso baixar o código binário e escrever a seguinte linha de comando:
java -jar selenium-server-standalone-2.0rc3.jar
O mesmo deve acontecer com Windows, uma vez que Java é
multiplataforma. Fazendo isso, um servidor é levantado e posso mandar
comandos para ele a fim de que ele repita o comando no navegador que eu
quiser. Por exemplo, abra o Firefox e vá até a URL do projeto, coloque o
usuário e a senha do admin. Por fim, clique no botão “entrar”, e
verifique se a página que abriu tem o texto “Bem vindo, Michael”.
O bacana de o Selenium abrir um servidor é que podemos trabalhar com
qualquer linguagem para enviar os dados para ele. O que a linguagem
server side precisa fazer, seja ela python, php, java, asp ou qualquer
outra, é enviar requisições para o servidor do Selenium. O Selenium, por
sua vez, pode ser executado em qualquer plataforma. Sendo um servidor,
você pode tê-lo em um ambiente Windows e enviar comandos de um Linux.
Você pode ter o Selenium rodando em um Mac e fazer testes em Safari (do
Mac) a partir de um Windows. Isso é bom pra caramba!
Tá, me convenceu, o selenium é bom… e o PHPUnit?
O PHPUnit é um framework de testes feito para PHP que já vem com
módulo de conexão com o Selenium. Assim você não precisa saber como deve
ser feita a requisição para o server ou detalhes de tranação.
Após
instalar o Pear (roda em sistemas Unix e Windows) e o Selenium em sua
máquina, você só precisa criar uma classe de testes estendendo a classe
PHPUnit_Extensions_SeleniumTestCase. Veja como é simples um código
escrito para se conectar no Selenium.
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
class NavegadorTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowser('*firefox'); $this->setBrowserUrl('http://localhost/projeto'); }
public function testTitle() { $this->open('/'); $this->assertTitle('Isto é um teste'); } }
Se quiser fazer testes mais complexos, verifique a lista de comandos
possíveis para o Selenium. Agora, se precisar, pode passar uma lista de
servidores ou navegadores em que você quer fazer os testes. Veja como
fica o código, definindo mais navegadores.
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
class NavegadorTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { array ( 'name' => 'Firefox on Linux', 'browser' => '*firefox', ), array( 'name' => 'Safari on MacOS X', 'browser' => '*safari', 'host' => '192.168.0.12', 'port' => 4444, 'timeout' => 30000, ), array( 'name' => 'Internet Explorer on Windows XP', 'browser' => '*iexplore', 'host' => 'my.windowsxp.box', 'port' => 4444, 'timeout' => 30000, ) );
protected function setUp() { $this->setBrowserUrl('http://192.168.0.1/'); }
public function testTitle() { $this->open('/'); $this->assertTitle('Página de exemplo'); } }
Para informações mais completas, veja mais detalhes sobre o PHPUnit com Selenium no site oficial do PHPUnit.
É isso!
artigo publicado originalmente no iMasters, por Michael Granados
|
Olá,
pessoal!
Neste artigo, gostaria de informar e mostrar como abrir uma tela modal usando o
ModalPopupExtender, depois que executou alguma pesquisa ou regra
dentro do código C#.NET. Funciona para as outras linguagens, mas o meu teste
está sendo feito apenas com a linguagem C#.NET.
Referências:
- Ferramenta:
Visual Studio 2010
- Linguagem:
C#.NET
- Plataforma:
ASP.NET - AjaxControlToolkit
O
AjaxControlToolkit foi desenvolvido para ajudar os desenvolvedores na criação de
web sites e aplicativos web. Você pode fazer download da dll ou código fonte aqui.
Em um artigo anterior, mostrei como usar o ModalDialogExtender, falei de css e do código para chamar a tela. O
problema maior foi que a tela é mostrada sem que acesse diretamente o código
para qualquer processamento antes de aparecer.
Veremos primeiro o processamento dentro da linguagem e no final, o
resultado será mostrado dentro da tela modal. Dessa maneira, fica muito mais
fácil usar essa grande funcionalidade, que evita abrir popup que muitas vezes
são bloqueados pelos browsers.
Mostrando o código
O
primeiro passo é colocar a dll referenciada em seu Toolbox. Criei uma nova aba e adicionei a dll que fiz download no
site asp.net.

Para
colocar todas as funcionalidades mostradas na Imagem 1, clique com o botão
direito em cima do Toolbox e
selecione a opção Add Tab.

Coloque
o nome que quiser na nova aba criada. Clique dentro da aba com o botão direito e
escolha a opção chamada Choose Items. Uma
tela nova é aberta para a indicação da dll.

Depois
de abrir a tela com as dlls, clique em Browser
e indica a dll localizada em um lugar do seu computador.

Depois
destes passos, vamos começar a desenvolver uma página de exemplo. Arraste
o componente da Toolbox chamado ModalPopupExtender para a página .aspx. Automaticamente
o componente coloca no início da página uma indicação.
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
Para
que funcione perfeitamente a popupextender, é necessário criar um Panel
normal dentro da página e com os componentes dentro. Componentes como GridView, Formulário, Image e outros do
.NET.
<asp:Panel id="pnlImagem" runat="server" CssClass="modalPopup" Style="display:none" Width="600px">
<div align="center">
<asp:Image ID="imgChequinhos" runat="server" Width="600px" />
<asp:Button ID="cmdFechar" runat="server" Text="Fechar" />
</div>
</asp:Panel>
Note
que coloquei o nome do Painel de pnlImage, o CssClass coloquei o modalPopup criado no artigo anterior e
um Style=”display:none” para não
aparecer na tela, só quando eu chamar.
Depois
de criar o Painel, criei um label
normal chamada lblTeste.
<asp:Label ID="lblTeste" runat="server"></asp:Label>
Ainda
falta colocar o modal indicando o painel e o label.
<cc1:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
BackgroundCssClass="modalBackground"
CancelControlID="cmdFechar" DropShadow="true"
PopupControlID="pnlImagem" PopupDragHandleControlID="panel3" TargetControlID="lblTeste">
</cc1:ModalPopupExtender>
Note
que foi adicionada uma propriedade chamada BackgroundCSSClass=”modalBackground”
indicando a parte do css, foi adicionado também um botão para fechar a tela
CancelControlID=”cmdFechar” localizado dentro do painel (code 2), foi colocado também a propriedade
PopupControlID=”pnlImagem”, que é o nome do painel criado, e a
TargetControlID=”lblTeste” indicando a label.
Após o
processamento de um clique qualquer, o código passa pelos métodos e depois
mostra o popup. No exemplo, no clique da grid ele deve mostrar uma imagem
de acordo com o registro.

Usei o
RowCommand para fazer essa funcionalidade. Não vou detalhar muito porque não é
o nosso foco falar dessa propriedade do grid. Mas depois de clicado e
processado, que chamo o modal .Show();
protected void gridImagem_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "PesquisarImagem")
{
ModalPopupExtender1.Show();
}
}
O nome
do id modal chama ModaPopupExtender1,
assim basta chamar o Show. O segredo está no componente label adicionado na
página e indicado no TargetControlID. No artigo anterior, o que era indicado
nessa propriedade era um botão e no clique dele aparecia o popup sem que
passasse pelo código .cs. Agora o processamento é feito primeiro para depois
aparecer o popup.

Fico
por aqui e qualquer dúvida pode entrar em contato.
artigo publicado originalmente no iMasters, por Mauricio Junior
|
Zend
Server CE é a
Edição da Comunidade do Servidor de Aplicação PHP da Zend Technologies. É um ambiente livre que pode ser utilizado para
executar aplicações PHP usando recursos adicionais comparados com a versão
PHP.net. Alguns desses recursos são:
- Zend Optimizer+, um acelerador
de códigos PHP byte
- Zend Data Cache, um sistema
de cache de dados para PHP
Usando o
Zend Optimizer+, conseguimos acelerar a execução de uma aplicação PHP sem mudar
o código. Basicamente, o Optimizer+ é um sistema de cache para o bytecode
gerado do interpretador PHP.
O Zend
Data Cache é um sistema de cache para PHP e pode ser usado para fazer o cache
de variáveis, objetos etc. Isso significa que você tem que modificar seu
código para usar esse cache. No entanto, a mudança no código PHP é muito
simples e limitada. Para mais informações sobre o Zend Data Cache, sugerimos a
leitura do White Paper “A
pratical guide to data caching with Zend Server” (pdf, inglês) de Shahar Evron, Gerente
de Produtos na Zend Technologies.
Basicamente
usando o Zend Server CE conseguimos acelerar a execução de uma aplicação PHP,
mas a questão é quanto conseguimos acelerar? A resposta depende da aplicação
PHP e comparada a quê.
Neste
artigo, executei um benchmark do Joomla, o famoso CMS escrito em PHP,
usando Zend Server CE vs. APC e Memcached. Para executar esse benchmark, eu
trabalhei em conjunto com Renato Salvatori da Cost, uma empresa de TI especializada em Joomla.
Em
detalhes, executamos o benchmark em duas fases:
- Usando o Zend Optimizer+ do
Zend Server CE vs. APC;
- Usando o mecanismo de cache
do Joomla nos seguintes backends: File, Memcached, APC e Zend Server CE
(usando File e Shared Memory).
Pra
conseguir usar o cache do Joomla com o Zend Server, usamos um plugin escrito por
mim e por Renato Salvatori - você pode fazer o download no fim
do post.
Metodologia
do benchmark
Usamos a
instalação padrão do Joomla 1.5.17 utilizando os dados de exemplo para o
conteúdo do site. Testamos a homepage do Joomla usando Apache Benchmark (ab)
com 100 pedidos e 10 usuários simultâneos (-n 100 -c 10). Executamos cada
experimento 6 vezes e pegamos a média dos resultados. Medimos o tempo por pedido (o que significa
através de todos os pedidos simultâneos em ms) e a taxa de transferência (Kbyte/sec).
Todos os
experimentos mostrados neste artigo foram executados usando CPU Intel Core 2 a
2.10 Ghz com 2 GB de RAM executando Gnu/Linux OS com kernel 2.6.28 . Usamos a
seguinte configuração de software: Zend Server 5 CE, Apache 2.2.11, PHP 5.3.2,
Joomla 1.5.17, Memcached 1.4.5, APC 3.1.3p1, MySQL 5.0.45.
APC vs
Zend Optimizer+
No
primeiro passo do experimento, executamos o benchmark com o cache do Joomla
desabilitado. Testamos o tempo de reposta da homepage com e sem o acelerador bytecode
do Zend Optimizer+ e APC. Os resultados estão na tabela 1.
|
tempo por pedido - através de todos os pedidos simultâneos (ms)
|
taxa de transferência
(Kbyte/sec)
|
Sem
Cache, sem Optimizer+, sem APC
|
114,017
|
286,87
|
Sem
Cache, APC
|
80,135
|
408,27
|
Sem
Cache, Optimizer+
|
71,019
|
460,70
|
Tabela 1: Tempos de resposta do Joomla usando aceleradores
PHP
Os
resultados mostram que o Zend Optimizer+ é o mais rápido. Usando Zend Server 5
CE, o Joomla roda 60% mais rápido que
PHP.net (sem acelerador) e 13% mais rápido que o APC. Reportamos os resultados
das taxas de transferência na Figura 1 (maior valor significa melhor
performance).

Figura 1: Taxa de Transferência (Kbyte/sec)
Experimento
de cache de dados
No
segundo passo do experimento, executamos o benchmark usando os plugins
caching do Joomla nos seguintes
sistemas de caching: File, APC, Memcached, Zend Server CE (arquivo),
Zend
Server CE (Shared Memory). Dividimos o experimento em duas partes: O
primeiro usando o acelerador de bytecode APC, e o segundo usando o
acelerador de códigos Zend Optimizer+. Abaixo,
reportamos os resultados desse experimento (Tabelas 2 e 3).
|
tempo por pedido, meio através de todos os pedidos
atuais (ms)
|
taxa de transferência (Kbyte/sec)
|
Cache:
File
|
53,383
|
612,91
|
Cache:
APC
|
49,275
|
664,23
|
Cache:
Memcached
|
50,507
|
647,73
|
Cache:
ZendServer file
|
51,541
|
634,51
|
Cache:
ZendServer shm
|
46,527
|
703,50
|
Tabela 2: Resultados com APC habilitado, e Zend Optimizer+ desabilitado
Como você
pode ver, o melhor resultado, em termos de performance, vem com o uso do Zend
Server CE (com sistema de cache de memória compartilhada, shm). O Zend Server
CE é 14% mais rápido que o File, 9% mais rápido que o Memcached, e 6% mais
rápido que o APC.
|
tempo por pedido, meio através de todos os pedidos
atuais (ms)
|
taxa de transferência (Kbyte/sec)
|
Cache:
File
|
40,716
|
803,54
|
Cache:
APC
|
38,898
|
841,13
|
Cache:
Memcached
|
39,058
|
837,90
|
Cache:
ZendServer file
|
39,102
|
836,95
|
Cache:
ZendServer shm
|
36,531
|
895,79
|
Tabela 3: Resultados com APC desabilitado, Zend Optimizer+ habilitado
Os mesmos
resultados vêm com o Zend Optimizer+ habilitado e com o APC
desabilitado. O sistema
de caching mais rápido é o Zend Server CE com Shared Memory. Zend Server
CE é 11% mais rápido que o File, 7% mais rápido que o Memcached, e 6%
mais rápido
que o APC
Se
compararmos os resultados de cache de dados usando APC ou Zend Optimizer+,
descobrimos que os melhores resultados vêm com o Zend Optimizer, o sistema de
caching de dados do Joomla roda 35% mais rápido comparado com o APC
(figura 2; maior valor significa melhor performance).

Figura 2: Taxa de transferência (Kbyte/sec)
Resumindo,
usando o Zend Optimizer+ e o Data Cache of Zend Server CE, você pode acelerar o
processo da execução do Joomla de 60% para 300% comparado com PHP.net (sem acelerador),
e de 13% para 35% comparado com o APC.
O plugin caching do Joomla para Zend Server CE
Para
possibilitar o uso do caching de dados do Zend Server CE com o Joomla, você tem
que instalar o plugin joomla_zendserver.zip. Você pode fazer o download aqui.
A
instalação desse novo plugin é muito fácil, você só tem que abrir o arquivo zendserver.tar.gz
e copiar os arquivos zendserver_disk.php e zendserver_shm.php na
pasta libraries/joomla/cache/storage/ do Joomla.
Depois
disso, você pode escolher o cache handler Zendserver_disk e Zendserver_shm a
partir da aba do Sistema no menu de Configuração Global na interface
administrativa do Joomla. É isso aí!
Conclusão
Neste
artigo, mostramos que o Zend Server CE é o PHP stack mais rápido para
executar
aplicativos Joomla. Os benefícios, e termos de performance, são ótimos: é
35% mais rápido que o APC e até 300% do que o PHP.net (sem
aceleradores).
Se você
estiver interessado em outros benchmarks do Zend Server CE, você pode ler o
White Paper “Optimizing Drupal Performance” (pdf, inglês), de Acquia e Zend
Technologies.
No
futuro, eu gostaria de executar mais benchmarks no Zend Server CE usando
outros softwares open source do PHP.Se você tiver alguma proposta, por
favor a
adicione nos comentários.
⁂
Texto original disponível em
http://www.zimuel.it/blog/2010/06/benchmarking-zend-server-ce-with-joomla/
artigo publicado originalmente no iMasters, por Enrico Zimuel
|
Eu e o criador do moo4q Ryan
Florence geralmente concordamos na maioria dos tópicos
relacionados com o JavaScript, dentre os quais o de que a maioria dos
frameworks em JavaScript, inclusive jQuery, MooTools e Dojo, tem muito mais
recursos do que a maioria dos websites precisa. Você não construiria um website
de um grande empreendimento ou de uma corporação sem um framework extenso em JavaScript,
mas muitos websites menores simplesmente não precisam de tantos recursos.
Entre no novo framework em JavaScript do
Florence, o SnackJS – um framework em
JavaScript que proporciona somente a funcionalidade que a maioria dos pequenos
websites precisa – e com somente 3KB!
Download SnackJS
O que significa “somente a
funcionalidade que a maioria dos pequenos websites precisa”? Para mim, isso quer dizer que tenham a
possibilidade de:
- trabalhar
mais facilmente com arrays
- recuperar
e modificar eficientemente classes e atributos etc de elementos CSS
- adicionar,
remover e dispensar event handlers facilmente
- executar
e manejar resultados de solicitações básicas de AJAX/JSON/JSONP
O SnackJS proporciona tudo
isso, com alguns extras:
- um
pequeno sistema pub/sub para comunicação app mais fácil
- um método estendido para mesclar superficialmente propriedades de objetos
- um
favorito de todos: um evento “ready”
- um
selector engine wraper para fácil
implementação de qualquer engine
selector (Slick, Sizzle etc.)
- um
método punch agindo como dojo.connect, no qual uma função pode ser atribuída
para executar sempre que outra função for executada
- uma
solução element store
Vamos dar uma olhada em
algumas partes do código SnackJS para que você possa “sentir” o seu uso.
snack.extend
Este método
simplesmente funde propriedades de qualquer número de objetos no primeiro
argumento:
var endObject = { color: "red" }; snack.extend( endObject, { color: "green", text: "Name" }, { color: "blue" } );
snack.punch
A habilidade de se "conectar"
a funções é extremamente útil no Dojo Toolkit, de forma que você não poderia
ser mais feliz do que ao vê-lo no SnackJS:
var myObjectWithFns = { color: "red", onColorChange: function(color) { this.color = color; } };
var reactor = function(color) { console.log("The color was just changed to: ",color); }; snack.punch(myObjectWithFns,"onColorChange",reactor,true); myObjectWithFns.onColorChange("red");
Sempre que myObjectWithFn.onColorChange é executado, a função reactor roda
imediatamente
snack.wrap
O
snack.wrap
funciona de forma muito similar ao método dojo.query, ou no emprego do
jQuery("selector") , no qual ele encapsula nós, de forma que
funcionalidade extra pode ser adicionada a ele. Os nós não são modificados,
uma vez que estão no MooTools.
var divs = snack.wrap("div");
divs.addClass("found");
divs.attach("click",function() { snack.wrap(this).removeClass("found"); });
snack.listener
O método snack.listener é sua maneira padrão de disparar eventos dos nós de forma a funcionar em qualquer navegador.
var listener = snack.listener({ node: document.getElementById("content"), event: "click" },function() { console.warn("You clicked on the node!"); });
listener.detach();
listener.attach();
Especialmente interessantes
são os métodos detach e attach, permitindo que você efetivamente habilite e
desabilite event listeners.
snack.request
Execute uma
solicitação AJAX padrão, com as opções-padrão:
var req = snack.request({ url: "get-user-bio.php", data: { userId: 1234 }, method: "get", now: false },function(error,response){ if(!error) { document.getElementById("content").innerHTML = response; } });
req.send();
snack.publisher:
Implementação PubSub
O SnackJS implementa o sempre
útil sistema pub/sub, com a criação do publisher e, então, publica e subscreve:
var pubsub = snack.publisher();
pubsub.subscribe("inputchange",function(val) { console.warn("The value was changed to: ",val); });
snack.wrap("#email").attach("keyup",function() { pubsub.publish("inputchange",[this.value]); });
A força do pub/sub é que você
não precisa fazer referências a a eventos ou a qualquer outra coisa – você só precisa
do nome do wire. Sempre que uma mensagem é publicada naquele wire, você saberá!
Essas são apenas algumas das
funcionalidades disponíveis no SnackJS. Há muitos outros métodos
disponíveis. Assim sendo, eu o encorajo a examinar a documentação do SnackJS.
Aposto que o SnackJS tem todas funcionalidades que você precisa para a maioria
dos websites!
Seguindo em
frente
O SnackJS foi recentemente
liberado, de forma que não há muitos módulos/plugins customizados disponíveis.
Há alguns itens que eu gostaria de ver adicionados ao SnackJS:
- definidor de estilos – Eu sei que a propriedade style de cada nó
é onde você define os estilos individuais, mas a opacidade dá mais
trabalho, uma vez que não é padrão, e um definidor que gerenciasse isso
automaticamente seria incrível
- objetos deferreds – Eles são enviados de Deus no Dojo, e poderiam revelar-se no SnackJS também
Download SnackJS
O SnackJS pode ser encontrado
no GitHub, e a documentação e os demos podem ser encontrados no snackjs.com. Parabéns ao Ryan Florence pelo seu
micro framework irado! Espero contribuir no futuro!
Logo estarei mostrando a
vocês como criar seu próprio SnackJS plugin para criar nós, colocá-los na
página obtendo e definindo seus
atributos! Mantenha-se ligado!
⁂
Texto original disponível em http://davidwalsh.name/snackjs
artigo publicado originalmente no iMasters, por David Walsh
|