Friday, May 11, 2007

Ruby and the Master File Table

If you already investigated Ruby's installation directory, you may have noticed the huge amount of files there. I've just installed Ruby 1.8.6 and Rails 1.2.3. The disk contains now 26,978 more files and 4,142 more folders.

A medium sized Windows installation has around 40,000 files and folders, meaning Ruby accounts for almost 50% of all Master File Table record entries when it is installed in an NTFS partition. The first obvious effect is that a search on the root of the drive must examine twice the number of files. The other, not so obvious, is that the MFT will fragment, because of the large number of small files.

Moreover, small files (typically 1,500 bytes or less) are stored directly inside the MFT. From those 26,978 files 20,660 are 1,500 bytes or smaller (not to say about the directories, whose sizes I don't know how to calculate, although I bet most are considered small), i.e. most of Ruby's files are inside the MFT.

If you don't want Ruby to be a big degradation factor for your hard disk performance, install it on a separate partition, which you can simply reformat latter if the MFT gets heavily fragmented.

Thursday, May 3, 2007

Prime number calculator

Do you remember back in your first classes in university when you was taught how to calculate a series of prime numbers in C or Pascal? Do you remember those tens of lines of code?

You need a lot less in Ruby:

def primes(up_to)
  prev = []
  (2..up_to).select do |x|
    max_p = Math.sqrt(x).truncate
    if !prev.find { |y| y <= max_p ? x % y == 0 : break }
      prev << x
    end
  end
end

Let's try it:

irb> primes(10)
=> [2, 3, 5, 7]
irb> primes(100)
=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
irb>

The method goes beyond naive approaches, testing each number only with previously found prime numbers that are not greater than its square root. On my machine it computes the primes up to 100,000 in under 3 seconds.

Wednesday, May 2, 2007

Initializing a lookup table in Rails

You're writing a migration script for a Rails application which will create a "Priorities" table with columns for name and position. What if you want to initialize it with well known values? Here's the Ruby way:

create_table :priorities do |t|
  t.column :name, :string
  t.column :position, :integer
end

say_with_time "Initializing priorities..." do
  ["low", "normal", "high"].each_with_index do |elem, i|
    Priority.create(:name => elem, :position => 1 + i)
  end
end