<commit_before>require 'git/gsub/version'
require 'active_support/inflector'
require 'optparse'
require 'shellwords'
require 'English'

module Git
  module Gsub
    def self.run(argv)
      opts = OptionParser.new

      self.class.module_eval do
        define_method(:usage) do |msg = nil|
          puts opts.to_s
          puts "error: #{msg}" if msg
          exit 1
        end
      end

      options = {}
      opts.on('-v', '--version', 'Print version') do |_v|
        options[:version] = true
      end

      opts.on('--snake', 'Substitute snake-cased expressions') do |_v|
        options[:snake] = true
      end

      opts.on('--camel', 'Substitute camel-cased expressions') do |_v|
        options[:camel] = true
      end

      opts.on('--kebab', 'Substitute kebab-cased expressions') do |_v|
        options[:kebab] = true
      end

      opts.on('--rename', 'Rename files along with substitution') do |_v|
        options[:rename] = true
      end

      opts.on('--dry-run', 'Print commands to be run') do |_v|
        options[:dry] = true
      end

      opts.banner = 'Usage: git gsub [options] FROM TO [PATHS]'

      begin
        args = opts.parse(argv)
      rescue OptionParser::InvalidOption => e
        usage e.message
      end

      if options[:version]
        version
      else
        from, to, *paths = args
        usage 'No FROM given' unless from
        usage 'No TO given' unless to
        Commands::Gsub.new(from, to, paths, options).run
        Commands::Rename.new(from, to, paths, options).run if options[:rename]
      end
    end

    def self.version
      puts Git::Gsub::VERSION
    end

    module Commands
      class Command
        attr_accessor :from, :to, :paths, :options

        def initialize(from, to, paths = [], options = {})
          @from = from
          @to = to
          @paths = paths
          @options = options
        end

        def run_commands(commands)
          if options[:dry]
            commands.each { |c| puts c }
          else
            commands.each { |c| system c }
          end
        end

        def args
          args = []
          args << [from, to]
          args << [from.camelcase, to.camelcase] if options[:camel]
          args << [from.underscore, to.underscore] if options[:snake]
          args << [from.underscore.dasherize, to.underscore.dasherize] if options[:kebab]

          args.compact
        end
      end

      class Gsub < Command
        def run
          commands = args.map { |from, to| build_command(from, to, paths) }.compact
          run_commands commands
        end

        def build_command(from, to, paths = [], _options = {})
          from, to, *paths = [from, to, *paths].map { |s| Shellwords.escape s }

          target_files = `git grep -l #{from} #{paths.join ' '}`.each_line.map(&:chomp).join ' '
          return if target_files.empty?

          %(perl -pi -e 's{#{from}}{#{to}}g' #{target_files})
        end
      end

      class Rename < Command
        def run
          commands = args.map { |from, to| build_command(from, to, paths) }
          run_commands commands
        end

        def build_command(from, to, paths = [], _options = {})
          from, to, *paths = [from, to, *paths].map { |s| Shellwords.escape s }

          %[for f in $(git ls-files #{paths.join ' '} | grep #{from}); do mkdir -p $(dirname $(echo $f | sed 's/#{from}/#{to}/g')); mv $f $(echo $f | sed 's/#{from}/#{to}/g') 2>/dev/null; done]
        end
      end
    end
  end
end<commit_msg>Restrict mv to be done inside repository<commit_after>require 'git/gsub/version'
require 'active_support/inflector'
require 'optparse'
require 'shellwords'
require 'English'

module Git
  module Gsub
    def self.run(argv)
      opts = OptionParser.new

      self.class.module_eval do
        define_method(:usage) do |msg = nil|
          puts opts.to_s
          puts "error: #{msg}" if msg
          exit 1
        end
      end

      options = {}
      opts.on('-v', '--version', 'Print version') do |_v|
        options[:version] = true
      end

      opts.on('--snake', 'Substitute snake-cased expressions') do |_v|
        options[:snake] = true
      end

      opts.on('--camel', 'Substitute camel-cased expressions') do |_v|
        options[:camel] = true
      end

      opts.on('--kebab', 'Substitute kebab-cased expressions') do |_v|
        options[:kebab] = true
      end

      opts.on('--rename', 'Rename files along with substitution') do |_v|
        options[:rename] = true
      end

      opts.on('--dry-run', 'Print commands to be run') do |_v|
        options[:dry] = true
      end

      opts.banner = 'Usage: git gsub [options] FROM TO [PATHS]'

      begin
        args = opts.parse(argv)
      rescue OptionParser::InvalidOption => e
        usage e.message
      end

      if options[:version]
        version
      else
        from, to, *paths = args
        usage 'No FROM given' unless from
        usage 'No TO given' unless to
        Commands::Gsub.new(from, to, paths, options).run
        Commands::Rename.new(from, to, paths, options).run if options[:rename]
      end
    end

    def self.version
      puts Git::Gsub::VERSION
    end

    module Commands
      class Command
        attr_accessor :from, :to, :paths, :options

        def initialize(from, to, paths = [], options = {})
          @from = from
          @to = to
          @paths = paths
          @options = options
        end

        def run_commands(commands)
          if options[:dry]
            commands.each { |c| puts c }
          else
            commands.each { |c| system c }
          end
        end

        def args
          args = []
          args << [from, to]
          args << [from.camelcase, to.camelcase] if options[:camel]
          args << [from.underscore, to.underscore] if options[:snake]
          args << [from.underscore.dasherize, to.underscore.dasherize] if options[:kebab]

          args.compact
        end
      end

      class Gsub < Command
        def run
          commands = args.map { |from, to| build_command(from, to, paths) }.compact
          run_commands commands
        end

        def build_command(from, to, paths = [], _options = {})
          from, to, *paths = [from, to, *paths].map { |s| Shellwords.escape s }

          target_files = `git grep -l #{from} #{paths.join ' '}`.each_line.map(&:chomp).join ' '
          return if target_files.empty?

          %(perl -pi -e 's{#{from}}{#{to}}g' #{target_files})
        end
      end

      class Rename < Command
        def run
          commands = args.map { |from, to| build_command(from, to, paths) }
          run_commands commands
        end

        def build_command(from, to, paths = [], _options = {})
          from, to, *paths = [from, to, *paths].map { |s| Shellwords.escape s }

          %[for f in $(git ls-files #{paths.join ' '} | grep #{from}); do mkdir -p $(dirname $(echo $f | sed 's/#{from}/#{to}/g')); git mv $f $(echo $f | sed 's/#{from}/#{to}/g') 2>/dev/null; done]
        end
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.13006065735646777, 'fraction_numerical': 0.0005642544787699252, 'mean_word_length': 1.9057377049180328, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '297433', 'n_tokens_mistral': 2244, 'n_tokens_neox': 2179, 'n_words': 636}