diff --git a/Gruntfile.js b/Gruntfile.js index 5e72101..4c46e29 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -193,6 +193,30 @@ module.exports = function(grunt) { dest: 'tmp/hello_partial_function.html'} ] }, + partials_glob_df: { // glob expansion partial search (like partials_dfprefixes) + options: { + directory: 'test/fixtures/partials/', + glob: 'sub-$1/pre_$2.mustache', + clear_cache: true + }, + files: [ + {data: 'test/fixtures/objects/hello_world.json', + template: 'test/fixtures/templates/hello_partial_dir.mustache', + dest: 'tmp/hello_partial_globdf.html'} + ] + }, + partials_glob: { + options: { + directory: 'test/fixtures/partials/', + glob: '{sub-$1,.}/$2.!(ms)', + clear_cache: true + }, + files: [ + {data: 'test/fixtures/objects/hello_world.json', + template: 'test/fixtures/templates/hello_partial_glob.mustache', + dest: 'tmp/hello_partial_glob.html'} + ] + }, batch_single_template_multiple_json_via_map: { options: { template: 'test/fixtures/templates/hello_world.html.mustache' diff --git a/README.md b/README.md index a38e516..2a65aad 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,25 @@ which prepended onto the partial reference, regardless of whether it included a directory or not. This option is still supported for backward compatibility and maintains the same behavior. +#### options.glob +Type: `String` +Default value: `""` + +A glob pattern to use to search for partials. If this option is set, `options.prefix_file`, `options.prefix_dir`, +`options.prefix` and `options.extension` will be ignored. The glob pattern will be expanded using +[`grunt.file.expand`](http://gruntjs.com/api/grunt.file#grunt.file.expand) and the first file found will be used. +If more than one file is found, a warning will be printed. + +You can use this variables in the pattern: + * `$0` The whole partial name + * `$1` The partial name's directory part + * `$2` The partial name's basename part + +Examples: + * `prefix_dir$1/prefix_file$2` does the same as using `options.prefix_file` and `options.prefix_dir` + * `$0.*` allows any extension + * `{images/$0.svg,partials/$0.mustache}` seaches for a partial either as `name.svg` in the `image` folder or as `name.mustache` in the `partials` folder. + #### options.clear_cache Type: `Boolean` Default value: `false` diff --git a/tasks/mustache_render.js b/tasks/mustache_render.js index 337f349..0dfd39a 100644 --- a/tasks/mustache_render.js +++ b/tasks/mustache_render.js @@ -22,6 +22,7 @@ module.exports = function gruntTask(grunt) { prefix : "", // discouraged; use prefix_dir and/or prefix_file prefix_dir : "", prefix_file : "", + glob: "", clear_cache : false, escape: true }; @@ -235,46 +236,78 @@ module.exports = function gruntTask(grunt) { var prefixDir = this.options.prefix_dir; var prefixFile = this.options.prefix_file; var prefixOld = this.options.prefix; - - if ((prefixDir || prefixFile) && prefixOld) { - throw new Error("old-style prefix option cannot be combined with the " + - "newer prefix_dir or prefix_file options"); - } + var glob = this.options.glob; + var baseDir = this.options.directory; + var partialFile; var dirname = path.dirname(name); var hasDir = dirname && dirname !== '.'; + var basename = path.basename(name); - if (prefixOld) { - if (hasDir) { - prefixDir = prefixOld; - grunt.log.error("Warning: partial reference " + name.yellow + " w/ " + - "prefix " + prefixOld.cyan + " will prepend prefix " + - "to the directory name, not the filename"); - } - else { prefixFile = prefixOld; } - } - - if (hasDir) { - if (prefixDir && ['.', '/'].indexOf(dirname[0]) !== -1) { - throw new Error("cannot use prefix when using a partial reference " + - "that points outside of the base directory"); - } - } else if (prefixDir) { - grunt.log.error("Warning: prefix_dir " + prefixDir.cyan + " has no " + - "effect for partial reference " + name.yellow); - } + if (glob) { + if (prefixDir || prefixFile || prefixOld) { + grunt.log.error("Warning: All prefix options are ignored when " + + "using the glob option!"); + } + glob = glob.replace(/\$0/g, name); + glob = glob.replace(/\$1/g, dirname); + glob = glob.replace(/\$2/g, basename); + + var partials = grunt.file.expand({cwd: baseDir}, glob); + if (partials.length === 0) { + grunt.log.error("Warning: partial reference " + name.yellow + + " yields the glob pattern " + glob.cyan + + ", which does not match anything in directory " + + baseDir.cyan); + } else { + if (partials.length > 1) { + grunt.log.error("Warning: glob pattern " + glob.cyan + + " for partial reference " + name.yellow + + " yields more than one file. Using the first." + + "Files found: \n" + partials.toString().yellow); + } + partialFile = path.join(baseDir, partials[0]); + } + } else { + if ((prefixDir || prefixFile) && prefixOld) { + throw new Error("old-style prefix option cannot be combined with " + + "the newer prefix_dir or prefix_file options"); + } - var basename = path.basename(name); - var filePath = path.join(this.options.directory, - hasDir ? prefixDir + dirname : '.', - prefixFile + basename + this.options.extension); + if (prefixOld) { + if (hasDir) { + prefixDir = prefixOld; + grunt.log.error("Warning: partial reference " + name.yellow + + " w/ prefix " + prefixOld.cyan + " will prepend " + + "prefix to the directory name, not the filename"); + } + else { prefixFile = prefixOld; } + } - if (grunt.file.exists(filePath)) { - return grunt.file.read(filePath); + if (hasDir) { + if (prefixDir && ['.', '/'].indexOf(dirname[0]) !== -1) { + throw new Error("cannot use prefix when using a partial " + + "reference that points outside of the base "+ + "directory"); + } + } else if (prefixDir) { + grunt.log.error("Warning: prefix_dir " + prefixDir.cyan + " has no " + + "effect for partial reference " + name.yellow); + } + var fileName = path.join(baseDir, hasDir ? prefixDir + dirname : '.', + prefixFile + basename + this.options.extension); + if (!grunt.file.exists(fileName)) { + grunt.log.error("Warning: partial reference " + name.yellow + + " yields " + fileName.cyan + + ", which does not exist"); + } else { + partialFile = fileName; + } } - grunt.log.error("Warning: partial reference " + name.yellow + " yields " + - filePath.cyan + ", which does not exist"); + if (partialFile) { + return grunt.file.read(partialFile); + } return ""; }; diff --git a/test/expected/hello_glob.html b/test/expected/hello_glob.html new file mode 100644 index 0000000..b29d1ed --- /dev/null +++ b/test/expected/hello_glob.html @@ -0,0 +1,12 @@ + + + + A partial + + +

Hello mustache with glob patterns!

+Hello glob pattern! + You can use any file extension :) + + + diff --git a/test/fixtures/partials/sub-b/another.fancy b/test/fixtures/partials/sub-b/another.fancy new file mode 100644 index 0000000..0caf915 --- /dev/null +++ b/test/fixtures/partials/sub-b/another.fancy @@ -0,0 +1 @@ +use any file extension :) diff --git a/test/fixtures/partials/sub-b/hello.ext b/test/fixtures/partials/sub-b/hello.ext new file mode 100644 index 0000000..994a700 --- /dev/null +++ b/test/fixtures/partials/sub-b/hello.ext @@ -0,0 +1 @@ +Hello glob pattern! diff --git a/test/fixtures/templates/hello_partial_glob.mustache b/test/fixtures/templates/hello_partial_glob.mustache new file mode 100644 index 0000000..d05927d --- /dev/null +++ b/test/fixtures/templates/hello_partial_glob.mustache @@ -0,0 +1,7 @@ +{{> head}} + +

Hello mustache with glob patterns!

+ {{> b/hello}} + You can {{> b/another}} + + diff --git a/test/mustache_render_test.js b/test/mustache_render_test.js index 9892806..507d972 100644 --- a/test/mustache_render_test.js +++ b/test/mustache_render_test.js @@ -203,6 +203,28 @@ exports.mustache_render = { test.done(); }, + partials_glob_df: function(test) { // glob expansion partial search (like dfprefixes) + test.expect(1); + + var actual = grunt.file.read('tmp/hello_partial_globdf.html'); + var expected = grunt.file.read('test/expected/hello_dfprefixes.html'); + test.equal(actual, expected, 'should find partials w/ glob ' + + '"sub-$1/pre_$2.mustache".'); + + test.done(); + }, + + partials_glob: function(test) { // glob expansion partial search + test.expect(1); + + var actual = grunt.file.read('tmp/hello_partial_glob.html'); + var expected = grunt.file.read('test/expected/hello_glob.html'); + test.equal(actual, expected, 'should find partials w/ glob ' + + '"?(+sub-$1)/$2.*".'); + + test.done(); + }, + batch_single_template_multiple_json_via_map: function(test) { test.expect(3);