erb 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59e65e447aa2698cab1c4f1f99322edabac2a8e480fb885c711529464f6842c8
4
+ data.tar.gz: 72e69acb55471846d7d07240a4c1ff023d0a6719ed24d9564f029dfd97b81402
5
+ SHA512:
6
+ metadata.gz: ea5447f6851f8752637b1b93aae084d58479808f65f11c3dd1d946e7f005cf4c0b1d607428f398ba2597b5ee48cc8c1e44bfdb6074eeb819b781d1c5d66dc927
7
+ data.tar.gz: 17bede5cf619b2d9d5f8d983835e9664dcd901920727071b59ba37698a0cc1f31624eef8a6132f14de780975f1f49860381103d7f54b0ad325104e8111ab1e0a
@@ -0,0 +1,24 @@
1
+ name: test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake test
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rake"
4
+ gem "test-unit"
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,36 @@
1
+ # Erb
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/erb`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'erb'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install erb
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hsbt/erb.
36
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "erb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "erb"
3
+ spec.version = "2.2.0"
4
+ spec.authors = ["Masatoshi SEKI"]
5
+ spec.email = ["seki@ruby-lang.org"]
6
+
7
+ spec.summary = %q{An easy to use but powerful templating system for Ruby.}
8
+ spec.description = %q{An easy to use but powerful templating system for Ruby.}
9
+ spec.homepage = "https://github.com/ruby/erb"
10
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
12
+
13
+ spec.metadata["homepage_uri"] = spec.homepage
14
+ spec.metadata["source_code_uri"] = spec.homepage
15
+
16
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+ spec.bindir = "libexec"
20
+ spec.executables = ["erb"]
21
+ spec.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,1079 @@
1
+ # -*- coding: us-ascii -*-
2
+ # frozen_string_literal: true
3
+ # = ERB -- Ruby Templating
4
+ #
5
+ # Author:: Masatoshi SEKI
6
+ # Documentation:: James Edward Gray II, Gavin Sinclair, and Simon Chiang
7
+ #
8
+ # See ERB for primary documentation and ERB::Util for a couple of utility
9
+ # routines.
10
+ #
11
+ # Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
12
+ #
13
+ # You can redistribute it and/or modify it under the same terms as Ruby.
14
+
15
+ require "cgi/util"
16
+
17
+ #
18
+ # = ERB -- Ruby Templating
19
+ #
20
+ # == Introduction
21
+ #
22
+ # ERB provides an easy to use but powerful templating system for Ruby. Using
23
+ # ERB, actual Ruby code can be added to any plain text document for the
24
+ # purposes of generating document information details and/or flow control.
25
+ #
26
+ # A very simple example is this:
27
+ #
28
+ # require 'erb'
29
+ #
30
+ # x = 42
31
+ # template = ERB.new <<-EOF
32
+ # The value of x is: <%= x %>
33
+ # EOF
34
+ # puts template.result(binding)
35
+ #
36
+ # <em>Prints:</em> The value of x is: 42
37
+ #
38
+ # More complex examples are given below.
39
+ #
40
+ #
41
+ # == Recognized Tags
42
+ #
43
+ # ERB recognizes certain tags in the provided template and converts them based
44
+ # on the rules below:
45
+ #
46
+ # <% Ruby code -- inline with output %>
47
+ # <%= Ruby expression -- replace with result %>
48
+ # <%# comment -- ignored -- useful in testing %>
49
+ # % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
50
+ # %% replaced with % if first thing on a line and % processing is used
51
+ # <%% or %%> -- replace with <% or %> respectively
52
+ #
53
+ # All other text is passed through ERB filtering unchanged.
54
+ #
55
+ #
56
+ # == Options
57
+ #
58
+ # There are several settings you can change when you use ERB:
59
+ # * the nature of the tags that are recognized;
60
+ # * the binding used to resolve local variables in the template.
61
+ #
62
+ # See the ERB.new and ERB#result methods for more detail.
63
+ #
64
+ # == Character encodings
65
+ #
66
+ # ERB (or Ruby code generated by ERB) returns a string in the same
67
+ # character encoding as the input string. When the input string has
68
+ # a magic comment, however, it returns a string in the encoding specified
69
+ # by the magic comment.
70
+ #
71
+ # # -*- coding: utf-8 -*-
72
+ # require 'erb'
73
+ #
74
+ # template = ERB.new <<EOF
75
+ # <%#-*- coding: Big5 -*-%>
76
+ # \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
77
+ # EOF
78
+ # puts template.result
79
+ #
80
+ # <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
81
+ #
82
+ #
83
+ # == Examples
84
+ #
85
+ # === Plain Text
86
+ #
87
+ # ERB is useful for any generic templating situation. Note that in this example, we use the
88
+ # convenient "% at start of line" tag, and we quote the template literally with
89
+ # <tt>%q{...}</tt> to avoid trouble with the backslash.
90
+ #
91
+ # require "erb"
92
+ #
93
+ # # Create template.
94
+ # template = %q{
95
+ # From: James Edward Gray II <james@grayproductions.net>
96
+ # To: <%= to %>
97
+ # Subject: Addressing Needs
98
+ #
99
+ # <%= to[/\w+/] %>:
100
+ #
101
+ # Just wanted to send a quick note assuring that your needs are being
102
+ # addressed.
103
+ #
104
+ # I want you to know that my team will keep working on the issues,
105
+ # especially:
106
+ #
107
+ # <%# ignore numerous minor requests -- focus on priorities %>
108
+ # % priorities.each do |priority|
109
+ # * <%= priority %>
110
+ # % end
111
+ #
112
+ # Thanks for your patience.
113
+ #
114
+ # James Edward Gray II
115
+ # }.gsub(/^ /, '')
116
+ #
117
+ # message = ERB.new(template, trim_mode: "%<>")
118
+ #
119
+ # # Set up template data.
120
+ # to = "Community Spokesman <spokesman@ruby_community.org>"
121
+ # priorities = [ "Run Ruby Quiz",
122
+ # "Document Modules",
123
+ # "Answer Questions on Ruby Talk" ]
124
+ #
125
+ # # Produce result.
126
+ # email = message.result
127
+ # puts email
128
+ #
129
+ # <i>Generates:</i>
130
+ #
131
+ # From: James Edward Gray II <james@grayproductions.net>
132
+ # To: Community Spokesman <spokesman@ruby_community.org>
133
+ # Subject: Addressing Needs
134
+ #
135
+ # Community:
136
+ #
137
+ # Just wanted to send a quick note assuring that your needs are being addressed.
138
+ #
139
+ # I want you to know that my team will keep working on the issues, especially:
140
+ #
141
+ # * Run Ruby Quiz
142
+ # * Document Modules
143
+ # * Answer Questions on Ruby Talk
144
+ #
145
+ # Thanks for your patience.
146
+ #
147
+ # James Edward Gray II
148
+ #
149
+ # === Ruby in HTML
150
+ #
151
+ # ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
152
+ # this example to provide a special binding when the template is run, so that the instance
153
+ # variables in the Product object can be resolved.
154
+ #
155
+ # require "erb"
156
+ #
157
+ # # Build template data class.
158
+ # class Product
159
+ # def initialize( code, name, desc, cost )
160
+ # @code = code
161
+ # @name = name
162
+ # @desc = desc
163
+ # @cost = cost
164
+ #
165
+ # @features = [ ]
166
+ # end
167
+ #
168
+ # def add_feature( feature )
169
+ # @features << feature
170
+ # end
171
+ #
172
+ # # Support templating of member data.
173
+ # def get_binding
174
+ # binding
175
+ # end
176
+ #
177
+ # # ...
178
+ # end
179
+ #
180
+ # # Create template.
181
+ # template = %{
182
+ # <html>
183
+ # <head><title>Ruby Toys -- <%= @name %></title></head>
184
+ # <body>
185
+ #
186
+ # <h1><%= @name %> (<%= @code %>)</h1>
187
+ # <p><%= @desc %></p>
188
+ #
189
+ # <ul>
190
+ # <% @features.each do |f| %>
191
+ # <li><b><%= f %></b></li>
192
+ # <% end %>
193
+ # </ul>
194
+ #
195
+ # <p>
196
+ # <% if @cost < 10 %>
197
+ # <b>Only <%= @cost %>!!!</b>
198
+ # <% else %>
199
+ # Call for a price, today!
200
+ # <% end %>
201
+ # </p>
202
+ #
203
+ # </body>
204
+ # </html>
205
+ # }.gsub(/^ /, '')
206
+ #
207
+ # rhtml = ERB.new(template)
208
+ #
209
+ # # Set up template data.
210
+ # toy = Product.new( "TZ-1002",
211
+ # "Rubysapien",
212
+ # "Geek's Best Friend! Responds to Ruby commands...",
213
+ # 999.95 )
214
+ # toy.add_feature("Listens for verbal commands in the Ruby language!")
215
+ # toy.add_feature("Ignores Perl, Java, and all C variants.")
216
+ # toy.add_feature("Karate-Chop Action!!!")
217
+ # toy.add_feature("Matz signature on left leg.")
218
+ # toy.add_feature("Gem studded eyes... Rubies, of course!")
219
+ #
220
+ # # Produce result.
221
+ # rhtml.run(toy.get_binding)
222
+ #
223
+ # <i>Generates (some blank lines removed):</i>
224
+ #
225
+ # <html>
226
+ # <head><title>Ruby Toys -- Rubysapien</title></head>
227
+ # <body>
228
+ #
229
+ # <h1>Rubysapien (TZ-1002)</h1>
230
+ # <p>Geek's Best Friend! Responds to Ruby commands...</p>
231
+ #
232
+ # <ul>
233
+ # <li><b>Listens for verbal commands in the Ruby language!</b></li>
234
+ # <li><b>Ignores Perl, Java, and all C variants.</b></li>
235
+ # <li><b>Karate-Chop Action!!!</b></li>
236
+ # <li><b>Matz signature on left leg.</b></li>
237
+ # <li><b>Gem studded eyes... Rubies, of course!</b></li>
238
+ # </ul>
239
+ #
240
+ # <p>
241
+ # Call for a price, today!
242
+ # </p>
243
+ #
244
+ # </body>
245
+ # </html>
246
+ #
247
+ #
248
+ # == Notes
249
+ #
250
+ # There are a variety of templating solutions available in various Ruby projects.
251
+ # For example, RDoc, distributed with Ruby, uses its own template engine, which
252
+ # can be reused elsewhere.
253
+ #
254
+ # Other popular engines could be found in the corresponding
255
+ # {Category}[https://www.ruby-toolbox.com/categories/template_engines] of
256
+ # The Ruby Toolbox.
257
+ #
258
+ class ERB
259
+ Revision = '$Date:: $' # :nodoc: #'
260
+
261
+ # Returns revision information for the erb.rb module.
262
+ def self.version
263
+ "erb.rb [2.2.0 #{ERB::Revision.split[1]}]"
264
+ end
265
+ end
266
+
267
+ #--
268
+ # ERB::Compiler
269
+ class ERB
270
+ # = ERB::Compiler
271
+ #
272
+ # Compiles ERB templates into Ruby code; the compiled code produces the
273
+ # template result when evaluated. ERB::Compiler provides hooks to define how
274
+ # generated output is handled.
275
+ #
276
+ # Internally ERB does something like this to generate the code returned by
277
+ # ERB#src:
278
+ #
279
+ # compiler = ERB::Compiler.new('<>')
280
+ # compiler.pre_cmd = ["_erbout=+''"]
281
+ # compiler.put_cmd = "_erbout.<<"
282
+ # compiler.insert_cmd = "_erbout.<<"
283
+ # compiler.post_cmd = ["_erbout"]
284
+ #
285
+ # code, enc = compiler.compile("Got <%= obj %>!\n")
286
+ # puts code
287
+ #
288
+ # <i>Generates</i>:
289
+ #
290
+ # #coding:UTF-8
291
+ # _erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _erbout
292
+ #
293
+ # By default the output is sent to the print method. For example:
294
+ #
295
+ # compiler = ERB::Compiler.new('<>')
296
+ # code, enc = compiler.compile("Got <%= obj %>!\n")
297
+ # puts code
298
+ #
299
+ # <i>Generates</i>:
300
+ #
301
+ # #coding:UTF-8
302
+ # print "Got ".freeze; print(( obj ).to_s); print "!\n".freeze
303
+ #
304
+ # == Evaluation
305
+ #
306
+ # The compiled code can be used in any context where the names in the code
307
+ # correctly resolve. Using the last example, each of these print 'Got It!'
308
+ #
309
+ # Evaluate using a variable:
310
+ #
311
+ # obj = 'It'
312
+ # eval code
313
+ #
314
+ # Evaluate using an input:
315
+ #
316
+ # mod = Module.new
317
+ # mod.module_eval %{
318
+ # def get(obj)
319
+ # #{code}
320
+ # end
321
+ # }
322
+ # extend mod
323
+ # get('It')
324
+ #
325
+ # Evaluate using an accessor:
326
+ #
327
+ # klass = Class.new Object
328
+ # klass.class_eval %{
329
+ # attr_accessor :obj
330
+ # def initialize(obj)
331
+ # @obj = obj
332
+ # end
333
+ # def get_it
334
+ # #{code}
335
+ # end
336
+ # }
337
+ # klass.new('It').get_it
338
+ #
339
+ # Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.
340
+ class Compiler # :nodoc:
341
+ class PercentLine # :nodoc:
342
+ def initialize(str)
343
+ @value = str
344
+ end
345
+ attr_reader :value
346
+ alias :to_s :value
347
+ end
348
+
349
+ class Scanner # :nodoc:
350
+ @scanner_map = {}
351
+ class << self
352
+ def register_scanner(klass, trim_mode, percent)
353
+ @scanner_map[[trim_mode, percent]] = klass
354
+ end
355
+ alias :regist_scanner :register_scanner
356
+ end
357
+
358
+ def self.default_scanner=(klass)
359
+ @default_scanner = klass
360
+ end
361
+
362
+ def self.make_scanner(src, trim_mode, percent)
363
+ klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
364
+ klass.new(src, trim_mode, percent)
365
+ end
366
+
367
+ DEFAULT_STAGS = %w(<%% <%= <%# <%).freeze
368
+ DEFAULT_ETAGS = %w(%%> %>).freeze
369
+ def initialize(src, trim_mode, percent)
370
+ @src = src
371
+ @stag = nil
372
+ @stags = DEFAULT_STAGS
373
+ @etags = DEFAULT_ETAGS
374
+ end
375
+ attr_accessor :stag
376
+ attr_reader :stags, :etags
377
+
378
+ def scan; end
379
+ end
380
+
381
+ class TrimScanner < Scanner # :nodoc:
382
+ def initialize(src, trim_mode, percent)
383
+ super
384
+ @trim_mode = trim_mode
385
+ @percent = percent
386
+ if @trim_mode == '>'
387
+ @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
388
+ @scan_line = self.method(:trim_line1)
389
+ elsif @trim_mode == '<>'
390
+ @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
391
+ @scan_line = self.method(:trim_line2)
392
+ elsif @trim_mode == '-'
393
+ @scan_reg = /(.*?)(^[ \t]*<%\-|<%\-|-%>\r?\n|-%>|#{(stags + etags).join('|')}|\z)/m
394
+ @scan_line = self.method(:explicit_trim_line)
395
+ else
396
+ @scan_reg = /(.*?)(#{(stags + etags).join('|')}|\n|\z)/m
397
+ @scan_line = self.method(:scan_line)
398
+ end
399
+ end
400
+
401
+ def scan(&block)
402
+ @stag = nil
403
+ if @percent
404
+ @src.each_line do |line|
405
+ percent_line(line, &block)
406
+ end
407
+ else
408
+ @scan_line.call(@src, &block)
409
+ end
410
+ nil
411
+ end
412
+
413
+ def percent_line(line, &block)
414
+ if @stag || line[0] != ?%
415
+ return @scan_line.call(line, &block)
416
+ end
417
+
418
+ line[0] = ''
419
+ if line[0] == ?%
420
+ @scan_line.call(line, &block)
421
+ else
422
+ yield(PercentLine.new(line.chomp))
423
+ end
424
+ end
425
+
426
+ def scan_line(line)
427
+ line.scan(@scan_reg) do |tokens|
428
+ tokens.each do |token|
429
+ next if token.empty?
430
+ yield(token)
431
+ end
432
+ end
433
+ end
434
+
435
+ def trim_line1(line)
436
+ line.scan(@scan_reg) do |tokens|
437
+ tokens.each do |token|
438
+ next if token.empty?
439
+ if token == "%>\n" || token == "%>\r\n"
440
+ yield('%>')
441
+ yield(:cr)
442
+ else
443
+ yield(token)
444
+ end
445
+ end
446
+ end
447
+ end
448
+
449
+ def trim_line2(line)
450
+ head = nil
451
+ line.scan(@scan_reg) do |tokens|
452
+ tokens.each do |token|
453
+ next if token.empty?
454
+ head = token unless head
455
+ if token == "%>\n" || token == "%>\r\n"
456
+ yield('%>')
457
+ if is_erb_stag?(head)
458
+ yield(:cr)
459
+ else
460
+ yield("\n")
461
+ end
462
+ head = nil
463
+ else
464
+ yield(token)
465
+ head = nil if token == "\n"
466
+ end
467
+ end
468
+ end
469
+ end
470
+
471
+ def explicit_trim_line(line)
472
+ line.scan(@scan_reg) do |tokens|
473
+ tokens.each do |token|
474
+ next if token.empty?
475
+ if @stag.nil? && /[ \t]*<%-/ =~ token
476
+ yield('<%')
477
+ elsif @stag && (token == "-%>\n" || token == "-%>\r\n")
478
+ yield('%>')
479
+ yield(:cr)
480
+ elsif @stag && token == '-%>'
481
+ yield('%>')
482
+ else
483
+ yield(token)
484
+ end
485
+ end
486
+ end
487
+ end
488
+
489
+ ERB_STAG = %w(<%= <%# <%)
490
+ def is_erb_stag?(s)
491
+ ERB_STAG.member?(s)
492
+ end
493
+ end
494
+
495
+ Scanner.default_scanner = TrimScanner
496
+
497
+ begin
498
+ require 'strscan'
499
+ rescue LoadError
500
+ else
501
+ class SimpleScanner < Scanner # :nodoc:
502
+ def scan
503
+ stag_reg = (stags == DEFAULT_STAGS) ? /(.*?)(<%[%=#]?|\z)/m : /(.*?)(#{stags.join('|')}|\z)/m
504
+ etag_reg = (etags == DEFAULT_ETAGS) ? /(.*?)(%%?>|\z)/m : /(.*?)(#{etags.join('|')}|\z)/m
505
+ scanner = StringScanner.new(@src)
506
+ while ! scanner.eos?
507
+ scanner.scan(@stag ? etag_reg : stag_reg)
508
+ yield(scanner[1])
509
+ yield(scanner[2])
510
+ end
511
+ end
512
+ end
513
+ Scanner.register_scanner(SimpleScanner, nil, false)
514
+
515
+ class ExplicitScanner < Scanner # :nodoc:
516
+ def scan
517
+ stag_reg = /(.*?)(^[ \t]*<%-|<%-|#{stags.join('|')}|\z)/m
518
+ etag_reg = /(.*?)(-%>|#{etags.join('|')}|\z)/m
519
+ scanner = StringScanner.new(@src)
520
+ while ! scanner.eos?
521
+ scanner.scan(@stag ? etag_reg : stag_reg)
522
+ yield(scanner[1])
523
+
524
+ elem = scanner[2]
525
+ if /[ \t]*<%-/ =~ elem
526
+ yield('<%')
527
+ elsif elem == '-%>'
528
+ yield('%>')
529
+ yield(:cr) if scanner.scan(/(\r?\n|\z)/)
530
+ else
531
+ yield(elem)
532
+ end
533
+ end
534
+ end
535
+ end
536
+ Scanner.register_scanner(ExplicitScanner, '-', false)
537
+ end
538
+
539
+ class Buffer # :nodoc:
540
+ def initialize(compiler, enc=nil, frozen=nil)
541
+ @compiler = compiler
542
+ @line = []
543
+ @script = +''
544
+ @script << "#coding:#{enc}\n" if enc
545
+ @script << "#frozen-string-literal:#{frozen}\n" unless frozen.nil?
546
+ @compiler.pre_cmd.each do |x|
547
+ push(x)
548
+ end
549
+ end
550
+ attr_reader :script
551
+
552
+ def push(cmd)
553
+ @line << cmd
554
+ end
555
+
556
+ def cr
557
+ @script << (@line.join('; '))
558
+ @line = []
559
+ @script << "\n"
560
+ end
561
+
562
+ def close
563
+ return unless @line
564
+ @compiler.post_cmd.each do |x|
565
+ push(x)
566
+ end
567
+ @script << (@line.join('; '))
568
+ @line = nil
569
+ end
570
+ end
571
+
572
+ def add_put_cmd(out, content)
573
+ out.push("#{@put_cmd} #{content.dump}.freeze#{"\n" * content.count("\n")}")
574
+ end
575
+
576
+ def add_insert_cmd(out, content)
577
+ out.push("#{@insert_cmd}((#{content}).to_s)")
578
+ end
579
+
580
+ # Compiles an ERB template into Ruby code. Returns an array of the code
581
+ # and encoding like ["code", Encoding].
582
+ def compile(s)
583
+ enc = s.encoding
584
+ raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
585
+ s = s.b # see String#b
586
+ magic_comment = detect_magic_comment(s, enc)
587
+ out = Buffer.new(self, *magic_comment)
588
+
589
+ self.content = +''
590
+ scanner = make_scanner(s)
591
+ scanner.scan do |token|
592
+ next if token.nil?
593
+ next if token == ''
594
+ if scanner.stag.nil?
595
+ compile_stag(token, out, scanner)
596
+ else
597
+ compile_etag(token, out, scanner)
598
+ end
599
+ end
600
+ add_put_cmd(out, content) if content.size > 0
601
+ out.close
602
+ return out.script, *magic_comment
603
+ end
604
+
605
+ def compile_stag(stag, out, scanner)
606
+ case stag
607
+ when PercentLine
608
+ add_put_cmd(out, content) if content.size > 0
609
+ self.content = +''
610
+ out.push(stag.to_s)
611
+ out.cr
612
+ when :cr
613
+ out.cr
614
+ when '<%', '<%=', '<%#'
615
+ scanner.stag = stag
616
+ add_put_cmd(out, content) if content.size > 0
617
+ self.content = +''
618
+ when "\n"
619
+ content << "\n"
620
+ add_put_cmd(out, content)
621
+ self.content = +''
622
+ when '<%%'
623
+ content << '<%'
624
+ else
625
+ content << stag
626
+ end
627
+ end
628
+
629
+ def compile_etag(etag, out, scanner)
630
+ case etag
631
+ when '%>'
632
+ compile_content(scanner.stag, out)
633
+ scanner.stag = nil
634
+ self.content = +''
635
+ when '%%>'
636
+ content << '%>'
637
+ else
638
+ content << etag
639
+ end
640
+ end
641
+
642
+ def compile_content(stag, out)
643
+ case stag
644
+ when '<%'
645
+ if content[-1] == ?\n
646
+ content.chop!
647
+ out.push(content)
648
+ out.cr
649
+ else
650
+ out.push(content)
651
+ end
652
+ when '<%='
653
+ add_insert_cmd(out, content)
654
+ when '<%#'
655
+ # commented out
656
+ end
657
+ end
658
+
659
+ def prepare_trim_mode(mode) # :nodoc:
660
+ case mode
661
+ when 1
662
+ return [false, '>']
663
+ when 2
664
+ return [false, '<>']
665
+ when 0, nil
666
+ return [false, nil]
667
+ when String
668
+ unless mode.match?(/\A(%|-|>|<>){1,2}\z/)
669
+ warn_invalid_trim_mode(mode, uplevel: 5)
670
+ end
671
+
672
+ perc = mode.include?('%')
673
+ if mode.include?('-')
674
+ return [perc, '-']
675
+ elsif mode.include?('<>')
676
+ return [perc, '<>']
677
+ elsif mode.include?('>')
678
+ return [perc, '>']
679
+ else
680
+ [perc, nil]
681
+ end
682
+ else
683
+ warn_invalid_trim_mode(mode, uplevel: 5)
684
+ return [false, nil]
685
+ end
686
+ end
687
+
688
+ def make_scanner(src) # :nodoc:
689
+ Scanner.make_scanner(src, @trim_mode, @percent)
690
+ end
691
+
692
+ # Construct a new compiler using the trim_mode. See ERB::new for available
693
+ # trim modes.
694
+ def initialize(trim_mode)
695
+ @percent, @trim_mode = prepare_trim_mode(trim_mode)
696
+ @put_cmd = 'print'
697
+ @insert_cmd = @put_cmd
698
+ @pre_cmd = []
699
+ @post_cmd = []
700
+ end
701
+ attr_reader :percent, :trim_mode
702
+
703
+ # The command to handle text that ends with a newline
704
+ attr_accessor :put_cmd
705
+
706
+ # The command to handle text that is inserted prior to a newline
707
+ attr_accessor :insert_cmd
708
+
709
+ # An array of commands prepended to compiled code
710
+ attr_accessor :pre_cmd
711
+
712
+ # An array of commands appended to compiled code
713
+ attr_accessor :post_cmd
714
+
715
+ private
716
+
717
+ # A buffered text in #compile
718
+ attr_accessor :content
719
+
720
+ def detect_magic_comment(s, enc = nil)
721
+ re = @percent ? /\G(?:<%#(.*)%>|%#(.*)\n)/ : /\G<%#(.*)%>/
722
+ frozen = nil
723
+ s.scan(re) do
724
+ comment = $+
725
+ comment = $1 if comment[/-\*-\s*(.*?)\s*-*-$/]
726
+ case comment
727
+ when %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
728
+ enc = Encoding.find($1.sub(/-(?:mac|dos|unix)/i, ''))
729
+ when %r"frozen[-_]string[-_]literal\s*:\s*([[:alnum:]]+)"
730
+ frozen = $1
731
+ end
732
+ end
733
+ return enc, frozen
734
+ end
735
+
736
+ def warn_invalid_trim_mode(mode, uplevel:)
737
+ warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + 1
738
+ end
739
+ end
740
+ end
741
+
742
+ #--
743
+ # ERB
744
+ class ERB
745
+ #
746
+ # Constructs a new ERB object with the template specified in _str_.
747
+ #
748
+ # An ERB object works by building a chunk of Ruby code that will output
749
+ # the completed template when run.
750
+ #
751
+ # If _trim_mode_ is passed a String containing one or more of the following
752
+ # modifiers, ERB will adjust its code generation as listed:
753
+ #
754
+ # % enables Ruby code processing for lines beginning with %
755
+ # <> omit newline for lines starting with <% and ending in %>
756
+ # > omit newline for lines ending in %>
757
+ # - omit blank lines ending in -%>
758
+ #
759
+ # _eoutvar_ can be used to set the name of the variable ERB will build up
760
+ # its output in. This is useful when you need to run multiple ERB
761
+ # templates through the same binding and/or when you want to control where
762
+ # output ends up. Pass the name of the variable to be used inside a String.
763
+ #
764
+ # === Example
765
+ #
766
+ # require "erb"
767
+ #
768
+ # # build data class
769
+ # class Listings
770
+ # PRODUCT = { :name => "Chicken Fried Steak",
771
+ # :desc => "A well messages pattie, breaded and fried.",
772
+ # :cost => 9.95 }
773
+ #
774
+ # attr_reader :product, :price
775
+ #
776
+ # def initialize( product = "", price = "" )
777
+ # @product = product
778
+ # @price = price
779
+ # end
780
+ #
781
+ # def build
782
+ # b = binding
783
+ # # create and run templates, filling member data variables
784
+ # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@product").result b
785
+ # <%= PRODUCT[:name] %>
786
+ # <%= PRODUCT[:desc] %>
787
+ # END_PRODUCT
788
+ # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@price").result b
789
+ # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
790
+ # <%= PRODUCT[:desc] %>
791
+ # END_PRICE
792
+ # end
793
+ # end
794
+ #
795
+ # # setup template data
796
+ # listings = Listings.new
797
+ # listings.build
798
+ #
799
+ # puts listings.product + "\n" + listings.price
800
+ #
801
+ # _Generates_
802
+ #
803
+ # Chicken Fried Steak
804
+ # A well messages pattie, breaded and fried.
805
+ #
806
+ # Chicken Fried Steak -- 9.95
807
+ # A well messages pattie, breaded and fried.
808
+ #
809
+ def initialize(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout')
810
+ # Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
811
+ if safe_level != NOT_GIVEN
812
+ warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.', uplevel: 1 if $VERBOSE || !ZERO_SAFE_LEVELS.include?(safe_level)
813
+ end
814
+ if legacy_trim_mode != NOT_GIVEN
815
+ warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.', uplevel: 1 if $VERBOSE
816
+ trim_mode = legacy_trim_mode
817
+ end
818
+ if legacy_eoutvar != NOT_GIVEN
819
+ warn 'Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.', uplevel: 1 if $VERBOSE
820
+ eoutvar = legacy_eoutvar
821
+ end
822
+
823
+ compiler = make_compiler(trim_mode)
824
+ set_eoutvar(compiler, eoutvar)
825
+ @src, @encoding, @frozen_string = *compiler.compile(str)
826
+ @filename = nil
827
+ @lineno = 0
828
+ @_init = self.class.singleton_class
829
+ end
830
+ NOT_GIVEN = Object.new
831
+ private_constant :NOT_GIVEN
832
+ ZERO_SAFE_LEVELS = [0, nil]
833
+ private_constant :ZERO_SAFE_LEVELS
834
+
835
+ ##
836
+ # Creates a new compiler for ERB. See ERB::Compiler.new for details
837
+
838
+ def make_compiler(trim_mode)
839
+ ERB::Compiler.new(trim_mode)
840
+ end
841
+
842
+ # The Ruby code generated by ERB
843
+ attr_reader :src
844
+
845
+ # The encoding to eval
846
+ attr_reader :encoding
847
+
848
+ # The optional _filename_ argument passed to Kernel#eval when the ERB code
849
+ # is run
850
+ attr_accessor :filename
851
+
852
+ # The optional _lineno_ argument passed to Kernel#eval when the ERB code
853
+ # is run
854
+ attr_accessor :lineno
855
+
856
+ #
857
+ # Sets optional filename and line number that will be used in ERB code
858
+ # evaluation and error reporting. See also #filename= and #lineno=
859
+ #
860
+ # erb = ERB.new('<%= some_x %>')
861
+ # erb.render
862
+ # # undefined local variable or method `some_x'
863
+ # # from (erb):1
864
+ #
865
+ # erb.location = ['file.erb', 3]
866
+ # # All subsequent error reporting would use new location
867
+ # erb.render
868
+ # # undefined local variable or method `some_x'
869
+ # # from file.erb:4
870
+ #
871
+ def location=((filename, lineno))
872
+ @filename = filename
873
+ @lineno = lineno if lineno
874
+ end
875
+
876
+ #
877
+ # Can be used to set _eoutvar_ as described in ERB::new. It's probably
878
+ # easier to just use the constructor though, since calling this method
879
+ # requires the setup of an ERB _compiler_ object.
880
+ #
881
+ def set_eoutvar(compiler, eoutvar = '_erbout')
882
+ compiler.put_cmd = "#{eoutvar}.<<"
883
+ compiler.insert_cmd = "#{eoutvar}.<<"
884
+ compiler.pre_cmd = ["#{eoutvar} = +''"]
885
+ compiler.post_cmd = [eoutvar]
886
+ end
887
+
888
+ # Generate results and print them. (see ERB#result)
889
+ def run(b=new_toplevel)
890
+ print self.result(b)
891
+ end
892
+
893
+ #
894
+ # Executes the generated ERB code to produce a completed template, returning
895
+ # the results of that code. (See ERB::new for details on how this process
896
+ # can be affected by _safe_level_.)
897
+ #
898
+ # _b_ accepts a Binding object which is used to set the context of
899
+ # code evaluation.
900
+ #
901
+ def result(b=new_toplevel)
902
+ unless @_init.equal?(self.class.singleton_class)
903
+ raise ArgumentError, "not initialized"
904
+ end
905
+ eval(@src, b, (@filename || '(erb)'), @lineno)
906
+ end
907
+
908
+ # Render a template on a new toplevel binding with local variables specified
909
+ # by a Hash object.
910
+ def result_with_hash(hash)
911
+ b = new_toplevel(hash.keys)
912
+ hash.each_pair do |key, value|
913
+ b.local_variable_set(key, value)
914
+ end
915
+ result(b)
916
+ end
917
+
918
+ ##
919
+ # Returns a new binding each time *near* TOPLEVEL_BINDING for runs that do
920
+ # not specify a binding.
921
+
922
+ def new_toplevel(vars = nil)
923
+ b = TOPLEVEL_BINDING
924
+ if vars
925
+ vars = vars.select {|v| b.local_variable_defined?(v)}
926
+ unless vars.empty?
927
+ return b.eval("tap {|;#{vars.join(',')}| break binding}")
928
+ end
929
+ end
930
+ b.dup
931
+ end
932
+ private :new_toplevel
933
+
934
+ # Define _methodname_ as instance method of _mod_ from compiled Ruby source.
935
+ #
936
+ # example:
937
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
938
+ # erb = ERB.new(File.read(filename))
939
+ # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
940
+ # print MyClass.new.render('foo', 123)
941
+ def def_method(mod, methodname, fname='(ERB)')
942
+ src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n"
943
+ mod.module_eval do
944
+ eval(src, binding, fname, -1)
945
+ end
946
+ end
947
+
948
+ # Create unnamed module, define _methodname_ as instance method of it, and return it.
949
+ #
950
+ # example:
951
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
952
+ # erb = ERB.new(File.read(filename))
953
+ # erb.filename = filename
954
+ # MyModule = erb.def_module('render(arg1, arg2)')
955
+ # class MyClass
956
+ # include MyModule
957
+ # end
958
+ def def_module(methodname='erb')
959
+ mod = Module.new
960
+ def_method(mod, methodname, @filename || '(ERB)')
961
+ mod
962
+ end
963
+
964
+ # Define unnamed class which has _methodname_ as instance method, and return it.
965
+ #
966
+ # example:
967
+ # class MyClass_
968
+ # def initialize(arg1, arg2)
969
+ # @arg1 = arg1; @arg2 = arg2
970
+ # end
971
+ # end
972
+ # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
973
+ # erb = ERB.new(File.read(filename))
974
+ # erb.filename = filename
975
+ # MyClass = erb.def_class(MyClass_, 'render()')
976
+ # print MyClass.new('foo', 123).render()
977
+ def def_class(superklass=Object, methodname='result')
978
+ cls = Class.new(superklass)
979
+ def_method(cls, methodname, @filename || '(ERB)')
980
+ cls
981
+ end
982
+ end
983
+
984
+ #--
985
+ # ERB::Util
986
+ class ERB
987
+ # A utility module for conversion routines, often handy in HTML generation.
988
+ module Util
989
+ public
990
+ #
991
+ # A utility method for escaping HTML tag characters in _s_.
992
+ #
993
+ # require "erb"
994
+ # include ERB::Util
995
+ #
996
+ # puts html_escape("is a > 0 & a < 10?")
997
+ #
998
+ # _Generates_
999
+ #
1000
+ # is a &gt; 0 &amp; a &lt; 10?
1001
+ #
1002
+ def html_escape(s)
1003
+ CGI.escapeHTML(s.to_s)
1004
+ end
1005
+ alias h html_escape
1006
+ module_function :h
1007
+ module_function :html_escape
1008
+
1009
+ #
1010
+ # A utility method for encoding the String _s_ as a URL.
1011
+ #
1012
+ # require "erb"
1013
+ # include ERB::Util
1014
+ #
1015
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
1016
+ #
1017
+ # _Generates_
1018
+ #
1019
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
1020
+ #
1021
+ def url_encode(s)
1022
+ s.to_s.b.gsub(/[^a-zA-Z0-9_\-.~]/n) { |m|
1023
+ sprintf("%%%02X", m.unpack1("C"))
1024
+ }
1025
+ end
1026
+ alias u url_encode
1027
+ module_function :u
1028
+ module_function :url_encode
1029
+ end
1030
+ end
1031
+
1032
+ #--
1033
+ # ERB::DefMethod
1034
+ class ERB
1035
+ # Utility module to define eRuby script as instance method.
1036
+ #
1037
+ # === Example
1038
+ #
1039
+ # example.rhtml:
1040
+ # <% for item in @items %>
1041
+ # <b><%= item %></b>
1042
+ # <% end %>
1043
+ #
1044
+ # example.rb:
1045
+ # require 'erb'
1046
+ # class MyClass
1047
+ # extend ERB::DefMethod
1048
+ # def_erb_method('render()', 'example.rhtml')
1049
+ # def initialize(items)
1050
+ # @items = items
1051
+ # end
1052
+ # end
1053
+ # print MyClass.new([10,20,30]).render()
1054
+ #
1055
+ # result:
1056
+ #
1057
+ # <b>10</b>
1058
+ #
1059
+ # <b>20</b>
1060
+ #
1061
+ # <b>30</b>
1062
+ #
1063
+ module DefMethod
1064
+ public
1065
+ # define _methodname_ as instance method of current module, using ERB
1066
+ # object or eRuby file
1067
+ def def_erb_method(methodname, erb_or_fname)
1068
+ if erb_or_fname.kind_of? String
1069
+ fname = erb_or_fname
1070
+ erb = ERB.new(File.read(fname))
1071
+ erb.def_method(self, methodname, fname)
1072
+ else
1073
+ erb = erb_or_fname
1074
+ erb.def_method(self, methodname, erb.filename || '(ERB)')
1075
+ end
1076
+ end
1077
+ module_function :def_erb_method
1078
+ end
1079
+ end