Readable Caesar cipher
All the caesar cypher does is rotate an alphabet by n places. If we let the alphabet be an Array, we can use Array#rotate to do the rotating for us. To substitute single characters, there is String#tr. Its name and usage are a little odd, but you'll quickly get used to it.

Basically, it maps characters in a String to characters in another String by their index. So "abc".tr("abc", "123") maps "a" to "1", "b" to "2" and "c" to "3".It expands ranges such as "a-c" first, so you can can write "abc".tr("abc", "123") as "abc".tr("a-c","1-3").

Though the interface is different, here's a simple implementation of the Caesar cypher.

module Caesar
  def self.encrypt(message, shift = 3)
    message.tr("a-zA-Z", rotated_alphabet(shift))
  end

  def self.decrypt(message, shift = 3)
    encrypt(message, 26 - shift)
  end

  def self.rotated_alphabet(shift)
    lower = "a".upto("z").to_a.rotate(shift)
    upper = "A".upto("Z").to_a.rotate(shift)

    lower.concat(upper).join
  end
end

Caesar.decrypt Caesar.encrypt("hi")
# =&gt; "hi"


For efficiency, you could change how you calculate the rotated alphabets. Here's an efficient, but not exactly a readable implementation.

  def self.rotated_alphabet(shift)
    lower = (97 + shift).chr # 97 is the ASCII code for "a"
    upper = (65 + shift).chr # 65 is the ASCII code for "A"

    "#{lower}-za-#{lower}#{upper}-ZA-#{upper}"
  end