Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active December 17, 2020 22:15
Show Gist options
  • Save JoshCheek/e577c2ab5fbe2a4c209de19bd5018032 to your computer and use it in GitHub Desktop.
Save JoshCheek/e577c2ab5fbe2a4c209de19bd5018032 to your computer and use it in GitHub Desktop.
Using Pry outside of the REPL
require 'pry'
def a() b end
def b() c end
def c() x = 1; binding; end
io = Object.new
io.instance_eval { @printed = [] }
def io.printed() @printed.tap { @printed = [] } end
def io.readline(prompt) nil end
def io.print(str) @printed << str; nil end
pry = Pry.new(
input: io,
output: io,
output_prefix: '',
prompt: [proc { '> ' }, proc { '* ' }],
target: a(),
auto_indent: true,
)
indent = Pry::Indent.new pry
repl = Object.new
repl.define_singleton_method :eval do |str|
vars = { raw_input: str }
str += "\n" unless str.end_with? "\n"
indent.reset if pry.eval_string.empty?
vars[:prev_prompt] = pry.select_prompt
vars[:prev_indentation] = pry.config.auto_indent ? indent.current_prefix.dup : ''
vars[:cooked_input] = str.dup
vars[:alive] = pry.eval(pry.config.auto_indent ? indent.indent(str) : str) # The real eval is here
vars[:next_prompt] = pry.select_prompt
vars[:next_indentation] = pry.config.auto_indent ? indent.current_prefix.dup : ''
vars[:is_command] = ::Pry.current[:pry_cmd_result].command?
vars[:retval] = ::Pry.current[:pry_cmd_result].retval
vars[:printed] = io.printed
vars
end
repl.eval "def omg"
# => {:raw_input=>"def omg",
# :prev_prompt=>"> ",
# :prev_indentation=>"",
# :cooked_input=>"def omg\n",
# :alive=>true,
# :next_prompt=>"* ",
# :next_indentation=>" ",
# :is_command=>false,
# :retval=>nil,
# :printed=>[]}
repl.eval "1+1"
# => {:raw_input=>"1+1",
# :prev_prompt=>"* ",
# :prev_indentation=>" ",
# :cooked_input=>"1+1\n",
# :alive=>true,
# :next_prompt=>"* ",
# :next_indentation=>" ",
# :is_command=>false,
# :retval=>nil,
# :printed=>[]}
repl.eval "end"
# => {:raw_input=>"end",
# :prev_prompt=>"* ",
# :prev_indentation=>" ",
# :cooked_input=>"end\n",
# :alive=>true,
# :next_prompt=>"> ",
# :next_indentation=>"",
# :is_command=>false,
# :retval=>nil,
# :printed=>[":omg\n"]}
repl.eval "omg"
# => {:raw_input=>"omg",
# :prev_prompt=>"> ",
# :prev_indentation=>"",
# :cooked_input=>"omg\n",
# :alive=>true,
# :next_prompt=>"> ",
# :next_indentation=>"",
# :is_command=>false,
# :retval=>nil,
# :printed=>["2\n"]}
repl.eval "x + 5"
# => {:raw_input=>"x + 5",
# :prev_prompt=>"> ",
# :prev_indentation=>"",
# :cooked_input=>"x + 5\n",
# :alive=>true,
# :next_prompt=>"> ",
# :next_indentation=>"",
# :is_command=>false,
# :retval=>nil,
# :printed=>["6\n"]}
require 'json'
repl.eval "ls -l"
# => {:raw_input=>"ls -l",
# :prev_prompt=>"> ",
# :prev_indentation=>"",
# :cooked_input=>"ls -l\n",
# :alive=>true,
# :next_prompt=>"> ",
# :next_indentation=>"",
# :is_command=>true,
# :retval=>void,
# :printed=>["x = 1\n"]}
@RobinDaugherty
Copy link

This is helpful! I also noticed that I could call pry_instance.evaluate_ruby("1 + 1") which seems to almost be intentional as a public method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment