module PostalCode

Constants

CityOffset
DB
FS
RS
StateOffset
VERSION

Public Class Methods

city(postal_code) click to toggle source

Return the city for the given postal code.

# File lib/postal_code.rb, line 36
def self.city postal_code
  fetch(postal_code)[CityOffset]
end
clear_cache() click to toggle source

Clear the in-memory postal code cache.

# File lib/postal_code.rb, line 29
def self.clear_cache
  @cache.clear
end
load_cache() click to toggle source

Load the entire postal code database into memory.

# File lib/postal_code.rb, line 16
def self.load_cache
  open(DB) do |db|
    db.each_line do |line|
      line.rstrip!  # remove RS
      pcode, city, state = line.split(FS)
      @cache[pcode] = [city, state]
    end
  end
end
state(postal_code) click to toggle source

Return the state (two-letter abbreviation) for the given postal code.

# File lib/postal_code.rb, line 43
def self.state postal_code
  fetch(postal_code)[StateOffset]
end
valid_format?(postal_code) click to toggle source

Postal codes must be strings because:

  1. Postal codes are not calculable, therefore should not be numeric.

  2. A postal code with a leading zero would be an octal. However, 08880 is an invalid octal numeric, yet a valid postal code.

# File lib/postal_code.rb, line 53
def self.valid_format? postal_code
  unless postal_code.is_a? String
    raise(TypeError, "postal code must be a string")
  end

  (postal_code =~ /^\d{5}(-\d{4})?$/) ? true : false
end

Private Class Methods

fetch(postal_code) click to toggle source

Fetch postal code record.

# File lib/postal_code.rb, line 64
def self.fetch postal_code
  return [nil, nil] unless valid_format? postal_code
  pcode = postal_code[0..4] # use first 5 characters; ignore ZIP+4 extension

  if @cache.has_key? pcode
    @cache[pcode]
  else
    records = %x[grep "^#{pcode}#{FS}" #{DB}].split(RS)

    if records.empty?
      [nil, nil]
    else
      @cache[pcode] = records.last.split(FS)[1..2]
    end
  end
end