diff --git a/README.markdown b/README.markdown
index 1cba64689..ff1ce7534 100644
--- a/README.markdown
+++ b/README.markdown
@@ -24,7 +24,7 @@ In general, the syntax of Handlebars.js templates is a superset
of Mustache templates. For basic syntax, check out the [Mustache
manpage](http://mustache.github.com/mustache.5.html).
-Once you have a template, use the Handlebars.compile method to compile
+Once you have a template, use the `Handlebars.compile` method to compile
the template into a function. The generated function takes a context
argument, which will be used to render the template.
@@ -55,12 +55,12 @@ template. Here's an example, which assumes that your objects have a URL
embedded in them, as well as the text for a link:
```js
-Handlebars.registerHelper('link_to', function(context) {
- return "" + context.body + "";
+Handlebars.registerHelper('link_to', function() {
+ return "" + this.body + "";
});
var context = { posts: [{url: "/hello-world", body: "Hello World!"}] };
-var source = "
{{#posts}}- {{{link_to this}}}
{{/posts}}
"
+var source = "{{#posts}}- {{{link_to}}}
{{/posts}}
"
var template = Handlebars.compile(source);
template(context);
@@ -72,6 +72,14 @@ template(context);
//
```
+Helpers take precedence over fields defined on the context. To access a field
+that is masked by a helper, a path reference may be used. In the example above
+a field named `link_to` on the `context` object would be referenced using:
+
+```
+{{./link_to}}
+```
+
Escaping
--------
@@ -93,17 +101,17 @@ templates easier and also changes a tiny detail of how partials work.
Handlebars.js supports an extended expression syntax that we call paths.
Paths are made up of typical expressions and . characters. Expressions
allow you to not only display data from the current context, but to
-display data from contexts that are descendents and ancestors of the
+display data from contexts that are descendants and ancestors of the
current context.
-To display data from descendent contexts, use the `.` character. So, for
+To display data from descendant contexts, use the `.` character. So, for
example, if your data were structured like:
```js
var data = {"person": { "name": "Alan" }, company: {"name": "Rad, Inc." } };
```
-you could display the person's name from the top-level context with the
+You could display the person's name from the top-level context with the
following expression:
```
@@ -130,12 +138,12 @@ When calling a helper, you can pass paths or Strings as parameters. For
instance:
```js
-Handlebars.registerHelper('link_to', function(title, context) {
- return "" + title + "!"
+Handlebars.registerHelper('link_to', function(title, options) {
+ return "" + title + "!"
});
var context = { posts: [{url: "/hello-world", body: "Hello World!"}] };
-var source = '{{#posts}}- {{{link_to "Post" this}}}
{{/posts}}
'
+var source = '{{#posts}}- {{{link_to "Post"}}}
{{/posts}}
'
var template = Handlebars.compile(source);
template(context);
@@ -177,12 +185,18 @@ template(data);
//
```
-Whenever the block helper is called it is given two parameters, the
-argument that is passed to the helper, or the current context if no
-argument is passed and the compiled contents of the block. Inside of
-the block helper the value of `this` is the current context, wrapped to
-include a method named `__get__` that helps translate paths into values
-within the helpers.
+Whenever the block helper is called it is given one or more parameters,
+any arguments that are passed in the helper in the call and an `options`
+object containing the `fn` function which executes the block's child.
+The block's current context may be accessed through `this`.
+
+Block helpers have the same syntax as mustache sections but should not be
+confused with one another. Sections are akin to an implicit `each` or
+`with` statement depending on the input data and helpers are explicit
+pieces of code that are free to implement whatever behavior they like.
+The [mustache spec](http://mustache.github.io/mustache.5.html)
+defines the exact behavior of sections. In the case of name conflicts,
+helpers are given priority.
### Partials
@@ -335,15 +349,18 @@ Handlebars in the Wild
* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to
structure your views, also with automatic data binding support.
* Les Hill (@leshill) wrote a Rails Asset Pipeline gem named
- handlebars_assets](http://github.com/leshill/handlebars_assets).
+ [handlebars_assets](http://github.com/leshill/handlebars_assets).
* [Gist about Synchronous and asynchronous loading of external handlebars templates](https://gist.github.com/2287070)
+* [Lumbar](walmartlabs.github.io/lumbar) provides easy module-based template management for handlebars projects.
+* [YUI](http://yuilibrary.com/yui/docs/handlebars/) implements a port of handlebars
+
+Have a project using Handlebars? Send us a [pull request](https://github.com/wycats/handlebars.js/pull/new/master)!
Helping Out
-----------
To build Handlebars.js you'll need a few things installed.
* Node.js
-* Jison, for building the compiler - `npm install jison`
* Ruby
* therubyracer, for running tests - `gem install therubyracer`
* rspec, for running tests - `gem install rspec`
@@ -353,11 +370,16 @@ and therubyracer if you've got bundler installed.
To build Handlebars.js from scratch, you'll want to run `rake compile`
in the root of the project. That will build Handlebars and output the
-results to the dist/ folder. To run tests, run `rake spec`. You can also
-run our set of benchmarks with `rake bench`.
+results to the dist/ folder. To run tests, run `rake test`. You can also
+run our set of benchmarks with `rake bench`. Node tests can be run with
+`npm test` or `rake npm_test`. The default rake target will compile and
+run both test suites.
+
+Some environments, notably Windows, have issues running therubyracer. Under these
+envrionments the `rake compile` and `npm test` should be sufficient to test
+most handlebars functionality.
-If you notice any problems, please report
-them to the GitHub issue tracker at
+If you notice any problems, please report them to the GitHub issue tracker at
[http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues).
Feel free to contact commondream or wycats through GitHub with any other
questions or feature requests. To submit changes fork the project and
diff --git a/Rakefile b/Rakefile
index 6fe5d849e..ac935ddb2 100644
--- a/Rakefile
+++ b/Rakefile
@@ -90,8 +90,24 @@ task :runtime => [:compile] do |task|
Rake::Task["dist/handlebars.runtime.js"].execute
end
+# Updates the various version numbers.
+task :version => [] do |task|
+ # TODO : Pull from package.json when the version numbers are synced
+ version = File.read("lib/handlebars/base.js").match(/Handlebars.VERSION = "(.*)";/)[1]
+
+ content = File.read("bower.json")
+ File.open("bower.json", "w") do |file|
+ file.puts content.gsub(/"version":.*/, "\"version\": \"#{version}\",")
+ end
+
+ content = File.read("handlebars.js.nuspec")
+ File.open("handlebars.js.nuspec", "w") do |file|
+ file.puts content.gsub(/.*<\/version>/, "#{version}")
+ end
+end
+
desc "build the build and runtime version of handlebars"
-task :release => [:build, :runtime]
+task :release => [:version, :build, :runtime]
directory "vendor"
diff --git a/bin/handlebars b/bin/handlebars
index d605e74db..5b1ba89c9 100755
--- a/bin/handlebars
+++ b/bin/handlebars
@@ -168,10 +168,14 @@ function processTemplate(template, root) {
if (argv.simple) {
output.push(handlebars.precompile(data, options) + '\n');
} else if (argv.partial) {
- if(argv.amd && argv._.length == 1){ output.push('return '); }
+ if(argv.amd && (argv._.length == 1 && !fs.statSync(argv._[0]).isDirectory())) {
+ output.push('return ');
+ }
output.push('Handlebars.partials[\'' + template + '\'] = template(' + handlebars.precompile(data, options) + ');\n');
} else {
- if(argv.amd && argv._.length == 1){ output.push('return '); }
+ if(argv.amd && (argv._.length == 1 && !fs.statSync(argv._[0]).isDirectory())) {
+ output.push('return ');
+ }
output.push('templates[\'' + template + '\'] = template(' + handlebars.precompile(data, options) + ');\n');
}
}
@@ -184,7 +188,7 @@ argv._.forEach(function(template) {
// Output the content
if (!argv.simple) {
if (argv.amd) {
- if(argv._.length > 1){
+ if(argv._.length > 1 || (argv._.length == 1 && fs.statSync(argv._[0]).isDirectory())) {
if(argv.partial){
output.push('return Handlebars.partials;\n');
} else {
diff --git a/bower.json b/bower.json
new file mode 100644
index 000000000..a5eb00b98
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,9 @@
+{
+ "name": "handlebars.js",
+ "version": "1.0.0-rc.4",
+ "main": "dist/handlebars.js",
+ "ignore": [
+ "node_modules",
+ "components"
+ ]
+}
diff --git a/dist/handlebars.js b/dist/handlebars.js
index cf0e7f30c..0b52f734c 100644
--- a/dist/handlebars.js
+++ b/dist/handlebars.js
@@ -36,7 +36,7 @@ THE SOFTWARE.
;
// lib/handlebars/base.js
-Handlebars.VERSION = "1.0.0-rc.3";
+Handlebars.VERSION = "1.0.0-rc.4";
Handlebars.COMPILER_REVISION = 3;
Handlebars.REVISION_CHANGES = {
@@ -159,19 +159,19 @@ Handlebars.registerHelper('each', function(context, options) {
return ret;
});
-Handlebars.registerHelper('if', function(context, options) {
- var type = toString.call(context);
- if(type === functionType) { context = context.call(this); }
+Handlebars.registerHelper('if', function(conditional, options) {
+ var type = toString.call(conditional);
+ if(type === functionType) { conditional = conditional.call(this); }
- if(!context || Handlebars.Utils.isEmpty(context)) {
+ if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
-Handlebars.registerHelper('unless', function(context, options) {
- return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
+Handlebars.registerHelper('unless', function(conditional, options) {
+ return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
@@ -651,7 +651,7 @@ case 33: return 5;
break;
}
};
-lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[a-zA-Z0-9_$:-]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$-\/]+)/,/^(?:$)/];
+lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}\/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@[a-zA-Z]+)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:\s+)/,/^(?:[a-zA-Z0-9_$\-\/\.]+)/,/^(?:$)/];
lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,33],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"par":{"rules":[31,32],"inclusive":false},"INITIAL":{"rules":[0,1,2,33],"inclusive":true}};
return lexer;})()
parser.lexer = lexer;
diff --git a/dist/handlebars.runtime.js b/dist/handlebars.runtime.js
index 1cc6962a1..bdf81dc9e 100644
--- a/dist/handlebars.runtime.js
+++ b/dist/handlebars.runtime.js
@@ -36,7 +36,7 @@ THE SOFTWARE.
;
// lib/handlebars/base.js
-Handlebars.VERSION = "1.0.0-rc.3";
+Handlebars.VERSION = "1.0.0-rc.4";
Handlebars.COMPILER_REVISION = 3;
Handlebars.REVISION_CHANGES = {
@@ -159,19 +159,19 @@ Handlebars.registerHelper('each', function(context, options) {
return ret;
});
-Handlebars.registerHelper('if', function(context, options) {
- var type = toString.call(context);
- if(type === functionType) { context = context.call(this); }
+Handlebars.registerHelper('if', function(conditional, options) {
+ var type = toString.call(conditional);
+ if(type === functionType) { conditional = conditional.call(this); }
- if(!context || Handlebars.Utils.isEmpty(context)) {
+ if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
-Handlebars.registerHelper('unless', function(context, options) {
- return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
+Handlebars.registerHelper('unless', function(conditional, options) {
+ return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
diff --git a/handlebars.js.nuspec b/handlebars.js.nuspec
new file mode 100644
index 000000000..9a16cc09d
--- /dev/null
+++ b/handlebars.js.nuspec
@@ -0,0 +1,17 @@
+
+
+
+ handlebars.js
+ 1.0.0-rc.4
+ handlebars.js Authors
+ https://github.com/wycats/handlebars.js/blob/master/LICENSE
+ https://github.com/wycats/handlebars.js/
+ false
+ Extension of the Mustache logicless template language
+
+ handlebars mustache template html
+
+
+
+
+
diff --git a/lib/handlebars.js b/lib/handlebars.js
index 7d85c2610..f82ec3bad 100644
--- a/lib/handlebars.js
+++ b/lib/handlebars.js
@@ -21,6 +21,17 @@ Handlebars.create = create;
module.exports = Handlebars; // instantiate an instance
+// Publish a Node.js require() handler for .handlebars and .hbs files
+if (require.extensions) {
+ var extension = function(module, filename) {
+ var fs = require("fs");
+ var templateString = fs.readFileSync(filename, "utf8");
+ module.exports = Handlebars.compile(templateString);
+ };
+ require.extensions[".handlebars"] = extension;
+ require.extensions[".hbs"] = extension;
+}
+
// BEGIN(BROWSER)
// END(BROWSER)
diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js
index 5e7ea0e71..0a9b18cd2 100644
--- a/lib/handlebars/base.js
+++ b/lib/handlebars/base.js
@@ -6,7 +6,7 @@ var Handlebars = {};
// BEGIN(BROWSER)
-Handlebars.VERSION = "1.0.0-rc.3";
+Handlebars.VERSION = "1.0.0-rc.4";
Handlebars.COMPILER_REVISION = 3;
Handlebars.REVISION_CHANGES = {
@@ -129,19 +129,19 @@ Handlebars.registerHelper('each', function(context, options) {
return ret;
});
-Handlebars.registerHelper('if', function(context, options) {
- var type = toString.call(context);
- if(type === functionType) { context = context.call(this); }
+Handlebars.registerHelper('if', function(conditional, options) {
+ var type = toString.call(conditional);
+ if(type === functionType) { conditional = conditional.call(this); }
- if(!context || Handlebars.Utils.isEmpty(context)) {
+ if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
return options.inverse(this);
} else {
return options.fn(this);
}
});
-Handlebars.registerHelper('unless', function(context, options) {
- return Handlebars.helpers['if'].call(this, context, {fn: options.inverse, inverse: options.fn});
+Handlebars.registerHelper('unless', function(conditional, options) {
+ return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
});
Handlebars.registerHelper('with', function(context, options) {
diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js
index dffc477b9..1e0e4c902 100644
--- a/lib/handlebars/utils.js
+++ b/lib/handlebars/utils.js
@@ -1,5 +1,7 @@
exports.attach = function(Handlebars) {
+var toString = Object.prototype.toString;
+
// BEGIN(BROWSER)
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
diff --git a/package.json b/package.json
index 7dda35743..ab3f6831e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "handlebars",
"description": "Extension of the Mustache logicless template language",
- "version": "1.0.10",
+ "version": "1.0.11",
"homepage": "http://www.handlebarsjs.com/",
"keywords": [
"handlebars mustache template html"
diff --git a/release-notes.md b/release-notes.md
new file mode 100644
index 000000000..93dabc2f3
--- /dev/null
+++ b/release-notes.md
@@ -0,0 +1,61 @@
+# Release Notes
+
+## Development
+- [#515](https://github.com/wycats/handlebars.js/issues/515) - Add node require extensions support ([@jjclark1982](https://github.com/jjclark1982))
+- [#517](https://github.com/wycats/handlebars.js/issues/517) - Fix amd precompiler output with directories ([@blessenm](https://github.com/blessenm))
+- [#519](https://github.com/wycats/handlebars.js/issues/519) - Fix partials with . name ([@jamesgorrie](https://github.com/jamesgorrie))
+- [#433](https://github.com/wycats/handlebars.js/issues/433) - Add support for unicode ids
+- [#469](https://github.com/wycats/handlebars.js/issues/469) - Add support for `?` in ids
+- Docs updates
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.11...master)
+
+## v1.0.11 / 1.0.0-rc4 - May 13 2013
+
+- [#458](https://github.com/wycats/handlebars.js/issues/458) - Fix `./foo` syntax ([@jpfiset](https://github.com/jpfiset))
+- [#460](https://github.com/wycats/handlebars.js/issues/460) - Allow `:` in unescaped identifers ([@jpfiset](https://github.com/jpfiset))
+- [#471](https://github.com/wycats/handlebars.js/issues/471) - Create release notes (These!)
+- [#456](https://github.com/wycats/handlebars.js/issues/456) - Allow escaping of `\\`
+- [#211](https://github.com/wycats/handlebars.js/issues/211) - Fix exception in `escapeExpression`
+- [#375](https://github.com/wycats/handlebars.js/issues/375) - Escape unicode newlines
+- [#461](https://github.com/wycats/handlebars.js/issues/461) - Do not fail when compiling `""`
+- [#302](https://github.com/wycats/handlebars.js/issues/302) - Fix sanity check in knownHelpersOnly mode
+- [#369](https://github.com/wycats/handlebars.js/issues/369) - Allow registration of multiple helpers and partial by passing definition object
+- Add bower package declaration ([@DevinClark](https://github.com/DevinClark))
+- Add NuSpec package declaration ([@MikeMayer](https://github.com/MikeMayer))
+- Handle empty context in `with` ([@thejohnfreeman](https://github.com/thejohnfreeman))
+- Support custom template extensions in CLI ([@matteoagosti](https://github.com/matteoagosti))
+- Fix Rhino support ([@broady](https://github.com/broady))
+- Include contexts in string mode ([@leshill](https://github.com/leshill))
+- Return precompiled scripts when compiling to AMD ([@JamesMaroney](https://github.com/JamesMaroney))
+- Docs updates ([@iangreenleaf](https://github.com/iangreenleaf), [@gilesbowkett](https://github.com/gilesbowkett), [@utkarsh2012](https://github.com/utkarsh2012))
+- Fix `toString` handling under IE and browserify ([@tommydudebreaux](https://github.com/tommydudebreaux))
+- Add program metadata
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.10...v1.0.11)
+
+## v1.0.10 - Node - Feb 27 2013
+
+- [#428](https://github.com/wycats/handlebars.js/issues/428) - Fix incorrect rendering of nested programs
+- Fix exception message ([@tricknotes](https://github.com/tricknotes))
+- Added negative number literal support
+- Concert library to single IIFE
+- Add handlebars-source gemspec ([@machty](https://github.com/machty))
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.9...v1.0.10)
+
+## v1.0.9 - Node - Feb 15 2013
+
+- Added `Handlebars.create` API in node module for sandboxed instances ([@tommydudebreaux](https://github.com/tommydudebreaux))
+
+[Commits](https://github.com/wycats/handlebars.js/compare/1.0.0-rc.3...v1.0.9)
+
+## 1.0.0-rc3 - Browser - Feb 14 2013
+
+- Prevent use of `this` or `..` in illogical place ([@leshill](https://github.com/leshill))
+- Allow AST passing for `parse`/`compile`/`precompile` ([@machty](https://github.com/machty))
+- Optimize generated output by inlining statements where possible
+- Check compiler version when evaluating templates
+- Package browser dist in npm package
+
+[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.8...1.0.0-rc.3)
diff --git a/spec/example_1.handlebars b/spec/example_1.handlebars
new file mode 100644
index 000000000..054e96cb8
--- /dev/null
+++ b/spec/example_1.handlebars
@@ -0,0 +1 @@
+{{foo}}
diff --git a/spec/example_2.hbs b/spec/example_2.hbs
new file mode 100644
index 000000000..963eab972
--- /dev/null
+++ b/spec/example_2.hbs
@@ -0,0 +1 @@
+Hello, {{name}}!
diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb
index 293fe1f74..0b58ce1b3 100644
--- a/spec/parser_spec.rb
+++ b/spec/parser_spec.rb
@@ -125,6 +125,10 @@ def path(*parts)
it "parses simple mustaches" do
ast_for("{{foo}}").should == root { mustache id("foo") }
+ ast_for("{{foo?}}").should == root { mustache id("foo?") }
+ ast_for("{{foo_}}").should == root { mustache id("foo_") }
+ ast_for("{{foo-}}").should == root { mustache id("foo-") }
+ ast_for("{{foo:}}").should == root { mustache id("foo:") }
end
it "parses simple mustaches with data" do
diff --git a/spec/qunit_spec.js b/spec/qunit_spec.js
index e2f7d47d0..ad690c60f 100644
--- a/spec/qunit_spec.js
+++ b/spec/qunit_spec.js
@@ -577,6 +577,13 @@ test("Partials with slash paths", function() {
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
});
+test("Partials with slash and point paths", function() {
+ var string = "Dudes: {{> shared/dude.thing}}";
+ var dude = "{{name}}";
+ var hash = {name:"Jeepers", another_dude:"Creepers"};
+ shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing':dude}], true, "Dudes: Jeepers", "Partials can use literal with points in paths");
+});
+
test("Multiple partial registration", function() {
Handlebars.registerPartial({
'shared/dude': '{{name}}',
@@ -1502,3 +1509,27 @@ test('isEmpty', function() {
equal(Handlebars.Utils.isEmpty('foo'), false);
equal(Handlebars.Utils.isEmpty({bar: 1}), false);
});
+
+if (typeof(require) !== 'undefined') {
+ suite('Require');
+
+ test('Load .handlebars files with require()', function() {
+ var template = require("./example_1");
+ assert.deepEqual(template, require("./example_1.handlebars"));
+
+ var expected = 'foo\n';
+ var result = template({foo: "foo"});
+
+ equal(result, expected);
+ });
+
+ test('Load .hbs files with require()', function() {
+ var template = require("./example_2");
+ assert.deepEqual(template, require("./example_2.hbs"));
+
+ var expected = 'Hello, World!\n';
+ var result = template({name: "World"});
+
+ equal(result, expected);
+ });
+}
diff --git a/src/handlebars.l b/src/handlebars.l
index 9af78ba34..349e78f26 100644
--- a/src/handlebars.l
+++ b/src/handlebars.l
@@ -32,7 +32,7 @@
"{{" { return 'OPEN'; }
"=" { return 'EQUALS'; }
-"."/[}/ ] { return 'ID'; }
+"."/[}\/ ] { return 'ID'; }
".." { return 'ID'; }
[\/.] { return 'SEP'; }
\s+ { /*ignore whitespace*/ }
@@ -44,11 +44,22 @@
"true"/[}\s] { return 'BOOLEAN'; }
"false"/[}\s] { return 'BOOLEAN'; }
\-?[0-9]+/[}\s] { return 'INTEGER'; }
-[a-zA-Z0-9_$:-]+/[=}\s\/.] { return 'ID'; }
+
+/*
+ID is the inverse of control characters.
+Control characters ranges:
+ [\s] Whitespace
+ [!"#%-,\./] !, ", #, %, &, ', (, ), *, +, ,, ., /, Exceptions in range: $, -
+ [;->@] ;, <, =, >, @, Exceptions in range: :, ?
+ [\[-\^`] [, \, ], ^, `, Exceptions in range: _
+ [\{-~] {, |, }, ~
+*/
+[^\s!"#%-,\.\/;->@\[-\^`\{-~]+/[=}\s\/.] { return 'ID'; }
+
'['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; }
. { return 'INVALID'; }
\s+ { /*ignore whitespace*/ }
-[a-zA-Z0-9_$-\/]+ { this.popState(); return 'PARTIAL_NAME'; }
+[a-zA-Z0-9_$\-\/\.]+ { this.popState(); return 'PARTIAL_NAME'; }
<> { return 'EOF'; }