Q:

Learn Ruby the Hard Way #41

Hi I`m learning from LRtHW and I got stuck.... 
I have program like this:
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) do |f| 
  f.each_line {|word| WORDS.push(word.chomp)}
end

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 name, also copies sentence
    result = sentence.gsub(/###/) {|x| class_names.pop}
    #fake other names
    result.gsub!(/\*\*\*/) {|x| other_names.pop}
    #fake parameter list
    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> "
    odp = gets.chomp

    if odp == "exit"
      exit(0)
    end

    #exit(0) unless STDIN.gets
    puts "\nANSWER: %s\n\n" % answer
  end
end  

I understand most of this code, but I have a problem with:
for sentence in [snippet, phrase]

I know that it is a "for" loop and it creates a "sentence" variable, but how does the loop know that it need to look in a key and value of hash "PHRASES"
And my second "wall" is:
question, answer = convert(snippet, phrase)

It looks like it creates and assigns "question" and "answer variables to the "convert" method with "snippet" and "phrase" parameters... again how does it assigns "question" to a key and answer to a value. 
I know that this is probably very simple but as for now it blocks my mind :(

A:

For your first question about the for-loop:
Look at where the for-loop is defined. It's  inside the convert() method, right? And the convert() method is passed two arguments: one snippet and one phrase. So the loop isn't "looking" for values in the PHRASES hash, you are the one supplying it. You're using the method's arguments.
For your second question about assignment:
In Ruby we can do something called "destructuring assignment". What this means is that we can assign an array to multiple variables, and each variable will hold one value in the array. That's what's happening in your program. The convert() method returns a two-item array, and you're giving a name (question and answer) to each item in the array.
Here's another example of a destructuring assignment:
a, b, c = [1, 2, 3]
a # => returns 1
b # => returns 2
c # returns 3

Try this out in IRB and see if you get the hang of it. Let me know if I can help clarify anything, or if I misunderstood your question. You should never feel bad about asking "simple" questions!

