erb 2.2.0

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,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