I wrote earlier:
# Version 1 is a function, and requires serial input.
Version 2 is a class, and handles random input, which means you can easily
use it to power your new graphical interface.
Cheers,
Dave
class MadLib
# You can enumerate the placeholders... not too useful, though.
include Enumerable
def initialize(string)
# the original madlib string is kept
@s = string
# a placeholder for each user entry required
# maps a tag name or number onto a [question, answer] array.
@placeholders = {}
# an index for each set of brackets in @s
# the key into @placeholders for each respective set of brackets
@index = []
# the initial scan gets tag names and assigns numbers for tags with no
name
i = '0'
@s.scan /\(\(([^:)]*):?(.*?)\)\)/ do |a, b|
if @placeholders.has_key? a
@index << a
elsif b.size > 0
@index << a
@placeholders.update a => [b, nil]
else
@index << i
@placeholders.update i => [a, nil]
i = i.succ
end
end
end
def []=(index, answer)
@placeholders[index][1] = answer
@placeholders[index]
end
def [](index)
@placeholders[index]
end
def outstanding
@index.select {|i| @placeholders[i][1].nil? }.uniq
end
def outstanding_questions
outstanding.map {|i| @placeholders[i][0] }
end
def each_outstanding
outstanding.each do |i|
yield @placeholders[i]
end
end
def all
@index.uniq
end
def all_questions
all.map {|i| @placeholders[i][0] }
end
def each
all.each do |i|
yield @placeholders[i]
end
end
def done?
@placeholders.all? {|k, v| v[1] }
end
def collect!
all.each do |i|
self[i] = yield @placeholders[i]
end
self
end
def to_s
if done?
story
else
""
end
end
private
def story
i = 0
@s.gsub /\(\(.*?\)\)/ do |token|
i = i.succ
@placeholders[@index[i - 1]][1]
end
end
end
if $0 == __FILE__
m = MadLib.new(ARGF.read)
m.collect! do |question, answer|
answer or begin
print "#{question}? "
gets.chomp
end
end
puts m
end