How do I drop to the IRB prompt from a running script? - ruby

Can I drop to an IRB prompt from a running Ruby script?
I want to run a script, but then have it give me an IRB prompt at a point in the program with the current state of the program, but not just by running rdebug and having a breakpoint.

Pry (an IRB alternative) also lets you do this, in fact it was designed from the ground up for exactly this use case :)
It's as easy as putting binding.pry at the point you want to start the session:
require 'pry'
x = 10
binding.pry
And inside the session:
pry(main)> puts x
=> 10
Check out the website: http://pry.github.com
Pry let's you:
drop into a session at any point in your code
view method source code
view method documentation (not using RI so you dont have to pre-generate it)
pop in and out of different contexts
syntax highlighting
gist integration
view and replay history
open editors to edit methods using edit obj.my_method syntax
A tonne more great and original features

you can use ruby-debug to get access to irb
require 'rubygems'
require 'ruby-debug'
x = 23
puts "welcome"
debugger
puts "end"
when program reaches debugger you will get access to irb.

apparently it requires a chunk of code to drop into irb.
Here's the link (seems to work well).
http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application
require 'irb'
module IRB
def self.start_session(binding) # call this method to drop into irb
unless #__initialized
args = ARGV
ARGV.replace(ARGV.dup)
IRB.setup(nil)
ARGV.replace(args)
#__initialized = true
end
workspace = WorkSpace.new(binding)
irb = Irb.new(workspace)
#CONF[:IRB_RC].call(irb.context) if #CONF[:IRB_RC]
#CONF[:MAIN_CONTEXT] = irb.context
catch(:IRB_EXIT) do
irb.eval_input
end
end
end

This feature is available from Ruby 2.4. You can just use binding.irb
E.g.
require 'irb'
a = 10
binding.irb
puts a
If you run above code, you will get irb console, so that you can inspect values of local variables and anything else that is in scope.
Source: http://blog.redpanthers.co/new-binding-irb-introduced-ruby-2-4/
Ruby commit: https://github.com/ruby/ruby/commit/493e48897421d176a8faf0f0820323d79ecdf94a

Just add this line to where you want the breakpoint:
require 'ruby-debug';debugger
but i suggest use pry instead of irb, which is super handy, insert the following line instead:
require 'pry'; binding.pry

I'm quite late to the game but if you're loading a script from within irb/pry already, a simple raise also works to pop you back out to the irb/pry prompt. I use this quite often when writing one off scripts within the rails console.

Related

irb fails at startup to pause at my code

scripts joe$ irb -rdebug arbo.rb
/Users/joe/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/x86_64- darwin16/continuation.bundle: warning: callcc is obsolete; use Fiber instead
Debug.rb
Emacs support available.
/Users/joe/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/irb/init.rb:23: unless #CONF[:PROMPT][#CONF[:PROMPT_MODE]]
18 IRB.init_error
19 IRB.parse_opts
20 IRB.run_config
21 IRB.load_modules
22
=> 23 unless #CONF[:PROMPT][#CONF[:PROMPT_MODE]]
24 IRB.fail(UndefinedPromptMode, #CONF[:PROMPT_MODE])
25 end
26 end
27
(rdb:1) `
It doesn't pause at the start of my program. It's pausing somewhere inside irb...
require "debug" will stop execution after being required, as described here.
Since you're letting irb require it for you (-rdebug), it is stopping execution after the line that requires it: IRB.load_modules.
Also, you should not run your program with irb (or pry), but with ruby: debug will end up fighting irb for your standard input.
If you're using pry, use binding.pry instead of require "debug" (and still invoke your code with ruby, not pry), like this:
require "pry"
def say(word)
binding.pry
puts word
end
say "Hello"
(and run with ruby file.rb; or without require "pry", invoke with ruby -rpry file.rb). In the same vein, you could use byebug with byebug instead of binding.pry.
The other part of the text you got shows that debug is written using continuations (for just one feature, restart), and continuations have been marked obsolete. Pry does not use continuations.

Customising IRB console for gem

I'd like to extend the default console application that is built as standard with bundle gem by applying some of the IRB config options.
Looking at the documentation, I can see that it should be possible for instance to change the prompt, and this works fine on an interactive session. For example I can play with the displayed prompt like this:
2.1.4 :001 > conf.prompt_mode=:SIMPLE
=> :SIMPLE
>>
?> conf.prompt_mode=:DEFAULT
=> :DEFAULT
irb(main):004:0>
However, I cannot find how to translate this into syntax for use in the console app. For example this script:
require 'irb'
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.start
Just starts with the generic configured prompt:
2.1.4 :001 >
I have spent some time trying to find an example use of IRB for a custom repl without loading global defaults, but not found anything I can copy from.
I can see that the undocumented method IRB.setup has something to do with this, it is setting all the config somehow. Is my only option to write my own version of IRB.start that applies my desired config after calling IRB.setup, or is there support for what I want to do built-in but not documented in standard location?
E.g. the following works, but I feel it's a bit heavy handed extending IRB module this way (and also prone to failing if IRB internals change).
require 'irb'
def IRB.custom_start custom_conf = {}
STDOUT.sync = true
IRB.setup(nil)
custom_conf.each do |k,v|
IRB.conf[k] = v
end
if #CONF[:SCRIPT]
irb = IRB::Irb.new(nil, #CONF[:SCRIPT])
else
irb = IRB::Irb.new
end
#CONF[:IRB_RC].call(irb.context) if #CONF[:IRB_RC]
#CONF[:MAIN_CONTEXT] = irb.context
trap("SIGINT") do
irb.signal_handle
end
begin
catch(:IRB_EXIT) do
irb.eval_input
end
ensure
irb_at_exit
end
end
IRB.custom_start :PROMPT_MODE => :SIMPLE
You can apply custom configurations in two ways.
The first one is to use irbrc file. It may be tricky in building console application (calling IRB.start from the ruby file instead of irb from the console).
The second one is the approach that you have described in the post. You can write your own IRB::start method based on the original one. There are exactly the same potential issues as in using undocumented API - it can break in the future with newer versions of irb.
You should think if you really need to build a console application on the top of irb. For example you can solve this problem using Pry. It allows to define configuration before starting interactive session.
require 'irb'
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.start
The approach above doesn't work because conf[:PROMPT_MODE] gets over-riden in a method called IRB.init_config here
When IRB.start is called, it calls IRB.setup which in turn calls the method IRB.init_config -- which over-rides conf[:PROMPT_MODE] setting.
Here is one approach which solves the problem (relies on internal knowledge of the implementation).
require 'irb'
module IRB
singleton_class.send(:alias_method, :old_setup, :setup)
def IRB.setup(ap_path)
IRB.old_setup(ap_path)
conf[:PROMPT_MODE] = :SIMPLE
end
end
IRB.start

Enabling a console for a Ruby app

I'm trying to add a console to my Ruby cli application (much like the Rails console), but I can't seem to find a solution that does what I need:
Colorization & syntax highlighting
Ability to pass in variables or use the current context
I'd like to use pry, but I can't figure out how to disable the code context from being printed out at the start of the session. I'd like it to immediately start the session without printing anything out besides the prompt.
Here's what currently gets printed when the pry session starts:
Frame number: 0/8
From: <file_path> # line <#> <Class>#<method>:
71: def console
72: client_setup
73: puts "Console Connected to #{#client.url}"
74: puts 'HINT: The #client object is available to you'
75: rescue StandardError => e
76: puts "WARNING: Couldn't connect to #{#client.url}"
77: ensure
78: Pry.config.prompt = proc { "> " }
79: binding.pry
=> 80: end
>
Here's what I want:
>
I've also tried a few other solutions, but here's my problems with each:
IRB: No colorization, doesn't seem customizable
ripl: No colorization or syntax highlighting
Any help here would be greatly appreciated!
We usually create a separate executable file like bin/console in our project and put there content similar to this:
#!/usr/bin/env ruby
require_relative "../application"
require "pry"
Pry.start
Where application.rb is a file which loads gems via Bundler and includes all necessary application-related files, so it will be possible to use application classes in the console.
It's easy to start your console with just ./bin/console command from your terminal.
If you need to customise the look of console then official wiki at github has enough information about this: https://github.com/pry/pry/wiki/Customization-and-configuration
What I ended up doing is defining a pretty simple/empty class to bind to:
class Console
def initialize(client)
#client = client
end
end
Then in my console method:
Pry.config.prompt = proc { '> ' }
Pry.plugins['stack_explorer'] && Pry.plugins['stack_explorer'].disable!
Pry.start(Console.new(#client))
Disabling the stack_explorer prevented it from printing the Frame number info, and inside the Pry session, I can access #client as expected.

create ruby definition on irb load

I would like to have a clear function in my irb console, but there isn't one. Here's what I type in every time I load irb from the terminal:
def cls
system 'clear'
end
It's not real hard to type this each time a load irb, but it would certainly be nice to have this function load automatically when irb starts.
Is it possible to do this?
When irb is starting up, it looks for the file .irbrc in your home directory. If the file exists, it evaluates it. So this file is the perfect place to add some generic stuff to irb...
For inspiration, mine looks like this:
require 'rubygems'
require 'pp'
require 'irb/ext/save-history'
# add $HOME/lib to the load path
$: << '~/lib'
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
def real_instance_methods_of(klass)
klass.instance_methods - ((klass.ancestors - [klass]).map(&:instance_methods).flatten)
end
class Class
def instance_methods_defined_here
real_instance_methods_of self
end
end
# more stuff...
# ...
EDIT: I just noticed the comment by Dave Newton now; he already pointed out the .irbrc solution...
on a mac just hit CMD + K to clear the screen

How to enable auto completion in Ruby's IRB

When I use Merb's built in console, I get tab auto-completion similar to a standard bash prompt. I find this useful and would like to enable it in non-merb IRB sessions. How do I get auto-completion in IRB?
Just drop require 'irb/completion' in your irbrc.
If that doesn't work try bond, http://tagaholic.me/bond/:
require 'bond'; require 'bond/completion'
Bond not only improves irb's completion, http://tagaholic.me/2009/07/22/better-irb-completion-with-bond.html, but also offers an easy dsl for making custom autocompletions.
This is just repeating the information on Cody Caughlan's comment above so it is easier to find:
either require 'irb/completion' or add the following to ~/.irbrc
IRB.conf[:AUTO_INDENT] = true
IRB.conf[:USE_READLINE] = true
IRB.conf[:LOAD_MODULES] = [] unless IRB.conf.key?(:LOAD_MODULES)
unless IRB.conf[:LOAD_MODULES].include?('irb/completion')
IRB.conf[:LOAD_MODULES] << 'irb/completion'
end
This is what worked for me on Mac OS 10.11.5. using rvm. Do the following :
sudo gem install bond
Create the file .irbrc in your home directory. vi ~/.irbrc
Add the following lines in the .irbrc file
require 'bond'
Bond.start
Save and close the file
Open irb and use tab key to autocomplete

Resources