Here is the plan. Create two arrays. One of the alphabet and one of the alphabet all mixed up. Then combine them to create a hash of key-and-value pairs. Once this process is complete, a message can be coded and a mixed-up message can be delivered to other participants in the spy ring. Standard stuff.
In Ruby, we are going to create our two alphabet objects with one-liners.
letters = ("a".."z").to_aThat basically means to create an object named 'letters' that will include the range of letters between 'a' and 'z', and then make it an array (to_a means 'to array') Simple so far. Now let's create a mixed up version that we'll call 'code'.
code = ("a".."z").to_a.shuffleSame as above but this time we've daisy-chained the 'shuffle' method, which does what you'd think it does. Our next task, to create a hash of the two arrays, can be accomplished in two simple lines.
hash = {}
letters.size.times do |i| hash[ letters[i]] = code[i] endAnd after running that little bit of code, Ruby will return the hash in a manner similar to this ...
{"a"=>"k", "b"=>"n", "c"=>"t", "d"=>"w", "e"=>"l", "f"=>"y", "g"=>"g", "h"=>"b", "i"=>"c", "j"=>"e", "k"=>"h", "l"=>"o", "m"=>"p", "n"=>"q", "o"=>"j", "p"=>"s", "q"=>"f", "r"=>"v", "s"=>"i", "t"=>"r", "u"=>"x", "v"=>"d", "w"=>"z", "x"=>"m", "y"=>"a", "z"=>"u"}Your results will not likely be the same. If they are, then you can be justified in feeling very creeped out, because it would be the same thing if both of us had a fresh deck of cards and shuffled them to match exactly.
This hash is represented in a Ruby object called 'hash', which is kinda confusing. Feel free to replace the word 'hash' with something like 'spy_key' or some such thing if you'd like. In any case, there is the issue of saving this newly created hash and this is where things get a little more complicated. But not too bad. The following code was found by googling 'how to save Ruby object'. I like it. The blogger who posted it, Marcus Westin, seems like a nice enough fellow. Here is his code for saving a Ruby object:
require 'zlib'
# Save any ruby object to disk!
# Objects are stored as gzipped marshal dumps.
#
# Example
#
# # First ruby process
# hash = {1 => "Entry1", 2 => "Entry2"}
# ObjectStash.sotre hash, 'hash.stash'
#
# ...
#
# # Another ruby process - same_hash will be identical to the original hash
# same_hash = ObjectStash.load 'hash.stash'
class ObjectStash
# Store an object as a gzipped file to disk
#
# Example
#
# hash = {1 => "Entry1", 2 => "Entry2"}
# ObjectStore.store hash, 'hash.stash.gz'
# ObjectStore.store hash, 'hash.stash', :gzip => false
def self.store obj, file_name, options={}
marshal_dump = Marshal.dump(obj)
file = File.new(file_name,'w')
file = Zlib::GzipWriter.new(file) unless options[:gzip] == false
file.write marshal_dump
file.close
return obj
end
# Read a marshal dump from file and load it as an object
#
# Example
#
# hash = ObjectStore.get 'hash.dump.gz'
# hash_no_gzip = ObjectStore.get 'hash.dump.gz'
def self.load file_name
begin
file = Zlib::GzipReader.open(file_name)
rescue Zlib::GzipFile::Error
file = File.open(file_name, 'r')
ensure
obj = Marshal.load file.read
file.close
return obj
end
end
end
if $0 == __FILE__
require 'test/unit'
class TestObjectStash < Test::Unit::TestCase @@tmp = '/tmp/TestObjectStash.stash' def test_hash_store_load hash1 = {:test=>'test'}
ObjectStash.store hash1, @@tmp
hash2 = ObjectStash.load @@tmp
assert hash1 == hash2
end
def test_hash_store_load_no_gzip
hash1 = {:test=>'test'}
ObjectStash.store hash1, @@tmp, :gzip => false
hash2 = ObjectStash.load @@tmp
assert hash1 == hash2
end
def test_self_stash
ObjectStash.store ObjectStash, @@tmp
assert ObjectStash == ObjectStash.load(@@tmp)
end
def test_self_stash_no_gzip
ObjectStash.store ObjectStash, @@tmp, :gzip => false
assert ObjectStash == ObjectStash.load(@@tmp)
end
end
endThere is a typo in the comment section, but I'm not going to correct it here. The code works fine. Once you load these methods into your console, you have some new tools in your toolbox. The way to store your hash is with the simple line (per instructions in the code).
ObjectStash.store hash, './hash.stash'
If you read it aloud, it's fairly straightforward. Invoke the ObjectStash.store method on the 'hash' object and (comma) store it in the current directory as a file named 'hash.stash'. You can store in on your ~/Desktop if you're playing along. Take a look at it. It is pure gobbly gook. You'll need Westin's entire code to call a separate method to open the weird file. It's done like this:
ObjectStash.load 'hash.stash'
Assuming you have the file stored in the same directory as your irb session, but that (ahem) goes without saying.
So the process is complete. Create the hash, write your secret message and deliver it furtively. In an email, attach the hash.stash file and include the following link: http://bit.ly/dmASNK. Your fellow spies will figure out that they need the code in the link to unpack your unreadable file. Not too bad. You can get the whole thing done before your second cup of coffee.
If you're wondering in the back of your mind if this becoming a bit much to ask of a six-year old, then you're right. Everyone knows that six-year-olds don't drink a 'second' cup of coffee. Feel free to substitute 'coffee' with 'milk'.
0 comments:
Post a Comment