Skip to content

Instantly share code, notes, and snippets.

@dvdbng
Created April 10, 2020 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dvdbng/a40a2fa0beedc6363efd854a8a5416a7 to your computer and use it in GitHub Desktop.
Save dvdbng/a40a2fa0beedc6363efd854a8a5416a7 to your computer and use it in GitHub Desktop.
Recursive replace in directory, replacement is dynamically created by ruby code
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'optparse'
require 'active_support/all'
options = {}
OptionParser.new do |opts|
opts.banner = 'Usage: gsubrb [options]'
opts.on('-r', '--replace [CODE]', String, 'Block that will be executed for each match') do |code|
options[:code] = code
end
opts.on('-f', '--find [REGEXP]', Regexp, 'Regexp to find') do |regexp|
options[:regexp] = regexp
end
end.parse!
options[:replacer] = eval("->(str, match) do #{options[:code]} end", nil, 'cmdline', 1)
def color(color, str)
ActiveSupport::LogSubscriber.new.send(:color, str, color)
end
def confirm
STDIN.gets.chomp == 'y'
end
p options
def run_search(options, replace)
replacer = options[:replacer]
`rg --files`.split("\n").each do |file|
contents = File.read(file)
next unless contents.valid_encoding?
lines = contents.split("\n", -1)
changed = false
new_lines = lines.each_with_index.map do |line, index|
line.gsub(options[:regexp]) do |str|
match = Regexp.last_match
resp = replacer.call(str, match).to_s
if resp != str
puts "In file #{color(:cyan, file)}:#{color(:blue, index + 1)}"
puts "#{match.pre_match}#{color(:red, str)}#{match.post_match}"
puts "#{match.pre_match}#{color(:green, resp)}#{match.post_match}"
end
changed ||= resp != str
resp
end
end
File.write(file, new_lines.join("\n")) if changed && replace
end
end
run_search(options, false)
puts
puts 'replace?'
run_search(options, true) if confirm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment