class ReVIEW::Preprocessor
Constants
- INF_INDENT
- KNOWN_DIRECTIVES
- TYPES
Public Class Methods
new(param)
click to toggle source
# File lib/review/preprocessor.rb, line 26 def initialize(param) @repository = ReVIEW::Preprocessor::Repository.new(param) @config = param ## do not use params in this class; only used in Repository @logger = ReVIEW.logger @leave_content = nil end
Public Instance Methods
process(path)
click to toggle source
# File lib/review/preprocessor.rb, line 33 def process(path) File.open(path) do |inf| @inf = inf @f = StringIO.new begin preproc(@inf) rescue Errno::ENOENT => e error! e.message end @f.string end end
Private Instance Methods
defvar(name, value)
click to toggle source
# File lib/review/preprocessor.rb, line 206 def defvar(name, value) @vartable[name] = value end
evaluate(path, chunk)
click to toggle source
# File lib/review/preprocessor.rb, line 228 def evaluate(path, chunk) outputs = get_output("ruby #{path}", false).split("\n").map(&:strip) chunk.map do |line| if /\# \$\d+/ =~ line.string # map result into source. line.edit { |s| s.sub(/\$(\d+)/) { outputs[$1.to_i - 1] } } else line end end end
expand(str)
click to toggle source
# File lib/review/preprocessor.rb, line 210 def expand(str) str.gsub(/\$\w+/) do |name| s = @vartable[name.sub('$', '')] s ? expand(s) : name end end
filename()
click to toggle source
# File lib/review/preprocessor.rb, line 263 def filename @inf.path end
get_output(cmd, use_stderr)
click to toggle source
# File lib/review/preprocessor.rb, line 240 def get_output(cmd, use_stderr) out = err = nil Open3.popen3(cmd) do |_stdin, stdout, stderr| out = stdout.readlines if use_stderr out.concat(stderr.readlines) else err = stderr.readlines end end if err && !err.empty? $stderr.puts '[unexpected stderr message]' err.each { |line| $stderr.print line } app_error 'get_output: got unexpected output' end num = 0 out.map { |line| Line.new(num += 1, line) } end
known_directive?(op)
click to toggle source
# File lib/review/preprocessor.rb, line 116 def known_directive?(op) KNOWN_DIRECTIVES.index(op) end
lineno()
click to toggle source
# File lib/review/preprocessor.rb, line 267 def lineno @inf.lineno end
location()
click to toggle source
# File lib/review/preprocessor.rb, line 259 def location "#{filename}:#{lineno}" end
minimum_indent(chunk)
click to toggle source
# File lib/review/preprocessor.rb, line 223 def minimum_indent(chunk) n = chunk.map { |line| line.empty? ? INF_INDENT : line.num_indent }.min n == INF_INDENT ? 0 : n end
optarg_value(spec)
click to toggle source
# File lib/review/preprocessor.rb, line 191 def optarg_value(spec) case spec when 'true' # [name=true], [name] true when 'false' # [name=false] false when 'nil' # [name=nil] nil when /^\d+$/ # [name=8] $&.to_i else # [name=val] spec end end
parse_directive(line, argc, *optdecl)
click to toggle source
# File lib/review/preprocessor.rb, line 158 def parse_directive(line, argc, *optdecl) m = /\A\#@(\w+)\((.*?)\)(?:\[(.*?)\])?\z/.match(line.strip) or app_error "wrong directive: #{line.strip}" op = m[1] args = m[2].split(/,\s*/) opts = parse_optargs(m[3]) return if (argc == 0) && args.empty? if argc == -1 # Any number of arguments are allowed. elsif args.size != argc app_error 'wrong arg size' end if opts wrong_opts = opts.keys - optdecl unless wrong_opts.empty? app_error "wrong option: #{wrong_opts.keys.join(' ')}" end end Directive.new(op, args, opts || {}) end
parse_optargs(str)
click to toggle source
# File lib/review/preprocessor.rb, line 180 def parse_optargs(str) return nil unless str table = {} str.split(/,\s*/).each do |a| name, spec = a.split('=', 2) table[name] = optarg_value(spec) end table end
preproc(f)
click to toggle source
# File lib/review/preprocessor.rb, line 48 def preproc(f) @vartable = {} @has_errors = false f.each_line do |line| begin case line when /\A\#@\#/, /\A\#\#\#\#/ @f.print line when /\A\#@defvar/ @f.print line direc = parse_directive(line, 2) defvar(*direc.args) when /\A\#@mapoutput/ direc = parse_directive(line, 1, 'stderr') @f.print line get_output(expand(direc.arg), direc['stderr']).each { |out| @f.print out.string } skip_list(f) when /\A\#@mapfile/ direc = parse_directive(line, 1, 'eval') path = expand(direc.arg) @leave_content = File.extname(path) == '.re' if direc['eval'] ent = evaluate(path, ent) else ent = @repository.fetch_file(path) end replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp when /\A\#@map(?:range)?/ direc = parse_directive(line, 2, 'unindent') path = expand(direc.args[0]) @leave_content = File.extname(path) == '.re' ent = @repository.fetch_range(path, direc.args[1]) or app_error "unknown range: #{path}: #{direc.args[1]}" ent = (direc['unindent'] ? unindent(ent, direc['unindent']) : ent) replace_block(f, line, ent, false) # FIXME: turn off lineno: tmp when /\A\#@end/ app_error 'unbaranced #@end' when /\A\#@/ op = line.slice(/@(\w+)/, 1) warn "unknown directive: #{line.strip}", location: location unless known_directive?(op) if op == 'warn' warn line.strip.sub(/\#@warn\((.+)\)/, '\1'), location: location end @f.print line when /\A\s*\z/ # empty line @f.puts else # rubocop:disable Lint/DuplicateBranch @f.print line end rescue ApplicationError => e @has_errors = true error e.message, location: location end end if @has_erros error! 'preprocessor failed.' end end
print_number(num)
click to toggle source
# File lib/review/preprocessor.rb, line 131 def print_number(num) @f.printf('%4s ', (num ? num.to_s : '')) end
replace_block(f, directive_line, newlines, with_lineno)
click to toggle source
# File lib/review/preprocessor.rb, line 120 def replace_block(f, directive_line, newlines, with_lineno) @f.print directive_line newlines.each do |line| if with_lineno print_number(line.number) end @f.print line.string end skip_list(f) end
skip_list(f)
click to toggle source
# File lib/review/preprocessor.rb, line 135 def skip_list(f) begline = f.lineno f.each_line do |line| case line when /\A\#@end/ @f.print line return nil when %r{\A//\}} unless @leave_content warn '//} seen in list', location: location @f.print line return nil end when /\A\#@\w/ warn "#{line.slice(/\A\#@\w+/)} seen in list", location: location @f.print line when /\A\#@/ @f.print line end end app_error "list reached end of file (beginning line = #{begline})" end
unindent(chunk, n)
click to toggle source
# File lib/review/preprocessor.rb, line 217 def unindent(chunk, n) n = minimum_indent(chunk) unless n.is_a?(Integer) re = /\A#{' ' * n}/ chunk.map { |line| line.edit { |s| s.sub(re, '') } } end