Warning
This is being rewritten based on the Python version, there may be errors.
In this exercise I'm going to teach you how to speak "object oriented". What I'll do is give you a small set of words with definitions you need to know. Then I'll give you a set of sentences with holes in them that you'll have to understand. Finally, I'm going to give you a large set of exercises that you have to complete to make these sentences solid in your vocabulary.
Alright, take some time to make flash cards for those and memorize them. As usual this won't make too much sense until after you're done with this exercise, but you need to know the base words first.
Next I have a list of Ruby code snippets on the left, and the English sentences for them:
In each of these where you see X, Y, M, J, K, Q, and foo you can treat those like blank spots. For example I can also write these sentences as:
Again, write these on some flash cards and drill them. Put the Ruby code snippet on the front and the sentence on the back. You have to be able to say the sentence exactly the same every time whenever you see that form. Not sort of the same, but exactly the same.
The final preparation for you is to combine the words drills with the phrase drills. What I want you to do for this drill is this:
I now have a little Ruby hack that will drill you on these words you know in an infinite manner. This is a simple script you should be able to figure out, and the only thing it does is use a library called urllib to download a list of words I have. Here's the script, which you should enter into oop_test.rb to work with it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | require 'open-uri'
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
"class ### < ###\nend" => "Make a class named ### that is-a ###.",
"class ###\n\tdef initialize(@@@)\n\tend\nend" => "class ### has-a initialize that takes @@@ parameters.",
"class ###\n\tdef ***(@@@)\n\tend\nend" => "class ### has-a function named *** that takes @@@ parameters.",
"*** = ###.new()" => "Set *** to an instance of class ###.",
"***.***(@@@)" => "From *** get the *** function, and call it with parameters @@@.",
"***.*** = '***'" => "From *** get the *** attribute and set it to '***'."
}
PHRASE_FIRST = ARGV[0] == "english"
open(WORD_URL) {|f|
f.each_line {|word| WORDS.push(word.chomp)}
}
def craft_names(rand_words, snippet, pattern, caps=false)
names = snippet.scan(pattern).map do
word = rand_words.pop()
caps ? word.capitalize : word
end
return names * 2
end
def craft_params(rand_words, snippet, pattern)
names = (0...snippet.scan(pattern).length).map do
param_count = rand(3) + 1
params = (0...param_count).map {|x| rand_words.pop() }
params.join(', ')
end
return names * 2
end
def convert(snippet, phrase)
rand_words = WORDS.sort_by {rand}
class_names = craft_names(rand_words, snippet, /###/, caps=true)
other_names = craft_names(rand_words, snippet, /\*\*\*/)
param_names = craft_params(rand_words, snippet, /@@@/)
results = []
for sentence in [snippet, phrase]
# fake class names, also copies sentence
result = sentence.gsub(/###/) {|x| class_names.pop }
# fake other names
result.gsub!(/\*\*\*/) {|x| other_names.pop }
# fake parameter lists
result.gsub!(/@@@/) {|x| param_names.pop }
results.push(result)
end
return results
end
# keep going until they hit CTRL-D
loop do
snippets = PHRASES.keys().sort_by {rand}
for snippet in snippets
phrase = PHRASES[snippet]
question, answer = convert(snippet, phrase)
if PHRASE_FIRST
question, answer = answer, question
end
print question, "\n\n> "
exit(0) unless STDIN.gets
puts "\nANSWER: %s\n\n" % answer
end
end
|
Here's an example of me running this and trying to answer the questions as accurately as possible. You can see that I type in the answer I think it is based on the phrases I've given you, and then the script prints out the correct answer. You should get your answers as close as possible.
$ ruby ex41.rb
class Branch
def initialize(bell, degree, arm)
end
end
> class Branch has-a initialize that takes bell, degree, and arm parameters.
ANSWER: class Branch has-a initialize that takes bell, degree, arm parameters.
bat.collar(death, arithmetic)
> From bat get the collar function can call it with death, arithmetic parameters.
ANSWER: From bat get the collar function, and call it with parameters death, arithmetic.
cannon.carpenter = 'corn'
> From cannon get the carpenter attribute and set it to 'corn'.
ANSWER: From cannon get the carpenter attribute and set it to 'corn'.
animal = Border.new()
> Set animal equal to an instance of class Border.
ANSWER: Set animal to an instance of class Border.
class Bat < Breakfast
end
> ^D
$
Next you should run the script with the "english" option so that you drill the inverse operation. Given an English phrase, write the code for it. Here's me doing that too:
ruby ex41.rb english
Make a class named Brother that is-a Cracker.
> class Brother < Cracker
ANSWER: class Brother < Cracker
end
From behavior get the cent function, and call it with parameters dress, board.
> behavior.cent(derss, board)
ANSWER: behavior.cent(dress, board)
Set basket to an instance of class Cough.
> ^D
$
Remember that these phrases are using nonsense words. Part of learning to read code well is to stop placing so much meaning on the names used for variables and classes. Too often people will read a word like "Cork" and suddenly get derailed because that word will confuse them about the meaning. In the above example, "Cork" is just an arbitrary name chosen for a class. Don't put any other meaning into it, and instead treat it like the patterns I've given you.
You are now to go on a new quest to read even more code and this time, to read the phrases you just learned in the code you read. You will look for all the files with classes, and then do the following:
The goal is to go through real code and start learning to "pattern match" the phrases you just learned against how they're used. If you drill this enough you should start to see these patterns shout at you in the code whereas before they just seemed like vague blank spots you didn't know.