commit a332ceeb7326452651c7a0f8b32567700a617163 Author: Ken Elf Mathieu Sternberg Date: Wed Feb 6 10:08:33 2013 -0800 Initial check-in. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..515ce9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/node_modules/ +tmp +#* +*~ diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 0000000..ce5e4ac --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,64 @@ +module.exports = (grunt) -> + + grunt.initConfig + pkg: grunt.file.readJSON('package.json') + + jshint: + files: [ "src/**/*.js", "test/**/*.js" ] + options: + curly: true + eqeqeq: true + immed: true + latedef: true + newcap: true + noarg: true + sub: true + undef: true + boss: true + eqnull: true + node: true + es5: true + + globals: {} + + clean: + files: ["tmp/"] + + coffee: + rubyHaml: + files: + "tasks/ruby-haml.js": "src/ruby-haml.coffee" + options: + bare: false + + rubyHaml: + test_html: + files: [ + {"tmp/01_straight.html": "test/fixtures/01_straight.haml"} + {"tmp/02_scored.html": "test/fixtures/02_scored.haml"} + ] + test_js: + files: [ + {"tmp/01_straight.js": "test/fixtures/01_straight.haml"} + {"tmp/02_scored.js": "test/fixtures/02_scored.haml"} + ] + options: + templatize: true + + nodeunit: + files: [ "test/*.js" ] + + watch: + files: "" + tasks: "default" + + + grunt.loadTasks "tasks" + + grunt.loadNpmTasks('grunt-coffee') + grunt.loadNpmTasks('grunt-contrib-watch') + grunt.loadNpmTasks('grunt-contrib-jshint') + grunt.loadNpmTasks('grunt-contrib-nodeunit') + grunt.loadNpmTasks('grunt-contrib-clean') + + grunt.registerTask "default", ["coffee:rubyHaml", "jshint", "rubyHaml:test_html", "rubyHaml:test_js", "nodeunit", "clean"] diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..f182efb --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,22 @@ +Copyright (c) 2012 Elf M. Sternberg + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1fec0af --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# grunt-ruby-haml + +Compile your HTML templates using Ruby + +## WHAT!? WHY!?!?!? + +Because I like underscore, and underscore templates. They come free +with Backbone. And Ruby's HAML treats them without abusing them. +It's not a great solution, but it's better than trying to write yet +another HAML parser. + +And before you get me started on Jade, or Mustache, or whatever: +forget it. Jade is a big learning curve for little reward, and the +rest are templating languages in their own right. + +## Getting Started + +Make sure you have Ruby and Haml available in you $PATH. + +Install this grunt plugin next to your project's [grunt.js +gruntfile][getting_started] with: `npm install grunt-ruby-haml` + +Then add this line to your project's `grunt.js` gruntfile: + +```javascript +grunt.loadNpmTasks('grunt-ruby-haml'); +``` + +## Documentation + +You'll need to install `grunt-ruby-haml`: + + npm install grunt-ruby-haml + +Then modify your `Gruntfile.js` file by adding the following line: + + grunt.loadNpmTasks('grunt-ruby-haml'); + +Then add some configuration for the plugin like so: + + grunt.initConfig({ + ... + ruby-haml: { + app: { + files: { + "public/index.html": "src/index.haml" + } + options: { + templatize: False + } + } + }, + ... + }); + +Then just run `grunt ruby-haml` and enjoy! + +Ruby-HAML will, by default, generate HTML. With the 'templatize' +option set to True, it will instead spit out an underscore template +ready to be rendered, wrapped in an AMD-compliant define() call. This +may be useful to some of you who want to use the output of the HAML +engine as a pre-parsed underscore template. + + +## Contributing +In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt][grunt]. + +## Release History +0.0.1 - Just what I've always run. Don't expect miracles + +## License +Copyright (c) 2013 Elf M. Sternberg +Licensed under the MIT license. diff --git a/package.json b/package.json new file mode 100644 index 0000000..f173d80 --- /dev/null +++ b/package.json @@ -0,0 +1,54 @@ +{ + "name": "grunt-ruby-haml", + "description": "HAML via the Ruby compiler for Grunt", + "version": "0.0.3", + "homepage": "https://github.com/elfsternberg/grunt-ruby-haml", + "author": { + "name": "Elf M. Sternberg", + "email": "elf.sternberg@gmail.com" + }, + "contributors": [ + { + "name": "Elf M. Sternberg", + "url": "https://github.com/elfsternberg" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/elfsternberg/grunt-ruby-haml.git" + }, + "bugs": { + "url": "https://github.com/elfsternberg/grunt-ruby-haml/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/elfsternberg/grunt-ruby-haml/blob/master/LICENSE-MIT" + } + ], + "main": "grunt.js", + "engines": { + "node": "*" + }, + "scripts": { + "test": "grunt test" + }, + "dependencies": { + "grunt": "=0.4.0a", + "coffee-script": "~1.3.1" + }, + "devDependencies": { + "grunt": "~0.4.x", + "coffee-script": "~1.3.1", + "grunt-contrib-watch": "~0.1.4", + "grunt-contrib-nodeunit": "~0.1.1", + "grunt-contrib-jshint": "~0.1.0", + "grunt-contrib-clean": ">=0.4.0rc6", + "async": "~0.2.2", + "underscore": "~1.4.4", + "grunt-coffee": "git://github.com/elfsternberg/grunt-coffee.git" + }, + "keywords": [ + "gruntplugin" + ] +} diff --git a/src/ruby-haml.coffee b/src/ruby-haml.coffee new file mode 100644 index 0000000..1a40b65 --- /dev/null +++ b/src/ruby-haml.coffee @@ -0,0 +1,40 @@ +# +# grunt-ruby-haml +# +# Copyright (c) 2013 Elf M. Sternberg +# Licensed under the MIT license. +# + +_ = require 'underscore' + +module.exports = (grunt) -> + + hamlize = (src, destPath, options, done) -> + args = + cmd: "haml" + args: [ "--unix-newlines", "--no-escape-attrs", "--double-quote-attributes", src ] + + grunt.util.spawn args, (err, result) -> + [ext, result] = if options.templatize + [".js", "define(function() { return " + _.template(result.stdout).source + "});"] + else + ["html", result.stdout] + + dest = destPath + destPath = (if dest then dest else path.dirname(src)) + if destPath.indexOf(ext, destPath.length - ext.length) == -1 + dest = path.join(destPath, path.basename(src, ".haml") + ext) + + grunt.file.write dest, result + done(null) + + grunt.registerMultiTask "rubyHaml", "Compile HAML with Ruby", -> + options = @options({templatize: false}) + done = @async() + sources = _.flatten(([i, file.dest] for i in file.src for file in @files when file.src.length > 0), true) + return done() if sources.length is 0 + grunt.util.async.forEachSeries sources, ((path, cb) -> + hamlize path[0], path[1], options, cb + ), done + + diff --git a/tasks/ruby-haml.js b/tasks/ruby-haml.js new file mode 100644 index 0000000..a744655 --- /dev/null +++ b/tasks/ruby-haml.js @@ -0,0 +1,62 @@ +(function() { + var _; + + _ = require('underscore'); + + module.exports = function(grunt) { + var hamlize; + hamlize = function(src, destPath, options, done) { + var args; + args = { + cmd: "haml", + args: ["--unix-newlines", "--no-escape-attrs", "--double-quote-attributes", src] + }; + return grunt.util.spawn(args, function(err, result) { + var dest, ext, _ref; + _ref = options.templatize ? [".js", "define(function() { return " + _.template(result.stdout).source + "});"] : ["html", result.stdout], ext = _ref[0], result = _ref[1]; + dest = destPath; + destPath = (dest ? dest : path.dirname(src)); + if (destPath.indexOf(ext, destPath.length - ext.length) === -1) { + dest = path.join(destPath, path.basename(src, ".haml") + ext); + } + grunt.file.write(dest, result); + return done(null); + }); + }; + return grunt.registerMultiTask("rubyHaml", "Compile HAML with Ruby", function() { + var done, file, i, options, sources; + options = this.options({ + templatize: false + }); + done = this.async(); + sources = _.flatten((function() { + var _i, _len, _ref, _results; + _ref = this.files; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + file = _ref[_i]; + if (file.src.length > 0) { + _results.push((function() { + var _j, _len1, _ref1, _results1; + _ref1 = file.src; + _results1 = []; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + i = _ref1[_j]; + _results1.push([i, file.dest]); + } + return _results1; + })()); + } + } + return _results; + }).call(this), true); + if (sources.length === 0) { + return done(); + } + return grunt.util.async.forEachSeries(sources, (function(path, cb) { + return hamlize(path[0], path[1], options, cb); + }), done); + }); + }; + +}).call(this); diff --git a/test/expected/01_straight.html b/test/expected/01_straight.html new file mode 100644 index 0000000..12acea9 --- /dev/null +++ b/test/expected/01_straight.html @@ -0,0 +1,10 @@ + + + + + TEST + + +

Just testing

+ + \ No newline at end of file diff --git a/test/expected/01_straight.js b/test/expected/01_straight.js new file mode 100644 index 0000000..43c18a4 --- /dev/null +++ b/test/expected/01_straight.js @@ -0,0 +1,7 @@ +define(function() { return function(obj){ +var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');}; +with(obj||{}){ +__p+='\n\n \n \n TEST\n \n \n

Just testing

\n \n'; +} +return __p; +}}); \ No newline at end of file diff --git a/test/expected/02_scored.html b/test/expected/02_scored.html new file mode 100644 index 0000000..1714d20 --- /dev/null +++ b/test/expected/02_scored.html @@ -0,0 +1,10 @@ + + + + + TEST + + +

<%= (2 + 2) %>

+ + \ No newline at end of file diff --git a/test/expected/02_scored.js b/test/expected/02_scored.js new file mode 100644 index 0000000..7a2f659 --- /dev/null +++ b/test/expected/02_scored.js @@ -0,0 +1,9 @@ +define(function() { return function(obj){ +var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');}; +with(obj||{}){ +__p+='\n\n \n \n TEST\n \n \n

'+ +((__t=( (2 + 2) ))==null?'':__t)+ +'

\n \n'; +} +return __p; +}}); \ No newline at end of file diff --git a/test/fixtures/01_straight.haml b/test/fixtures/01_straight.haml new file mode 100644 index 0000000..86e45da --- /dev/null +++ b/test/fixtures/01_straight.haml @@ -0,0 +1,7 @@ +!!! 5 +%html{:xmlns => "http://www.w3.org/1999/xhtml"} + %head + %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/ + %title TEST + %body + %h1 Just testing diff --git a/test/fixtures/02_scored.haml b/test/fixtures/02_scored.haml new file mode 100644 index 0000000..5926f61 --- /dev/null +++ b/test/fixtures/02_scored.haml @@ -0,0 +1,7 @@ +!!! 5 +%html{:xmlns => "http://www.w3.org/1999/xhtml"} + %head + %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/ + %title TEST + %body + %h1 <%= (2 + 2) %> diff --git a/test/ruby-haml_test.js b/test/ruby-haml_test.js new file mode 100644 index 0000000..f5d3ded --- /dev/null +++ b/test/ruby-haml_test.js @@ -0,0 +1,29 @@ +"use strict"; + +var grunt = require('grunt'), + fs = require('fs'), + path = require('path'), + files = [ + ["tmp/01_straight.html", "test/expected/01_straight.html"], + ["tmp/02_scored.html", "test/expected/02_scored.html"], + ["tmp/01_straight.js", "test/expected/01_straight.js"], + ["tmp/02_scored.js", "test/expected/02_scored.js"] + ] + + +fs.existsSync = fs.existsSync ? fs.existsSync : path.existsSync; + +exports.coffee = { + + setUp: function(done) { + done(); + }, + + 'task': function(test) { + test.expect(files.length); + files.forEach(function(file) { + test.equal(grunt.file.read(file[0]), grunt.file.read(file[1])); + }); + test.done(); + } +};