quinta-feira, 18 de setembro de 2014

Grails + sass + jade + handlebars + coffe

Fala galera,

A pouco tempo comecei a usar outras tecnologias otimizadoras no processo de desenvolvimento junto do Grails. São elas:

- sass
- jade
- handlebars
- coffee

Para tal necessidade eu fui atrás de alguns plugins do grails, mas não fiquei satisfeito com alguns deles. Primeiro por que alguns encontram-se desatualizados e com pouca documentação, e ainda tem alguns bugs. Ora, se pararmos para pensar, essas ferramentas são complementares ao desenvolvimento, apenas voltadas para a produtividade, então não se deve perder muito tempo com complexidades na configuração do ambiente. Para resolver o problema eu acabei usando uma estrutura separada do grails para o controle, uma que eu postei aqui no blog a poucos dias.. usando o gulp para realizar a tarefa.

Então foi simples.. Eu criei a seguinte estrutura no projeto grails (dentro de assets):


Para esse projeto uso a versão do grails 2.3.4, e essa versão ainda não trabalha com o plugin assets por padrão.

Crieu meu gulpfile com o seguinte script:



gulp = require 'gulp'
sass = require 'gulp-sass'
jade = require 'gulp-jade'
coffee = require 'gulp-coffee'
handlebars = require 'gulp-handlebars'
concat = require 'gulp-concat'
declare = require 'gulp-declare'
wrap = require 'gulp-wrap'

errorHandler = (err) ->
 console.log err

sources = {}
destinations = {}

sources.sass = 'grails-app/assets/stylesheets/**/*.scss'
sources.coffee = 'grails-app/assets/coffeescripts/**/*.coffee'
sources.jade = 'grails-app/assets/jade/**/*.jade'
sources.handlebars = 'grails-app/assets/templates/**/*.html'
 
destinations.css = 'web-app/css'
destinations.js = 'web-app/js'
destinations.templates = 'grails-app/assets/templates'
destinations.handlebars = 'web-app/js/bi/templates'


watcher = (task) ->
  (evt) ->
   console.log 'run ' + evt.path
   gulp.start task
   
gulp.task 'compile:sass', ->
 gulp.src(sources.sass)
 .pipe(sass({sourceComments: 'normal'}).on('error', errorHandler))
 .pipe(gulp.dest(destinations.css))

gulp.task 'compile:coffee', ->
 gulp.src(sources.coffee)
 .pipe(coffee({bare: true, sourcemap: true}).on('error', errorHandler))
 .pipe(gulp.dest(destinations.js))

gulp.task 'compile:jade', ->
 gulp.src(sources.jade)
 .pipe(jade().on('error', errorHandler))
 .pipe(gulp.dest(destinations.templates))

gulp.task 'compile:handlebars', ->
 gulp.src(sources.handlebars)
 .pipe(handlebars())
 .pipe(wrap('Handlebars.template(<%= contents %>)'))
 .pipe(declare({
  namespace: 'View.templates',
  noRedeclare: true
 }))
 .pipe(concat('templates.js'))
 .pipe(gulp.dest(destinations.handlebars))


gulp.task 'default', ->
 gulp.start 'compile:sass', 'compile:coffee', 'compile:jade', 'compile:handlebars'


gulp.task 'watch:sass', ->
 gulp.watch sources.sass, watcher 'compile:sass'

gulp.task 'watch:coffee', ->
 gulp.watch sources.coffee, watcher 'compile:coffee'


gulp.task 'watch:jade', ->
 gulp.watch sources.jade, watcher 'compile:jade'

gulp.task 'watch:handlebars', ->
 gulp.watch sources.handlebars, watcher 'compile:handlebars'

gulp.task 'watch', ->
 gulp.start 'watch:sass', 'watch:coffee', 'watch:jade', 'watch:handlebars'
  
 

E logo depois (ou antes) de subir meu projeto grails é só executar:

gulp watch

E então ficar atentos com o console do gulp quanto a erros de complilação. E não se esqueça de instalar as dependências usadas no gulp via npm.

Espero que ajude! Abraço

segunda-feira, 1 de setembro de 2014

Classes com CoffeScript

Salve galera,


Vou dar uma help de como criar uma classe javascript com costrutor, atributos e metodos usando coffeescript.

Para o exemplo, vamos criar uma classe Spinner. Vamos crar uma imagem de carregamento nesse site: 





No site selecione a opção PNG sprite, crie seu spinner e faça o download da imagem. Na documentação tem os exemplos de css e também um link para o  javascript, que deve ser algo mais ou menos assim:



(function() {
    SpriteSpinner = function(el, options){
        var self = this,
            img = el.children[0];
        this.interval = options.interval || 10;
        this.diameter = options.diameter || img.width;
        this.count = 0;
        this.el = el;
        img.setAttribute("style", "position:absolute");
        el.style.width = this.diameter+"px";
        el.style.height = this.diameter+"px";        

        return this;
    };
    SpriteSpinner.prototype.start = function(){
        var self = this,
            count = 0,
            img = this.el.children[0];
        this.el.style.display = "";
        self.loop = setInterval(function(){
            if(count == 19){
                count = 0;
            }
            img.style.top = (-self.diameter*count)+"px";
            count++;
        }, this.interval);

        $(this.el).parent().css('display', 'block')
    };
    SpriteSpinner.prototype.stop = function(){
        clearInterval(this.loop);
        this.el.style.display = "none";
    };
    document.SpriteSpinner = SpriteSpinner;
})(); 


E com base nesse código vamos criar nossa elegante classe usando coffee:

    class SpriteSpinner

        constructor: (options) ->            
            @el = $(options.el)[0]
            img = @el.children[0]
            @interval = options.interval || 10
            @diameter = options.diameter || img.width
            @count = 0            
            img.setAttribute "style", "position:absolute"
            @el.style.width = @diameter + "px";
            @el.style.height = @diameter + "px";       


        start: ->                     
            count = 0
            self = @
            img = @el.children[0]   
            @el.style.display = ""
            @loop = setInterval (  ->           
                count = 0 if  count == 19
                img.style.top = (-self.diameter * count) + "px"
                count++   
                return
            ), @interval

            $(@.el).parent().css 'display', 'block'
        
        stop: -> 
            clearInterval @loop 
            @el.style.display = "none"   

Detalhes:

No constructor você pode definir os atributos da classe usando o  @, que serão automágicamente criados na complicação para js.

Para usar

    spinner = new SpriteSpinner {interval: 50, el: '#spinnerWrapper'}

    spinner.start()

    setInterval( ->
       spinner.stop()
    , 10000)




Até a próxima!

MVIRAL - SMS em massa

Fala galera,


Acabamos de lançar uma ferramenta para envio de SMS em massa chamada MVIRAL.

Com o MVIRAL você envia SMS em massa para usuários ou grupo de usuários, permitindo ainda a criação de agendamentos e criação de modelos de mensagens. 

Também criamos uma API de integração para softwares de terceiros. É fácil e simples de usar. Acesse e confira http://www.mviral.com.br/


Grails plugin - this expression must be true

Salve galera,


Outro dia me deparei com o erro abaixo no grails 2.3.4. Para resolver basta atualizar o plugin abaixo da seguinte forma:

compile ':plugin-config:0.2.0'


Caused by IllegalArgumentException: [Assertion failed] - this expression must be true
->>  340 | newInstance in org.grails.plugin.config.AbstractConfigHelper$ConfigObjectProxy
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|    111 | doCall    in org.grails.plugin.config.DefaultConfigHelper$_enhanceConfigObjectClass_closure3
|     44 | doCall .  in GrailsJadeGrailsPlugin$_closure1
|    756 | invokeBeanDefiningClosure in grails.spring.BeanBuilder
|    584 | beans . . in     ''
|    527 | invokeMethod in     ''
|    262 | run . . . in java.util.concurrent.FutureTask
|   1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
|    615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^    745 | run       in java.lang.Thread

quinta-feira, 28 de agosto de 2014

gulp + jade + handlebars + sass + coffee

Salve  galera,

Nesses últimos dias venho explorando tecnologias ligadas a nodejs, e com isso me deparei com um "novo" mundo repleto de novas possibilidades, novas ideias, novos paradigmas e novas ferramentes!

Com isso, estava eu seguindo um tutorial de integração entre jade, handlebars, coffee e backbone. Mas como o tutorial além de antigo destinava-se para desenvolvedores com mais conhecimento sobre essas ferramentas, não consegui prosseguir, e para conseguir o que pretendia precisei "garimpar" e montar minha ideia a partir de outros lugares obscuros da internet (mentira, googlei mesmo! ;) )

Para começo eu precisava de uma ferramente de buil que executasse os seguintes passos:

  1. Compilação do templete jade para html (para usar no handlebars)
  2. Compilação do template handlebars para js (para otimização)
  3. Compilação do sass para css
  4. Compilação do coffee para js
  5. Deploy do html na pasta de destino
Além do processo de build, eu ainda precisava de um "auto-build", por questões óbivias de produtividade, como em oferecido em ferramentes como grails, rails ou django. Foi então que lembrei que nas minhas leituras dos últimos dias achei um blog bem interessante chamado blog.lambda3.com.br, e em um de seus artigos li uma lista de ferramentas usadas com com nodejs, entre elas uma ferramente de build chamada gulp gulpjs.com e logo fui atrás desse cara para ver se poderia fazer minha configuração de buid. E eis que construi o seguinte script:




gulp = require 'gulp' 
sass = require 'gulp-sass'
jade = require 'gulp-jade'
coffee = require 'gulp-coffee'
handlebars = require 'gulp-handlebars'
concat = require 'gulp-concat'
declare = require 'gulp-declare'
wrap = require 'gulp-wrap'

errorHandler = (err) ->
 console.log err

sources = {}
destinations = {}

sources.sass = 'src/styles/**/*.scss'
sources.coffee = 'src/scripts/**/*.coffee'
sources.jade = 'src/jade/**/*.jade'
sources.html = 'src/html/**/*.html'
sources.handlebars = 'src/compiled-templates/**/*.html'
 
destinations.css = 'dist/css'
destinations.js = 'dist/js'
destinations.templates = 'src/compiled-templates'
destinations.base = 'dist/'
destinations.handlebars = 'dist/js'


watcher = (task) ->
  (evt) ->
   console.log 'run ' + evt.path
   gulp.start task
  
 
gulp.task 'compile:sass', ->
 gulp.src(sources.sass)
 .pipe(sass({sourceComments: 'normal'}).on('error', errorHandler))
 .pipe(gulp.dest(destinations.css))

gulp.task 'compile:coffee', ->
 gulp.src(sources.coffee)
 .pipe(coffee({bare: true, sourcemap: true}).on('error', errorHandler))
 .pipe(gulp.dest(destinations.js))

gulp.task 'compile:jade', ->
 gulp.src(sources.jade)
 .pipe(jade().on('error', errorHandler))
 .pipe(gulp.dest(destinations.templates))

gulp.task 'compile:handlebars', ->
 gulp.src(sources.handlebars)
 .pipe(handlebars())
 .pipe(wrap('Handlebars.template(<%= contents %>)'))
 .pipe(declare({
  namespace: 'View.templates',
  noRedeclare: true
 }))
 .pipe(concat('templates.js'))
 .pipe(gulp.dest(destinations.handlebars))

gulp.task 'copy:html', ->
 gulp.src(sources.html)
 .pipe(gulp.dest(destinations.base))

gulp.task 'default', ->
 gulp.start 'compile:sass', 'compile:coffee', 'compile:jade', 'compile:handlebars','copy:html' 


gulp.task 'watch:sass', ->
 gulp.watch sources.sass, watcher 'compile:sass'

gulp.task 'watch:coffee', ->
 gulp.watch sources.coffee, watcher 'compile:coffee'


gulp.task 'watch:jade', ->
 gulp.watch sources.jade, watcher 'compile:jade'

gulp.task 'watch:handlebars', ->
 gulp.watch sources.handlebars, watcher 'copy:handlebars'

gulp.task 'watch:html', ->
 gulp.watch sources.html, watcher 'copy:html'

gulp.task 'watch', ->
 gulp.start 'watch:sass', 'watch:coffee', 'watch:jade', 'watch:handlebars','watch:html' 


Coloque esse conteúdo em um arquivo .coffee e execute chamando gulp watch para o auto deploy ou apenas gulp para executar o build completo, que no caso está definido na task default. Lembrando que a instalação dos componetes declarados nos "require" devem ser feitos via npm. Ex.:

npm install gulp --save-dev

Certamente isso deve ajudar quem está começando, assim como eu.

Até a próxima!

quinta-feira, 24 de julho de 2014

Drop foreign key MySQL

Primeiro temos que saber o nome da chave. Para isso podemos usar:

use information_schema;

select TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME from KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME = 'table_name';

Ou usar:

show create table table_name;

Agora que sabemos o nome podemos remover

alter table table_name drop foreign key key_name;

terça-feira, 3 de junho de 2014

Dump Mysql import many files

Fala galera,

Aqui um comando simples mas muito útil que precisei para importar um dump do mysql com vários arquivos e vários bancos de dados. Para executar tem que estar dentro da pasta do dump

find . -name '*.sql' | awk '{ print "source",$0 }' | mysql -u root -p --batch