Skip to content

Commit

Permalink
Merge pull request #389 from leshill/partial_names
Browse files Browse the repository at this point in the history
Partials can be paths
  • Loading branch information
wycats committed Dec 24, 2012
2 parents 070e12f + b58c2dd commit bf4c813
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 27 deletions.
16 changes: 9 additions & 7 deletions lib/handlebars/compiler/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,10 @@ var Handlebars = require('./base');
// pass or at runtime.
};

Handlebars.AST.PartialNode = function(id, context) {
this.type = "partial";

// TODO: disallow complex IDs

this.id = id;
this.context = context;
Handlebars.AST.PartialNode = function(partialName, context) {
this.type = "partial";
this.partialName = partialName;
this.context = context;
};

var verifyMatch = function(open, close) {
Expand Down Expand Up @@ -93,6 +90,11 @@ var Handlebars = require('./base');
this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
};

Handlebars.AST.PartialNameNode = function(name) {
this.type = "PARTIAL_NAME";
this.name = name;
};

Handlebars.AST.DataNode = function(id) {
this.type = "DATA";
this.id = id;
Expand Down
4 changes: 2 additions & 2 deletions lib/handlebars/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Handlebars.JavaScriptCompiler = function() {};
},

partial: function(partial) {
var id = partial.id;
var partialName = partial.partialName;
this.usePartial = true;

if(partial.context) {
Expand All @@ -169,7 +169,7 @@ Handlebars.JavaScriptCompiler = function() {};
this.opcode('push', 'depth0');
}

this.opcode('invokePartial', id.original);
this.opcode('invokePartial', partialName.name);
this.opcode('append');
},

Expand Down
6 changes: 5 additions & 1 deletion lib/handlebars/compiler/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Handlebars.PrintVisitor.prototype.mustache = function(mustache) {
};

Handlebars.PrintVisitor.prototype.partial = function(partial) {
var content = this.accept(partial.id);
var content = this.accept(partial.partialName);
if(partial.context) { content = content + " " + this.accept(partial.context); }
return this.pad("{{> " + content + " }}");
};
Expand Down Expand Up @@ -111,6 +111,10 @@ Handlebars.PrintVisitor.prototype.ID = function(id) {
}
};

Handlebars.PrintVisitor.prototype.PARTIAL_NAME = function(partialName) {
return "PARTIAL:" + partialName.name;
};

Handlebars.PrintVisitor.prototype.DATA = function(data) {
return "@" + data.id;
};
Expand Down
12 changes: 10 additions & 2 deletions spec/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ def data(id)
"@#{id}"
end

def partial_name(name)
"PARTIAL:#{name}"
end

def path(*parts)
"PATH:#{parts.join("/")}"
end
Expand Down Expand Up @@ -218,11 +222,15 @@ def path(*parts)
end

it "parses a partial" do
ast_for("{{> foo }}").should == root { partial id("foo") }
ast_for("{{> foo }}").should == root { partial partial_name("foo") }
end

it "parses a partial with context" do
ast_for("{{> foo bar}}").should == root { partial id("foo"), id("bar") }
ast_for("{{> foo bar}}").should == root { partial partial_name("foo"), id("bar") }
end

it "parses a partial with a complex name" do
ast_for("{{> shared/partial}}").should == root { partial partial_name("shared/partial") }
end

it "parses a comment" do
Expand Down
14 changes: 11 additions & 3 deletions spec/qunit_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,21 @@ test("GH-14: a partial preceding a selector", function() {
shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers Creepers", "Regular selectors can follow a partial");
});

test("Partials with literal paths", function() {
var string = "Dudes: {{> [dude]}}";
test("Partials with slash paths", function() {
var string = "Dudes: {{> shared/dude}}";
var dude = "{{name}}";
var hash = {name:"Jeepers", another_dude:"Creepers"};
shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
});

test("Partials with integer path", function() {
var string = "Dudes: {{> 404}}";
var dude = "{{name}}";
var hash = {name:"Jeepers", another_dude:"Creepers"};
shouldCompileToWithPartials(string, [hash, {}, {404:dude}], true, "Dudes: Jeepers", "Partials can use literal paths");
});


suite("String literal parameters");

test("simple literals work", function() {
Expand Down
16 changes: 8 additions & 8 deletions spec/tokenizer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,24 +132,24 @@ def tokenize(string)
result[4].should be_token("CONTENT", " baz")
end

it "tokenizes a partial as 'OPEN_PARTIAL ID CLOSE'" do
it "tokenizes a partial as 'OPEN_PARTIAL PARTIAL_NAME CLOSE'" do
result = tokenize("{{> foo}}")
result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
result.should match_tokens(%w(OPEN_PARTIAL PARTIAL_NAME CLOSE))
end

it "tokenizes a partial with context as 'OPEN_PARTIAL ID ID CLOSE'" do
it "tokenizes a partial with context as 'OPEN_PARTIAL PARTIAL_NAME ID CLOSE'" do
result = tokenize("{{> foo bar }}")
result.should match_tokens(%w(OPEN_PARTIAL ID ID CLOSE))
result.should match_tokens(%w(OPEN_PARTIAL PARTIAL_NAME ID CLOSE))
end

it "tokenizes a partial without spaces as 'OPEN_PARTIAL ID CLOSE'" do
it "tokenizes a partial without spaces as 'OPEN_PARTIAL PARTIAL_NAME CLOSE'" do
result = tokenize("{{>foo}}")
result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
result.should match_tokens(%w(OPEN_PARTIAL PARTIAL_NAME CLOSE))
end

it "tokenizes a partial space at the end as 'OPEN_PARTIAL ID CLOSE'" do
it "tokenizes a partial space at the end as 'OPEN_PARTIAL PARTIAL_NAME CLOSE'" do
result = tokenize("{{>foo }}")
result.should match_tokens(%w(OPEN_PARTIAL ID CLOSE))
result.should match_tokens(%w(OPEN_PARTIAL PARTIAL_NAME CLOSE))
end

it "tokenizes a comment as 'COMMENT'" do
Expand Down
6 changes: 4 additions & 2 deletions src/handlebars.l
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

%x mu emu com
%x mu emu com par

%%

Expand All @@ -19,7 +19,7 @@

<com>[\s\S]*?"--}}" { yytext = yytext.substr(0, yyleng-4); this.popState(); return 'COMMENT'; }

<mu>"{{>" { return 'OPEN_PARTIAL'; }
<mu>"{{>" { this.begin("par"); return 'OPEN_PARTIAL'; }
<mu>"{{#" { return 'OPEN_BLOCK'; }
<mu>"{{/" { return 'OPEN_ENDBLOCK'; }
<mu>"{{^" { return 'OPEN_INVERSE'; }
Expand All @@ -46,6 +46,8 @@
<mu>[a-zA-Z0-9_$-]+/[=}\s\/.] { return 'ID'; }
<mu>'['[^\]]*']' { yytext = yytext.substr(1, yyleng-2); return 'ID'; }
<mu>. { return 'INVALID'; }
<par>\s+ { /*ignore whitespace*/ }
<par>[a-zA-Z0-9_$-/]+ { this.popState(); return 'PARTIAL_NAME'; }
<INITIAL,mu><<EOF>> { return 'EOF'; }
8 changes: 6 additions & 2 deletions src/handlebars.yy
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ mustache


partial
: OPEN_PARTIAL path CLOSE { $$ = new yy.PartialNode($2); }
| OPEN_PARTIAL path path CLOSE { $$ = new yy.PartialNode($2, $3); }
: OPEN_PARTIAL partialName CLOSE { $$ = new yy.PartialNode($2); }
| OPEN_PARTIAL partialName path CLOSE { $$ = new yy.PartialNode($2, $3); }
;

simpleInverse
Expand Down Expand Up @@ -91,6 +91,10 @@ hashSegment
| ID EQUALS DATA { $$ = [$1, new yy.DataNode($3)]; }
;

partialName
: PARTIAL_NAME { $$ = new yy.PartialNameNode($1); }
;

path
: pathSegments { $$ = new yy.IdNode($1); }
;
Expand Down

0 comments on commit bf4c813

Please sign in to comment.