summaryrefslogtreecommitdiff
path: root/libexec/erb
blob: de7d5888c346e8c9e6238a516cb3597534536258 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/usr/bin/env ruby
# Tiny eRuby --- ERB2
# Copyright (c) 1999-2000,2002 Masatoshi SEKI
# You can redistribute it and/or modify it under the same terms as Ruby.

require 'erb'

class ERB
  module Main
    def ARGV.switch
      return nil if self.empty?
      arg = self.shift
      return nil if arg == '--'
      case arg
      when /\A-(.)(.*)/
        if $1 == '-'
          arg, @maybe_arg = arg.split(/=/, 2)
          return arg
        end
        raise 'unknown switch "-"' if $2[0] == ?- and $1 != 'T'
        if $2.size > 0
          self.unshift "-#{$2}"
          @maybe_arg = $2
        else
          @maybe_arg = nil
        end
        "-#{$1}"
      when /\A(\w+)=/
        arg
      else
        self.unshift arg
        nil
      end
    end

    def ARGV.req_arg
      (@maybe_arg || self.shift || raise('missing argument')).tap {
        @maybe_arg = nil
      }
    end

    def trim_mode_opt(trim_mode, disable_percent)
      return trim_mode if disable_percent
      case trim_mode
      when 0
        return '%'
      when 1
        return '%>'
      when 2
        return '%<>'
      when '-'
        return '%-'
      end
    end
    module_function :trim_mode_opt

    def run(factory=ERB)
      trim_mode = 0
      disable_percent = false
      variables = {}
      begin
        while switch = ARGV.switch
          case switch
          when '-x'                        # ruby source
            output = true
          when '-n'                        # line number
            number = true
          when '-v'                        # verbose
            $VERBOSE = true
          when '--version'                 # version
            STDERR.puts factory.version
            exit
          when '-d', '--debug'             # debug
            $DEBUG = true
          when '-r'                        # require
            require ARGV.req_arg
          when '-T'                        # trim mode
            arg = ARGV.req_arg
            if arg == '-'
              trim_mode = arg
              next
            end
            raise "invalid trim mode #{arg.dump}" unless arg =~ /\A[0-2]\z/
            trim_mode = arg.to_i
          when '-E', '--encoding'
            arg = ARGV.req_arg
            set_encoding(*arg.split(/:/, 2))
          when '-U'
            set_encoding(Encoding::UTF_8, Encoding::UTF_8)
          when '-P'
            disable_percent = true
          when '--help'
            raise ''
          when /\A-/
            raise "Unknown switch: #{switch.dump}"
          else
            var, val = *switch.split('=', 2)
            (variables ||= {})[var] = val
          end
        end
      rescue                               # usage
        message = $!.to_s
        STDERR.puts message unless message.empty?
        STDERR.puts 'Usage:'
        STDERR.puts "  #{File.basename($0)} [options] [filepaths]"
        STDERR.puts <<EOU

Options:
  -d          --debug      Set $DEBUG to enable debugging.
  -E ex[:in]  --encoding ex[:in]
                           Set default external and internal encodings.
  -h          --help       Print this text and exit.
  -n                       Print generated Ruby source code with line numbers;
                           ignored if given without option -x.
  -P                       Disable execution tag shorthand (for lines beginning with '%').
  -r library               Load the named library.
  -T trim_mode             Specify trim_mode:
                           '0' means '%'; '1' means '%>'; '2' means '<>'; '-' means '%-'.
  -U                       Set default encoding to UTF-8.
  -v                       Set $VERBOSE to enable debugging,
              --version    Print ERB version string and exit.
  -x                       Print generated Ruby source code.
              --           Treat all following words as filepaths (not options).
  name=value               Set the variable named name to the given string value.

Filepaths:
  The erb program reads the text from all files at the filepaths as a single ERB template:
  plain text, possibly with embedded ERB tags;
  filepaths may be repeated.

  The pseudo-filepath '-' (hyphen character) specifies the standard input.

  If no filepaths are given, the sole input is the standard input.

See details and examples at https://docs.ruby-lang.org/en/master/erb_executable_md.html
EOU
        exit 1
      end

      $<.set_encoding(Encoding::UTF_8, nil)
      src = $<.read
      filename = $FILENAME
      exit 2 unless src
      trim = trim_mode_opt(trim_mode, disable_percent)
      erb = factory.new(src, trim_mode: trim)
      erb.filename = filename
      if output
        if number
          erb.src.each_line.with_index do |line, l|
            puts "%3d %s"%[l+1, line]
          end
        else
          puts erb.src
        end
      else
        bind = TOPLEVEL_BINDING
        if variables
          enc = erb.encoding
          for var, val in variables do
            val = val.encode(enc) if val
            bind.local_variable_set(var, val)
          end
        end
        erb.run(bind)
      end
    end
    module_function :run

    def set_encoding(extern, intern = nil)
      verbose, $VERBOSE = $VERBOSE, nil
      Encoding.default_external = extern unless extern.nil? || extern == ""
      Encoding.default_internal = intern unless intern.nil? || intern == ""
      [$stdin, $stdout, $stderr].each do |io|
        io.set_encoding(extern, intern)
      end
    ensure
      $VERBOSE = verbose
    end
    module_function :set_encoding
    class << self; private :set_encoding; end
  end
end

ERB::Main.run