MouseOver Studio

MouseOver Studio header image 2

1, 2, 3… Aprendendo a caminhar com SproutCore

July 18th, 2008 por Diego Carrion · 3 comentários

Varias pessoas já falaram sobre Sproutcore aqui no Brasil:

pelo que agora é a vez de brincar um pouco.

O primeiro passo para trabalhar com o SproutCore é baixar ele e conseguimos aquilo executando o seguinte comando no terminal (RubyGems deve estar corretamente instalado):

sudo gem install sproutcore

Ao executar o comando anteriormente mencionado o terminal ira mostrar o que esta sendo realizado. No meu caso, entra outras mensagens apareceram as seguintes:

Successfully installed merb-core-0.9.3
Successfully installed erubis-2.6.2

Ao ver aquilo me perguntei: Merb? O que tem a ver?

Pesquisei um pouco e parece que o Sproutcore é baseado no Merb, o que me diz que deve ser bem dinâmico e compatível com plugins. Podem ler uma breve descrição sobre o Merb aqui.

Sobre o Erubis, ele é uma implementação do eRuby, um sistema de templates para Ruby similar ao Freemarker do Java. A teoria é que o SproutCore utiliza o Erubis nas views, o que é bom porque é um tecnologia já conhecida, o que facilita as coisas.

Agora que temos o SproutCore instalado vamos criar um projeto. O projeto que vou criar se chamara sproutcore-demo. A sintaxe para a criação é similar a do Rails, somente muda o nome do comando:

sproutcore sproutcore_demo

O output, entre outras coisas, me disse que posso inicializar o sc-server e entrar na minha aplicação no browser. O sc-server parece ser um servidor que vem embutido com o SproutCore, algo similar ao WEBRick que vem com o Rails. Inicializei o sc-server executando dentro da pasta sproutcore-demo recém criada o comando:

sc-server

Algo que me chamo a atenção no output do ultimo comando foi a seguinte linha:

~Using Mongrel adapter

Que legal, parece que o SproutCore mantem o foco em fazer coisas novas e não em reinventar a roda. Por tal motivo tudo indica que ele inclui o Mongrel como servidor padrão em vez de criar um novo.

Acessei http://localhost:4020/sproutcore_demo e apareceu uma tela idêntica a essa.

Agora, tal como o post-it sugere, vamos preencher um pouco nossa aplicação com um model, um controller e uma view.

Começaremos criando um controller com o seguinte comando:

sc-gen controller sproutcore_demo/app

A execução do comando ira ter criado dois arquivos: clients/sproutcore_demo/controllers/app.js e o respetivo teste clients/sproutcore_demo/tests/app.rhtml. No meu caso o valor do cliente foi igual ao do nome do projeto, quer dizer: sproutcore_demo .

Mas o que são esses clientes? Cada cliente é uma especie de aplicação, pelo que podemos ter varias aplicações para um único serviço SproutCore ao contrario de criar um serviço para cada aplicação que queiramos ter.

No nosso novo controller temos o seguinte codigo:

SproutcoreDemo.appController = SC.Object.create({}) ;

Sabemos que em JavaScript as chaves ({}) definem um objeto e o método create utiliza o que foi passado como parâmetro para criar um objeto que herda dele mesmo. Vamos mexer um pouco nesse objeto e criar um atributo e um método, deixando o código algo assim:

SproutcoreDemo.appController = SC.Object.create({
	cor: "Branco",
	trocarCor: function() {
		var novaCor = (this.cor == "Branco") ? "Preto" : "Branco";
		this.set("cor", novaCor);
	}
});

Criei um método que muda o valor do atributo para poder testar um tal binding do SproutCore que não sei bem como funciona mas agora vamos descobrir.

Continuaremos editando uma view, o arquivo clients/sproutcore_demo/english.lproj/body.rhtml. Mas espera ai, o que é esse english.lproj? Ah ta, o SproutCore suporta localização (somar um ponto) e na teoria um poderia colocar pastas para cada idioma. A localização no SproutCore é algo que tenho que testar proximamente, mas agora editarei o ultimo arquivo mencionado e substituirei o conteúdo da div.sc-welcome com:

<%= label_view :labelId,
  :tag => ‘h1′,
  :bind => { :value => ‘SproutcoreDemo.appController.cor’ } %>
<%= button_view :buttonId,
  :title => ‘Trocar cor’,
  :action => ‘SproutcoreDemo.appController.trocarCor’ %>

O código é um pouco auto-explicável mas o que é aquele bind e por que trocamos o valor do atributo cor chamando o método set e não com uma simples atribuição?

SC.Object é uma classe que herda de SC.Observable, a classe que declara o método set. O método set alem de trocar o valor do atributo passado como parâmetro se encarrega de outras coisas como responder aos observadores do mesmo. Com o atributo bind do helper button_view (que herda de view como todos os demais helpers) estamos indicado que o atributo indicado como chave esta observando ao atributo indicado como valor, que no nosso caso seriam value e SproutcoreDemo.appController.cor respetivamente.

Uma referencia sobre os diferentes view helpers do SproutCore pode ser encontrada aqui.

Se acessarmos http://localhost:4020/sproutcore_demo deve aparecer a palavra Branco e um botão com o texto Trocar Cor que ao ser acionado devera alternar a primeira palavra entre Branco e Preto.

Agora que conhecemos bem melhor como o SproutCore funciona vamos criar algo mas complexo. Primeiro criaremos um model onde guardaremos a cor ativa (Branco ou Preto). No controller criaremos uma função que troque a cor e um observer que contara quantas vezes a cor mudo. Na view teremos o botão que chama a função para trocar a cor e uma barra de progresso que ira aumentando cada vez que a cor mudar (o valor de ela ira ter um bind com o numero de vezes que a cor mudou).

Continuamos agora criando um model:

sc-gen model sproutcore-demo/carro

O comando anterior devera ter criado três arquivos: clients/sproutcore_demo/models/carro.js, clients/sproutcore_demo/fixtures/carro.js e para que não exista nenhum motivo para não criar testes, clients/sproutcore_demo/tests/models/carro.rhtml.

Antes de continuar, o que é esse fixture?

O fixture é um código que é executado quando a aplicação é carregada e tem como finalidade criar registros iniciais. Mas por que é executado esse código quando a aplicação carrega? O arquivo clients/sproutcore_demo/main.js é um script que é carregado por padrão quando o servidor é inicializado e se nos dirigirmos a ele vamos nos encontrar com a seguinte linha:

SproutcoreDemo.server.preload(SproutcoreDemo.FIXTURES);

A seguinte linha, tal e como parece, indica que os fixtures devem ser carregados. Se apagarmos o comentarmos essa linha, os fixtures vão deixar de ser executados (:

Como eu quero que minha aplicação conte sempre com os dois últimos carros que comprei :P, vou adicionar o seguinte código no fixture carro.js:

require('core') ;
SproutcoreDemo.FIXTURES = SproutcoreDemo.FIXTURES.concat([
	{
		guid: 1,
		type: 'Carro',
		cor: 'Branco',
		fabricante: 'Porsche'
	},
	{
		guid: 2,
		type: 'Carro',
		cor: 'Amarelo',
		fabricante: 'Ferrari'
	}
]);

guid e type são atributos necessários e o guid deve ser único.

Já devem estar se perguntando por que indiquei como type Carro e não SproutcoreDemo.Carro. Resulta que nossa aplicação conta com um script clients/sproutcore_demo/core.js que define um namespace padrão para ser utilizado nos registros:

server: SC.Server.create({ prefix: ['SproutcoreDemo'] }),

Podem ter notado se escolheram um nome de projeto com - que em alguns casos o nome do namespace gerado foi SproutcoreDemo e em outros Sproutcore-demo, que é um nome invalido para um objeto em JavaScript. Isso parece ser um erro no SproutCore e de ser assim é uma boa ocasião para por teu nome na lista de commiters do projeto.

Voltando no código, o controller criado anteriormente ficara agora assim:

SproutcoreDemo.appController = SC.Object.create({
	cor: null,
	numeroDeMudancasDeCor: 0,
	observadorDeCor: function() {
		this.set("numeroDeMudancasDeCor", ++this.numeroDeMudancasDeCor);
	}.observes('cor'),
	trocarCor: function() {
		var novaCor;
		if (!this.cor) {
			novaCor = SproutcoreDemo.Carro.find(1).get("cor");
		} else {
			novaCor = (this.cor == "Branco") ? "Preto" : "Branco";
		}
		this.set("cor", novaCor);
	}
});

Eu sei que a estrutura do código no é das melhores mas é somente um exemplo para testar o framework.

A função trocarCor, como já sabemos e como o mesmo nome diz, terá como objetivo trocar o valor de cor. A diferença é que agora a cor sera pega pela primeira vez do carro com guid igual a 1.

Pegamos a cor do carro chamando o método get e não diretamente para que assim o framework possa trabalhar com os observadores e os binds e também porque Carro.cor não existe :D, o SproutCore cria uma estrutura interna que ainda não analisei.

Na função observadorDeCor temos algo novo. Ela chama o método observes e passa como parâmetro cor, indicando que queremos que seja chamada cada vez que o atributo passado como parâmetro mudar.

Antes de explicar o fluxo completo do procedimento, vamos modificar nossa view, o arquivo clients/sproutcore_demo/english.lproj/body.rhtml:

<% content_for('body') do %>
<%= label_view :labelId, :tag => ‘h1′, :bind => { :value => ‘SproutcoreDemo.appController.cor’ } %> <%= button_view :buttonId, :title => ‘Trocar cor’, :action => ‘SproutcoreDemo.appController.trocarCor’ %> <%= progress_view :progressId, :minimum => 0, :maximum => 100, :bind => { :value => ‘SproutcoreDemo.appController.numeroDeMudancasDeCor’} %>
<% end %>

Os dois primeiros helpers já conhecemos, mas o terceiro é novo; mesmo assim não é dificil descubrir o que ele faz. O helper progress_view cria uma barra de progresso, que no nosso caso vai de zero a cem. O valor da barra de progresso terá um bind com o numero de mudanças da cor, pelo que cada vez que troquemos o valor de cor a barrinha devera ir se prenchendo.

Se tentarem acessar agora a view não vão a ver a barrinha porque ela precisa ter certos estilos, eu utilizei os seguintes (eles podem ser escritos no arquivo body.css):

.progress {
  width: 100px;
  height: 10px;
  border: thin solid #AAAAAA;
}

.progress .inner {
  width: 0px;
  height: 10px;
  background-color: #AAAAAA;
}

Agora sim o funcionamento da nossa aplicação:

Ao entrar na tela, não ira aparecer nenhum valor para cor porque não foi setado algum no controller. Ao acionar o botão Trocar Cor pela primeira vez, o controller ira procurar o carro com guid 1 e pegar o cor dele; futuramente ira alternar entre Branco e Preto. Agora o mais legal, cada vez que o valor de cor mudar, a função observadorDeCor sera chamada e ela ira aumentar em uma unidade o valor de numeroDeMudancasDeCor, o que ocasionara que a barra de progresso aumente.

O que chama muito a atenção e que os atributos não sabem quem os estão observando, somente o framework. Nosso controller não se preocupa com sair distribuindo dados, nem se importa com saber para onde aqueles dados vão, deixamos isso para o framework. Os negócios são assim agora, é somente ver os RSS, notificações por email, etc…

Isso foi tudo e desculpem se no final os erros de ortografia aumentar, o corretor ortográfico do Firefox parece que deixa de funcionar direito quando o texto começa a ficar longo :P

Ate a próxima!

Tags: JavaScript · Tutoriales · framework · ruby · sproutcore

3 respostas ate agora ↓

Deixar um comentário