#!/usr/bin/env ruby
# continuation_koans.rb is based on ara.t.howard's metakoans.rb utility.
#
# continuation_koans.rb is an arduous set of exercises designed to
# stretch continuation-programming muscle. The focus is on
# implementing a simple catch/throw system, similar to what already
# exists in Ruby.
#
# The basic usage is:
#
# result = cc_catch(:tag) {
# do_something()
# cc_throw(:tag, 1)
# fail "You never get here"
# }
# assert_equal 1, result
#
# Yourw path, should you choose to follow it, is to write a single
# file 'throwcatch.rb' implementing all functionality required by the
# koans below. As a student of meta-programming your course will be
# guided by a guru whose wisdom and pithy sayings will assist you on
# your journey.
#
# A successful student will eventually be able to do this
#
# harp:~ > ruby metakoans.rb knowledge.rb
# koan_01 has expanded your awareness
# koan_02 has expanded your awareness
# koan_03 has expanded your awareness
# koan_04 has expanded your awareness
# koan_05 has expanded your awareness
# koan_06 has expanded your awareness
# koan_07 has expanded your awareness
# koan_08 has expanded your awareness
# koan_09 has expanded your awareness
# koan_10 has expanded your awareness
# mountains are again merely mountains
#
module MetaKoans
#
# A catch block that does nothing should return nil
#
def koan_01
result = cc_catch(:x) { }
assert { result == nil }
end
#
# A catch block with no throws should return the last value of the
# block
#
def koan_02
result = cc_catch(:x) { :default_value }
assert { result == :default_value }
end
#
# A throw should terminate the catch block immediately. Nil should be
# returned.
#
def koan_03
result = cc_catch(:x) {
cc_throw(:x)
fail "Oops"
}
assert { result == nil }
end
#
# A throw should terminate the catch block immediately. The thrown
# value should be returned.
#
def koan_04
result = cc_catch(:x) {
cc_throw(:x, :thrown_value)
fail "Oops"
}
assert { result == :thrown_value }
end
#
# A throw with no catch should raise a NameError
#
def koan_05
begin
cc_throw :x
fail "Oops"
rescue NameError => ex
assert { ex.message == "uncaught throw `x'" }
end
end
#
# A throw with a different symbol should raise a NameError
#
def koan_06
begin
cc_catch(:y) {
cc_throw :x
}
fail "Oops"
rescue NameError => ex
assert { ex.message == "uncaught throw `x'" }
end
end
#
# Nested throws should find the proper catch block
#
def koan_07
result = cc_catch(:y) {
cc_catch(:x) {
cc_throw :y, 1
}
fail "Oops"
}
assert { result == 1 }
end
#
#
#
def koan_08
result = cc_catch(:y) {
cc_catch(:y) {
cc_throw :y, 1
}
cc_throw :y, 2
}
assert { result == 2 }
end
#
# into the void
#
def koan_09
result = cc_catch(:y) {
res = cc_catch(:x) {
cc_catch(:y) {
cc_throw :x, :good
}
:bad
}
cc_throw :y, res
:bad
}
assert { result == :good }
end
#
# Beyond the void
#
def koan_10
result = :ok
begin
cc_catch(:x) {
fail "Oops"
}
result = :bad
rescue RuntimeError
end
begin
cc_throw(:x)
rescue NameError
end
assert { result == :ok }
end
def assert()
bool = yield
abort "assert{ #{ caller.first[%r/^.*(?=:)/] } } #=> #{ bool.inspect }" unless bool
end
end
class MetaStudent
def initialize knowledge
require knowledge
end
def ponder koan
begin
send koan
true
rescue => e
STDERR.puts %Q[#{ e.message } (#{ e.class })\n#{ e.backtrace.join 10.chr }]
false
end
end
end
class MetaGuru
require "singleton"
include Singleton
def enlighten student
student.extend MetaKoans
koans = student.methods.grep(%r/koan/).sort
attainment = nil
koans.each do |koan|
awakened = student.ponder koan
if awakened
puts "#{ koan } has expanded your awareness"
attainment = koan
else
puts "#{ koan } still requires meditation"
break
end
end
puts(
case attainment
when nil
"mountains are merely mountains"
when 'koan_01', 'koan_02'
"learn the rules so you know how to break them properly"
when 'koan_03', 'koan_04'
"remember that silence is sometimes the best answer"
when 'koan_05', 'koan_06'
"sleep is the best meditation"
when 'koan_07'
"when you lose, don't lose the lesson"
when 'koan_08', 'koan_09'
"things are not what they appear to be: nor are they otherwise"
else
"mountains are again merely mountains"
end
)
end
def self::method_missing m, *a, &b
instance.send m, *a, &b
end
end
knowledge = ARGV.shift or abort "#{ $0 } knowledge.rb"
student = MetaStudent::new knowledge
MetaGuru.enlighten student
|