handlebars 0.0.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +1 -1
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +1 -1
  5. data/README.mdown +44 -0
  6. data/Rakefile +3 -0
  7. data/handlebars.gemspec +19 -13
  8. data/lib/handlebars.rb +4 -3
  9. data/lib/handlebars/context.rb +37 -0
  10. data/lib/handlebars/version.rb +1 -1
  11. data/spec/handlebars_spec.rb +40 -0
  12. data/spike.rb +17 -0
  13. data/vendor/handlebars/.gitignore +6 -0
  14. data/vendor/handlebars/.jshintrc +50 -0
  15. data/vendor/handlebars/.npmignore +11 -0
  16. data/vendor/handlebars/Gemfile +5 -0
  17. data/vendor/handlebars/LICENSE +20 -0
  18. data/vendor/handlebars/README.markdown +315 -0
  19. data/vendor/handlebars/Rakefile +116 -0
  20. data/vendor/handlebars/bench/benchwarmer.js +149 -0
  21. data/vendor/handlebars/bench/handlebars.js +163 -0
  22. data/vendor/handlebars/bin/handlebars +139 -0
  23. data/vendor/handlebars/lib/handlebars.js +14 -0
  24. data/vendor/handlebars/lib/handlebars/base.js +101 -0
  25. data/vendor/handlebars/lib/handlebars/compiler/ast.js +103 -0
  26. data/vendor/handlebars/lib/handlebars/compiler/base.js +27 -0
  27. data/vendor/handlebars/lib/handlebars/compiler/compiler.js +808 -0
  28. data/vendor/handlebars/lib/handlebars/compiler/index.js +7 -0
  29. data/vendor/handlebars/lib/handlebars/compiler/printer.js +137 -0
  30. data/vendor/handlebars/lib/handlebars/compiler/visitor.js +13 -0
  31. data/vendor/handlebars/lib/handlebars/runtime.js +68 -0
  32. data/vendor/handlebars/lib/handlebars/utils.js +68 -0
  33. data/vendor/handlebars/package.json +25 -0
  34. data/vendor/handlebars/spec/acceptance_spec.rb +101 -0
  35. data/vendor/handlebars/spec/parser_spec.rb +264 -0
  36. data/vendor/handlebars/spec/qunit_spec.js +1067 -0
  37. data/vendor/handlebars/spec/spec_helper.rb +157 -0
  38. data/vendor/handlebars/spec/tokenizer_spec.rb +254 -0
  39. data/vendor/handlebars/src/handlebars.l +42 -0
  40. data/vendor/handlebars/src/handlebars.yy +99 -0
  41. metadata +93 -77
  42. data/README.md +0 -39
  43. data/lib/handlebars/generator.rb +0 -4
  44. data/lib/handlebars/parser.rb +0 -240
  45. data/spec/generator_spec.rb +0 -5
  46. data/spec/parser_spec.rb +0 -163
  47. data/spec/spec_helper.rb +0 -17
@@ -0,0 +1,116 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ def compile_parser
5
+ system "jison src/handlebars.yy src/handlebars.l"
6
+ if $?.success?
7
+ File.open("lib/handlebars/compiler/parser.js", "w") do |file|
8
+ file.puts File.read("handlebars.js") + ";"
9
+ end
10
+
11
+ sh "rm handlebars.js"
12
+ else
13
+ puts "Failed to run Jison."
14
+ end
15
+ end
16
+
17
+ file "lib/handlebars/compiler/parser.js" => ["src/handlebars.yy","src/handlebars.l"] do
18
+ if ENV['PATH'].split(':').any? {|folder| File.exists?(folder+'/jison')}
19
+ compile_parser
20
+ else
21
+ puts "Jison is not installed. Trying `npm install jison`."
22
+ sh "npm install jison -g"
23
+ compile_parser
24
+ end
25
+ end
26
+
27
+ task :compile => "lib/handlebars/compiler/parser.js"
28
+
29
+ desc "run the spec suite"
30
+ task :spec => [:release] do
31
+ system "rspec -cfs spec"
32
+ end
33
+
34
+ task :default => [:compile, :spec]
35
+
36
+ def remove_exports(string)
37
+ match = string.match(%r{^// BEGIN\(BROWSER\)\n(.*)\n^// END\(BROWSER\)}m)
38
+ match ? match[1] : string
39
+ end
40
+
41
+ minimal_deps = %w(base compiler/parser compiler/base compiler/ast utils compiler/compiler runtime).map do |file|
42
+ "lib/handlebars/#{file}.js"
43
+ end
44
+
45
+ runtime_deps = %w(base utils runtime).map do |file|
46
+ "lib/handlebars/#{file}.js"
47
+ end
48
+
49
+ directory "dist"
50
+
51
+ minimal_deps.unshift "dist"
52
+
53
+ def build_for_task(task)
54
+ FileUtils.rm_rf("dist/*") if File.directory?("dist")
55
+ FileUtils.mkdir_p("dist")
56
+
57
+ contents = []
58
+ task.prerequisites.each do |filename|
59
+ next if filename == "dist"
60
+
61
+ contents << "// #{filename}\n" + remove_exports(File.read(filename)) + ";"
62
+ end
63
+
64
+ File.open(task.name, "w") do |file|
65
+ file.puts contents.join("\n")
66
+ end
67
+ end
68
+
69
+ file "dist/handlebars.js" => minimal_deps do |task|
70
+ build_for_task(task)
71
+ end
72
+
73
+ file "dist/handlebars.runtime.js" => runtime_deps do |task|
74
+ build_for_task(task)
75
+ end
76
+
77
+ task :build => [:compile, "dist/handlebars.js"]
78
+ task :runtime => [:compile, "dist/handlebars.runtime.js"]
79
+
80
+ desc "build the build and runtime version of handlebars"
81
+ task :release => [:build, :runtime]
82
+
83
+ directory "vendor"
84
+
85
+ desc "benchmark against dust.js and mustache.js"
86
+ task :bench => "vendor" do
87
+ require "open-uri"
88
+ #File.open("vendor/mustache.js", "w") do |file|
89
+ #file.puts open("https://github.com/janl/mustache.js/raw/master/mustache.js").read
90
+ #file.puts "module.exports = Mustache;"
91
+ #end
92
+
93
+ File.open("vendor/benchmark.js", "w") do |file|
94
+ file.puts open("https://raw.github.com/bestiejs/benchmark.js/master/benchmark.js").read
95
+ end
96
+
97
+ #if File.directory?("vendor/dustjs")
98
+ #system "cd vendor/dustjs && git pull"
99
+ #else
100
+ #system "git clone git://github.com/akdubya/dustjs.git vendor/dustjs"
101
+ #end
102
+
103
+ #if File.directory?("vendor/coffee")
104
+ #system "cd vendor/coffee && git pull"
105
+ #else
106
+ #system "git clone git://github.com/jashkenas/coffee-script.git vendor/coffee"
107
+ #end
108
+
109
+ #if File.directory?("vendor/eco")
110
+ #system "cd vendor/eco && git pull && npm update"
111
+ #else
112
+ #system "git clone git://github.com/sstephenson/eco.git vendor/eco && cd vendor/eco && npm update"
113
+ #end
114
+
115
+ system "node bench/handlebars.js"
116
+ end
@@ -0,0 +1,149 @@
1
+
2
+ var Benchmark = require("benchmark");
3
+
4
+ var BenchWarmer = function(names) {
5
+ this.benchmarks = [];
6
+ this.currentBenches = [];
7
+ this.names = [];
8
+ this.errors = {};
9
+ };
10
+
11
+ var print = require("sys").print;
12
+
13
+ BenchWarmer.prototype = {
14
+ winners: function(benches) {
15
+ var result = Benchmark.filter(benches, function(bench) { return bench.cycles; });
16
+
17
+ if (result.length > 1) {
18
+ result.sort(function(a, b) { return b.compare(a); });
19
+ first = result[0];
20
+ last = result[result.length - 1];
21
+
22
+ var winners = [];
23
+
24
+ Benchmark.each(result, function(bench) {
25
+ if (bench.compare(first) === 0) {
26
+ winners.push(bench);
27
+ }
28
+ });
29
+
30
+ return winners;
31
+ } else {
32
+ return result;
33
+ }
34
+ },
35
+ suite: function(suite, fn) {
36
+ this.suiteName = suite;
37
+ this.first = true;
38
+
39
+ var self = this;
40
+
41
+ fn(function(name, benchFn) {
42
+ self.push(name, benchFn);
43
+ });
44
+ },
45
+ push: function(name, fn) {
46
+ if(this.names.indexOf(name) == -1) {
47
+ this.names.push(name);
48
+ }
49
+
50
+ var first = this.first, suiteName = this.suiteName, self = this;
51
+ this.first = false;
52
+
53
+ var bench = new Benchmark(function() {
54
+ fn();
55
+ }, {
56
+ name: this.suiteName + ": " + name,
57
+ onComplete: function() {
58
+ if(first) { self.startLine(suiteName); }
59
+ self.writeBench(bench);
60
+ self.currentBenches.push(bench);
61
+ }, onError: function() {
62
+ self.errors[this.name] = this;
63
+ }
64
+ });
65
+
66
+ this.benchmarks.push(bench);
67
+ },
68
+ bench: function() {
69
+ var benchSize = 0, names = this.names, self = this, i, l;
70
+
71
+ for(i=0, l=names.length; i<l; i++) {
72
+ var name = names[i];
73
+
74
+ if(benchSize < name.length) { benchSize = name.length; }
75
+ }
76
+
77
+ this.nameSize = benchSize + 2;
78
+ this.benchSize = 20;
79
+ var horSize = 0;
80
+
81
+ this.startLine("ops/msec");
82
+ horSize = horSize + "ops/msec ".length;
83
+ for(i=0, l=names.length; i<l; i++) {
84
+ print(names[i] + new Array(this.benchSize - names[i].length + 1).join(" "));
85
+ horSize = horSize + this.benchSize;
86
+ }
87
+
88
+ print("WINNER(S)");
89
+ horSize = horSize + "WINNER(S)".length;
90
+
91
+ print("\n" + new Array(horSize + 1).join("-"));
92
+
93
+ Benchmark.invoke(this.benchmarks, {
94
+ name: "run",
95
+ onComplete: function() {
96
+ var errors = false, prop, bench;
97
+ for(prop in self.errors) { if(self.errors.hasOwnProperty(prop)) { errors = true; break; } }
98
+
99
+ if(errors) {
100
+ print("\n\nErrors:\n");
101
+ for(prop in self.errors) {
102
+ if(self.errors.hasOwnProperty(prop)) {
103
+ bench = self.errors[prop];
104
+ print("\n" + bench.name + ":\n");
105
+ print(bench.error.message);
106
+ if(bench.error.stack) {
107
+ print(bench.error.stack.join("\n"));
108
+ }
109
+ print("\n");
110
+ }
111
+ }
112
+ }
113
+ }
114
+ });
115
+
116
+ print("\n");
117
+ },
118
+ startLine: function(name) {
119
+ var winners = Benchmark.map(this.winners(this.currentBenches), function(bench) {
120
+ return bench.name.split(": ")[1];
121
+ });
122
+
123
+ this.currentBenches = [];
124
+
125
+ print(winners.join(", "));
126
+ print("\n");
127
+ var padding = this.nameSize - name.length + 1;
128
+ name = name + new Array(padding).join(" ");
129
+ print(name);
130
+ },
131
+ writeBench: function(bench) {
132
+ var out;
133
+
134
+ if(!bench.error) {
135
+ var count = bench.hz,
136
+ moe = count * bench.stats.RME / 100;
137
+
138
+ out = Math.round(count / 1000) + " ±" + Math.round(moe / 1000) + " (" + bench.cycles + ")";
139
+ } else {
140
+ out = "E";
141
+ }
142
+
143
+ var padding = this.benchSize - out.length + 1;
144
+ out = out + new Array(padding).join(" ");
145
+ print(out);
146
+ }
147
+ };
148
+
149
+ module.exports = BenchWarmer;
@@ -0,0 +1,163 @@
1
+ require.paths.push("lib");
2
+ require.paths.push("vendor");
3
+ require.paths.push("vendor/dustjs/lib");
4
+ require.paths.push("vendor/coffee/lib");
5
+ require.paths.push("vendor/eco/lib");
6
+
7
+
8
+ var BenchWarmer = require("./benchwarmer");
9
+ Handlebars = require("handlebars");
10
+
11
+ var dust = require("dust");
12
+ var Mustache = require("mustache");
13
+ var ecoExports = require("eco");
14
+
15
+ eco = function(str) {
16
+ return ecoExports(str);
17
+ }
18
+
19
+ var benchDetails = {
20
+ string: {
21
+ context: {},
22
+ handlebars: "Hello world",
23
+ dust: "Hello world",
24
+ mustache: "Hello world",
25
+ eco: "Hello world"
26
+ },
27
+ variables: {
28
+ context: {name: "Mick", count: 30},
29
+ handlebars: "Hello {{name}}! You have {{count}} new messages.",
30
+ dust: "Hello {name}! You have {count} new messages.",
31
+ mustache: "Hello {{name}}! You have {{count}} new messages.",
32
+ eco: "Hello <%= @name %>! You have <%= @count %> new messages."
33
+ },
34
+ object: {
35
+ context: { person: { name: "Larry", age: 45 } },
36
+ handlebars: "{{#with person}}{{name}}{{age}}{{/with}}",
37
+ dust: "{#person}{name}{age}{/person}",
38
+ mustache: "{{#person}}{{name}}{{age}}{{/person}}"
39
+ },
40
+ array: {
41
+ context: { names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] },
42
+ handlebars: "{{#each names}}{{name}}{{/each}}",
43
+ dust: "{#names}{name}{/names}",
44
+ mustache: "{{#names}}{{name}}{{/names}}",
45
+ eco: "<% for item in @names: %><%= item.name %><% end %>"
46
+ },
47
+ partial: {
48
+ context: { peeps: [{name: "Moe", count: 15}, {name: "Larry", count: 5}, {name: "Curly", count: 1}] },
49
+ partials: {
50
+ mustache: { variables: "Hello {{name}}! You have {{count}} new messages." },
51
+ handlebars: { variables: "Hello {{name}}! You have {{count}} new messages." }
52
+ },
53
+ handlebars: "{{#each peeps}}{{>variables}}{{/each}}",
54
+ dust: "{#peeps}{>variables/}{/peeps}",
55
+ mustache: "{{#peeps}}{{>variables}}{{/peeps}}"
56
+ },
57
+ recursion: {
58
+ context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] },
59
+ partials: {
60
+ mustache: { recursion: "{{name}}{{#kids}}{{>recursion}}{{/kids}}" },
61
+ handlebars: { recursion: "{{name}}{{#each kids}}{{>recursion}}{{/each}}" }
62
+ },
63
+ handlebars: "{{name}}{{#each kids}}{{>recursion}}{{/each}}",
64
+ dust: "{name}{#kids}{>recursion:./}{/kids}",
65
+ mustache: "{{name}}{{#kids}}{{>recursion}}{{/kids}}"
66
+ },
67
+ complex: {
68
+ handlebars: "<h1>{{header}}</h1>{{#if items}}<ul>{{#each items}}{{#if current}}" +
69
+ "<li><strong>{{name}}</strong></li>{{^}}" +
70
+ "<li><a href=\"{{url}}\">{{name}}</a></li>{{/if}}" +
71
+ "{{/each}}</ul>{{^}}<p>The list is empty.</p>{{/if}}",
72
+
73
+ dust: "<h1>{header}</h1>\n" +
74
+ "{?items}\n" +
75
+ " <ul>\n" +
76
+ " {#items}\n" +
77
+ " {#current}\n" +
78
+ " <li><strong>{name}</strong></li>\n" +
79
+ " {:else}\n" +
80
+ " <li><a href=\"{url}\">{name}</a></li>\n" +
81
+ " {/current}\n" +
82
+ " {/items}\n" +
83
+ " </ul>\n" +
84
+ "{:else}\n" +
85
+ " <p>The list is empty.</p>\n" +
86
+ "{/items}",
87
+ context: {
88
+ header: function() {
89
+ return "Colors";
90
+ },
91
+ items: [
92
+ {name: "red", current: true, url: "#Red"},
93
+ {name: "green", current: false, url: "#Green"},
94
+ {name: "blue", current: false, url: "#Blue"}
95
+ ]
96
+ }
97
+ }
98
+
99
+ };
100
+
101
+ handlebarsTemplates = {};
102
+ ecoTemplates = {};
103
+
104
+ var warmer = new BenchWarmer();
105
+
106
+ var makeSuite = function(name) {
107
+ warmer.suite(name, function(bench) {
108
+ var templateName = name;
109
+ var details = benchDetails[templateName];
110
+ var mustachePartials = details.partials && details.partials.mustache;
111
+ var mustacheSource = details.mustache;
112
+ var context = details.context;
113
+
114
+ var error = function() { throw new Error("EWOT"); };
115
+
116
+
117
+ //bench("dust", function() {
118
+ //dust.render(templateName, context, function(err, out) { });
119
+ //});
120
+
121
+ bench("handlebars", function() {
122
+ handlebarsTemplates[templateName](context);
123
+ });
124
+
125
+ //if(ecoTemplates[templateName]) {
126
+ //bench("eco", function() {
127
+ //ecoTemplates[templateName](context);
128
+ //});
129
+ //} else {
130
+ //bench("eco", error);
131
+ //}
132
+
133
+ //if(mustacheSource) {
134
+ //bench("mustache", function() {
135
+ //Mustache.to_html(mustacheSource, context, mustachePartials);
136
+ //});
137
+ //} else {
138
+ //bench("mustache", error);
139
+ //}
140
+ });
141
+ }
142
+
143
+ for(var name in benchDetails) {
144
+ if(benchDetails.hasOwnProperty(name)) {
145
+ dust.loadSource(dust.compile(benchDetails[name].dust, name));
146
+ handlebarsTemplates[name] = Handlebars.compile(benchDetails[name].handlebars);
147
+
148
+ if(benchDetails[name].eco) { ecoTemplates[name] = eco(benchDetails[name].eco); }
149
+
150
+ var partials = benchDetails[name].partials;
151
+ if(partials) {
152
+ for(var partialName in partials.handlebars) {
153
+ if(partials.handlebars.hasOwnProperty(partialName)) {
154
+ Handlebars.registerPartial(partialName, partials.handlebars[partialName]);
155
+ }
156
+ }
157
+ }
158
+
159
+ makeSuite(name);
160
+ }
161
+ }
162
+
163
+ warmer.bench();
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ var optimist = require('optimist')
4
+ .usage('Precompile handlebar templates.\nUsage: $0 template...', {
5
+ 'f': {
6
+ 'type': 'string',
7
+ 'description': 'Output File',
8
+ 'alias': 'output'
9
+ },
10
+ 'k': {
11
+ 'type': 'string',
12
+ 'description': 'Known helpers',
13
+ 'alias': 'known'
14
+ },
15
+ 'o': {
16
+ 'type': 'boolean',
17
+ 'description': 'Known helpers only',
18
+ 'alias': 'knownOnly'
19
+ },
20
+ 'm': {
21
+ 'type': 'boolean',
22
+ 'description': 'Minimize output',
23
+ 'alias': 'min'
24
+ },
25
+ 's': {
26
+ 'type': 'boolean',
27
+ 'description': 'Output template function only.',
28
+ 'alias': 'simple'
29
+ },
30
+ 'r': {
31
+ 'type': 'string',
32
+ 'description': 'Template root. Base value that will be stripped from template names.',
33
+ 'alias': 'root'
34
+ }
35
+ })
36
+
37
+ .check(function(argv) {
38
+ var template = [0];
39
+ if (!argv._.length) {
40
+ throw 'Must define at least one template or directory.';
41
+ }
42
+
43
+ argv._.forEach(function(template) {
44
+ try {
45
+ fs.statSync(template);
46
+ } catch (err) {
47
+ throw 'Unable to open template file "' + template + '"';
48
+ }
49
+ });
50
+ })
51
+ .check(function(argv) {
52
+ if (argv.simple && argv.min) {
53
+ throw 'Unable to minimze simple output';
54
+ }
55
+ if (argv.simple && (argv._.length !== 1 || fs.statSync(argv._[0]).isDirectory())) {
56
+ throw 'Unable to output multiple templates in simple mode';
57
+ }
58
+ });
59
+
60
+ var fs = require('fs'),
61
+ handlebars = require('../lib/handlebars'),
62
+ basename = require('path').basename,
63
+ uglify = require('uglify-js');
64
+
65
+ var argv = optimist.argv,
66
+ template = argv._[0];
67
+
68
+ // Convert the known list into a hash
69
+ var known = {};
70
+ if (argv.known && !Array.isArray(argv.known)) {
71
+ argv.known = [argv.known];
72
+ }
73
+ if (argv.known) {
74
+ for (var i = 0, len = argv.known.length; i < len; i++) {
75
+ known[argv.known[i]] = true;
76
+ }
77
+ }
78
+
79
+ var output = [];
80
+ if (!argv.simple) {
81
+ output.push('(function() {\n var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};\n');
82
+ }
83
+ function processTemplate(template, root) {
84
+ var path = template,
85
+ stat = fs.statSync(path);
86
+ if (stat.isDirectory()) {
87
+ fs.readdirSync(template).map(function(file) {
88
+ var path = template + '/' + file;
89
+
90
+ if (/\.handlebars$/.test(path) || fs.statSync(path).isDirectory()) {
91
+ processTemplate(path, root || template);
92
+ }
93
+ });
94
+ } else {
95
+ var data = fs.readFileSync(path, 'utf8');
96
+
97
+ var options = {
98
+ knownHelpers: known,
99
+ knownHelpersOnly: argv.o
100
+ };
101
+
102
+ // Clean the template name
103
+ if (!root) {
104
+ template = basename(template);
105
+ } else if (template.indexOf(root) === 0) {
106
+ template = template.substring(root.length+1);
107
+ }
108
+ template = template.replace(/\.handlebars$/, '');
109
+
110
+ if (argv.simple) {
111
+ output.push(handlebars.precompile(data, options) + '\n');
112
+ } else {
113
+ output.push('templates[\'' + template + '\'] = template(' + handlebars.precompile(data, options) + ');\n');
114
+ }
115
+ }
116
+ }
117
+
118
+ argv._.forEach(function(template) {
119
+ processTemplate(template, argv.root);
120
+ });
121
+
122
+ // Output the content
123
+ if (!argv.simple) {
124
+ output.push('})();');
125
+ }
126
+ output = output.join('');
127
+
128
+ if (argv.min) {
129
+ var ast = uglify.parser.parse(output);
130
+ ast = uglify.uglify.ast_mangle(ast);
131
+ ast = uglify.uglify.ast_squeeze(ast);
132
+ output = uglify.uglify.gen_code(ast);
133
+ }
134
+
135
+ if (argv.output) {
136
+ fs.writeFileSync(argv.output, output, 'utf8');
137
+ } else {
138
+ console.log(output);
139
+ }