ejs-rcompiler 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +60 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +1 -0
- data/ejs-rcompiler.gemspec +68 -0
- data/lib/ejs/compiler.rb +91 -0
- data/lib/ejs/grammar.rb +658 -0
- data/lib/ejs/grammar.treetop +91 -0
- data/lib/ejs/parse_error.rb +11 -0
- data/lib/ejs/parser.rb +8 -0
- data/lib/ejs-rcompiler.rb +1 -0
- data/spec/compiler_spec.rb +70 -0
- data/spec/fixtures/Cities.ejs +6 -0
- data/spec/fixtures/Cities.js +21 -0
- data/spec/parser_spec.rb +57 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +25 -0
- metadata +111 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ben Curren
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
= ejs-rcompiler
|
2
|
+
|
3
|
+
A simple ruby compiler that compiles an ejs file to js. Here is an example usage:
|
4
|
+
|
5
|
+
== In file named or.ui.Cities.ejs
|
6
|
+
<ul>
|
7
|
+
<%# Loop through each city %>
|
8
|
+
<% $.each(cities, function() { %>
|
9
|
+
<li><%= this.name %></li>
|
10
|
+
<% }) %>
|
11
|
+
</ul>
|
12
|
+
|
13
|
+
== Compile the file like so
|
14
|
+
compiler = Ejs::Compiler.new
|
15
|
+
compiler.compile(ejs_file)
|
16
|
+
|
17
|
+
This will create a .js file with a JavaScript class name that matches the file name.
|
18
|
+
|
19
|
+
== You can then require the output js file as such.
|
20
|
+
<script src="/javascripts/or.ui.Cities.js"></script>
|
21
|
+
<script>
|
22
|
+
document.body.innerHTML = or.ui.Cities.template({
|
23
|
+
cities: [{ name: "Paris" }, { name: "Mountain View" }, { name: "Las Vegas" }]
|
24
|
+
});
|
25
|
+
</script>
|
26
|
+
|
27
|
+
== Note on Patches/Pull Requests
|
28
|
+
|
29
|
+
* Fork the project.
|
30
|
+
* Make your feature addition or bug fix.
|
31
|
+
* Add tests for it. This is important so I don't break it in a
|
32
|
+
future version unintentionally.
|
33
|
+
* Commit, do not mess with rakefile, version, or history.
|
34
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
35
|
+
* Send me a pull request. Bonus points for topic branches.
|
36
|
+
|
37
|
+
== Copyright
|
38
|
+
|
39
|
+
Copyright (c) 2010 Ben Curren. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ejs-rcompiler"
|
8
|
+
gem.summary = %Q{Ejs to Javascript compiler written in Ruby. This allows you to define HTML heavy Javascript components in EJS and compile them down to Javascript functions for later use.}
|
9
|
+
gem.description = %Q{Ejs to Javascript compiler.}
|
10
|
+
gem.email = "ben@outright.com"
|
11
|
+
gem.homepage = "http://github.com/bcurren/ejs-rcompiler"
|
12
|
+
gem.authors = ["Ben Curren"]
|
13
|
+
gem.add_dependency "treetop", ">= 1.4.0"
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "ejs-rcompiler #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
47
|
+
|
48
|
+
PARSER_FILE="lib/ejs/grammar.rb"
|
49
|
+
GRAMMAR_FILE="lib/ejs/grammar.treetop"
|
50
|
+
|
51
|
+
namespace :treetop do
|
52
|
+
desc "Generate parser from treetop grammar."
|
53
|
+
task :generate => PARSER_FILE
|
54
|
+
end
|
55
|
+
|
56
|
+
file PARSER_FILE => GRAMMAR_FILE do |t|
|
57
|
+
require 'treetop'
|
58
|
+
compiler = Treetop::Compiler::GrammarCompiler.new
|
59
|
+
compiler.compile(t.prerequisites[0], t.name)
|
60
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec" }
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ejs-rcompiler}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ben Curren"]
|
12
|
+
s.date = %q{2010-09-27}
|
13
|
+
s.description = %q{Ejs to Javascript compiler.}
|
14
|
+
s.email = %q{ben@outright.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"autotest/discover.rb",
|
27
|
+
"ejs-rcompiler.gemspec",
|
28
|
+
"lib/ejs-rcompiler.rb",
|
29
|
+
"lib/ejs/compiler.rb",
|
30
|
+
"lib/ejs/grammar.rb",
|
31
|
+
"lib/ejs/grammar.treetop",
|
32
|
+
"lib/ejs/parse_error.rb",
|
33
|
+
"lib/ejs/parser.rb",
|
34
|
+
"spec/compiler_spec.rb",
|
35
|
+
"spec/fixtures/Cities.ejs",
|
36
|
+
"spec/fixtures/Cities.js",
|
37
|
+
"spec/parser_spec.rb",
|
38
|
+
"spec/spec.opts",
|
39
|
+
"spec/spec_helper.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/bcurren/ejs-rcompiler}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.6}
|
45
|
+
s.summary = %q{Ejs to Javascript compiler written in Ruby. This allows you to define HTML heavy Javascript components in EJS and compile them down to Javascript functions for later use.}
|
46
|
+
s.test_files = [
|
47
|
+
"spec/compiler_spec.rb",
|
48
|
+
"spec/parser_spec.rb",
|
49
|
+
"spec/spec_helper.rb"
|
50
|
+
]
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
54
|
+
s.specification_version = 3
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_runtime_dependency(%q<treetop>, [">= 1.4.0"])
|
58
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<treetop>, [">= 1.4.0"])
|
61
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<treetop>, [">= 1.4.0"])
|
65
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/ejs/compiler.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/parser")
|
2
|
+
require File.expand_path("#{File.dirname(__FILE__)}/parse_error")
|
3
|
+
|
4
|
+
module Ejs
|
5
|
+
AUTOGENERATED = "// Autogenerated from an Ejs file. Edits may be lost.\n"
|
6
|
+
|
7
|
+
class Compiler
|
8
|
+
def initialize
|
9
|
+
@parser = Parser.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile(source_path, namespace = nil, target_path = source_path.gsub(/\.ejs\Z/, '.js'))
|
13
|
+
File.open(target_path, 'w') do |target_file|
|
14
|
+
target_file.write(AUTOGENERATED+"\n\n")
|
15
|
+
target_file.write(js_source(source_path, namespace))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# compile a ejs file into javascript
|
20
|
+
def js_source(source_path, namespace = nil, output_as_array = false)
|
21
|
+
template_name = File.basename(source_path, ".ejs")
|
22
|
+
template_name = "#{namespace}.#{template_name}" if namespace
|
23
|
+
|
24
|
+
js_source_from_string(template_name, File.read(source_path), output_as_array)
|
25
|
+
end
|
26
|
+
|
27
|
+
# compile a string containing ejs source into javascript
|
28
|
+
def js_source_from_string(template_name, content, output_as_array = false)
|
29
|
+
buffer = []
|
30
|
+
parsed = @parser.parse(content)
|
31
|
+
if parsed.nil?
|
32
|
+
raise ParseError.new(@parser.failure_reason, @parser.failure_line, @parser.failure_column)
|
33
|
+
end
|
34
|
+
|
35
|
+
template_namespace(buffer, template_name)
|
36
|
+
template_header(buffer, template_name)
|
37
|
+
parsed.elements.each do |element|
|
38
|
+
push_content(buffer, element)
|
39
|
+
end
|
40
|
+
template_footer(buffer)
|
41
|
+
|
42
|
+
output_as_array ? buffer : buffer.join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def template_namespace(buffer, template_name)
|
48
|
+
ns = template_name.split(".")
|
49
|
+
ns_str = "window"
|
50
|
+
begin
|
51
|
+
ns_str = "#{ns_str}.#{ns.shift}"
|
52
|
+
buffer.push("#{ns_str} = #{ns_str} || {};")
|
53
|
+
end until ns.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def template_header(buffer, template_name)
|
57
|
+
buffer.push("#{template_name}.template = function(options) {")
|
58
|
+
buffer.push(" var p = [];")
|
59
|
+
buffer.push(" with(options) {")
|
60
|
+
end
|
61
|
+
|
62
|
+
def push_content(buffer, element)
|
63
|
+
case element.node_type
|
64
|
+
when 'static_content'
|
65
|
+
buffer.push(" p.push('#{escape(element.text_value)}');")
|
66
|
+
when 'scriplet'
|
67
|
+
buffer.push(" #{element.text_value.strip}")
|
68
|
+
when 'expression'
|
69
|
+
buffer.push(" p.push(#{element.text_value.strip});")
|
70
|
+
when 'comment'
|
71
|
+
buffer.push(" /*#{element.text_value}*/")
|
72
|
+
else
|
73
|
+
raise "Unknown node_type encountered while parsing: #{element.node_type}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def template_footer(buffer)
|
78
|
+
buffer.push(" }")
|
79
|
+
buffer.push(" return p.join('');")
|
80
|
+
buffer.push("}")
|
81
|
+
end
|
82
|
+
|
83
|
+
def escape(content)
|
84
|
+
content.
|
85
|
+
gsub(/\n/, '\n').
|
86
|
+
gsub(/\t/, '\t').
|
87
|
+
gsub(/"/, '\"').
|
88
|
+
gsub(/'/, "\\\\'") # yes, this is how you escape a single quote
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/ejs/grammar.rb
ADDED
@@ -0,0 +1,658 @@
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
module Ejs
|
5
|
+
module Grammar
|
6
|
+
include Treetop::Runtime
|
7
|
+
|
8
|
+
def root
|
9
|
+
@root ||= :program
|
10
|
+
end
|
11
|
+
|
12
|
+
def _nt_program
|
13
|
+
start_index = index
|
14
|
+
if node_cache[:program].has_key?(index)
|
15
|
+
cached = node_cache[:program][index]
|
16
|
+
if cached
|
17
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
18
|
+
@index = cached.interval.end
|
19
|
+
end
|
20
|
+
return cached
|
21
|
+
end
|
22
|
+
|
23
|
+
s0, i0 = [], index
|
24
|
+
loop do
|
25
|
+
i1 = index
|
26
|
+
r2 = _nt_expression
|
27
|
+
if r2
|
28
|
+
r1 = r2
|
29
|
+
else
|
30
|
+
r3 = _nt_comment
|
31
|
+
if r3
|
32
|
+
r1 = r3
|
33
|
+
else
|
34
|
+
r4 = _nt_scriplet
|
35
|
+
if r4
|
36
|
+
r1 = r4
|
37
|
+
else
|
38
|
+
r5 = _nt_static_content
|
39
|
+
if r5
|
40
|
+
r1 = r5
|
41
|
+
else
|
42
|
+
@index = i1
|
43
|
+
r1 = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
if r1
|
49
|
+
s0 << r1
|
50
|
+
else
|
51
|
+
break
|
52
|
+
end
|
53
|
+
end
|
54
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
55
|
+
|
56
|
+
node_cache[:program][start_index] = r0
|
57
|
+
|
58
|
+
r0
|
59
|
+
end
|
60
|
+
|
61
|
+
module Expression0
|
62
|
+
def script_content
|
63
|
+
elements[1]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
module Expression1
|
69
|
+
def node_type
|
70
|
+
"expression"
|
71
|
+
end
|
72
|
+
|
73
|
+
def text_value
|
74
|
+
script_content.text_value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def _nt_expression
|
79
|
+
start_index = index
|
80
|
+
if node_cache[:expression].has_key?(index)
|
81
|
+
cached = node_cache[:expression][index]
|
82
|
+
if cached
|
83
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
84
|
+
@index = cached.interval.end
|
85
|
+
end
|
86
|
+
return cached
|
87
|
+
end
|
88
|
+
|
89
|
+
i0, s0 = index, []
|
90
|
+
if has_terminal?('<%=', false, index)
|
91
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
92
|
+
@index += 3
|
93
|
+
else
|
94
|
+
terminal_parse_failure('<%=')
|
95
|
+
r1 = nil
|
96
|
+
end
|
97
|
+
s0 << r1
|
98
|
+
if r1
|
99
|
+
r2 = _nt_script_content
|
100
|
+
s0 << r2
|
101
|
+
if r2
|
102
|
+
if has_terminal?('%>', false, index)
|
103
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
104
|
+
@index += 2
|
105
|
+
else
|
106
|
+
terminal_parse_failure('%>')
|
107
|
+
r3 = nil
|
108
|
+
end
|
109
|
+
s0 << r3
|
110
|
+
end
|
111
|
+
end
|
112
|
+
if s0.last
|
113
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
114
|
+
r0.extend(Expression0)
|
115
|
+
r0.extend(Expression1)
|
116
|
+
else
|
117
|
+
@index = i0
|
118
|
+
r0 = nil
|
119
|
+
end
|
120
|
+
|
121
|
+
node_cache[:expression][start_index] = r0
|
122
|
+
|
123
|
+
r0
|
124
|
+
end
|
125
|
+
|
126
|
+
module Comment0
|
127
|
+
def script_content
|
128
|
+
elements[1]
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
module Comment1
|
134
|
+
def node_type
|
135
|
+
"comment"
|
136
|
+
end
|
137
|
+
|
138
|
+
def text_value
|
139
|
+
script_content.text_value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def _nt_comment
|
144
|
+
start_index = index
|
145
|
+
if node_cache[:comment].has_key?(index)
|
146
|
+
cached = node_cache[:comment][index]
|
147
|
+
if cached
|
148
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
149
|
+
@index = cached.interval.end
|
150
|
+
end
|
151
|
+
return cached
|
152
|
+
end
|
153
|
+
|
154
|
+
i0, s0 = index, []
|
155
|
+
if has_terminal?('<%#', false, index)
|
156
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
157
|
+
@index += 3
|
158
|
+
else
|
159
|
+
terminal_parse_failure('<%#')
|
160
|
+
r1 = nil
|
161
|
+
end
|
162
|
+
s0 << r1
|
163
|
+
if r1
|
164
|
+
r2 = _nt_script_content
|
165
|
+
s0 << r2
|
166
|
+
if r2
|
167
|
+
if has_terminal?('%>', false, index)
|
168
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
169
|
+
@index += 2
|
170
|
+
else
|
171
|
+
terminal_parse_failure('%>')
|
172
|
+
r3 = nil
|
173
|
+
end
|
174
|
+
s0 << r3
|
175
|
+
end
|
176
|
+
end
|
177
|
+
if s0.last
|
178
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
179
|
+
r0.extend(Comment0)
|
180
|
+
r0.extend(Comment1)
|
181
|
+
else
|
182
|
+
@index = i0
|
183
|
+
r0 = nil
|
184
|
+
end
|
185
|
+
|
186
|
+
node_cache[:comment][start_index] = r0
|
187
|
+
|
188
|
+
r0
|
189
|
+
end
|
190
|
+
|
191
|
+
module Scriplet0
|
192
|
+
def script_content
|
193
|
+
elements[1]
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
module Scriplet1
|
199
|
+
def node_type
|
200
|
+
"scriplet"
|
201
|
+
end
|
202
|
+
|
203
|
+
def text_value
|
204
|
+
script_content.text_value
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def _nt_scriplet
|
209
|
+
start_index = index
|
210
|
+
if node_cache[:scriplet].has_key?(index)
|
211
|
+
cached = node_cache[:scriplet][index]
|
212
|
+
if cached
|
213
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
214
|
+
@index = cached.interval.end
|
215
|
+
end
|
216
|
+
return cached
|
217
|
+
end
|
218
|
+
|
219
|
+
i0, s0 = index, []
|
220
|
+
if has_terminal?('<%', false, index)
|
221
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
222
|
+
@index += 2
|
223
|
+
else
|
224
|
+
terminal_parse_failure('<%')
|
225
|
+
r1 = nil
|
226
|
+
end
|
227
|
+
s0 << r1
|
228
|
+
if r1
|
229
|
+
r2 = _nt_script_content
|
230
|
+
s0 << r2
|
231
|
+
if r2
|
232
|
+
if has_terminal?('%>', false, index)
|
233
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
234
|
+
@index += 2
|
235
|
+
else
|
236
|
+
terminal_parse_failure('%>')
|
237
|
+
r3 = nil
|
238
|
+
end
|
239
|
+
s0 << r3
|
240
|
+
end
|
241
|
+
end
|
242
|
+
if s0.last
|
243
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
244
|
+
r0.extend(Scriplet0)
|
245
|
+
r0.extend(Scriplet1)
|
246
|
+
else
|
247
|
+
@index = i0
|
248
|
+
r0 = nil
|
249
|
+
end
|
250
|
+
|
251
|
+
node_cache[:scriplet][start_index] = r0
|
252
|
+
|
253
|
+
r0
|
254
|
+
end
|
255
|
+
|
256
|
+
module StaticContent0
|
257
|
+
def node_type
|
258
|
+
"static_content"
|
259
|
+
end
|
260
|
+
|
261
|
+
def text_value
|
262
|
+
elements.map do |element|
|
263
|
+
element.text_value
|
264
|
+
end.join('')
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def _nt_static_content
|
269
|
+
start_index = index
|
270
|
+
if node_cache[:static_content].has_key?(index)
|
271
|
+
cached = node_cache[:static_content][index]
|
272
|
+
if cached
|
273
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
274
|
+
@index = cached.interval.end
|
275
|
+
end
|
276
|
+
return cached
|
277
|
+
end
|
278
|
+
|
279
|
+
s0, i0 = [], index
|
280
|
+
loop do
|
281
|
+
i1 = index
|
282
|
+
r2 = _nt_right_delimeter_escaped
|
283
|
+
if r2
|
284
|
+
r1 = r2
|
285
|
+
else
|
286
|
+
r3 = _nt_left_delimeter_escaped
|
287
|
+
if r3
|
288
|
+
r1 = r3
|
289
|
+
else
|
290
|
+
r4 = _nt_unescaped_static_content
|
291
|
+
if r4
|
292
|
+
r1 = r4
|
293
|
+
else
|
294
|
+
@index = i1
|
295
|
+
r1 = nil
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
if r1
|
300
|
+
s0 << r1
|
301
|
+
else
|
302
|
+
break
|
303
|
+
end
|
304
|
+
end
|
305
|
+
if s0.empty?
|
306
|
+
@index = i0
|
307
|
+
r0 = nil
|
308
|
+
else
|
309
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
310
|
+
r0.extend(StaticContent0)
|
311
|
+
end
|
312
|
+
|
313
|
+
node_cache[:static_content][start_index] = r0
|
314
|
+
|
315
|
+
r0
|
316
|
+
end
|
317
|
+
|
318
|
+
module ScriptContent0
|
319
|
+
def text_value
|
320
|
+
elements.map do |element|
|
321
|
+
element.text_value
|
322
|
+
end.join('')
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def _nt_script_content
|
327
|
+
start_index = index
|
328
|
+
if node_cache[:script_content].has_key?(index)
|
329
|
+
cached = node_cache[:script_content][index]
|
330
|
+
if cached
|
331
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
332
|
+
@index = cached.interval.end
|
333
|
+
end
|
334
|
+
return cached
|
335
|
+
end
|
336
|
+
|
337
|
+
s0, i0 = [], index
|
338
|
+
loop do
|
339
|
+
i1 = index
|
340
|
+
r2 = _nt_right_delimeter_escaped
|
341
|
+
if r2
|
342
|
+
r1 = r2
|
343
|
+
else
|
344
|
+
r3 = _nt_left_delimeter_escaped
|
345
|
+
if r3
|
346
|
+
r1 = r3
|
347
|
+
else
|
348
|
+
r4 = _nt_unescape_script_content
|
349
|
+
if r4
|
350
|
+
r1 = r4
|
351
|
+
else
|
352
|
+
@index = i1
|
353
|
+
r1 = nil
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
if r1
|
358
|
+
s0 << r1
|
359
|
+
else
|
360
|
+
break
|
361
|
+
end
|
362
|
+
end
|
363
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
364
|
+
r0.extend(ScriptContent0)
|
365
|
+
|
366
|
+
node_cache[:script_content][start_index] = r0
|
367
|
+
|
368
|
+
r0
|
369
|
+
end
|
370
|
+
|
371
|
+
module RightDelimeterEscaped0
|
372
|
+
def text_value
|
373
|
+
'%>'
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def _nt_right_delimeter_escaped
|
378
|
+
start_index = index
|
379
|
+
if node_cache[:right_delimeter_escaped].has_key?(index)
|
380
|
+
cached = node_cache[:right_delimeter_escaped][index]
|
381
|
+
if cached
|
382
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
383
|
+
@index = cached.interval.end
|
384
|
+
end
|
385
|
+
return cached
|
386
|
+
end
|
387
|
+
|
388
|
+
if has_terminal?('%%>', false, index)
|
389
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
390
|
+
r0.extend(RightDelimeterEscaped0)
|
391
|
+
@index += 3
|
392
|
+
else
|
393
|
+
terminal_parse_failure('%%>')
|
394
|
+
r0 = nil
|
395
|
+
end
|
396
|
+
|
397
|
+
node_cache[:right_delimeter_escaped][start_index] = r0
|
398
|
+
|
399
|
+
r0
|
400
|
+
end
|
401
|
+
|
402
|
+
module LeftDelimeterEscaped0
|
403
|
+
def text_value
|
404
|
+
'<%'
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def _nt_left_delimeter_escaped
|
409
|
+
start_index = index
|
410
|
+
if node_cache[:left_delimeter_escaped].has_key?(index)
|
411
|
+
cached = node_cache[:left_delimeter_escaped][index]
|
412
|
+
if cached
|
413
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
414
|
+
@index = cached.interval.end
|
415
|
+
end
|
416
|
+
return cached
|
417
|
+
end
|
418
|
+
|
419
|
+
if has_terminal?('<%%', false, index)
|
420
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
421
|
+
r0.extend(LeftDelimeterEscaped0)
|
422
|
+
@index += 3
|
423
|
+
else
|
424
|
+
terminal_parse_failure('<%%')
|
425
|
+
r0 = nil
|
426
|
+
end
|
427
|
+
|
428
|
+
node_cache[:left_delimeter_escaped][start_index] = r0
|
429
|
+
|
430
|
+
r0
|
431
|
+
end
|
432
|
+
|
433
|
+
module UnescapedStaticContent0
|
434
|
+
end
|
435
|
+
|
436
|
+
def _nt_unescaped_static_content
|
437
|
+
start_index = index
|
438
|
+
if node_cache[:unescaped_static_content].has_key?(index)
|
439
|
+
cached = node_cache[:unescaped_static_content][index]
|
440
|
+
if cached
|
441
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
442
|
+
@index = cached.interval.end
|
443
|
+
end
|
444
|
+
return cached
|
445
|
+
end
|
446
|
+
|
447
|
+
s0, i0 = [], index
|
448
|
+
loop do
|
449
|
+
i1, s1 = index, []
|
450
|
+
i2 = index
|
451
|
+
if has_terminal?('<%%', false, index)
|
452
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
453
|
+
@index += 3
|
454
|
+
else
|
455
|
+
terminal_parse_failure('<%%')
|
456
|
+
r3 = nil
|
457
|
+
end
|
458
|
+
if r3
|
459
|
+
r2 = nil
|
460
|
+
else
|
461
|
+
@index = i2
|
462
|
+
r2 = instantiate_node(SyntaxNode,input, index...index)
|
463
|
+
end
|
464
|
+
s1 << r2
|
465
|
+
if r2
|
466
|
+
i4 = index
|
467
|
+
if has_terminal?('%%>', false, index)
|
468
|
+
r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
469
|
+
@index += 3
|
470
|
+
else
|
471
|
+
terminal_parse_failure('%%>')
|
472
|
+
r5 = nil
|
473
|
+
end
|
474
|
+
if r5
|
475
|
+
r4 = nil
|
476
|
+
else
|
477
|
+
@index = i4
|
478
|
+
r4 = instantiate_node(SyntaxNode,input, index...index)
|
479
|
+
end
|
480
|
+
s1 << r4
|
481
|
+
if r4
|
482
|
+
i6 = index
|
483
|
+
if has_terminal?('<%', false, index)
|
484
|
+
r7 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
485
|
+
@index += 2
|
486
|
+
else
|
487
|
+
terminal_parse_failure('<%')
|
488
|
+
r7 = nil
|
489
|
+
end
|
490
|
+
if r7
|
491
|
+
r6 = nil
|
492
|
+
else
|
493
|
+
@index = i6
|
494
|
+
r6 = instantiate_node(SyntaxNode,input, index...index)
|
495
|
+
end
|
496
|
+
s1 << r6
|
497
|
+
if r6
|
498
|
+
i8 = index
|
499
|
+
if has_terminal?('%>', false, index)
|
500
|
+
r9 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
501
|
+
@index += 2
|
502
|
+
else
|
503
|
+
terminal_parse_failure('%>')
|
504
|
+
r9 = nil
|
505
|
+
end
|
506
|
+
if r9
|
507
|
+
r8 = nil
|
508
|
+
else
|
509
|
+
@index = i8
|
510
|
+
r8 = instantiate_node(SyntaxNode,input, index...index)
|
511
|
+
end
|
512
|
+
s1 << r8
|
513
|
+
if r8
|
514
|
+
if index < input_length
|
515
|
+
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
516
|
+
@index += 1
|
517
|
+
else
|
518
|
+
terminal_parse_failure("any character")
|
519
|
+
r10 = nil
|
520
|
+
end
|
521
|
+
s1 << r10
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
if s1.last
|
527
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
528
|
+
r1.extend(UnescapedStaticContent0)
|
529
|
+
else
|
530
|
+
@index = i1
|
531
|
+
r1 = nil
|
532
|
+
end
|
533
|
+
if r1
|
534
|
+
s0 << r1
|
535
|
+
else
|
536
|
+
break
|
537
|
+
end
|
538
|
+
end
|
539
|
+
if s0.empty?
|
540
|
+
@index = i0
|
541
|
+
r0 = nil
|
542
|
+
else
|
543
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
544
|
+
end
|
545
|
+
|
546
|
+
node_cache[:unescaped_static_content][start_index] = r0
|
547
|
+
|
548
|
+
r0
|
549
|
+
end
|
550
|
+
|
551
|
+
module UnescapeScriptContent0
|
552
|
+
end
|
553
|
+
|
554
|
+
def _nt_unescape_script_content
|
555
|
+
start_index = index
|
556
|
+
if node_cache[:unescape_script_content].has_key?(index)
|
557
|
+
cached = node_cache[:unescape_script_content][index]
|
558
|
+
if cached
|
559
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
560
|
+
@index = cached.interval.end
|
561
|
+
end
|
562
|
+
return cached
|
563
|
+
end
|
564
|
+
|
565
|
+
s0, i0 = [], index
|
566
|
+
loop do
|
567
|
+
i1, s1 = index, []
|
568
|
+
i2 = index
|
569
|
+
if has_terminal?('%>', false, index)
|
570
|
+
r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
|
571
|
+
@index += 2
|
572
|
+
else
|
573
|
+
terminal_parse_failure('%>')
|
574
|
+
r3 = nil
|
575
|
+
end
|
576
|
+
if r3
|
577
|
+
r2 = nil
|
578
|
+
else
|
579
|
+
@index = i2
|
580
|
+
r2 = instantiate_node(SyntaxNode,input, index...index)
|
581
|
+
end
|
582
|
+
s1 << r2
|
583
|
+
if r2
|
584
|
+
i4 = index
|
585
|
+
if has_terminal?('%%>', false, index)
|
586
|
+
r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
587
|
+
@index += 3
|
588
|
+
else
|
589
|
+
terminal_parse_failure('%%>')
|
590
|
+
r5 = nil
|
591
|
+
end
|
592
|
+
if r5
|
593
|
+
r4 = nil
|
594
|
+
else
|
595
|
+
@index = i4
|
596
|
+
r4 = instantiate_node(SyntaxNode,input, index...index)
|
597
|
+
end
|
598
|
+
s1 << r4
|
599
|
+
if r4
|
600
|
+
i6 = index
|
601
|
+
if has_terminal?('<%%', false, index)
|
602
|
+
r7 = instantiate_node(SyntaxNode,input, index...(index + 3))
|
603
|
+
@index += 3
|
604
|
+
else
|
605
|
+
terminal_parse_failure('<%%')
|
606
|
+
r7 = nil
|
607
|
+
end
|
608
|
+
if r7
|
609
|
+
r6 = nil
|
610
|
+
else
|
611
|
+
@index = i6
|
612
|
+
r6 = instantiate_node(SyntaxNode,input, index...index)
|
613
|
+
end
|
614
|
+
s1 << r6
|
615
|
+
if r6
|
616
|
+
if index < input_length
|
617
|
+
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
618
|
+
@index += 1
|
619
|
+
else
|
620
|
+
terminal_parse_failure("any character")
|
621
|
+
r8 = nil
|
622
|
+
end
|
623
|
+
s1 << r8
|
624
|
+
end
|
625
|
+
end
|
626
|
+
end
|
627
|
+
if s1.last
|
628
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
629
|
+
r1.extend(UnescapeScriptContent0)
|
630
|
+
else
|
631
|
+
@index = i1
|
632
|
+
r1 = nil
|
633
|
+
end
|
634
|
+
if r1
|
635
|
+
s0 << r1
|
636
|
+
else
|
637
|
+
break
|
638
|
+
end
|
639
|
+
end
|
640
|
+
if s0.empty?
|
641
|
+
@index = i0
|
642
|
+
r0 = nil
|
643
|
+
else
|
644
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
645
|
+
end
|
646
|
+
|
647
|
+
node_cache[:unescape_script_content][start_index] = r0
|
648
|
+
|
649
|
+
r0
|
650
|
+
end
|
651
|
+
|
652
|
+
end
|
653
|
+
|
654
|
+
class GrammarParser < Treetop::Runtime::CompiledParser
|
655
|
+
include Grammar
|
656
|
+
end
|
657
|
+
|
658
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Ejs
|
2
|
+
grammar Grammar
|
3
|
+
rule program
|
4
|
+
(expression / comment / scriplet / static_content)*
|
5
|
+
end
|
6
|
+
|
7
|
+
rule expression
|
8
|
+
'<%=' script_content '%>' {
|
9
|
+
def node_type
|
10
|
+
"expression"
|
11
|
+
end
|
12
|
+
|
13
|
+
def text_value
|
14
|
+
script_content.text_value
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
rule comment
|
20
|
+
'<%#' script_content '%>' {
|
21
|
+
def node_type
|
22
|
+
"comment"
|
23
|
+
end
|
24
|
+
|
25
|
+
def text_value
|
26
|
+
script_content.text_value
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
rule scriplet
|
32
|
+
'<%' script_content '%>' {
|
33
|
+
def node_type
|
34
|
+
"scriplet"
|
35
|
+
end
|
36
|
+
|
37
|
+
def text_value
|
38
|
+
script_content.text_value
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
rule static_content
|
44
|
+
(right_delimeter_escaped / left_delimeter_escaped / unescaped_static_content)+ {
|
45
|
+
def node_type
|
46
|
+
"static_content"
|
47
|
+
end
|
48
|
+
|
49
|
+
def text_value
|
50
|
+
elements.map do |element|
|
51
|
+
element.text_value
|
52
|
+
end.join('')
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
rule script_content
|
58
|
+
(right_delimeter_escaped / left_delimeter_escaped / unescape_script_content)* {
|
59
|
+
def text_value
|
60
|
+
elements.map do |element|
|
61
|
+
element.text_value
|
62
|
+
end.join('')
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
rule right_delimeter_escaped
|
68
|
+
'%%>' {
|
69
|
+
def text_value
|
70
|
+
'%>'
|
71
|
+
end
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
rule left_delimeter_escaped
|
76
|
+
'<%%' {
|
77
|
+
def text_value
|
78
|
+
'<%'
|
79
|
+
end
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
rule unescaped_static_content
|
84
|
+
(!'<%%' !'%%>' !'<%' !'%>' .)+
|
85
|
+
end
|
86
|
+
|
87
|
+
rule unescape_script_content
|
88
|
+
(!'%>' !'%%>' !'<%%' .)+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Ejs
|
2
|
+
class ParseError < StandardError
|
3
|
+
attr_reader :failure_reason, :failure_line, :failure_column
|
4
|
+
def initialize(failure_reason, failure_line, failure_column)
|
5
|
+
@failure_reason = failure_reason
|
6
|
+
@failure_line = failure_line
|
7
|
+
@failure_column = failure_column
|
8
|
+
super(@failure_reason)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/ejs/parser.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/ejs/compiler")
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'tempfile'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
describe "Compiler" do
|
6
|
+
before(:each) do
|
7
|
+
@compiler = Ejs::Compiler.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should js_source_from_string function header and footer" do
|
11
|
+
compiled = @compiler.js_source_from_string("TemplateName", "", true)
|
12
|
+
|
13
|
+
compiled[0].should == "window.TemplateName = window.TemplateName || {};"
|
14
|
+
compiled[1].should == "TemplateName.template = function(options) {"
|
15
|
+
compiled[2].should == " var p = [];"
|
16
|
+
compiled[3].should == " with(options) {"
|
17
|
+
|
18
|
+
compiled[-3].should == " }"
|
19
|
+
compiled[-2].should == " return p.join('');"
|
20
|
+
compiled[-1].should == "}"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add namespace declaration" do
|
24
|
+
compiled = @compiler.js_source_from_string("my.namespace.MyClass", "", true)
|
25
|
+
compiled[0].should == "window.my = window.my || {};"
|
26
|
+
compiled[1].should == "window.my.namespace = window.my.namespace || {};"
|
27
|
+
compiled[2].should == "window.my.namespace.MyClass = window.my.namespace.MyClass || {};"
|
28
|
+
compiled[3].should == "my.namespace.MyClass.template = function(options) {"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should js_source_from_string static content" do
|
32
|
+
compiled = @compiler.js_source_from_string("TemplateName", "<p>Static output</p>", true)
|
33
|
+
compiled[4].should == " p.push('<p>Static output</p>');"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should escape static content" do
|
37
|
+
compiled = @compiler.js_source_from_string("TemplateName", "\"\'\n\t", true)
|
38
|
+
compiled[4].should == " p.push('\\\"\\\'\\n\\t');"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should js_source_from_string scriplet" do
|
42
|
+
compiled = @compiler.js_source_from_string("TemplateName", "<% console.log('test') %>", true)
|
43
|
+
compiled[4].should == " console.log('test')"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should js_source_from_string expression" do
|
47
|
+
compiled = @compiler.js_source_from_string("TemplateName", "<%= this.name %>", true)
|
48
|
+
compiled[4].should == " p.push(this.name);"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should js_source_from_string comments" do
|
52
|
+
compiled = @compiler.js_source_from_string("TemplateName", "<%# This is a comment %>", true)
|
53
|
+
compiled[4].should == " /* This is a comment */"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should raise exception when syntax is invalid" do
|
57
|
+
lambda{ @compiler.js_source_from_string("Name", "<%= this.name %> %>") }.should raise_error(::Ejs::ParseError)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should compile a source file to a target file" do
|
61
|
+
fixtures = "#{File.dirname(__FILE__)}/fixtures"
|
62
|
+
target_file = "/tmp/Cities.js"
|
63
|
+
expected_target_file = "#{fixtures}/Cities.js"
|
64
|
+
|
65
|
+
FileUtils.rm(target_file) if File.exist?(target_file)
|
66
|
+
|
67
|
+
@compiler.compile("#{fixtures}/Cities.ejs", "or.ui", target_file)
|
68
|
+
File.open(target_file).read.should == File.open(expected_target_file).read
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// Autogenerated from an Ejs file. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
window.or = window.or || {};
|
5
|
+
window.or.ui = window.or.ui || {};
|
6
|
+
window.or.ui.Cities = window.or.ui.Cities || {};
|
7
|
+
or.ui.Cities.template = function(options) {
|
8
|
+
var p = [];
|
9
|
+
with(options) {
|
10
|
+
p.push('<ul>\n ');
|
11
|
+
/* Loop through each city */
|
12
|
+
p.push('\n ');
|
13
|
+
$.each(cities, function() {
|
14
|
+
p.push('\n <li>');
|
15
|
+
p.push(this.name);
|
16
|
+
p.push('</li>\n ');
|
17
|
+
})
|
18
|
+
p.push('\n</ul>\n');
|
19
|
+
}
|
20
|
+
return p.join('');
|
21
|
+
}
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Parser" do
|
4
|
+
before(:each) do
|
5
|
+
@parser = Ejs::Parser.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should parse static content" do
|
9
|
+
parsed = parse("<p>Static output</p>")
|
10
|
+
parsed.size.should == 1
|
11
|
+
parsed[0].node_type.should == 'static_content'
|
12
|
+
parsed[0].text_value.should == '<p>Static output</p>'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should parse scriplet" do
|
16
|
+
parsed = parse("<% console.log('test') %>")
|
17
|
+
parsed.size.should == 1
|
18
|
+
parsed[0].node_type.should == 'scriplet'
|
19
|
+
parsed[0].text_value.should == " console.log('test') "
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should parse expression" do
|
23
|
+
parsed = parse("<%= this.name %>")
|
24
|
+
parsed.size.should == 1
|
25
|
+
parsed[0].node_type.should == 'expression'
|
26
|
+
parsed[0].text_value.should == " this.name "
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse comment" do
|
30
|
+
parsed = parse("<%# This is a comment %>")
|
31
|
+
parsed.size.should == 1
|
32
|
+
parsed[0].node_type.should == 'comment'
|
33
|
+
parsed[0].text_value.should == " This is a comment "
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should escape left and right delimter in script content" do
|
37
|
+
parsed = parse("<% console.log('Example: <%% puts 'test' %%>') %>")
|
38
|
+
parsed.size.should == 1
|
39
|
+
parsed[0].node_type.should == 'scriplet'
|
40
|
+
parsed[0].text_value.should == " console.log('Example: <% puts 'test' %>') "
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should escape elft and right delimeter in staic content" do
|
44
|
+
parsed = parse("<%% this is a test %%>")
|
45
|
+
parsed.size.should == 1
|
46
|
+
parsed[0].node_type.should == 'static_content'
|
47
|
+
parsed[0].text_value.should == "<% this is a test %>"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def parse(ejs_conent)
|
53
|
+
result = @parser.parse(ejs_conent)
|
54
|
+
result.should_not be_nil
|
55
|
+
result.elements
|
56
|
+
end
|
57
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ejs-rcompiler'
|
5
|
+
require 'spec'
|
6
|
+
require 'spec/autorun'
|
7
|
+
|
8
|
+
Spec::Runner.configure do |config|
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
Spec::Matchers.define :equal_ignoring_spaces do |expected|
|
13
|
+
match do |actual|
|
14
|
+
clean_spaces(actual) == clean_spaces(expected)
|
15
|
+
end
|
16
|
+
|
17
|
+
def clean_spaces(text)
|
18
|
+
text = "" if text.nil?
|
19
|
+
text.
|
20
|
+
gsub(/\s+/, " ").
|
21
|
+
strip.
|
22
|
+
gsub(/' /, "'").
|
23
|
+
gsub(/ '/, "'")
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ejs-rcompiler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ben Curren
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-27 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: treetop
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 4
|
30
|
+
- 0
|
31
|
+
version: 1.4.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 2
|
44
|
+
- 9
|
45
|
+
version: 1.2.9
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: Ejs to Javascript compiler.
|
49
|
+
email: ben@outright.com
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- LICENSE
|
56
|
+
- README.rdoc
|
57
|
+
files:
|
58
|
+
- .document
|
59
|
+
- .gitignore
|
60
|
+
- LICENSE
|
61
|
+
- README.rdoc
|
62
|
+
- Rakefile
|
63
|
+
- VERSION
|
64
|
+
- autotest/discover.rb
|
65
|
+
- ejs-rcompiler.gemspec
|
66
|
+
- lib/ejs-rcompiler.rb
|
67
|
+
- lib/ejs/compiler.rb
|
68
|
+
- lib/ejs/grammar.rb
|
69
|
+
- lib/ejs/grammar.treetop
|
70
|
+
- lib/ejs/parse_error.rb
|
71
|
+
- lib/ejs/parser.rb
|
72
|
+
- spec/compiler_spec.rb
|
73
|
+
- spec/fixtures/Cities.ejs
|
74
|
+
- spec/fixtures/Cities.js
|
75
|
+
- spec/parser_spec.rb
|
76
|
+
- spec/spec.opts
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
has_rdoc: true
|
79
|
+
homepage: http://github.com/bcurren/ejs-rcompiler
|
80
|
+
licenses: []
|
81
|
+
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options:
|
84
|
+
- --charset=UTF-8
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.3.6
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: Ejs to Javascript compiler written in Ruby. This allows you to define HTML heavy Javascript components in EJS and compile them down to Javascript functions for later use.
|
108
|
+
test_files:
|
109
|
+
- spec/compiler_spec.rb
|
110
|
+
- spec/parser_spec.rb
|
111
|
+
- spec/spec_helper.rb
|