<head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> <link href="dev/github.css" rel="stylesheet" type="text/css" /> </head> <h1 id="yet-another-set-of-irb-hacks">Yet Another Set of IRB Hacks</h1> <h2 id="setup">Setup</h2> <pre><code>$ gem sources --add http://rubygems.org $ gem install irb_hacks </code></pre> <p>Add to your <code>~/.irbrc</code>:</p> <pre><code>require "rubygems" require "irb_hacks" </code></pre> <p>Now fire up IRB for a quick test:</p> <pre><code>$ irb irb> ae (snippet)>> </code></pre> <p>If you see “(snippet)”, you’re ready to go.</p> <h2 id="the-hacks">The Hacks</h2> <h3 id="code-snippets----a-and-ae">Code snippets – <code>a</code> and <code>ae</code></h3> <p>There’s often a need to invoke our work-in-progress code a number of times using the same arguments, wrapping block, etc. For that, “code snippets” feature is quite handy.</p> <p><code>irb_hacks</code> gem provides the two methods with short, meaningless (and thus conflict-free) names – <code>a</code> and <code>ae</code>. <code>a</code> means nothing, it’s just the first letter of the alphabet. <code>a</code> <strong>invokes</strong> the last-edited snippet. <code>ae</code> <strong>lets you edit</strong> the actual snippet (it roughly stands for “a” + “edit”).</p> <p>A very basic example:</p> <pre><code>irb> ae (snippet)>> puts "Hello, world" irb> a Hello, world </code></pre> <p>Snippet arguments are supported. It’s an array called <code>args</code> in snippet context.</p> <pre><code>irb> ae (snippet)>> p "args", args irb> a 10, 1.0, "a string" "args" [10, 1.0, "a string"] </code></pre> <p>Snippets work just like normal Ruby methods – they return the value of the last statement executed.</p> <pre><code>irb> ae (snippet)>> ["alfa", "zulu", "bravo"] + args irb> puts a("charlie").sort alfa bravo charlie zulu </code></pre> <p>Snippets support code blocks. It’s a <code>Proc</code> called <code>block</code> in snippet context. Usage example follows (suppose you’re building a simplistic <code>/etc/passwd</code> parser).</p> <pre><code>irb> ae (snippet)>> File.readlines("/etc/passwd").map(&block).each {|s| p s}; nil irb> a {|s| ar = s.split(":"); {:name => ar[0], :uid => ar[2]}} {:uid=>"0", :name=>"root"} {:uid=>"1", :name=>"bin"} {:uid=>"2", :name=>"daemon"} {:uid=>"3", :name=>"adm"} ... </code></pre> <p>Snippets are <strong>persistent</strong> though IRB invocations. That’s quite handy, since not all stuff can be dynamically reloaded and sometimes one has to restart IRB to ensure a clean reload.</p> <pre><code>irb> ae (snippet)>> puts "Snippets are persistent!" irb> exit $ irb irb> a Snippets are persistent! </code></pre> <p>Just in case, snippet history file is called <code>.irb_snippet_history</code> in your <code>$HOME</code>.</p> <p>Snippets maintain <strong>their own</strong> Readline history. When you press [Up] and [Down] keys in <code>ae</code>, you browse the previously used snippets, not just your previous IRB input. Don’t retype the snippet you used yesterday – press [Up] a couple times and you’ll see it.</p> <pre><code>irb> ae (snippet)>> puts "snippet one" irb> hala irb> bala irb> ae (snippet)>> puts "snippet two" irb> foo irb> moo irb> ae (snippet)>> # Pressing [Up] will give you... (snippet)>> puts "snippet two" # Pressing [Up] again will give you... (snippet)>> puts "snippet one" </code></pre> <h3 id="browse-program-data-with-gnu-less">Browse program data with GNU <code>less</code></h3> <p>Sometimes the data your code works with is too long to fit in a console window. The clearest example of this are variables filled with text content, e.g. <a href="http://github.com/whymirror/hpricot">Hpricot</a> documents/elements.</p> <p>To solve that, the greatest paging program of all times, GNU <code>less</code>, comes to the rescue.</p> <pre><code>$ irb irb> files = Dir["/etc/*"].sort # Some bulky array... irb> less files # ... which you browse interactively! </code></pre> <p>In block form, <code>less</code> hack intercepts everything output to <code>STDOUT</code> (and, optionally, to <code>STDERR</code>), and feeds it to the pager.</p> <pre><code>$ irb irb> less do puts "Hello, world" end </code></pre> <p>Now with <code>STDERR</code> capture:</p> <pre><code>$ irb irb> less(:stderr) do puts "to stdout" STDERR.puts "to stderr" end </code></pre> <p>To specify another paging program or tweak <code>less</code> options, write in your <code>~/.irbrc</code>:</p> <pre><code>IrbHacks.less_cmd = "more" </code></pre> <p>, or something else you find appropriate.</p> <h3 id="break-execution-and-return-instant-value">Break execution and return instant value</h3> <p>By using <code>IrbHacks.break(value)</code> you break snippet execution and make it return <code>value</code>. This is a simple yet powerful debugging technique.</p> <p>Suppose you’re debugging the code which contains something like:</p> <pre><code>csv.each_with_index do |fc_row, i| row = OpenHash[*fc_row.map {|k, v| [(k.to_sym rescue k), (v.to_s.strip rescue v)]}.flatten(1)] ... </code></pre> <p>There’s something wrong with the code and you want to see if <code>row</code> is given the correct value. To do it, use <code>IrbHacks.break</code>:</p> <pre><code>csv.each_with_index do |fc_row, i| row = OpenHash[*fc_row.map {|k, v| [(k.to_sym rescue k), (v.to_s.strip rescue v)]}.flatten(1)] IrbHacks.break(row) </code></pre> <p>Now all you have to do is write an <code>ae</code> snippet and call it. <code>row</code> value will be available in IRB for inspection:</p> <pre><code>irb> ae (snippet)>> Klass.new.method(args) irb> row = a # Back in IRB. Do whatever you want with `row` value now. irb> </code></pre> <p>Each <code>IrbHacks.break</code> call raises an <code>IrbHacks::BreakException</code>. If you see them popping out during runtime, find the appropriate <code>IrbHacks.break</code> calls and defuse them.</p> <h2 id="feedback">Feedback</h2> <p>Send bug reports, suggestions and criticisms through <a href="http://github.com/dadooda/irb_hacks">project’s page on GitHub</a>.</p> <p>Licensed under the MIT License.</p>