4 require 'test/unit/assertions'
6 class FillMeInError < StandardError
9 def ruby_version?(version)
10 RUBY_VERSION =~ /^#{version}/ ||
11 (version == 'jruby' && defined?(JRUBY_VERSION)) ||
12 (version == 'mri' && ! defined?(JRUBY_VERSION))
15 def in_ruby_version(*versions)
16 yield if versions.any? { |v| ruby_version?(v) }
19 def __(value="FILL ME IN", value19=:mu)
20 if RUBY_VERSION < "1.9"
23 (value19 == :mu) ? value : value19
27 def _n_(value=999999, value19=:mu)
28 if RUBY_VERSION < "1.9"
31 (value19 == :mu) ? value : value19
35 def ___(value=FillMeInError)
46 in_ruby_version("1.9") do
47 public :method_missing
54 #shamelessly stolen (and modified) from redgreen
56 :clear => 0, :black => 30, :red => 31,
57 :green => 32, :yellow => 33, :blue => 34,
58 :magenta => 35, :cyan => 36,
63 COLORS.each do |color, value|
64 module_eval "def #{color}(string); colorize(string, #{value}); end"
68 def colorize(string, color_value)
72 color(color_value) + string + color(COLORS[:clear])
76 def color(color_value)
82 attr_reader :failure, :failed_test, :pass_count
84 in_ruby_version("1.8") do
85 AssertionError = Test::Unit::AssertionFailedError
88 in_ruby_version("1.9") do
90 AssertionError = MiniTest::Assertion
92 AssertionError = Test::Unit::AssertionFailedError
103 PROGRESS_FILE_NAME = '.path_progress'
105 def add_progress(prog)
107 exists = File.exists?(PROGRESS_FILE_NAME)
108 File.open(PROGRESS_FILE_NAME,'a+') do |f|
109 f.print "#{',' if exists}#{prog}"
115 if File.exists?(PROGRESS_FILE_NAME)
116 File.open(PROGRESS_FILE_NAME,'r') do |f|
117 @_contents = f.read.to_s.gsub(/\s/,'').split(',')
129 if @pass_count > progress.last.to_i
130 @observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.")
134 @failure = step.failure
135 add_progress(@pass_count)
136 @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.")
146 failure.is_a?(AssertionError)
151 @observations.each{|c| puts c }
163 total_tests = EdgeCase::Koan.total_tests
164 scale = bar_width.to_f/total_tests
165 print Color.green("your path thus far [")
166 happy_steps = (pass_count*scale).to_i
167 happy_steps = 1 if happy_steps == 0 && pass_count > 0
168 print Color.green('.'*happy_steps)
171 print Color.cyan('_'*(bar_width-1-happy_steps))
173 print Color.green(']')
174 print " #{pass_count}/#{total_tests}"
179 completed = <<-ENDTEXT
182 , ,,: :::::::::::::,, :::: : ,
183 , ,,, ,:::::::::::::::::::, ,: ,: ,,
184 :, ::, , , :, ,::::::::::::::::::, ::: ,::::
185 : : ::, ,:::::::: ::, ,::::
186 , ,::::: :,:::::::,::::,
187 ,: , ,:,,: :::::::::::::
188 ::,: ,,:::, ,::::::::::::,
189 ,:::, :,,::: ::::::::::::,
190 ,::: :::::::, Mountains are again merely mountains ,::::::::::::
191 :::,,,:::::: ::::::::::::
192 ,:::::::::::, ::::::::::::,
193 :::::::::::, ,::::::::::::
194 ::::::::::::: ,::::::::::::
195 :::::::::::: Ruby Koans ::::::::::::,
196 :::::::::::: ,::::::::::::,
197 :::::::::::, , ::::::::::::
198 ,:::::::::::::, brought to you by ,,::::::::::::,
199 :::::::::::::: ,::::::::::::
200 ::::::::::::::, ,:::::::::::::
201 ::::::::::::, EdgeCase Software Artisans , ::::::::::::
202 :,::::::::: :::: :::::::::::::
203 ,::::::::::: ,: ,,:::::::::::::,
204 :::::::::::: ,::::::::::::::,
205 :::::::::::::::::, ::::::::::::::::
206 :::::::::::::::::::, ::::::::::::::::
207 ::::::::::::::::::::::, ,::::,:, , ::::,:::
208 :::::::::::::::::::::::, ::,: ::,::, ,,: ::::
209 ,:::::::::::::::::::: ::,, , ,, ,::::
210 ,:::::::::::::::: ::,, , ,:::,
219 puts "The Master says:"
220 puts Color.cyan(" You have not yet reached enlightenment.")
221 if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1)
222 puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.")
223 elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1
224 puts Color.cyan(" Do not lose hope.")
225 elsif progress.last.to_i > 0
226 puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.")
230 def guide_through_error
232 puts "The answers you seek..."
233 puts Color.red(indent(failure.message).join)
235 puts "Please meditate on the following code:"
237 puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
239 puts embolden_first_line_only(indent(failure.backtrace))
244 def embolden_first_line_only(text)
257 text = text.split(/\n/) if text.is_a?(String)
258 text.collect{|t| " #{t}"}
261 def find_interesting_lines(backtrace)
262 backtrace.reject { |line|
263 line =~ /test\/unit\/|edgecase\.rb/
267 # Hat's tip to Ara T. Howard for the zen statements from his
268 # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html)
269 def a_zenlike_statement
271 zen_statement = "Mountains are again merely mountains"
273 zen_statement = case (@pass_count % 10)
275 "mountains are merely mountains"
277 "learn the rules so you know how to break them properly"
279 "remember that silence is sometimes the best answer"
281 "sleep is the best meditation"
283 "when you lose, don't lose the lesson"
285 "things are not what they appear to be: nor are they otherwise"
288 puts Color.green(zen_statement)
293 include Test::Unit::Assertions
295 attr_reader :name, :failure, :koan_count, :step_count, :koan_file
297 def initialize(name, koan_file=nil, koan_count=0, step_count=0)
300 @koan_count = koan_count
301 @step_count = step_count
302 @koan_file = koan_file
323 rescue StandardError, EdgeCase::Sensei::AssertionError => ex
328 rescue StandardError, EdgeCase::Sensei::AssertionError => ex
329 failed(ex) if passed?
335 # Class methods for the EdgeCase test suite.
337 def inherited(subclass)
338 subclasses << subclass
341 def method_added(name)
342 testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s
345 def end_of_enlightenment
346 @tests_disabled = true
349 def command_line(args)
353 @test_pattern = Regexp.new($1)
355 @test_pattern = Regexp.new(Regexp.quote($1))
360 fail "Unknown command line argument '#{arg}'"
366 # Lazy initialize list of subclasses
371 # Lazy initialize list of test methods.
377 @tests_disabled ||= false
381 @test_pattern ||= /^test_/
385 self.subclasses.inject(0){|total, k| total + k.testmethods.size }
392 sensei = EdgeCase::Sensei.new
394 sensei.observe(step.meditate)
400 catch(:edgecase_exit) {
402 EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index|
403 koan.testmethods.each do |method_name|
404 step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1)
414 EdgeCase::Koan.command_line(ARGV)
415 EdgeCase::ThePath.new.walk