ruby-ejs 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +58 -0
  4. data/lib/ejs.rb +275 -0
  5. data/lib/ruby/ejs.rb +1 -0
  6. metadata +118 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b4cdfc1984dfe0f7075d095ff8db803283877f7a81c3ab63f80f1d0148293bc1
4
+ data.tar.gz: 588d1484185dc5a8f0106fed729b4e2c0a740f44313edeccd9206aded072675e
5
+ SHA512:
6
+ metadata.gz: 937490d4c14a05dff25f1862defa7f62726887cac90d98776a17f205c9b347724003bf1a2be09b66276de2d6f577409f83be3d53e68dab7193db741a214ecc6c
7
+ data.tar.gz: 41834e5dddde678ebfd4073658e8e90807362e1b6588b140b74dc54349013265afa687fe3d9f861de08d6bb61487a4f1f139cf59505f30b6265e14af06ed0e6e
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Sam Stephenson
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.
@@ -0,0 +1,58 @@
1
+ EJS (Embedded JavaScript) template compiler for Ruby [![Circle CI](https://circleci.com/gh/malomalo/ruby-ejs.svg?style=svg)](https://circleci.com/gh/malomalo/ruby-ejs)
2
+ ====================================================
3
+
4
+ EJS templates embed JavaScript code inside `<% ... %>` tags, much like
5
+ ERB. This library is a port of
6
+ [Underscore.js](http://documentcloud.github.com/underscore/)'s
7
+ [`_.template`
8
+ function](http://documentcloud.github.com/underscore/#template) to
9
+ Ruby, and strives to maintain the same syntax and semantics.
10
+
11
+ Pass an EJS template to `EJS.compile` to generate a JavaScript
12
+ function:
13
+
14
+ EJS.compile("Hello <%= name %>")
15
+ # => "function(obj){...}"
16
+
17
+ Invoke the function in a JavaScript environment to produce a string
18
+ value. You can pass an optional object specifying local variables for
19
+ template evaluation.
20
+
21
+ The EJS tag syntax is as follows:
22
+
23
+ * `<% ... %>` silently evaluates the statement inside the tags.
24
+ * `<%= ... %>` evaluates the expression inside the tags and inserts
25
+ its string value into the template output.
26
+ * `<%- ... %>` behaves like `<%= ... %>` but HTML-escapes its output.
27
+
28
+ If a evalation tag (`<%=`) ends with an open function, the function
29
+ return a compiled template. For example:
30
+
31
+ ```erb
32
+ <% formTag = function(template) { return '<form>\n'+template()+'\n</form>'; } %>
33
+
34
+ <%= formTag(function () { %>
35
+ <input type="submit" />
36
+ <% }) %>
37
+ ```
38
+
39
+ generates:
40
+
41
+ ```html
42
+ <form>
43
+ <input type="submit" />
44
+ </form>
45
+ ```
46
+
47
+ If you have the [ExecJS](https://github.com/sstephenson/execjs/)
48
+ library and a suitable JavaScript runtime installed, you can pass a
49
+ template and an optional hash of local variables to `EJS.evaluate`:
50
+
51
+ EJS.evaluate("Hello <%= name %>", :name => "world")
52
+ # => "Hello world"
53
+
54
+ -----
55
+
56
+ &copy; 2012 Sam Stephenson
57
+
58
+ Released under the MIT license
@@ -0,0 +1,275 @@
1
+ module EJS
2
+
3
+ DEFAULTS = {
4
+ open_tag: '<%',
5
+ close_tag: '%>',
6
+
7
+ open_tag_modifiers: {
8
+ escape: '=',
9
+ unescape: '-',
10
+ comment: '#',
11
+ literal: '%'
12
+ },
13
+
14
+ close_tag_modifiers: {
15
+ trim: '-',
16
+ literal: '%'
17
+ },
18
+
19
+ escape: nil
20
+ }
21
+
22
+ ASSET_DIR = File.join(__dir__, 'ruby', 'ejs', 'assets')
23
+
24
+ class << self
25
+
26
+ # Compiles an EJS template to a JavaScript function. The compiled
27
+ # function takes an optional argument, an object specifying local
28
+ # variables in the template. You can optionally pass the
29
+ # `:evaluation_pattern` and `:interpolation_pattern` options to
30
+ # `compile` if you want to specify a different tag syntax for the
31
+ # template.
32
+ #
33
+ # EJS.compile("Hello <%= name %>")
34
+ # # => "function(obj){...}"
35
+ #
36
+ def transform(source, options = {})
37
+ options = default(options)
38
+
39
+ output = if options[:escape]
40
+ "import {" + options[:escape].split('.').reverse.join(" as escape} from '") + "';\n"
41
+ else
42
+ "import {escape} from 'ejs';\n"
43
+ end
44
+
45
+ output << "export default function (locals) {\n"
46
+ output << function_source(source, options)
47
+ output << "}"
48
+
49
+ output
50
+ end
51
+
52
+ def compile(source, options = {})
53
+ options = default(options)
54
+
55
+ output = "function(locals, escape) {\n"
56
+ output << function_source(source, options)
57
+ output << "}"
58
+ output
59
+ end
60
+
61
+
62
+ # Evaluates an EJS template with the given local variables and
63
+ # compiler options. You will need the ExecJS
64
+ # (https://github.com/sstephenson/execjs/) library and a
65
+ # JavaScript runtime available.
66
+ #
67
+ # EJS.evaluate("Hello <%= name %>", name: "world")
68
+ # # => "Hello world"
69
+ #
70
+ def evaluate(template, locals = {}, options = {})
71
+ require "execjs"
72
+ context = ExecJS.compile(<<-JS)
73
+ #{escape_function}
74
+
75
+ var template = #{compile(template, options)}
76
+ var evaluate = function(locals) {
77
+ return template(locals, escape);
78
+ }
79
+ JS
80
+ context.call("evaluate", locals)
81
+ end
82
+
83
+ protected
84
+
85
+ def default(options)
86
+ options = DEFAULTS.merge(options)
87
+
88
+ [:open_tag_modifiers, :close_tag_modifiers].each do |k|
89
+ DEFAULTS[k].each do |sk, v|
90
+ next if options[k].has_key?(sk)
91
+ options[k] = v
92
+ end
93
+ end
94
+
95
+ options
96
+ end
97
+
98
+ def escape_module
99
+ escape_function.sub('function', 'export function')
100
+ end
101
+
102
+ def escape_function(name='escape')
103
+ <<-JS
104
+ function #{name}(string) {
105
+ if (string !== undefined && string != null) {
106
+ return String(string).replace(/[&<>'"\\/]/g, function (c) {
107
+ return '&#' + c.codePointAt(0) + ';';
108
+ });
109
+ } else {
110
+ return '';
111
+ }
112
+ }
113
+ JS
114
+ end
115
+
116
+ def chars_balanced?(str, chars)
117
+ a = chars[0]
118
+ b = chars[1]
119
+ str = str.sub(/"(\\.|[^"])+"/, '')
120
+ str = str.sub(/'(\\.|[^'])+'/, '')
121
+ a_count = str.scan(/#{a}/).length
122
+ b_count = str.scan(/#{b}/).length
123
+
124
+ a_count - b_count
125
+ end
126
+
127
+
128
+ def digest(source, options)
129
+ open_tag_count = 0
130
+ close_tag_count = 0
131
+ tag_length = nil
132
+ # var index, tagType, tagModifier, tagModifiers, matchingModifier, prefix;
133
+ index = nil
134
+ tag_type = nil
135
+ tag_modifiers = nil
136
+ tag_modifier = nil
137
+ prefix =nil
138
+ matching_modifier = nil
139
+ last_tag_modifier = nil
140
+ next_open_index = source.index(options[:open_tag])
141
+ next_close_index = source.index(options[:close_tag])
142
+
143
+ while next_open_index || next_close_index
144
+ if (next_close_index && (!next_open_index || next_close_index < next_open_index))
145
+ index = next_close_index
146
+ tag_type = :close
147
+ tag_length = options[:close_tag].length
148
+ tag_modifiers = options[:close_tag_modifiers]
149
+ close_tag_count += 1
150
+ matching_modifier = tag_modifiers.find do |k, v|
151
+ source[index - v.length, v.length] == v
152
+ end
153
+ else
154
+ index = next_open_index
155
+ tag_type = :open
156
+ tag_length = options[:open_tag].length
157
+ tag_modifiers = options[:open_tag_modifiers]
158
+ open_tag_count += 1
159
+ matching_modifier = tag_modifiers.find do |k, v|
160
+ source[index + tag_length, v.length] == v
161
+ end
162
+ end
163
+
164
+ if matching_modifier
165
+ tag_length += matching_modifier[1].length
166
+ tag_modifier = matching_modifier[0]
167
+ else
168
+ tag_modifier = :default
169
+ end
170
+
171
+ if tag_modifier == :literal
172
+ if tag_type == :open
173
+ source = source[0, tag_length - matching_modifier[1].length] + source[(index + tag_length)..-1]
174
+ # source = source.slice(0, index + tagLength - matchingModifier[1].length) + source.slice(index + tagLength);
175
+ open_tag_count -= 1
176
+ else
177
+ close_tag_count -= 1
178
+ if index == 0
179
+ source = source[(index + matching_modifier[1].length)..-1]
180
+ else
181
+ source = source[0..index] + source[(index + matching_modifier[1].length)..-1]
182
+ end
183
+ end
184
+
185
+ next_open_index = source.index(options.openTag, index + tag_length - matching_modifier[1].length);
186
+ next_close_index = source.index(options.closeTag, index + tag_length - matching_modifier[1].length);
187
+ next
188
+ end
189
+
190
+ if index != 0
191
+ if tag_type == :close
192
+ if matching_modifier
193
+ yield(source[0...(matching_modifier[1].length)], :js, last_tag_modifier)
194
+ else
195
+ yield(source[0...index], :js, last_tag_modifier)
196
+ end
197
+ else
198
+ yield(source[0...index], :text, last_tag_modifier)
199
+ end
200
+
201
+ source = source[index..-1]
202
+ end
203
+
204
+ if tag_type == :close && matching_modifier
205
+ source = source[(tag_length - matching_modifier[1].length)..-1]
206
+ source.lstrip!
207
+ else
208
+ source = source[tag_length..-1]
209
+ end
210
+ next_open_index = source.index(options[:open_tag])
211
+ next_close_index = source.index(options[:close_tag])
212
+ last_tag_modifier = tag_modifier
213
+ end
214
+
215
+ if open_tag_count != close_tag_count
216
+ raise "Could not find closing tag for \"#{options[(tag_type.to_s + '_tag').to_sym]}\"."
217
+ end
218
+
219
+ yield(source, :text, tag_modifier)
220
+ end
221
+
222
+
223
+ def function_source(source, options)
224
+ stack = []
225
+ output = " var __output = [], __append = __output.push.bind(__output);\n"
226
+ output << " with (locals || {}) {\n"
227
+
228
+ digest(source, options) do |segment, type, modifier|
229
+ if type == :js
230
+ if segment.match(/\A\s*\}/m)
231
+ case stack.pop
232
+ when :escape
233
+ output << "\n return __output.join(\"\");\n"
234
+ output << segment << " ));\n"
235
+ when :unescape
236
+ output << "\n return __output.join(\"\");\n"
237
+ output << segment << " );\n"
238
+ else
239
+ output << " " << segment << "\n"
240
+ end
241
+ elsif segment.match(/\)\s*\{\s*\Z/m)
242
+ stack << modifier
243
+ case modifier
244
+ when :escape
245
+ output << " __append(escape(" << segment
246
+ output << "\n var __output = [], __append = __output.push.bind(__output);\n"
247
+ when :unescape
248
+ output << " __append(" << segment
249
+ output << "\n var __output = [], __append = __output.push.bind(__output);\n"
250
+ else
251
+ output << " " << segment << "\n"
252
+ end
253
+ else
254
+ case modifier
255
+ when :escape
256
+ output << " __append(escape(" << segment << "));\n"
257
+ when :unescape
258
+ output << " __append(" << segment << ");\n"
259
+ else
260
+ output << " " << segment << "\n"
261
+ end
262
+ end
263
+ elsif segment.length > 0
264
+ output << " __append(`" + segment.gsub("\\"){"\\\\"}.gsub(/\n/, '\\n').gsub(/\r/, '\\r') + "`);\n"
265
+ end
266
+ end
267
+
268
+ output << " }\n"
269
+ output << " return __output.join(\"\");\n"
270
+
271
+ output
272
+ end
273
+
274
+ end
275
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(__dir__, '..', 'ejs'))
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-ejs
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Bracy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: execjs
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Compile EJS (Embedded JavaScript) templates in Ruby.
84
+ email:
85
+ - jonbracy@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - LICENSE
91
+ - README.md
92
+ - lib/ejs.rb
93
+ - lib/ruby/ejs.rb
94
+ homepage: https://github.com/malomalo/ruby-ejs
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.7.4
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: EJS (Embedded JavaScript) template compiler
118
+ test_files: []