# Copyright (c) 2020 Jerome Arbez-Gindre # frozen_string_literal: true module DefMastership # Change included filenames on one line at a time class RenameIncludedFilesLineModifier < LineModifierBase LOCAL_FILTERS = [ Filter.new(DMRegexp::VARIABLE_DEF, :new_variable_def, false), Filter.new(DMRegexp::DEFINITION, :new_definition, true), Filter.new(DMRegexp::BLOCK, :block_delimiter, true), Filter.new(DMRegexp::EMPTY_LINE, :empty_line, false), Filter.new(DMRegexp::WHATEVER, :new_line, true) ].freeze private_constant :LOCAL_FILTERS def self.from_config(config) new.from_config(config) end def initialize super @config = { from_regexp: '', to_template: '' } @variables = {} @definition_parser = DefinitionParser.new(self) end def replace(line) match = matched?(line) return line unless match new_line = line.gsub(complete_regexp_from(from_regexp)) do text_with(match, to_template % hmerge(match)) end rename_file(line, new_line) new_line end def add_new_definition(match, _line) @config[:reference] = match[:reference] end def add_line(_match, _line) end def new_variable_def(match, line) @variables[match[:varname].to_sym] = match[:value] line end private def matched?(line) return if line.commented? parse(line) return if @definition_parser.idle? return unless line =~ complete_regexp_from(from_regexp) match = Regexp.last_match return if @config[:cancel_if_match] && match[:filename] =~ Regexp.new(cancel_if_match) match end def parse(line) LOCAL_FILTERS.each do |filter| next unless line.match(filter.regexp) line = generate_event(filter.event, Regexp.last_match, line) break if filter.consumed_line end end def rename_file(from, to) @changes << [extract_filename(from), extract_filename(to)] File.rename(extract_filename(from), extract_filename(to)) end def extract_filename(include_statement) filename = include_statement .gsub(Regexp.new(DMRegexp::INCLUDE_KEYWORD), '') .gsub(Regexp.new(DMRegexp::INCLUDE_OPTIONS), '') filename.dup.scan(DMRegexp::VARIABLE_USE) do |_| varname = Regexp.last_match[:varname] next if @variables[varname.to_sym].nil? filename.gsub!("{#{varname}}", @variables[varname.to_sym]) end filename.chomp end def complete_regexp_from(from) Regexp.new( DMRegexp::INCLUDE_KEYWORD + DMRegexp::INCLUDE_PATH + "(?#{from})" + DMRegexp::INCLUDE_OPTIONS ) end def text_with(match, to) "include::#{match[:path] || ''}#{to}[#{match[:options]}]" end def hmerge(match) @config.merge(match.names.map(&:to_sym).zip(match.captures).to_h) end def generate_event(event, match, line) if respond_to?(event) public_send(event, match, line) else @definition_parser.public_send(event, match, line) end line end end end