erb 4.0.1-java

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.
@@ -0,0 +1,471 @@
1
+ #--
2
+ # ERB::Compiler
3
+ #
4
+ # Compiles ERB templates into Ruby code; the compiled code produces the
5
+ # template result when evaluated. ERB::Compiler provides hooks to define how
6
+ # generated output is handled.
7
+ #
8
+ # Internally ERB does something like this to generate the code returned by
9
+ # ERB#src:
10
+ #
11
+ # compiler = ERB::Compiler.new('<>')
12
+ # compiler.pre_cmd = ["_erbout=+''"]
13
+ # compiler.put_cmd = "_erbout.<<"
14
+ # compiler.insert_cmd = "_erbout.<<"
15
+ # compiler.post_cmd = ["_erbout"]
16
+ #
17
+ # code, enc = compiler.compile("Got <%= obj %>!\n")
18
+ # puts code
19
+ #
20
+ # <i>Generates</i>:
21
+ #
22
+ # #coding:UTF-8
23
+ # _erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _erbout
24
+ #
25
+ # By default the output is sent to the print method. For example:
26
+ #
27
+ # compiler = ERB::Compiler.new('<>')
28
+ # code, enc = compiler.compile("Got <%= obj %>!\n")
29
+ # puts code
30
+ #
31
+ # <i>Generates</i>:
32
+ #
33
+ # #coding:UTF-8
34
+ # print "Got ".freeze; print(( obj ).to_s); print "!\n".freeze
35
+ #
36
+ # == Evaluation
37
+ #
38
+ # The compiled code can be used in any context where the names in the code
39
+ # correctly resolve. Using the last example, each of these print 'Got It!'
40
+ #
41
+ # Evaluate using a variable:
42
+ #
43
+ # obj = 'It'
44
+ # eval code
45
+ #
46
+ # Evaluate using an input:
47
+ #
48
+ # mod = Module.new
49
+ # mod.module_eval %{
50
+ # def get(obj)
51
+ # #{code}
52
+ # end
53
+ # }
54
+ # extend mod
55
+ # get('It')
56
+ #
57
+ # Evaluate using an accessor:
58
+ #
59
+ # klass = Class.new Object
60
+ # klass.class_eval %{
61
+ # attr_accessor :obj
62
+ # def initialize(obj)
63
+ # @obj = obj
64
+ # end
65
+ # def get_it
66
+ # #{code}
67
+ # end
68
+ # }
69
+ # klass.new('It').get_it
70
+ #
71
+ # Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.
72
+ class ERB::Compiler # :nodoc:
73
+ class PercentLine # :nodoc:
74
+ def initialize(str)
75
+ @value = str
76
+ end
77
+ attr_reader :value
78
+ alias :to_s :value
79
+ end
80
+
81
+ class Scanner # :nodoc:
82
+ @scanner_map = {}
83
+ class << self
84
+ def register_scanner(klass, trim_mode, percent)
85
+ @scanner_map[[trim_mode, percent]] = klass
86
+ end
87
+ alias :regist_scanner :register_scanner
88
+ end
89
+
90
+ def self.default_scanner=(klass)
91
+ @default_scanner = klass
92
+ end
93
+
94
+ def self.make_scanner(src, trim_mode, percent)
95
+ klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
96
+ klass.new(src, trim_mode, percent)
97
+ end
98
+
99
+ DEFAULT_STAGS = %w(<%% <%= <%# <%).freeze
100
+ DEFAULT_ETAGS = %w(%%> %>).freeze
101
+ def initialize(src, trim_mode, percent)
102
+ @src = src
103
+ @stag = nil
104
+ @stags = DEFAULT_STAGS
105
+ @etags = DEFAULT_ETAGS
106
+ end
107
+ attr_accessor :stag
108
+ attr_reader :stags, :etags
109
+
110
+ def scan; end
111
+ end
112
+
113
+ class TrimScanner < Scanner # :nodoc:
114
+ def initialize(src, trim_mode, percent)
115
+ super
116
+ @trim_mode = trim_mode
117
+ @percent = percent
118
+ if @trim_mode == '>'
119
+ @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
120
+ @scan_line = self.method(:trim_line1)
121
+ elsif @trim_mode == '<>'
122
+ @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
123
+ @scan_line = self.method(:trim_line2)
124
+ elsif @trim_mode == '-'
125
+ @scan_reg = /(.*?)(^[ \t]*<%\-|<%\-|-%>\r?\n|-%>|#{(stags + etags).join('|')}|\z)/m
126
+ @scan_line = self.method(:explicit_trim_line)
127
+ else
128
+ @scan_reg = /(.*?)(#{(stags + etags).join('|')}|\n|\z)/m
129
+ @scan_line = self.method(:scan_line)
130
+ end
131
+ end
132
+
133
+ def scan(&block)
134
+ @stag = nil
135
+ if @percent
136
+ @src.each_line do |line|
137
+ percent_line(line, &block)
138
+ end
139
+ else
140
+ @scan_line.call(@src, &block)
141
+ end
142
+ nil
143
+ end
144
+
145
+ def percent_line(line, &block)
146
+ if @stag || line[0] != ?%
147
+ return @scan_line.call(line, &block)
148
+ end
149
+
150
+ line[0] = ''
151
+ if line[0] == ?%
152
+ @scan_line.call(line, &block)
153
+ else
154
+ yield(PercentLine.new(line.chomp))
155
+ end
156
+ end
157
+
158
+ def scan_line(line)
159
+ line.scan(@scan_reg) do |tokens|
160
+ tokens.each do |token|
161
+ next if token.empty?
162
+ yield(token)
163
+ end
164
+ end
165
+ end
166
+
167
+ def trim_line1(line)
168
+ line.scan(@scan_reg) do |tokens|
169
+ tokens.each do |token|
170
+ next if token.empty?
171
+ if token == "%>\n" || token == "%>\r\n"
172
+ yield('%>')
173
+ yield(:cr)
174
+ else
175
+ yield(token)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ def trim_line2(line)
182
+ head = nil
183
+ line.scan(@scan_reg) do |tokens|
184
+ tokens.each do |token|
185
+ next if token.empty?
186
+ head = token unless head
187
+ if token == "%>\n" || token == "%>\r\n"
188
+ yield('%>')
189
+ if is_erb_stag?(head)
190
+ yield(:cr)
191
+ else
192
+ yield("\n")
193
+ end
194
+ head = nil
195
+ else
196
+ yield(token)
197
+ head = nil if token == "\n"
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+ def explicit_trim_line(line)
204
+ line.scan(@scan_reg) do |tokens|
205
+ tokens.each do |token|
206
+ next if token.empty?
207
+ if @stag.nil? && /[ \t]*<%-/ =~ token
208
+ yield('<%')
209
+ elsif @stag && (token == "-%>\n" || token == "-%>\r\n")
210
+ yield('%>')
211
+ yield(:cr)
212
+ elsif @stag && token == '-%>'
213
+ yield('%>')
214
+ else
215
+ yield(token)
216
+ end
217
+ end
218
+ end
219
+ end
220
+
221
+ ERB_STAG = %w(<%= <%# <%)
222
+ def is_erb_stag?(s)
223
+ ERB_STAG.member?(s)
224
+ end
225
+ end
226
+
227
+ Scanner.default_scanner = TrimScanner
228
+
229
+ begin
230
+ require 'strscan'
231
+ rescue LoadError
232
+ else
233
+ class SimpleScanner < Scanner # :nodoc:
234
+ def scan
235
+ stag_reg = (stags == DEFAULT_STAGS) ? /(.*?)(<%[%=#]?|\z)/m : /(.*?)(#{stags.join('|')}|\z)/m
236
+ etag_reg = (etags == DEFAULT_ETAGS) ? /(.*?)(%%?>|\z)/m : /(.*?)(#{etags.join('|')}|\z)/m
237
+ scanner = StringScanner.new(@src)
238
+ while ! scanner.eos?
239
+ scanner.scan(@stag ? etag_reg : stag_reg)
240
+ yield(scanner[1])
241
+ yield(scanner[2])
242
+ end
243
+ end
244
+ end
245
+ Scanner.register_scanner(SimpleScanner, nil, false)
246
+
247
+ class ExplicitScanner < Scanner # :nodoc:
248
+ def scan
249
+ stag_reg = /(.*?)(^[ \t]*<%-|<%-|#{stags.join('|')}|\z)/m
250
+ etag_reg = /(.*?)(-%>|#{etags.join('|')}|\z)/m
251
+ scanner = StringScanner.new(@src)
252
+ while ! scanner.eos?
253
+ scanner.scan(@stag ? etag_reg : stag_reg)
254
+ yield(scanner[1])
255
+
256
+ elem = scanner[2]
257
+ if /[ \t]*<%-/ =~ elem
258
+ yield('<%')
259
+ elsif elem == '-%>'
260
+ yield('%>')
261
+ yield(:cr) if scanner.scan(/(\r?\n|\z)/)
262
+ else
263
+ yield(elem)
264
+ end
265
+ end
266
+ end
267
+ end
268
+ Scanner.register_scanner(ExplicitScanner, '-', false)
269
+ end
270
+
271
+ class Buffer # :nodoc:
272
+ def initialize(compiler, enc=nil, frozen=nil)
273
+ @compiler = compiler
274
+ @line = []
275
+ @script = +''
276
+ @script << "#coding:#{enc}\n" if enc
277
+ @script << "#frozen-string-literal:#{frozen}\n" unless frozen.nil?
278
+ @compiler.pre_cmd.each do |x|
279
+ push(x)
280
+ end
281
+ end
282
+ attr_reader :script
283
+
284
+ def push(cmd)
285
+ @line << cmd
286
+ end
287
+
288
+ def cr
289
+ @script << (@line.join('; '))
290
+ @line = []
291
+ @script << "\n"
292
+ end
293
+
294
+ def close
295
+ return unless @line
296
+ @compiler.post_cmd.each do |x|
297
+ push(x)
298
+ end
299
+ @script << (@line.join('; '))
300
+ @line = nil
301
+ end
302
+ end
303
+
304
+ def add_put_cmd(out, content)
305
+ out.push("#{@put_cmd} #{content.dump}.freeze#{"\n" * content.count("\n")}")
306
+ end
307
+
308
+ def add_insert_cmd(out, content)
309
+ out.push("#{@insert_cmd}((#{content}).to_s)")
310
+ end
311
+
312
+ # Compiles an ERB template into Ruby code. Returns an array of the code
313
+ # and encoding like ["code", Encoding].
314
+ def compile(s)
315
+ enc = s.encoding
316
+ raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
317
+ s = s.b # see String#b
318
+ magic_comment = detect_magic_comment(s, enc)
319
+ out = Buffer.new(self, *magic_comment)
320
+
321
+ self.content = +''
322
+ scanner = make_scanner(s)
323
+ scanner.scan do |token|
324
+ next if token.nil?
325
+ next if token == ''
326
+ if scanner.stag.nil?
327
+ compile_stag(token, out, scanner)
328
+ else
329
+ compile_etag(token, out, scanner)
330
+ end
331
+ end
332
+ add_put_cmd(out, content) if content.size > 0
333
+ out.close
334
+ return out.script, *magic_comment
335
+ end
336
+
337
+ def compile_stag(stag, out, scanner)
338
+ case stag
339
+ when PercentLine
340
+ add_put_cmd(out, content) if content.size > 0
341
+ self.content = +''
342
+ out.push(stag.to_s)
343
+ out.cr
344
+ when :cr
345
+ out.cr
346
+ when '<%', '<%=', '<%#'
347
+ scanner.stag = stag
348
+ add_put_cmd(out, content) if content.size > 0
349
+ self.content = +''
350
+ when "\n"
351
+ content << "\n"
352
+ add_put_cmd(out, content)
353
+ self.content = +''
354
+ when '<%%'
355
+ content << '<%'
356
+ else
357
+ content << stag
358
+ end
359
+ end
360
+
361
+ def compile_etag(etag, out, scanner)
362
+ case etag
363
+ when '%>'
364
+ compile_content(scanner.stag, out)
365
+ scanner.stag = nil
366
+ self.content = +''
367
+ when '%%>'
368
+ content << '%>'
369
+ else
370
+ content << etag
371
+ end
372
+ end
373
+
374
+ def compile_content(stag, out)
375
+ case stag
376
+ when '<%'
377
+ if content[-1] == ?\n
378
+ content.chop!
379
+ out.push(content)
380
+ out.cr
381
+ else
382
+ out.push(content)
383
+ end
384
+ when '<%='
385
+ add_insert_cmd(out, content)
386
+ when '<%#'
387
+ # commented out
388
+ end
389
+ end
390
+
391
+ def prepare_trim_mode(mode) # :nodoc:
392
+ case mode
393
+ when 1
394
+ return [false, '>']
395
+ when 2
396
+ return [false, '<>']
397
+ when 0, nil
398
+ return [false, nil]
399
+ when String
400
+ unless mode.match?(/\A(%|-|>|<>){1,2}\z/)
401
+ warn_invalid_trim_mode(mode, uplevel: 5)
402
+ end
403
+
404
+ perc = mode.include?('%')
405
+ if mode.include?('-')
406
+ return [perc, '-']
407
+ elsif mode.include?('<>')
408
+ return [perc, '<>']
409
+ elsif mode.include?('>')
410
+ return [perc, '>']
411
+ else
412
+ [perc, nil]
413
+ end
414
+ else
415
+ warn_invalid_trim_mode(mode, uplevel: 5)
416
+ return [false, nil]
417
+ end
418
+ end
419
+
420
+ def make_scanner(src) # :nodoc:
421
+ Scanner.make_scanner(src, @trim_mode, @percent)
422
+ end
423
+
424
+ # Construct a new compiler using the trim_mode. See ERB::new for available
425
+ # trim modes.
426
+ def initialize(trim_mode)
427
+ @percent, @trim_mode = prepare_trim_mode(trim_mode)
428
+ @put_cmd = 'print'
429
+ @insert_cmd = @put_cmd
430
+ @pre_cmd = []
431
+ @post_cmd = []
432
+ end
433
+ attr_reader :percent, :trim_mode
434
+
435
+ # The command to handle text that ends with a newline
436
+ attr_accessor :put_cmd
437
+
438
+ # The command to handle text that is inserted prior to a newline
439
+ attr_accessor :insert_cmd
440
+
441
+ # An array of commands prepended to compiled code
442
+ attr_accessor :pre_cmd
443
+
444
+ # An array of commands appended to compiled code
445
+ attr_accessor :post_cmd
446
+
447
+ private
448
+
449
+ # A buffered text in #compile
450
+ attr_accessor :content
451
+
452
+ def detect_magic_comment(s, enc = nil)
453
+ re = @percent ? /\G(?:<%#(.*)%>|%#(.*)\n)/ : /\G<%#(.*)%>/
454
+ frozen = nil
455
+ s.scan(re) do
456
+ comment = $+
457
+ comment = $1 if comment[/-\*-\s*([^\s].*?)\s*-\*-$/]
458
+ case comment
459
+ when %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
460
+ enc = Encoding.find($1.sub(/-(?:mac|dos|unix)/i, ''))
461
+ when %r"frozen[-_]string[-_]literal\s*:\s*([[:alnum:]]+)"
462
+ frozen = $1
463
+ end
464
+ end
465
+ return enc, frozen
466
+ end
467
+
468
+ def warn_invalid_trim_mode(mode, uplevel:)
469
+ warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + 1
470
+ end
471
+ end
@@ -0,0 +1,46 @@
1
+ #--
2
+ # ERB::DefMethod
3
+ #
4
+ # Utility module to define eRuby script as instance method.
5
+ #
6
+ # === Example
7
+ #
8
+ # example.rhtml:
9
+ # <% for item in @items %>
10
+ # <b><%= item %></b>
11
+ # <% end %>
12
+ #
13
+ # example.rb:
14
+ # require 'erb'
15
+ # class MyClass
16
+ # extend ERB::DefMethod
17
+ # def_erb_method('render()', 'example.rhtml')
18
+ # def initialize(items)
19
+ # @items = items
20
+ # end
21
+ # end
22
+ # print MyClass.new([10,20,30]).render()
23
+ #
24
+ # result:
25
+ #
26
+ # <b>10</b>
27
+ #
28
+ # <b>20</b>
29
+ #
30
+ # <b>30</b>
31
+ #
32
+ module ERB::DefMethod
33
+ # define _methodname_ as instance method of current module, using ERB
34
+ # object or eRuby file
35
+ def def_erb_method(methodname, erb_or_fname)
36
+ if erb_or_fname.kind_of? String
37
+ fname = erb_or_fname
38
+ erb = ERB.new(File.read(fname))
39
+ erb.def_method(self, methodname, fname)
40
+ else
41
+ erb = erb_or_fname
42
+ erb.def_method(self, methodname, erb.filename || '(ERB)')
43
+ end
44
+ end
45
+ module_function :def_erb_method
46
+ end
data/lib/erb/util.rb ADDED
@@ -0,0 +1,62 @@
1
+ #--
2
+ # ERB::Escape
3
+ #
4
+ # A subset of ERB::Util. Unlike ERB::Util#html_escape, we expect/hope
5
+ # Rails will not monkey-patch ERB::Escape#html_escape.
6
+ begin
7
+ # We don't build the C extension for JRuby, TruffleRuby, and WASM
8
+ if $LOAD_PATH.resolve_feature_path('erb/escape')
9
+ require 'erb/escape'
10
+ end
11
+ rescue LoadError # resolve_feature_path raises LoadError on TruffleRuby 22.3.0
12
+ end
13
+ unless defined?(ERB::Escape)
14
+ module ERB::Escape
15
+ def html_escape(s)
16
+ CGI.escapeHTML(s.to_s)
17
+ end
18
+ module_function :html_escape
19
+ end
20
+ end
21
+
22
+ #--
23
+ # ERB::Util
24
+ #
25
+ # A utility module for conversion routines, often handy in HTML generation.
26
+ module ERB::Util
27
+ #
28
+ # A utility method for escaping HTML tag characters in _s_.
29
+ #
30
+ # require "erb"
31
+ # include ERB::Util
32
+ #
33
+ # puts html_escape("is a > 0 & a < 10?")
34
+ #
35
+ # _Generates_
36
+ #
37
+ # is a &gt; 0 &amp; a &lt; 10?
38
+ #
39
+ include ERB::Escape # html_escape
40
+ module_function :html_escape
41
+ alias h html_escape
42
+ module_function :h
43
+
44
+ #
45
+ # A utility method for encoding the String _s_ as a URL.
46
+ #
47
+ # require "erb"
48
+ # include ERB::Util
49
+ #
50
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
51
+ #
52
+ # _Generates_
53
+ #
54
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
55
+ #
56
+ def url_encode(s)
57
+ CGI.escapeURIComponent(s.to_s)
58
+ end
59
+ alias u url_encode
60
+ module_function :u
61
+ module_function :url_encode
62
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ class ERB
3
+ VERSION = '4.0.1'
4
+ private_constant :VERSION
5
+ end