erb 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/erb.rb CHANGED
@@ -14,6 +14,9 @@
14
14
 
15
15
  require 'cgi/util'
16
16
  require 'erb/version'
17
+ require 'erb/compiler'
18
+ require 'erb/def_method'
19
+ require 'erb/util'
17
20
 
18
21
  #
19
22
  # = ERB -- Ruby Templating
@@ -264,486 +267,7 @@ class ERB
264
267
  def self.version
265
268
  VERSION
266
269
  end
267
- end
268
270
 
269
- #--
270
- # ERB::Compiler
271
- class ERB
272
- # = ERB::Compiler
273
- #
274
- # Compiles ERB templates into Ruby code; the compiled code produces the
275
- # template result when evaluated. ERB::Compiler provides hooks to define how
276
- # generated output is handled.
277
- #
278
- # Internally ERB does something like this to generate the code returned by
279
- # ERB#src:
280
- #
281
- # compiler = ERB::Compiler.new('<>')
282
- # compiler.pre_cmd = ["_erbout=+''"]
283
- # compiler.put_cmd = "_erbout.<<"
284
- # compiler.insert_cmd = "_erbout.<<"
285
- # compiler.post_cmd = ["_erbout"]
286
- #
287
- # code, enc = compiler.compile("Got <%= obj %>!\n")
288
- # puts code
289
- #
290
- # <i>Generates</i>:
291
- #
292
- # #coding:UTF-8
293
- # _erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _erbout
294
- #
295
- # By default the output is sent to the print method. For example:
296
- #
297
- # compiler = ERB::Compiler.new('<>')
298
- # code, enc = compiler.compile("Got <%= obj %>!\n")
299
- # puts code
300
- #
301
- # <i>Generates</i>:
302
- #
303
- # #coding:UTF-8
304
- # print "Got ".freeze; print(( obj ).to_s); print "!\n".freeze
305
- #
306
- # == Evaluation
307
- #
308
- # The compiled code can be used in any context where the names in the code
309
- # correctly resolve. Using the last example, each of these print 'Got It!'
310
- #
311
- # Evaluate using a variable:
312
- #
313
- # obj = 'It'
314
- # eval code
315
- #
316
- # Evaluate using an input:
317
- #
318
- # mod = Module.new
319
- # mod.module_eval %{
320
- # def get(obj)
321
- # #{code}
322
- # end
323
- # }
324
- # extend mod
325
- # get('It')
326
- #
327
- # Evaluate using an accessor:
328
- #
329
- # klass = Class.new Object
330
- # klass.class_eval %{
331
- # attr_accessor :obj
332
- # def initialize(obj)
333
- # @obj = obj
334
- # end
335
- # def get_it
336
- # #{code}
337
- # end
338
- # }
339
- # klass.new('It').get_it
340
- #
341
- # Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.
342
- class Compiler # :nodoc:
343
- class PercentLine # :nodoc:
344
- def initialize(str)
345
- @value = str
346
- end
347
- attr_reader :value
348
- alias :to_s :value
349
- end
350
-
351
- class Scanner # :nodoc:
352
- @scanner_map = {}
353
- class << self
354
- def register_scanner(klass, trim_mode, percent)
355
- @scanner_map[[trim_mode, percent]] = klass
356
- end
357
- alias :regist_scanner :register_scanner
358
- end
359
-
360
- def self.default_scanner=(klass)
361
- @default_scanner = klass
362
- end
363
-
364
- def self.make_scanner(src, trim_mode, percent)
365
- klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
366
- klass.new(src, trim_mode, percent)
367
- end
368
-
369
- DEFAULT_STAGS = %w(<%% <%= <%# <%).freeze
370
- DEFAULT_ETAGS = %w(%%> %>).freeze
371
- def initialize(src, trim_mode, percent)
372
- @src = src
373
- @stag = nil
374
- @stags = DEFAULT_STAGS
375
- @etags = DEFAULT_ETAGS
376
- end
377
- attr_accessor :stag
378
- attr_reader :stags, :etags
379
-
380
- def scan; end
381
- end
382
-
383
- class TrimScanner < Scanner # :nodoc:
384
- def initialize(src, trim_mode, percent)
385
- super
386
- @trim_mode = trim_mode
387
- @percent = percent
388
- if @trim_mode == '>'
389
- @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
390
- @scan_line = self.method(:trim_line1)
391
- elsif @trim_mode == '<>'
392
- @scan_reg = /(.*?)(%>\r?\n|#{(stags + etags).join('|')}|\n|\z)/m
393
- @scan_line = self.method(:trim_line2)
394
- elsif @trim_mode == '-'
395
- @scan_reg = /(.*?)(^[ \t]*<%\-|<%\-|-%>\r?\n|-%>|#{(stags + etags).join('|')}|\z)/m
396
- @scan_line = self.method(:explicit_trim_line)
397
- else
398
- @scan_reg = /(.*?)(#{(stags + etags).join('|')}|\n|\z)/m
399
- @scan_line = self.method(:scan_line)
400
- end
401
- end
402
-
403
- def scan(&block)
404
- @stag = nil
405
- if @percent
406
- @src.each_line do |line|
407
- percent_line(line, &block)
408
- end
409
- else
410
- @scan_line.call(@src, &block)
411
- end
412
- nil
413
- end
414
-
415
- def percent_line(line, &block)
416
- if @stag || line[0] != ?%
417
- return @scan_line.call(line, &block)
418
- end
419
-
420
- line[0] = ''
421
- if line[0] == ?%
422
- @scan_line.call(line, &block)
423
- else
424
- yield(PercentLine.new(line.chomp))
425
- end
426
- end
427
-
428
- def scan_line(line)
429
- line.scan(@scan_reg) do |tokens|
430
- tokens.each do |token|
431
- next if token.empty?
432
- yield(token)
433
- end
434
- end
435
- end
436
-
437
- def trim_line1(line)
438
- line.scan(@scan_reg) do |tokens|
439
- tokens.each do |token|
440
- next if token.empty?
441
- if token == "%>\n" || token == "%>\r\n"
442
- yield('%>')
443
- yield(:cr)
444
- else
445
- yield(token)
446
- end
447
- end
448
- end
449
- end
450
-
451
- def trim_line2(line)
452
- head = nil
453
- line.scan(@scan_reg) do |tokens|
454
- tokens.each do |token|
455
- next if token.empty?
456
- head = token unless head
457
- if token == "%>\n" || token == "%>\r\n"
458
- yield('%>')
459
- if is_erb_stag?(head)
460
- yield(:cr)
461
- else
462
- yield("\n")
463
- end
464
- head = nil
465
- else
466
- yield(token)
467
- head = nil if token == "\n"
468
- end
469
- end
470
- end
471
- end
472
-
473
- def explicit_trim_line(line)
474
- line.scan(@scan_reg) do |tokens|
475
- tokens.each do |token|
476
- next if token.empty?
477
- if @stag.nil? && /[ \t]*<%-/ =~ token
478
- yield('<%')
479
- elsif @stag && (token == "-%>\n" || token == "-%>\r\n")
480
- yield('%>')
481
- yield(:cr)
482
- elsif @stag && token == '-%>'
483
- yield('%>')
484
- else
485
- yield(token)
486
- end
487
- end
488
- end
489
- end
490
-
491
- ERB_STAG = %w(<%= <%# <%)
492
- def is_erb_stag?(s)
493
- ERB_STAG.member?(s)
494
- end
495
- end
496
-
497
- Scanner.default_scanner = TrimScanner
498
-
499
- begin
500
- require 'strscan'
501
- rescue LoadError
502
- else
503
- class SimpleScanner < Scanner # :nodoc:
504
- def scan
505
- stag_reg = (stags == DEFAULT_STAGS) ? /(.*?)(<%[%=#]?|\z)/m : /(.*?)(#{stags.join('|')}|\z)/m
506
- etag_reg = (etags == DEFAULT_ETAGS) ? /(.*?)(%%?>|\z)/m : /(.*?)(#{etags.join('|')}|\z)/m
507
- scanner = StringScanner.new(@src)
508
- while ! scanner.eos?
509
- scanner.scan(@stag ? etag_reg : stag_reg)
510
- yield(scanner[1])
511
- yield(scanner[2])
512
- end
513
- end
514
- end
515
- Scanner.register_scanner(SimpleScanner, nil, false)
516
-
517
- class ExplicitScanner < Scanner # :nodoc:
518
- def scan
519
- stag_reg = /(.*?)(^[ \t]*<%-|<%-|#{stags.join('|')}|\z)/m
520
- etag_reg = /(.*?)(-%>|#{etags.join('|')}|\z)/m
521
- scanner = StringScanner.new(@src)
522
- while ! scanner.eos?
523
- scanner.scan(@stag ? etag_reg : stag_reg)
524
- yield(scanner[1])
525
-
526
- elem = scanner[2]
527
- if /[ \t]*<%-/ =~ elem
528
- yield('<%')
529
- elsif elem == '-%>'
530
- yield('%>')
531
- yield(:cr) if scanner.scan(/(\r?\n|\z)/)
532
- else
533
- yield(elem)
534
- end
535
- end
536
- end
537
- end
538
- Scanner.register_scanner(ExplicitScanner, '-', false)
539
- end
540
-
541
- class Buffer # :nodoc:
542
- def initialize(compiler, enc=nil, frozen=nil)
543
- @compiler = compiler
544
- @line = []
545
- @script = +''
546
- @script << "#coding:#{enc}\n" if enc
547
- @script << "#frozen-string-literal:#{frozen}\n" unless frozen.nil?
548
- @compiler.pre_cmd.each do |x|
549
- push(x)
550
- end
551
- end
552
- attr_reader :script
553
-
554
- def push(cmd)
555
- @line << cmd
556
- end
557
-
558
- def cr
559
- @script << (@line.join('; '))
560
- @line = []
561
- @script << "\n"
562
- end
563
-
564
- def close
565
- return unless @line
566
- @compiler.post_cmd.each do |x|
567
- push(x)
568
- end
569
- @script << (@line.join('; '))
570
- @line = nil
571
- end
572
- end
573
-
574
- def add_put_cmd(out, content)
575
- out.push("#{@put_cmd} #{content.dump}.freeze#{"\n" * content.count("\n")}")
576
- end
577
-
578
- def add_insert_cmd(out, content)
579
- out.push("#{@insert_cmd}((#{content}).to_s)")
580
- end
581
-
582
- # Compiles an ERB template into Ruby code. Returns an array of the code
583
- # and encoding like ["code", Encoding].
584
- def compile(s)
585
- enc = s.encoding
586
- raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
587
- s = s.b # see String#b
588
- magic_comment = detect_magic_comment(s, enc)
589
- out = Buffer.new(self, *magic_comment)
590
-
591
- self.content = +''
592
- scanner = make_scanner(s)
593
- scanner.scan do |token|
594
- next if token.nil?
595
- next if token == ''
596
- if scanner.stag.nil?
597
- compile_stag(token, out, scanner)
598
- else
599
- compile_etag(token, out, scanner)
600
- end
601
- end
602
- add_put_cmd(out, content) if content.size > 0
603
- out.close
604
- return out.script, *magic_comment
605
- end
606
-
607
- def compile_stag(stag, out, scanner)
608
- case stag
609
- when PercentLine
610
- add_put_cmd(out, content) if content.size > 0
611
- self.content = +''
612
- out.push(stag.to_s)
613
- out.cr
614
- when :cr
615
- out.cr
616
- when '<%', '<%=', '<%#'
617
- scanner.stag = stag
618
- add_put_cmd(out, content) if content.size > 0
619
- self.content = +''
620
- when "\n"
621
- content << "\n"
622
- add_put_cmd(out, content)
623
- self.content = +''
624
- when '<%%'
625
- content << '<%'
626
- else
627
- content << stag
628
- end
629
- end
630
-
631
- def compile_etag(etag, out, scanner)
632
- case etag
633
- when '%>'
634
- compile_content(scanner.stag, out)
635
- scanner.stag = nil
636
- self.content = +''
637
- when '%%>'
638
- content << '%>'
639
- else
640
- content << etag
641
- end
642
- end
643
-
644
- def compile_content(stag, out)
645
- case stag
646
- when '<%'
647
- if content[-1] == ?\n
648
- content.chop!
649
- out.push(content)
650
- out.cr
651
- else
652
- out.push(content)
653
- end
654
- when '<%='
655
- add_insert_cmd(out, content)
656
- when '<%#'
657
- # commented out
658
- end
659
- end
660
-
661
- def prepare_trim_mode(mode) # :nodoc:
662
- case mode
663
- when 1
664
- return [false, '>']
665
- when 2
666
- return [false, '<>']
667
- when 0, nil
668
- return [false, nil]
669
- when String
670
- unless mode.match?(/\A(%|-|>|<>){1,2}\z/)
671
- warn_invalid_trim_mode(mode, uplevel: 5)
672
- end
673
-
674
- perc = mode.include?('%')
675
- if mode.include?('-')
676
- return [perc, '-']
677
- elsif mode.include?('<>')
678
- return [perc, '<>']
679
- elsif mode.include?('>')
680
- return [perc, '>']
681
- else
682
- [perc, nil]
683
- end
684
- else
685
- warn_invalid_trim_mode(mode, uplevel: 5)
686
- return [false, nil]
687
- end
688
- end
689
-
690
- def make_scanner(src) # :nodoc:
691
- Scanner.make_scanner(src, @trim_mode, @percent)
692
- end
693
-
694
- # Construct a new compiler using the trim_mode. See ERB::new for available
695
- # trim modes.
696
- def initialize(trim_mode)
697
- @percent, @trim_mode = prepare_trim_mode(trim_mode)
698
- @put_cmd = 'print'
699
- @insert_cmd = @put_cmd
700
- @pre_cmd = []
701
- @post_cmd = []
702
- end
703
- attr_reader :percent, :trim_mode
704
-
705
- # The command to handle text that ends with a newline
706
- attr_accessor :put_cmd
707
-
708
- # The command to handle text that is inserted prior to a newline
709
- attr_accessor :insert_cmd
710
-
711
- # An array of commands prepended to compiled code
712
- attr_accessor :pre_cmd
713
-
714
- # An array of commands appended to compiled code
715
- attr_accessor :post_cmd
716
-
717
- private
718
-
719
- # A buffered text in #compile
720
- attr_accessor :content
721
-
722
- def detect_magic_comment(s, enc = nil)
723
- re = @percent ? /\G(?:<%#(.*)%>|%#(.*)\n)/ : /\G<%#(.*)%>/
724
- frozen = nil
725
- s.scan(re) do
726
- comment = $+
727
- comment = $1 if comment[/-\*-\s*([^\s].*?)\s*-\*-$/]
728
- case comment
729
- when %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
730
- enc = Encoding.find($1.sub(/-(?:mac|dos|unix)/i, ''))
731
- when %r"frozen[-_]string[-_]literal\s*:\s*([[:alnum:]]+)"
732
- frozen = $1
733
- end
734
- end
735
- return enc, frozen
736
- end
737
-
738
- def warn_invalid_trim_mode(mode, uplevel:)
739
- warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + 1
740
- end
741
- end
742
- end
743
-
744
- #--
745
- # ERB
746
- class ERB
747
271
  #
748
272
  # Constructs a new ERB object with the template specified in _str_.
749
273
  #
@@ -980,98 +504,3 @@ class ERB
980
504
  cls
981
505
  end
982
506
  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
- CGI.escapeURIComponent(s.to_s)
1023
- end
1024
- alias u url_encode
1025
- module_function :u
1026
- module_function :url_encode
1027
- end
1028
- end
1029
-
1030
- #--
1031
- # ERB::DefMethod
1032
- class ERB
1033
- # Utility module to define eRuby script as instance method.
1034
- #
1035
- # === Example
1036
- #
1037
- # example.rhtml:
1038
- # <% for item in @items %>
1039
- # <b><%= item %></b>
1040
- # <% end %>
1041
- #
1042
- # example.rb:
1043
- # require 'erb'
1044
- # class MyClass
1045
- # extend ERB::DefMethod
1046
- # def_erb_method('render()', 'example.rhtml')
1047
- # def initialize(items)
1048
- # @items = items
1049
- # end
1050
- # end
1051
- # print MyClass.new([10,20,30]).render()
1052
- #
1053
- # result:
1054
- #
1055
- # <b>10</b>
1056
- #
1057
- # <b>20</b>
1058
- #
1059
- # <b>30</b>
1060
- #
1061
- module DefMethod
1062
- public
1063
- # define _methodname_ as instance method of current module, using ERB
1064
- # object or eRuby file
1065
- def def_erb_method(methodname, erb_or_fname)
1066
- if erb_or_fname.kind_of? String
1067
- fname = erb_or_fname
1068
- erb = ERB.new(File.read(fname))
1069
- erb.def_method(self, methodname, fname)
1070
- else
1071
- erb = erb_or_fname
1072
- erb.def_method(self, methodname, erb.filename || '(ERB)')
1073
- end
1074
- end
1075
- module_function :def_erb_method
1076
- end
1077
- end
data/libexec/erb CHANGED
@@ -74,11 +74,6 @@ class ERB
74
74
  $DEBUG = true
75
75
  when '-r' # require
76
76
  require ARGV.req_arg
77
- when '-S' # security level
78
- warn 'warning: -S option of erb command is deprecated. Please do not use this.'
79
- arg = ARGV.req_arg
80
- raise "invalid safe_level #{arg.dump}" unless arg =~ /\A[0-1]\z/
81
- safe_level = arg.to_i
82
77
  when '-T' # trim mode
83
78
  arg = ARGV.req_arg
84
79
  if arg == '-'
@@ -127,12 +122,7 @@ EOU
127
122
  filename = $FILENAME
128
123
  exit 2 unless src
129
124
  trim = trim_mode_opt(trim_mode, disable_percent)
130
- if safe_level.nil?
131
- erb = factory.new(src, trim_mode: trim)
132
- else
133
- # [deprecated] This will be removed at Ruby 2.7.
134
- erb = factory.new(src, safe_level, trim_mode: trim)
135
- end
125
+ erb = factory.new(src, trim_mode: trim)
136
126
  erb.filename = filename
137
127
  if output
138
128
  if number
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masatoshi SEKI
8
- autorequire:
8
+ - Takashi Kokubun
9
+ autorequire:
9
10
  bindir: libexec
10
11
  cert_chain: []
11
- date: 2022-10-25 00:00:00.000000000 Z
12
+ date: 2022-11-26 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: cgi
@@ -27,9 +28,11 @@ dependencies:
27
28
  description: An easy to use but powerful templating system for Ruby.
28
29
  email:
29
30
  - seki@ruby-lang.org
31
+ - takashikkbn@gmail.com
30
32
  executables:
31
33
  - erb
32
- extensions: []
34
+ extensions:
35
+ - ext/erb/escape/extconf.rb
33
36
  extra_rdoc_files: []
34
37
  files:
35
38
  - ".github/workflows/test.yml"
@@ -42,7 +45,12 @@ files:
42
45
  - bin/console
43
46
  - bin/setup
44
47
  - erb.gemspec
48
+ - ext/erb/escape/escape.c
49
+ - ext/erb/escape/extconf.rb
45
50
  - lib/erb.rb
51
+ - lib/erb/compiler.rb
52
+ - lib/erb/def_method.rb
53
+ - lib/erb/util.rb
46
54
  - lib/erb/version.rb
47
55
  - libexec/erb
48
56
  homepage: https://github.com/ruby/erb
@@ -52,7 +60,7 @@ licenses:
52
60
  metadata:
53
61
  homepage_uri: https://github.com/ruby/erb
54
62
  source_code_uri: https://github.com/ruby/erb
55
- post_install_message:
63
+ post_install_message:
56
64
  rdoc_options: []
57
65
  require_paths:
58
66
  - lib
@@ -68,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
76
  version: '0'
69
77
  requirements: []
70
78
  rubygems_version: 3.3.7
71
- signing_key:
79
+ signing_key:
72
80
  specification_version: 4
73
81
  summary: An easy to use but powerful templating system for Ruby.
74
82
  test_files: []