ice 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +80 -3
- data/VERSION +1 -1
- data/ice.gemspec +3 -2
- data/ice_js/lib/path_helper.js +35 -10
- data/ice_js/spec/support/js.jar +0 -0
- data/ice_js/spec/unit/spec.js +92 -9
- data/init.rb +3 -1
- data/lib/extras/ice_view.rb +0 -3
- data/lib/ice/cubeable.rb +0 -1
- data/lib/parser.js +2 -21
- data/spec/cube_spec.rb +0 -1
- data/spec/ice_spec.rb +5 -2
- data/spec/spec_helper.rb +0 -1
- metadata +4 -3
data/README.markdown
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Ice Ice Baby!
|
2
2
|
|
3
|
-
The Ice project allows user-created templates to be written in the javascript programming language.
|
3
|
+
The Ice project allows user-created templates to be written in the javascript programming language. Thanks to the [therubyracer](http://github.com/cowboyd/therubyracer) they are then interpreted using Google's V8 javascript engine.
|
4
4
|
|
5
|
-
Ice
|
5
|
+
Ice is similar to Liquid in terms of safety, but uses javascript to leverage the powers of a language most developers are familiar with. Ice runs the templates through an erb-ish parser (written by [Mark Turansky](http://blog.markturansky.com/BetterJavascriptTemplates.html)).
|
6
|
+
|
7
|
+
Your users can then write Ice templates like:
|
6
8
|
|
7
9
|
<table>
|
8
10
|
<tr><th>Name</th><th>Email</th></tr>
|
@@ -19,7 +21,7 @@ These templates can be run from the appropriate views directory, provided they h
|
|
19
21
|
|
20
22
|
## Why another templating engine when there is Liquid?
|
21
23
|
|
22
|
-
Liquid is excellent but
|
24
|
+
[Liquid](http://github.com/tobi/liquid) is excellent but it showing its age in a few ways:
|
23
25
|
|
24
26
|
* Hard to extend without knowing Liquid internals
|
25
27
|
* Introduces yet-another-language, whereas many designers/developers are already familiar with javascript
|
@@ -28,6 +30,8 @@ Liquid is excellent but has several disadvantages
|
|
28
30
|
|
29
31
|
Note that we're still big fans of Liquid. In fact, we call this project "Ice" as a tribute (extending the metaphor, we use "Cubes" where they have "Drops").
|
30
32
|
|
33
|
+
In addition, our ice_view.rb file is almost directly ripped out of the liquid project.
|
34
|
+
|
31
35
|
## Installation
|
32
36
|
|
33
37
|
For Rails:
|
@@ -79,6 +83,79 @@ This generates association helper functions such as comment_ids, num_comments, h
|
|
79
83
|
|
80
84
|
Note that the results of all associations and revealed functions are also sanitized via to_ice.
|
81
85
|
|
86
|
+
## NavBar
|
87
|
+
|
88
|
+
To make it easier to generate links, we added a NavBar class to the javascript helpers. THis class has an open and close method, as well as a link_to mehod which either takes a url, or a url and a link label.
|
89
|
+
|
90
|
+
<% var nav = new NavBar() %>
|
91
|
+
<%= nav.open() %>
|
92
|
+
<%= nav.link_to("Bar", "/foo") %>
|
93
|
+
<%= nav.link_to("http://ludicast.com") %>
|
94
|
+
<%= nav.close() %>
|
95
|
+
|
96
|
+
This then generates the following html
|
97
|
+
|
98
|
+
<ul class="linkBar">
|
99
|
+
<li><a href="/foo">Bar</a></li>
|
100
|
+
<li><a href="http://ludicast.com">http://ludicast.com</a></li>
|
101
|
+
</ul>
|
102
|
+
|
103
|
+
You'll notice that the resulting html code is shorter than the generator code, making this look inefficient. However the NavBar also takes options so if the NavBar above was instantiated with:
|
104
|
+
|
105
|
+
<% var nav = new NavBar({nav_open:"<div>", nav_close:"</div>",link_wrapper:function(link){
|
106
|
+
return "<span>" + link + "</span>"
|
107
|
+
|
108
|
+
it would automatically generate
|
109
|
+
|
110
|
+
<div>
|
111
|
+
<span><a href="/foo">Bar</a></span>
|
112
|
+
<span><a href="http://ludicast.com">http://ludicast.com</a></span>
|
113
|
+
</div>
|
114
|
+
|
115
|
+
Also, if you want to make a site- or page-wide change, all you need to do is add these options to the NavBar class like
|
116
|
+
|
117
|
+
NavBar.default_options = {nav_open:"<div>", nav_close:"</div>",link_wrapper:function(link){
|
118
|
+
return "<span>" + link + "</span>"
|
119
|
+
}}
|
120
|
+
|
121
|
+
Then all links will generate with these options, unless overridden in the NavBar's constructor. If the NavBar has a separator property added, it will add that separator between links. If a link is not shown (due to access restrictions or whatever in the link_wrapper function) the separator obviously will not appear for that link. So the code
|
122
|
+
|
123
|
+
bar.separator = "---"
|
124
|
+
bar.link_wrapper = function (link) {
|
125
|
+
if (link.match(/aa/)) {
|
126
|
+
return ""
|
127
|
+
} else {
|
128
|
+
return link
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
would cause
|
133
|
+
|
134
|
+
bar.open() + bar.link_to("ff") + bar.link_to("aa") + bar.link_to("gg") + bar.close()
|
135
|
+
|
136
|
+
to render as:
|
137
|
+
|
138
|
+
links.should.eql "<div><a href=\"ff\">ff</a>----<a href=\"gg\">gg</a></div>"
|
139
|
+
|
140
|
+
## Routes
|
141
|
+
|
142
|
+
Keeping with our tradition of stealing from other projects, we took the code from [RouteJs middleware](http://coderack.org/users/kossnocorp/middlewares/88-routesjs) to expose to our templates all your routes. This is a big convenience and lets you put in your templates things like:
|
143
|
+
|
144
|
+
<% var nav = new NavBar() %>
|
145
|
+
<%= nav.open() %>
|
146
|
+
<%= nav.link_to("List Pizzas", pizzas_path() ) %>
|
147
|
+
<%= nav.link_to("Modify Pizza", edit_pizza_path({id: pizza.id})) %>
|
148
|
+
<%= nav.close() %>
|
149
|
+
|
150
|
+
which is converted into
|
151
|
+
|
152
|
+
<ul class="linkBar">
|
153
|
+
<li><a href="/pizzas">List Pizzas</a></li>
|
154
|
+
<li><a href="/pizzas/2/edit">Modify Pizza</a></li>
|
155
|
+
</ul>
|
156
|
+
|
157
|
+
Note that some people might claim that it is insecure to expose your resources like this, but that probably should be dealt with on a case-by-case basis.
|
158
|
+
|
82
159
|
## Note on Patches/Pull Requests
|
83
160
|
|
84
161
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
data/ice.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ice}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nate Kidwell"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-09}
|
13
13
|
s.description = %q{User templates written in javascript}
|
14
14
|
s.email = %q{nate@ludicast.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
"ice_js/spec/rhino.js",
|
34
34
|
"ice_js/spec/server.html",
|
35
35
|
"ice_js/spec/server.rb",
|
36
|
+
"ice_js/spec/support/js.jar",
|
36
37
|
"ice_js/spec/unit/spec.helper.js",
|
37
38
|
"ice_js/spec/unit/spec.js",
|
38
39
|
"init.rb",
|
data/ice_js/lib/path_helper.js
CHANGED
@@ -1,24 +1,49 @@
|
|
1
|
-
function link_to(
|
2
|
-
if (!
|
3
|
-
|
1
|
+
function link_to(label, link, opts) {
|
2
|
+
if (! link) {
|
3
|
+
link = label
|
4
4
|
}
|
5
|
-
|
6
|
-
return "<a href=\"" + location + "\">" + label + "</a>"
|
5
|
+
return "<a href=\"" + link + "\">" + label + "</a>"
|
7
6
|
}
|
8
7
|
|
9
|
-
var NavBar = function () {
|
8
|
+
var NavBar = function (options) {
|
9
|
+
var defaults = NavBar.default_options
|
10
|
+
for (var default_option in defaults) {
|
11
|
+
if (defaults.hasOwnProperty(default_option)) {
|
12
|
+
this[default_option] = defaults[default_option]
|
13
|
+
}
|
14
|
+
}
|
10
15
|
|
16
|
+
for (var option in options) {
|
17
|
+
if (options.hasOwnProperty(option)) {
|
18
|
+
this[option] = options[option]
|
19
|
+
}
|
20
|
+
}
|
11
21
|
}
|
12
22
|
|
13
|
-
NavBar.prototype.link_to = function (link) {
|
14
|
-
|
23
|
+
NavBar.prototype.link_to = function (label, link) {
|
24
|
+
link_code = link_to(label, link)
|
25
|
+
|
26
|
+
if (this.link_wrapper) {
|
27
|
+
link_data = this.link_wrapper(link_code)
|
28
|
+
} else {
|
29
|
+
link_data = "<li>" + link_code + "</li>"
|
30
|
+
}
|
31
|
+
if (link_data) {
|
32
|
+
if (this.link_data && this.separator) {
|
33
|
+
link_data = this.separator + link_data
|
34
|
+
}
|
35
|
+
this.link_data = link_data
|
36
|
+
}
|
37
|
+
return link_data;
|
15
38
|
}
|
16
39
|
|
40
|
+
|
17
41
|
NavBar.prototype.open = function () {
|
18
|
-
return "<ul class=\"linkBar\">"
|
42
|
+
return this.nav_open || "<ul class=\"linkBar\">"
|
19
43
|
}
|
20
44
|
|
21
45
|
NavBar.prototype.close = function () {
|
22
|
-
return "</ul>"
|
46
|
+
return this.nav_close || "</ul>"
|
23
47
|
}
|
24
48
|
|
49
|
+
NavBar.default_options = {}
|
Binary file
|
data/ice_js/spec/unit/spec.js
CHANGED
@@ -1,17 +1,100 @@
|
|
1
|
-
describe "
|
2
|
-
|
3
|
-
|
1
|
+
describe "NavBar"
|
2
|
+
|
3
|
+
describe "by default"
|
4
|
+
before_each
|
5
|
+
bar = new NavBar()
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
it "should generate list by default"
|
10
|
+
(bar.open() + bar.close()).should.eql "<ul class=\"linkBar\"></ul>"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should generate list with internal links"
|
14
|
+
|
15
|
+
links = (bar.open() + bar.link_to("ff") + bar.link_to("aa") + bar.close())
|
16
|
+
|
17
|
+
links.should.eql "<ul class=\"linkBar\"><li><a href=\"ff\">ff</a></li><li><a href=\"aa\">aa</a></li></ul>"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should take optional titles"
|
21
|
+
|
22
|
+
links = (bar.open() + bar.link_to("ff", "aa") + bar.close())
|
23
|
+
|
24
|
+
links.should.eql "<ul class=\"linkBar\"><li><a href=\"aa\">ff</a></li></ul>"
|
25
|
+
end
|
26
|
+
|
4
27
|
end
|
5
28
|
|
29
|
+
describe "with options"
|
30
|
+
before_each
|
31
|
+
bar = new NavBar( {nav_open:"<div>", nav_close:"</div>",link_wrapper:function(link){
|
32
|
+
return "<span>" + link + "</span>"
|
33
|
+
}} )
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should generate list with wrappers"
|
37
|
+
links = (bar.open() + bar.link_to("ff") + bar.close())
|
38
|
+
|
39
|
+
links.should.eql "<div><span><a href=\"ff\">ff</a></span></div>"
|
40
|
+
end
|
6
41
|
|
7
|
-
it "should generate list by default"
|
8
|
-
(bar.open() + bar.close()).should.eql "<ul class=\"linkBar\"></ul>"
|
9
42
|
end
|
10
43
|
|
11
|
-
|
44
|
+
describe "with separator"
|
45
|
+
before_each
|
46
|
+
separator = " --- "
|
47
|
+
bar = new NavBar({separator: separator})
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not separate single links"
|
51
|
+
links = (bar.open() + bar.link_to("ff") + bar.close())
|
52
|
+
links.should.eql "<ul class=\"linkBar\"><li><a href=\"ff\">ff</a></li></ul>"
|
53
|
+
end
|
12
54
|
|
13
|
-
|
55
|
+
it "should separate multiple links"
|
56
|
+
links = (bar.open() + bar.link_to("ff") + bar.link_to("aa") + bar.close())
|
57
|
+
links.should.eql "<ul class=\"linkBar\"><li><a href=\"ff\">ff</a></li>" + separator + "<li><a href=\"aa\">aa</a></li></ul>"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not display for missing links"
|
61
|
+
bar.nav_open = "<div>"
|
62
|
+
bar.nav_close = "</div>"
|
63
|
+
bar.link_wrapper = function (link) {
|
64
|
+
if (link.match(/aa/)) {
|
65
|
+
return ""
|
66
|
+
} else {
|
67
|
+
return link
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
links = (bar.open() + bar.link_to("ff") + bar.link_to("aa") + bar.link_to("gg") + bar.close())
|
72
|
+
links.should.eql "<div><a href=\"ff\">ff</a>" + separator + "<a href=\"gg\">gg</a></div>"
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
describe "with class-wide options"
|
79
|
+
before_each
|
80
|
+
NavBar.default_options = {nav_open:"<div>", nav_close:"</div>",link_wrapper:function(link){
|
81
|
+
return "<span>" + link + "</span>"
|
82
|
+
}}
|
83
|
+
bar = new NavBar( )
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should generate list with wrappers"
|
87
|
+
links = (bar.open() + bar.link_to("ff") + bar.close())
|
88
|
+
|
89
|
+
links.should.eql "<div><span><a href=\"ff\">ff</a></span></div>"
|
90
|
+
end
|
91
|
+
|
92
|
+
after_each
|
93
|
+
NavBar.default_options = {}
|
94
|
+
end
|
14
95
|
|
15
|
-
links.should.eql "<ul class=\"linkBar\"><li><a href=\"ff\">ff</a></li><li><a href=\"aa\">aa</a></li></ul>"
|
16
96
|
end
|
17
|
-
|
97
|
+
|
98
|
+
|
99
|
+
end
|
100
|
+
|
data/init.rb
CHANGED
data/lib/extras/ice_view.rb
CHANGED
@@ -44,12 +44,9 @@ class IceView
|
|
44
44
|
assigns.merge!(local_assigns.stringify_keys)
|
45
45
|
|
46
46
|
route_functions = "<% " + get_routes + " %>"
|
47
|
-
puts route_functions
|
48
|
-
5.times {puts "****************************"}
|
49
47
|
|
50
48
|
path_helper_code = File.read(File.dirname(__FILE__) + "/../../ice_js/lib/path_helper.js")
|
51
49
|
path_helper = "<% " + path_helper_code + " %>"
|
52
|
-
puts path_helper
|
53
50
|
source = route_functions + path_helper + source
|
54
51
|
|
55
52
|
|
data/lib/ice/cubeable.rb
CHANGED
data/lib/parser.js
CHANGED
@@ -256,19 +256,6 @@ var Jst = function () {
|
|
256
256
|
return fragment.toString();
|
257
257
|
}
|
258
258
|
|
259
|
-
function safeWrite(s) {
|
260
|
-
s = s.toString();
|
261
|
-
s = s.replaceAll('&', '&');
|
262
|
-
s = s.replaceAll('"', '"');
|
263
|
-
s = s.replaceAll('<', '<');
|
264
|
-
s = s.replaceAll('>', '>');
|
265
|
-
html += s;
|
266
|
-
}
|
267
|
-
|
268
|
-
function safeWriteln(s) {
|
269
|
-
safeWrite(s + "\n");
|
270
|
-
}
|
271
|
-
|
272
259
|
function write(s) {
|
273
260
|
html += s;
|
274
261
|
}
|
@@ -292,14 +279,8 @@ var Jst = function () {
|
|
292
279
|
c = stack.pop();
|
293
280
|
if (stack.peek() == '%') { //delimiter!
|
294
281
|
c = stack.pop();
|
295
|
-
if (stack.peek() == "=") {
|
296
|
-
//
|
297
|
-
stack.pop();
|
298
|
-
fragment = parseExpression(stack);
|
299
|
-
appendExpressionFragment(writer, fragment,
|
300
|
-
"safeWrite");
|
301
|
-
} else if (stack.peek() == "+") {
|
302
|
-
// expression, don't escape html
|
282
|
+
if (stack.peek() == "=" || stack.peek() == "+") {
|
283
|
+
//not escaping html right now
|
303
284
|
stack.pop()
|
304
285
|
fragment = parseExpression(stack);
|
305
286
|
appendExpressionFragment(writer, fragment,
|
data/spec/cube_spec.rb
CHANGED
data/spec/ice_spec.rb
CHANGED
@@ -2,8 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe "Ice" do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
5
|
it "converts a javascript template to html" do
|
8
6
|
Ice.convert_template("<%= 'hello world' %>").should == "hello world"
|
9
7
|
end
|
@@ -13,6 +11,11 @@ describe "Ice" do
|
|
13
11
|
Ice.convert_template("<%= hola + ' ' + mundo %>", vars).should == "hello world"
|
14
12
|
end
|
15
13
|
|
14
|
+
it "accepts ampersands" do
|
15
|
+
vars = {:foo => "&"}
|
16
|
+
Ice.convert_template("<%= foo %>", vars).should == "&"
|
17
|
+
end
|
18
|
+
|
16
19
|
it "takes variables as string" do
|
17
20
|
vars = {'hola' => "hello", 'mundo' => "world" }
|
18
21
|
Ice.convert_template("<%= hola + ' ' + mundo %>", vars).should == "hello world"
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 3
|
9
|
+
version: 0.2.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nate Kidwell
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-09 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- ice_js/spec/rhino.js
|
86
86
|
- ice_js/spec/server.html
|
87
87
|
- ice_js/spec/server.rb
|
88
|
+
- ice_js/spec/support/js.jar
|
88
89
|
- ice_js/spec/unit/spec.helper.js
|
89
90
|
- ice_js/spec/unit/spec.js
|
90
91
|
- init.rb
|