Tagged With   lib:name=irb , post:type=snippet , post:lang=ruby

Irb History Itches Eliminated

Irb, ruby’s interactive shell, is awesome for interactive programming. You can write a few lines and test out that language feature you weren’t aware of. However as your testing becomes more elaborate it can become annoying to rewrite your code. So how do you retrieve old code? Your history, of course.

When I read programming articles, I like to find the final source code so I don’t copy and paste several times. I’m laaaayzy like that. Update: The newer and improved version of the code we’re going to talk about is here.

From the ruby garden I found out where my history was stored, Readline::HISTORY. Wanting to make command history access as intuitive as possible, I wanted to pull up commands by the command numbers seen in irb’s prompt. Noticing that Readline::HISTORY starts out with previous history, I saved its original size for later use. To pull up commands inclusively between two numbers I did the following:

$original_history_size = Readline::HISTORY.size
def history_list(first_num,second_num=Readline::HISTORY.size - 1)
  Readline::HISTORY.to_a[(first_num + $original_history_size - 1) .. (second_num +
$original_history_size - 1) ]
end

And what if wanted to print these out in a more readable format or eval some of the lines to bring back the code to a previous state?

def print_history(*args)
  puts history_list(*args).join("\n")
end
def eval_history(*args)
  eval %[ #{history_list(*args).join("\n")} ]
end

Now, what if I wanted to only eval certain lines of the code say lines 1,4,8-12,15. Well I wrote a brief Array method, multislice, that literally would take the previous string ‘1,4,8-12,15’ and return back the 1st,4th,8th-12th and 15th elements of an array. With multislice I wrote a method similar to history_list.

As I wrote these methods I wondered if I’d satisified all my itches for a more rapid irb programming environment. Wellll, all except one: editing already entered irb code, without the hassle of consciously pasting code and naming a temporary file. So naturally I used an automatically generated tempfile using tempfile.rb. First I wrote a method to edit a string:

def edit(string=nil,editor=ENV['EDITOR'])
  editor ||= raise "editor must be given or defined by EDITOR environment variable"
  tempfile = Tempfile.new('edit')
  File.open(tempfile.path,'w') {|f| f.write(string) } if string
  system("#{editor} #{tempfile.path}")
  File.open(tempfile.path) {|f| f.read }
end

And then another to edit specified commands:

def edit_history(*args)
  history_string = history_list_or_slice(*args).join("\n")
  edit(history_string)
end

So for now my irb itches are satisfied. Are yours?

Enjoyed this post? Tell others! hacker newsHacker News | twitterTwitter | DeliciousDelicious | redditReddit
blog comments powered by Disqus