Hello,

My implementation does two passes. The first one gets the questions and 
changes the tags by a label (if it does not have a label it's created 
with the name "anonymous<number>". After answering questions the second 
pass just translates the tags by the answers. I had to add an array to 
keeping the questions order as I was using a hash to store the 
questions and answers. I had also to strip return characters, I know it 
should be a more elegant solution. The problem was the tags with return 
characters in it.

Here is the code

--8<------
class QAPair
   attr_accessor :question, :answer
   def initialize(q, a="empty")
     @question=q
     @answer=a
   end
end

class MadLib

   def initialize(text)
     @original=text.tr("\r\n", "  ") # take care of multiline
     @anon_number=0
     @qa=Hash.new # Questions and Answers
     @qa_order=Array.new

     process
   end

   def process
     @processed=@original.gsub(/\(\((.*?)\)\)/) {|matched|
       question=matched[2..-3] # strip parentheses
       name="anonymous"+@anon_number.to_s
       if res=question.match(/(.*?):(.*)/)
         question=res[2]
         name=res[1]
       elsif @qa.include?(question)
         name=question
       else
         @anon_number+=1
       end
       @qa[name]=QAPair.new(question)
       @qa_order << name if !@qa_order.include? name
       "(("+name+"))"
     }
   end

   def make_questions
     @qa_order.each {|name|
       pair=@qa[name]
       print "Give me a "+pair.question+": "
       pair.answer=STDIN.gets.chop
     }
   end

   def create_text
     @processed.gsub(/\(\(.*?\)\)/) {|matched|
       name=matched[2..-3]
       @qa[name].answer
     }
   end

end

if ARGV[0]
   begin
     test=MadLib.new(File.read(ARGV[0]))
   rescue
     puts "File #{ARGV[0]} not found."
     exit -1
   end
else
   puts "madlib file as parameter is needed"
   exit -1
end

test.make_questions
puts test.create_text
------>8--