.irbrc on Windows

Posted by Nick Sieger Tue, 30 May 2006 16:57:00 GMT

Having trouble getting IRB to use a .irbrc file on Windows? The following seems to work:

  1. Create the .irbrc file in your %USERPROFILE% directory.
  2. Create an environment variable in the System Properties->Advanced Tab->Environment Variables area called HOME and set it to %USERPROFILE%.

An alternate approach is to create an environment variable called IRBRC and set it to the full path of the .irbrc file.

Perhaps IRB should be updated to look in %USERPROFILE% on Windows?

Plug: for handy .irbrc contents refer to this previous post.

Posted in  | Tags  | 1 comment | no trackbacks

Rails is simpler than Office

Posted by Nick Sieger Fri, 26 May 2006 03:32:00 GMT

Before my big blog drought at the beginning of the year, I had an entry queued up talking about some success I’d experienced with Rails. A lot in the Rails world has progressed since then, but I still think the story is worth documenting. Also, the code to generate a PDF of mailing labels may be useful to somebody out there.

I’ve had some Rails success lately building a home-use mailing list manager/rolodex application. There are plenty of ways that such a list could be maintained without resorting to a full web application framework such as Rails, but what the heck! The mailing list started life as an MS Access database; after my work computer was re-imaged I no longer had “access to Access” so it had a temporary layover in an Excel spreadsheet. Within the past couple of months I had moved it to a MySQL database as a way to nurture my fledgling Rails efforts.

Ok, so nothing real special so far, except that in order to print mailing labels (one of the primary reasons for keeping such a list) I’d have to export the names to a .csv file and do a mail merge with Word. Until the most recent mailing.

On a Saturday night I had the brainstorm to use Austin Ziegler’s PDF::Writer library to create a printable PDF directly from the Rails app, thus skipping the need to go through the mail merge rigamarole. Only a couple of hours of effort later, I had my mother-in-law’s Christmas mailing list printed out! Anyone who has ever done a mail merge with Word knows that clicking a single link to create the printable versions of the mailing labels is a huge improvement in usability. And finally, no MS bits were harmed in the production of this mailing!

My starting point in building the code to generate PDFs was this page in the Rails wiki. I decided to use the method that describes installing an “rpdf” template handler. Nowadays, you may as well use Josh Charles’ Rails PDF plugin, but for posterity I’ve packaged up my effort as a simple plugin as well (install into an existing Rails application with ./script/plugin install http://svn.caldersphere.net/svn/main/plugins/pdfrender).

With the plugin in place, all that’s necessary is a controller method to set up the data for the view, and the view code itself. The controller is as straightforward as you’d expect:

class AddressController < ApplicationController
  # ...

  def pdf
    @addresses = Address.find(:all, :order => 'last_name, first_name')
    render :layout => false
  end
end

The view code is a little more hairy but with a little thought the dimensioning and layout code could easily be DRY’d out.

FONT = "Times-Roman"
FONT_SIZE = 12

COLS = 3
LABELS_PER_PAGE = 30
LABELS_PER_COL = 10

# margins: .5in top & bottom, 0.19 in left and right
# table column widths: 2.63in | 0.13in | 2.63in | 0.13in | 2.63in
# table rows: 1in height

MARG_X = pdf.in2pts 0.19
MARG_Y = pdf.in2pts 0.5

CELL_Y = pdf.in2pts 1
CELL_X = pdf.in2pts 2.63

COL_PAD_X = pdf.in2pts 0.19

COL1_X = MARG_X 
COL2_X = COL1_X + CELL_X + COL_PAD_X
COL3_X = COL2_X + CELL_X + COL_PAD_X

CELL_PAD_X = pdf.in2pts 0.13
CELL_PAD_Y = pdf.in2pts 0.25
CELL_LINE_Y = FONT_SIZE + 2

def cell_x(col)
  [COL1_X, COL2_X, COL3_X][col] + CELL_PAD_X
end

def cell_y(row, line)
  MARG_Y + ((LABELS_PER_COL - row) * CELL_Y) - CELL_PAD_Y - (line * CELL_LINE_Y)
end

def add_label(row, col, addr, pdf)
  if addr
    pdf.add_text_wrap(cell_x(col), cell_y(row, 0), CELL_X, addr.name, FONT_SIZE)
    pdf.add_text_wrap(cell_x(col), cell_y(row, 1), CELL_X, addr.address, FONT_SIZE)
    pdf.add_text_wrap(cell_x(col), cell_y(row, 2), CELL_X, "#{addr.city}, #{addr.state} #{addr.zip}", FONT_SIZE)
  end
end

pdf.select_font(FONT)

pages = @addresses.length / LABELS_PER_PAGE
pages += 1 if (@addresses.length % LABELS_PER_PAGE) > 0

0.upto(pages - 1) do |page|
  start = page * LABELS_PER_PAGE
  address_page = @addresses[start..start+LABELS_PER_PAGE]

  0.upto(LABELS_PER_COL - 1) do |row|
    add_label(row, 0, address_page[row*COLS], pdf)
    add_label(row, 1, address_page[row*COLS+1], pdf)
    add_label(row, 2, address_page[row*COLS+2], pdf)
  end

  pdf.new_page unless page + 1 == pages
end

And that’s it! Avery labels in Rails!

Posted in ,  | Tags , ,  | no comments | no trackbacks

Hackers who are fathers and _why

Posted by Nick Sieger Fri, 05 May 2006 14:24:00 GMT

Spotted on ruby-talk today was this anecdote on a Ruby hacker/father and son, and I just had to share here.

I trotted my 11 year old son over to the Poignant Guide and he laughed like crazy at the Cartoon Foxes and did a little programming, but soon got bored. Wait a minute Alex, let’s try one more thing, Dwe.. Array. Wow, how do I make my R kill big time (He knows all about cheats). I showed him the character’s values and he promptly put in a hugh number for the Rabbit’s strength. He was delighted to see the larger and larger negative life values appear whenever he attacked. Dad, is this how all my Gameboy programs work? Yes, son. Hey, dad I want to do 6dof animation too, can you teach me? Yes son, here’s a few books for you -- Computer Graphics, Foley et al and Physics for Game Developers, Bourg. Not sure he’ll read them right away, but the whole episode saved me another $49.95 Game Cube cartridge.

Posted in  | no comments | no trackbacks

Virtual Ruby?

Posted by Nick Sieger Tue, 02 May 2006 18:56:00 GMT

I had a chance to dabble around with Python a tiny bit today, building the XSV XML schema validator. Got it working fairly easily on my MacBook Pro after a minor detour. Later, I needed to build another copy on a shared linux dev box where I didn’t have root access. Now how does this work in Python? Fortunately, the answer was close at hand: a virtual python instance. Nice! You can create a replica of the main python install, and add your personal site-packages there. The only thing that gets copied is the python executable plus a bunch of symlinks to the main libraries and packages. After that point all you need to do is put your virtual python executable ahead of the main executable on your PATH.

If I were to install local packages/gems with Ruby, I’d probably either build my own Ruby or maintain a local packages directory and constantly customize RUBYLIB. Seems like a suboptimal solution. Has anyone attempted a virtual-ruby.rb that does the same as virtual-python.py?

Posted in  | 3 comments | no trackbacks

Tweaking IRB

Posted by Nick Sieger Sun, 23 Apr 2006 04:02:00 GMT

IRB (Interactive Ruby Shell) is one of those tools that a hacker learning Ruby hopefully discovers right away. It’s an extremely useful way to learn the language, verify hunches, test assumptions, and get immediate feedback. IRB promotes learning by doing, which is the best way of making something stick in your head. (You can even try an online version of irb without even installing Ruby!)

The first order of business when using IRB is to setup your preferences. If you haven’t done so already, create the file ~/.irbrc (%USERPROFILE%.irbrc on windows native ruby). .irbrc is just a regular ruby script where you can run arbitrary ruby code at the start of your IRB session. Add the following to .irbrc:

require 'irb/completion'
ARGV.concat [ "--readline", "--prompt-mode", "simple" ]

This sets up usage of readline in your session and turns on TAB completion, making IRB feel as comfortable as regular old bash. Now you can type Kernel::<TAB> and get a list of available methods! Good.

Next, the thing that you find yourself doing after using IRB for a while is cutting and pasting code from your console buffer over to your text editor. Don’t have Ruby’s reflection rules down yet? Not sure whether to use instance_eval or module_eval when working on that metaprogramming hack? Working inside Rails’ script/console and searching for the right ActiveRecord finder options? No matter how good your terminal program, you probably have to use the mouse to select text out of it to copy to your text editor, and hackers hate having to switch from the keyboard to the mouse when in the flow of programming.

So here’s a technique that will append commands entered in your IRB session to a file in your home directory (idea from ruby-talk:58931). Put the following in your .irbrc:

module Readline
  module History
    LOG = "#{ENV['HOME']}/.irb-history"

    def self.write_log(line)
      File.open(LOG, 'ab') {|f| f << "#{line}
"}
    end

    def self.start_session_log
      write_log("
# session start: #{Time.now}

")
      at_exit { write_log("
# session stop: #{Time.now}
") }
    end
  end

  alias :old_readline :readline
  def readline(*args)
    ln = old_readline(*args)
    begin
      History.write_log(ln)
    rescue
    end
    ln
  end
end

Readline::History.start_session_log

Now every line typed into IRB will immediately be saved into ~/.irb-history. Exercise left to the reader to bind a custom keystroke and macro to yank the last line out of that file and automatically paste into your text editor.

Long-time bash users know that the shell maintains a history of commands across sessions so that you can access commands you typed yesterday. Wouldn’t it be nice to do this in IRB as well? Wish granted:

require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"

Happy ruby hacking! If you find any more handy IRB tips leave them at rubygarden, and let me know about them.

Footnote: I realize there is duplication and non-DRY happening here with two copies of your IRB history, but I came across these techniques at two different times, and the functions they serve seem different enough to potentially use them both. If you don’t like that, choose whichever is more appropriate for your needs.

(Hope this post serves your needs Dan.)

Posted in  | 2 comments | no trackbacks

Older posts: 1 2 3 4