Created
April 28, 2022 20:42
-
-
Save gtm19/81028a3d33fa973b4ea262e9687cc42b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./encrypt.rb | |
# 1. Get an array of all the letters of the alphabet | |
# See: https://ruby-doc.org/core-3.0.2/Range.html | |
LETTERS = ("A".."Z").to_a | |
# Alternatively: | |
# LETTERS = Array ("A".."Z") | |
def encrypt(text, offset = -3) | |
# Parameter checking: ------------------------------------------------------- | |
# See: https://www.exceptionalcreatures.com/bestiary/ArgumentError.html#making-a-strong-argument | |
raise ArgumentError.new( | |
"Expected `text` to be a String, but it is a #{text.class}" | |
) unless text.is_a? String | |
raise ArgumentError.new( | |
"Expected `offset` to be an Integer, but it is a #{offset.class}" | |
) unless offset.is_a? Integer | |
# --------------------------------------------------------------------------- | |
# 2. split the input into individual letters | |
# See: https://ruby-doc.org/core-3.0.2/String.html#method-i-split | |
text_split = text.split("") | |
# 3. iterate over each letter: | |
# See: https://ruby-doc.org/core-3.0.2/Enumerable.html#method-i-map | |
text_split.map! do |letter| | |
# 4. get the index of each letter in the alphabet (A = 0 ... Z = 25) | |
# See: https://ruby-doc.org/core-3.0.2/Array.html#method-i-index | |
index = LETTERS.index(letter) | |
# 5. add offset to index and get remainder on division by 26 | |
# 24, 25, 26, 27, 28 | |
# Y Z A B C | |
# 24, 25, 0, 1, 2 | |
# ^ ^ ^ --- same as remainder on division by 26 | |
# See: https://ruby-doc.org/core-3.0.2/Numeric.html#method-i-25 for % usage | |
# See: https://www.rubyguides.com/2019/10/ruby-ternary-operator/ for ternary operator | |
index ? LETTERS[(index + offset) % 26] : letter | |
# or (if not writing with decryption in mind:) | |
# since arr[-n] is equivalent to arr[arr.length + 1 - n] | |
# index ? LETTERS[index - 3] : letter | |
# See: https://ruby-doc.org/core-3.0.2/Array.html#class-Array-label-Accessing+Elements | |
end | |
# 6. join it all back up | |
# See: https://ruby-doc.org/core-3.0.2/Array.html#method-i-join | |
return text_split.join | |
end | |
def decrypt(text) | |
encrypt(text, offset = 3) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# .spec/encrypt_spec.rb | |
require_relative "../encrypt" | |
describe "#encrypt" do | |
it "returns a string" do | |
# See: https://rspec.info/documentation/3.10/rspec-expectations/#identity | |
expect(encrypt("SOME TEXT")).to be_a(String) | |
end | |
it "returns an empty string when param is ''" do | |
# See: https://rspec.info/documentation/3.10/rspec-expectations/#equivalence | |
expect(encrypt("")).to eq("") | |
end | |
it "raises an error if text param is not a string" do | |
# See: https://rspec.info/documentation/3.10/rspec-expectations/#expecting-errors | |
# NOTE: the expression must be in { CURLY BRACES } for expected errors | |
expect { encrypt(1) }.to raise_error(ArgumentError) | |
expect { encrypt(nil) }.to raise_error(ArgumentError) | |
expect { encrypt(true) }.to raise_error(ArgumentError) | |
end | |
it "returns the 3-letter backward-shifted text" do | |
input = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" | |
encrypted = encrypt(input) | |
expected = "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD" | |
expect(encrypted).to eq(expected) | |
end | |
end | |
describe "#decrypt" do | |
it "returns the 3-letter forward-shifted text" do | |
input = "FK ZOVMQLDOXMEV, X ZXBPXO ZFMEBO, XIPL HKLTK XP ZXBPXO'P ZFMEBO, QEB PEFCQ ZFMEBO, ZXBPXO'P ZLAB LO ZXBPXO PEFCQ, FP LKB LC QEB PFJMIBPQ XKA JLPQ TFABIV HKLTK BKZOVMQFLK QBZEKFNRBP. FQ FP X QVMB LC PRYPQFQRQFLK ZFMEBO FK TEFZE BXZE IBQQBO FK QEB MIXFKQBUQ FP OBMIXZBA YV X IBQQBO PLJB CFUBA KRJYBO LC MLPFQFLKP ALTK QEB XIMEXYBQ. CLO BUXJMIB, TFQE X IBCQ PEFCQ LC 3, A TLRIA YB OBMIXZBA YV X, B TLRIA YBZLJB Y, XKA PL LK. QEB JBQELA FP KXJBA XCQBO GRIFRP ZXBPXO, TEL RPBA FQ FK EFP MOFSXQB ZLOOBPMLKABKZB." | |
decrypted = decrypt(input) | |
# Paragraph from Wikipedia: https://en.wikipedia.org/wiki/Caesar_cipher | |
expected = "IN CRYPTOGRAPHY, A CAESAR CIPHER, ALSO KNOWN AS CAESAR'S CIPHER, THE SHIFT CIPHER, CAESAR'S CODE OR CAESAR SHIFT, IS ONE OF THE SIMPLEST AND MOST WIDELY KNOWN ENCRYPTION TECHNIQUES. IT IS A TYPE OF SUBSTITUTION CIPHER IN WHICH EACH LETTER IN THE PLAINTEXT IS REPLACED BY A LETTER SOME FIXED NUMBER OF POSITIONS DOWN THE ALPHABET. FOR EXAMPLE, WITH A LEFT SHIFT OF 3, D WOULD BE REPLACED BY A, E WOULD BECOME B, AND SO ON. THE METHOD IS NAMED AFTER JULIUS CAESAR, WHO USED IT IN HIS PRIVATE CORRESPONDENCE." | |
expect(decrypted).to eq(expected) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment