Module: PryDeveloperTools

Defined in:
lib/pry-developer_tools/version.rb,
lib/pry-developer_tools/commands.rb

Constant Summary collapse

VERSION =
'0.1.1'
Commands =
Pry::CommandSet.new do
  create_command "define-command", "Define a Pry command for this session." do
    banner <<-BANNER
      Usage: define-command "name", "my description" do
        p "I do something"
      end

      Define a Pry command.
    BANNER

    def process
      if args.empty?
        raise Pry::CommandError, "Provide an arg!"
      end

      prime_string = "command #{arg_string}\n"
      command_string = _pry_.r(target, prime_string)

      eval_string.replace <<-HERE
        _pry_.commands.instance_eval do
          #{command_string}
        end
      HERE
    end
  end

  create_command "reload-command", "Reload a Pry command." do
    banner <<-BANNER
      Usage: reload-command command
      Reload a Pry command.
    BANNER

    def process
      command = _pry_.commands.find_command(args.first)

      if command.nil?
        raise Pry::CommandError, 'No command found.'
      end

      source_code = command.block.source
      file, lineno = command.block.source_location

      set = Pry::CommandSet.new do
        eval(source_code, binding, file, lineno)
      end

      _pry_.commands.delete(command.name)
      _pry_.commands.import(set)
    end
  end

  create_command "edit-command", "Edit a Pry command." do
    banner <<-BANNER
      Usage: edit-command [options] command
      Edit a Pry command.
    BANNER

    def options(opt)
      opt.on :p, :patch, 'Perform a in-memory edit of a command'
    end

    def process
      if args.empty?
        raise Pry::CommandError, "No command given."
      end

      @command, @_target = find_command_and_target

      case
      when opts.present?(:patch)
        edit_temporarily
      else
        edit_permanently
      end
    end

    def find_command_and_target
      raw = args.first

      if raw.include?('#')
        command, method = raw.split('#', 2)
        command = _pry_.commands.find_command(command)
        target  = command.instance_method(method) rescue nil
      else
        command = _pry_.commands.find_command(raw)
        target  = command.block rescue nil
      end

      if command.nil?
        raise Pry::CommandError, "No command found."
      end

      if target.nil?
        raise Pry::CommandError, "Method '#{method}' could not be found."
      end

      [command, target]
    end

    def edit_permanently
      file, lineno = @_target.source_location
      invoke_editor(file, lineno, true)

      command_set = silence_warnings do
        eval File.read(file), TOPLEVEL_BINDING, file, 1
      end

      unless command_set.is_a?(Pry::CommandSet)
        raise Pry::CommandError,
              "Expected file '#{file}' to return a CommandSet"
      end

      _pry_.commands.delete(@command.name)
      _pry_.commands.import(command_set)
      set_file_and_dir_locals(file)
    end

    def edit_temporarily
      source_code = Pry::Method(@_target).source
      modified_code = nil

      temp_file do |f|
        f.write(source_code)
        f.flush

        invoke_editor(f.path, 1, true)
        modified_code = File.read(f.path)
      end

      command_set = Pry::CommandSet.new do
        silence_warnings do
          pry = Pry.new :input => StringIO.new(modified_code)
          pry.rep(binding)
        end
      end

      _pry_.commands.delete(@command.name)
      _pry_.commands.import(command_set)
    end
  end
end