guard-templates 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in guard-templates.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Guard::Templates
2
+
3
+ Guard::Templates is a [Guard](https://github.com/guard/guard) plugin that pre-compiles or translates your project's JS-language templates into include-ready Javascript files.
4
+
5
+ ## Installation
6
+ If using Bundler, just add guard-templates to your Gemfile
7
+
8
+ ```ruby
9
+ group :development do
10
+ gem 'guard-templates'
11
+ end
12
+ ```
13
+
14
+ Alternatively, install it system-wide with
15
+
16
+ ```
17
+ gem install guard-templates
18
+ ```
19
+
20
+ Guard::Templates uses [ExecJS](https://github.com/sstephenson/execjs) for intermediary-stage compilation. You can install one of several JS engines and JSON libraries that it will use - see the ExecJS documentation for details. Presently, this is only necessary if you want to transform your Jade templates into precompiled functions.
21
+
22
+ ## Usage
23
+ Once guard-templates is installed you can add a sample Guardfile with:
24
+
25
+ ```
26
+ guard init templates
27
+ ```
28
+
29
+ This will look something like:
30
+
31
+ ```ruby
32
+ guard 'templates', :output => 'public/javascript/templates.js', :namespace => 'MyApp' do
33
+ watch(/app\/javascripts\/templates\/(.*)\.jade$/)
34
+ end
35
+ ```
36
+
37
+ Change the watch and output paths to match your application, and run
38
+
39
+ ```
40
+ guard&
41
+ ```
42
+
43
+ ## Options
44
+
45
+ ```namespace``` Set to your application's namespace, defaults to 'this'. Use this to keep your templates out of the global scope like a good Javascript citizen.
46
+ ```output``` Path relative to Guard where the compiled Javascript files will be output. If this is a filename ending in .js, all of the templates will be attached to a single object, as above.
47
+
48
+ ### Template Languages Without Precompiling Support
49
+ Presently, aside from Jade, this means all of them. :-) See adding new languages below if you'd like support precompilation for your favorite Javascript templating language.
50
+
51
+ With a templates directory that looks like:
52
+
53
+ ```
54
+ templates/
55
+ ├── foo
56
+ │   └── bar.handlebars
57
+ └── index.handlebars
58
+ ```
59
+
60
+ Then ```:output => 'public/javascripts``` will produce a public/javascripts that looks like:
61
+
62
+ ```
63
+ public/
64
+ └── javascripts
65
+ ├── foo
66
+ │   └── bar.js
67
+ └── index.js
68
+ ```
69
+
70
+ Each file contains the stringified template contents of the handlebars file:
71
+
72
+ ```javascript
73
+ MyApp['index'] = "<div>{{index}}</div>\n"
74
+ ```
75
+
76
+ If output is a path ending in .js, the templates will be compiled to an object in that file. Using the example above with ```:output => 'public/javascripts/templates.js'```, we get a single file result:
77
+
78
+ ```
79
+ public/
80
+ └── javascripts
81
+ └── templates.js
82
+ ```
83
+
84
+ that looks like:
85
+
86
+ ```javascript
87
+ MyApp.templates = {
88
+ "index": "<div>{{index}}</div>\n",
89
+ "foo/bar": "<p>{{example}}</p>\n"
90
+ }
91
+ ```
92
+
93
+ ### With Precompiling Jade
94
+ Templates with a .jade extension will be precompiled with Jade's compiler and turned into anonymous functions. The only difference between precompiled and unprecompiled templates is the precompiled ones get turned into functions rather than strings in the resulting Javascript.
95
+
96
+ With this filesystem structure, and a watch pattern like ```watch(/templates\/(.*)\.jade$/)```
97
+
98
+ ```
99
+ templates/
100
+ ├── foo
101
+ │   └── other.jade
102
+ └── index.jade
103
+ ```
104
+
105
+ ```:output => 'public/javascripts/templates.js'``` will produce a templates.js that looks like:
106
+
107
+ ```javascript
108
+ MyApp.templates = {
109
+ "foo/other": function anonymous(locals, attrs, escape, rethrow) {
110
+ //function contents
111
+ },
112
+ "index": function anonymous(locals, attrs, escape, rethrow) {
113
+ // function contents
114
+ }
115
+ }
116
+ ```
117
+
118
+ You can then include templates.js in your application and render the templates by calling the functions in question. I.e:
119
+
120
+ ```javascript
121
+ MyApp.templates['foo/other']()
122
+ ```
123
+
124
+ With ```:output => 'public/javascripts'```, each .jade file will be compiled to an individual .js file, like so:
125
+
126
+ ```
127
+ ├── public
128
+ │   └── javascripts
129
+ │   ├── foo
130
+ │   │   └── other.js
131
+ │   └── index.js
132
+ ├── templates
133
+ │   ├── foo
134
+ │   │   └── other.jade
135
+ │   └── index.jade
136
+ ```
137
+
138
+ With the contents of each compiled js file looking like:
139
+
140
+ ```javascript
141
+ MyApp['index'] = function anonymous(locals, attrs, escape, rethrow) {
142
+ //function contents
143
+ }
144
+ ```
145
+
146
+ ## Precompilation
147
+ Currently, only [Jade](https://github.com/visionmedia/jade) is supported. All other template types fall back to being inlined as string literals.
148
+
149
+ ### Adding Precompilation Support For Other Languages
150
+ Adding precompilation support for your favorite language is as simple as adding a single class method to Guard::Templates::Compilers. When checking for precompilation support for a particular file extension, guard-templates looks for a class method named ```compile_<extension>``` in that module. It should accept a string (representing the template source) and return a stringified Javascript function. See ```compile_jade``` in Guard::Templates::Compilers for an example.
151
+
152
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ Gem::Specification.new do |s|
4
+ s.name = "guard-templates"
5
+ s.version = "0.0.1"
6
+ s.authors = ["Thomas Mayfield"]
7
+ s.email = ["Thomas.Mayfield@gmail.com"]
8
+ s.homepage = ""
9
+ s.summary = "Javascript template compilation via Guard"
10
+ s.description = "Guard plugin for smart, automatic compilation of your Javascript template files into usable Javascript"
11
+
12
+ s.rubyforge_project = "guard-templates"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_path = "lib"
18
+
19
+ s.add_runtime_dependency "guard"
20
+ s.add_runtime_dependency "execjs"
21
+ s.add_runtime_dependency "json"
22
+ s.add_development_dependency "bundler"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "fakefs"
25
+ end
@@ -0,0 +1,123 @@
1
+
2
+ var jade = (function(exports){
3
+ /*!
4
+ * Jade - runtime
5
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
6
+ * MIT Licensed
7
+ */
8
+
9
+ /**
10
+ * Lame Array.isArray() polyfill for now.
11
+ */
12
+
13
+ if (!Array.isArray) {
14
+ Array.isArray = function(arr){
15
+ return '[object Array]' == Object.prototype.toString.call(arr);
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Lame Object.keys() polyfill for now.
21
+ */
22
+
23
+ if (!Object.keys) {
24
+ Object.keys = function(obj){
25
+ var arr = [];
26
+ for (var key in obj) {
27
+ if (obj.hasOwnProperty(key)) {
28
+ arr.push(key);
29
+ }
30
+ }
31
+ return arr;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Render the given attributes object.
37
+ *
38
+ * @param {Object} obj
39
+ * @return {String}
40
+ * @api private
41
+ */
42
+
43
+ exports.attrs = function attrs(obj){
44
+ var buf = []
45
+ , terse = obj.terse;
46
+ delete obj.terse;
47
+ var keys = Object.keys(obj)
48
+ , len = keys.length;
49
+ if (len) {
50
+ buf.push('');
51
+ for (var i = 0; i < len; ++i) {
52
+ var key = keys[i]
53
+ , val = obj[key];
54
+ if ('boolean' == typeof val || null == val) {
55
+ if (val) {
56
+ terse
57
+ ? buf.push(key)
58
+ : buf.push(key + '="' + key + '"');
59
+ }
60
+ } else if ('class' == key && Array.isArray(val)) {
61
+ buf.push(key + '="' + exports.escape(val.join(' ')) + '"');
62
+ } else {
63
+ buf.push(key + '="' + exports.escape(val) + '"');
64
+ }
65
+ }
66
+ }
67
+ return buf.join(' ');
68
+ };
69
+
70
+ /**
71
+ * Escape the given string of `html`.
72
+ *
73
+ * @param {String} html
74
+ * @return {String}
75
+ * @api private
76
+ */
77
+
78
+ exports.escape = function escape(html){
79
+ return String(html)
80
+ .replace(/&(?!\w+;)/g, '&amp;')
81
+ .replace(/</g, '&lt;')
82
+ .replace(/>/g, '&gt;')
83
+ .replace(/"/g, '&quot;');
84
+ };
85
+
86
+ /**
87
+ * Re-throw the given `err` in context to the
88
+ * the jade in `filename` at the given `lineno`.
89
+ *
90
+ * @param {Error} err
91
+ * @param {String} filename
92
+ * @param {String} lineno
93
+ * @api private
94
+ */
95
+
96
+ exports.rethrow = function rethrow(err, filename, lineno){
97
+ if (!filename) throw err;
98
+
99
+ var context = 3
100
+ , str = require('fs').readFileSync(filename, 'utf8')
101
+ , lines = str.split('\n')
102
+ , start = Math.max(lineno - context, 0)
103
+ , end = Math.min(lines.length, lineno + context);
104
+
105
+ // Error context
106
+ var context = lines.slice(start, end).map(function(line, i){
107
+ var curr = i + start + 1;
108
+ return (curr == lineno ? ' > ' : ' ')
109
+ + curr
110
+ + '| '
111
+ + line;
112
+ }).join('\n');
113
+
114
+ // Alter exception message
115
+ err.path = filename;
116
+ err.message = (filename || 'Jade') + ':' + lineno
117
+ + '\n' + context + '\n\n' + err.message;
118
+ throw err;
119
+ };
120
+
121
+ return exports;
122
+
123
+ })({});