43 Commits

Author SHA1 Message Date
Jim Weirich
b0a01786f4 Updated koan directory from src. 2010-08-27 09:44:10 -04:00
Rene Mendoza
ed2ef0f439 Added autotest support to RubyKoans 2010-08-27 09:38:09 -04:00
Rene Mendoza
1f6c0e03a5 Color support for Ruby Koans 2010-08-27 09:38:09 -04:00
Rene Mendoza
06c47eb284 Added autotest support and added colorized output of tests 2010-08-27 09:37:33 -04:00
Jim Weirich
bc1a20a310 Tweeks on the color module 2010-08-27 09:35:33 -04:00
Jim Weirich
e6fc8f6434 Renamed method 2010-08-27 09:35:33 -04:00
Jim Weirich
36f93c6c63 Updated koans with changed from src. 2010-08-26 07:58:28 -04:00
Jim Weirich
bc55853983 Updated comment 2010-08-26 07:57:28 -04:00
Jim Weirich
d17cc7b457 Disable colorization when the NO_COLOR env variable is defined. 2010-08-26 07:55:04 -04:00
Jim Weirich
f88e9f1dfc Removed method missing from color module. 2010-08-26 07:53:22 -04:00
Jim Weirich
05d5ab9a5e Added colors to output (based on renemendoza's patch). 2010-08-26 07:45:31 -04:00
Jim Weirich
1b31a5b4dc Updated koans from new regex section. 2010-08-22 02:03:17 -04:00
Jim Weirich
3aa75e86aa Fixed spelling of repetition. 2010-08-22 01:55:02 -04:00
Jim Weirich
9c0ccd53a2 Merge branch 'master' of git://github.com/JEG2/ruby_koans into numeric
* 'master' of git://github.com/JEG2/ruby_koans:
  Adding Regular Expression koans.
  Fixing a bug that was causing some number Koans to be presolved.
2010-08-22 01:36:28 -04:00
James Edward Gray II
9a459a7eb3 Adding Regular Expression koans. 2010-08-21 22:11:06 -05:00
James Edward Gray II
e1ada6ca9f Fixing a bug that was causing some number Koans to be presolved. 2010-08-21 15:34:54 -05:00
Jonathan Castello
a5180d9ea1 Typo fix: changed "parenthesis" to "parentheses" 2010-08-21 11:32:57 -07:00
Jim Weirich
7db19b5e92 White space fixes 2010-08-21 09:01:10 -04:00
Jim Weirich
aa21cae64b Merge branch 'master' of http://github.com/Twisol/ruby_koans into twisol
* 'master' of http://github.com/Twisol/ruby_koans:
  With 'test_in_ruby_1_8_single_characters_are_represented_by_strings', changed the name to use '1.9', since it's in an in_ruby_version("1.9") block. (Confused me for a good while.)
2010-08-21 08:55:49 -04:00
Jonathan Castello
7c52931392 With 'test_in_ruby_1_8_single_characters_are_represented_by_strings', changed the name to use '1.9', since it's in an in_ruby_version("1.9") block. (Confused me for a good while.) 2010-08-21 01:33:13 -07:00
Jim Weirich
028e4a0c75 Updated README (tweeks words, whitespace cleanup) 2010-08-17 08:41:18 -04:00
Jim Weirich
eee3429394 Updated the koans directory. 2010-08-16 16:57:13 -04:00
Jim Weirich
6365c8d61d Now supporting Test::Unit as well under Ruby 1.9. 2010-08-16 16:56:42 -04:00
Jim Weirich
f2ac27f52e Added support for minitest under Ruby 1.9. 2010-08-16 16:53:56 -04:00
Jim Weirich
c4549eb24b Make method_missing public in the test framework for Ruby 1.9. 2010-08-16 15:40:54 -04:00
Jim Weirich
ee9a03740b Setup load path in path_to_enlightenment, so -I not needed in Rakefile. 2010-08-16 15:39:46 -04:00
Jim Weirich
8ef93f1d3a UPdated koans to match latest source. 2010-08-16 15:06:12 -04:00
Jim Weirich
7046294343 Answers now Ruby 1.9 compliant 2010-08-16 15:05:20 -04:00
Jim Weirich
e8456fa321 Added current directory to rake runner. 2010-08-16 15:03:44 -04:00
Jim Weirich
138bc7c9bc Minor change to comment about regular expressions. 2010-08-16 14:59:04 -04:00
Jim Weirich
2c3b65ec79 Updated require with yucky File.dirname(__FILE__) hacks. 2010-08-16 14:40:37 -04:00
Jim Weirich
fbd36f6b0d Reworded question. 2010-08-16 13:59:58 -04:00
Jim Weirich
56206e0a41 Removed unneeded check for no args. 2010-04-20 16:26:57 -04:00
Jim Weirich
308ad5d9c5 Added constants to koans path to enlightenment. 2010-04-20 16:26:18 -04:00
Jim Weirich
c40424e9a4 Updates source to be consistent with the _n_ changes. 2010-04-20 16:25:19 -04:00
Jim Weirich
f0b1560f34 Added about_constants 2010-04-20 16:17:34 -04:00
Jim Weirich
3b824d0e86 Modified to be less dependent on exact method and constant counts. 2010-04-20 16:17:24 -04:00
Jim Weirich
110ff38b3f Added a numeric fill in method (_n_) 2010-04-20 16:16:55 -04:00
Jim Weirich
1d1ab85777 Generated new koans directory. 2010-01-15 09:53:28 -05:00
Jim Weirich
d4c9150453 Added swap example to parallel assignments 2010-01-15 09:51:50 -05:00
Jim Weirich
ec6458e174 Renamed if test to avoid method name conflict. 2010-01-15 09:46:17 -05:00
Jim Weirich
6c69bcb0ef Added [1,1,3] case for triangles. 2010-01-15 09:39:48 -05:00
Jim Weirich
6052c776bc Use .values rather than .keys in values test (http://www.pivotaltracker.com/story/show/2177802) 2010-01-14 14:31:30 -05:00
67 changed files with 972 additions and 237 deletions

View File

@@ -1,29 +1,29 @@
= EdgeCase Ruby Koans
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
The goal is to learn the Ruby language, syntax, structure, and some common
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
The goal is to learn the Ruby language, syntax, structure, and some common
functions and libraries. We also teach you culture. Testing is not just something we
pay lip service to, but something we live. It is essential in your quest to learn
and do great things in the language.
pay lip service to, but something we live. It is essential in your quest to learn
and do great things in the language.
== The Structure
The koans are broken out into areas by file, hashes are covered in about_hashes.rb,
modules are introduced in about_modules.rb, etc. They are presented in order in the
path_to_enlightenment.rb file.
The koans are broken out into areas by file, hashes are covered in about_hashes.rb,
modules are introduced in about_modules.rb, etc. They are presented in order in the
path_to_enlightenment.rb file.
Each koan builds up your knowledge of Ruby and builds upon itself. It will stop at
the first place you need to correct.
Each koan builds up your knowledge of Ruby and builds upon itself. It will stop at
the first place you need to correct.
Some koans simply need to have the correct answer substituted for an incorrect one.
Some, however, require you to supply your own answer. If you see the method +__+ (a
double underscore) listed, it is a hint to you to supply your own code in order to
make it work correctly.
Some koans simply need to have the correct answer substituted for an incorrect one.
Some, however, require you to supply your own answer. If you see the method +__+ (a
double underscore) listed, it is a hint to you to supply your own code in order to
make it work correctly.
== Installing Ruby
If you do not have Ruby setup, please visit http://ruby-lang.org/en/downloads/ for
operating specific instructions. In order to run this you need ruby and rake
If you do not have Ruby setup, please visit http://ruby-lang.org/en/downloads/ for
operating specific instructions. In order to run this you need ruby and rake
installed. To check the installations simply type:
*nix platforms from any terminal window:
@@ -33,11 +33,11 @@ installed. To check the installations simply type:
Windows from the command prompt (cmd.exe)
c:\ruby --version
c:\ruby --version
c:\rake --version
Any response for Ruby with a version number greater than 1.8 is fine (should be
around 1.8.6 or more). Any version of rake will do.
Any response for Ruby with a version number greater than 1.8 is fine (should be
around 1.8.6 or more). Any version of rake will do.
== The Path To Enlightenment
@@ -48,18 +48,18 @@ recommended way to run them as we might build more functionality into this task)
[ruby_koans] $ rake # runs the default target :walk_the_path
[ruby_koans] $ ruby path_to_enlightenment.rb # simply call the file directly
Windows is the same thing
c:\ruby_koans\rake # runs the default target :walk_the_path
c:\ruby_koans\ruby path_to_enlightenment.rb # simply call the file directly
=== Red, Green, Refactor
In test-driven development the mantra has always been, red, green, refactor. Write a
failing test and run it (red), make the test pass (green), then refactor it (that is
look at the code and see if you can make it any better. In this case you will need
to run the koan and see it fail (red), make the test pass (green), then take a
to run the koan and see it fail (red), make the test pass (green), then take a
moment and reflect upon the test to see what it is teaching you and improve the
code to better communicate its intent (refactor).
@@ -68,26 +68,26 @@ The very first time you run it you will see the following output:
[ ruby_koans ] $ rake
(in /Users/person/dev/ruby_koans)
cd koans
Thinking AboutAsserts
test_assert_truth has damaged your karma.
You have not yet reached enlightenment ...
<false> is not true.
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
mountains are merely mountains
You have come to your first stage. If you notice it is telling you where to look for
the first solution:
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
We then open up the about_asserts.rb file and look at the first test:
# We shall contemplate truth by testing reality, via asserts.
@@ -97,13 +97,13 @@ We then open up the about_asserts.rb file and look at the first test:
We then change the +false+ to +true+ and run the test again. After you are
done, think about what you are learning. In this case, ignore everything except
the method name (+test_assert_truth+) and the parts inside the method (everything
before the +end+).
In this case the goal is for you to see that if you pass a value to the +assert+
the method name (+test_assert_truth+) and the parts inside the method (everything
before the +end+).
In this case the goal is for you to see that if you pass a value to the +assert+
method, it will either ensure it is +true+ and continue on, or fail if in fact
the statement is +false+.
the statement is +false+.
== Inspiration
A special thanks to Mike Clark and Ara Howard for inspiring this

View File

@@ -21,6 +21,7 @@ module Koans
line = line.gsub(/\b____\([^\)]+\)/, "____")
line = line.gsub(/\b___\([^\)]+\)/, "___")
line = line.gsub(/\b__\([^\)]+\)/, "__")
line = line.gsub(/\b_n_\([^\)]+\)/, "_n_")
line = line.gsub(%r(/\#\{__\}/), "/__/")
line
end
@@ -28,6 +29,8 @@ module Koans
def Koans.make_koan_file(infile, outfile)
if infile =~ /edgecase/
cp infile, outfile
elsif infile =~ /autotest/
cp_r infile, outfile
else
open(infile) do |ins|
open(outfile, "w") do |outs|

View File

@@ -1,29 +1,29 @@
= EdgeCase Ruby Koans
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
The goal is to learn the Ruby language, syntax, structure, and some common
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
The goal is to learn the Ruby language, syntax, structure, and some common
functions and libraries. We also teach you culture. Testing is not just something we
pay lip service to, but something we live. It is essential in your quest to learn
and do great things in the language.
pay lip service to, but something we live. It is essential in your quest to learn
and do great things in the language.
== The Structure
The koans are broken out into areas by file, hashes are covered in about_hashes.rb,
modules are introduced in about_modules.rb, etc. They are presented in order in the
path_to_enlightenment.rb file.
The koans are broken out into areas by file, hashes are covered in about_hashes.rb,
modules are introduced in about_modules.rb, etc. They are presented in order in the
path_to_enlightenment.rb file.
Each koan builds up your knowledge of Ruby and builds upon itself. It will stop at
the first place you need to correct.
Each koan builds up your knowledge of Ruby and builds upon itself. It will stop at
the first place you need to correct.
Some koans simply need to have the correct answer substituted for an incorrect one.
Some, however, require you to supply your own answer. If you see the method +__+ (a
double underscore) listed, it is a hint to you to supply your own code in order to
make it work correctly.
Some koans simply need to have the correct answer substituted for an incorrect one.
Some, however, require you to supply your own answer. If you see the method +__+ (a
double underscore) listed, it is a hint to you to supply your own code in order to
make it work correctly.
== Installing Ruby
If you do not have Ruby setup, please visit http://ruby-lang.org/en/downloads/ for
operating specific instructions. In order to run this you need ruby and rake
If you do not have Ruby setup, please visit http://ruby-lang.org/en/downloads/ for
operating specific instructions. In order to run this you need ruby and rake
installed. To check the installations simply type:
*nix platforms from any terminal window:
@@ -33,11 +33,11 @@ installed. To check the installations simply type:
Windows from the command prompt (cmd.exe)
c:\ruby --version
c:\ruby --version
c:\rake --version
Any response for Ruby with a version number greater than 1.8 is fine (should be
around 1.8.6 or more). Any version of rake will do.
Any response for Ruby with a version number greater than 1.8 is fine (should be
around 1.8.6 or more). Any version of rake will do.
== The Path To Enlightenment
@@ -48,18 +48,18 @@ recommended way to run them as we might build more functionality into this task)
[ruby_koans] $ rake # runs the default target :walk_the_path
[ruby_koans] $ ruby path_to_enlightenment.rb # simply call the file directly
Windows is the same thing
c:\ruby_koans\rake # runs the default target :walk_the_path
c:\ruby_koans\ruby path_to_enlightenment.rb # simply call the file directly
=== Red, Green, Refactor
In test-driven development the mantra has always been, red, green, refactor. Write a
failing test and run it (red), make the test pass (green), then refactor it (that is
look at the code and see if you can make it any better. In this case you will need
to run the koan and see it fail (red), make the test pass (green), then take a
to run the koan and see it fail (red), make the test pass (green), then take a
moment and reflect upon the test to see what it is teaching you and improve the
code to better communicate its intent (refactor).
@@ -68,26 +68,26 @@ The very first time you run it you will see the following output:
[ ruby_koans ] $ rake
(in /Users/person/dev/ruby_koans)
cd koans
Thinking AboutAsserts
test_assert_truth has damaged your karma.
You have not yet reached enlightenment ...
<false> is not true.
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
mountains are merely mountains
You have come to your first stage. If you notice it is telling you where to look for
the first solution:
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
We then open up the about_asserts.rb file and look at the first test:
# We shall contemplate truth by testing reality, via asserts.
@@ -97,13 +97,13 @@ We then open up the about_asserts.rb file and look at the first test:
We then change the +false+ to +true+ and run the test again. After you are
done, think about what you are learning. In this case, ignore everything except
the method name (+test_assert_truth+) and the parts inside the method (everything
before the +end+).
In this case the goal is for you to see that if you pass a value to the +assert+
the method name (+test_assert_truth+) and the parts inside the method (everything
before the +end+).
In this case the goal is for you to see that if you pass a value to the +assert+
method, it will either ensure it is +true+ and continue on, or fail if in fact
the statement is +false+.
the statement is +false+.
== Inspiration
A special thanks to Mike Clark and Ara Howard for inspiring this

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutArrayAssignment < EdgeCase::Koan
def test_non_parallel_assignment
@@ -35,4 +35,11 @@ class AboutArrayAssignment < EdgeCase::Koan
assert_equal __, first_name
end
def test_swapping_with_parallel_assignment
first_name = "Roy"
last_name = "Rob"
first_name, last_name = last_name, first_name
assert_equal __, first_name
assert_equal __, last_name
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutArrays < EdgeCase::Koan
def test_creating_arrays

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env ruby
# -*- ruby -*-
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutAsserts < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutBlocks < EdgeCase::Koan
def method_with_block

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutClassMethods < EdgeCase::Koan
class Dog
@@ -19,11 +19,11 @@ class AboutClassMethods < EdgeCase::Koan
def test_objects_have_methods
fido = Dog.new
assert_equal __, fido.methods.size
assert fido.methods.size > _n_
end
def test_classes_have_methods
assert_equal __, Dog.methods.size
assert Dog.methods.size > _n_
end
def test_you_can_define_methods_on_individual_objects

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutClasses < EdgeCase::Koan
class Dog
@@ -43,7 +43,7 @@ class AboutClasses < EdgeCase::Koan
fido = Dog2.new
fido.set_name("Fido")
assert_equal __, fido.instance_variable_get("@name")
assert_equal __, fido.instance_variable_get("@name")
end
def test_you_can_rip_the_value_out_using_instance_eval
@@ -89,7 +89,7 @@ class AboutClasses < EdgeCase::Koan
assert_equal __, fido.name
end
# ------------------------------------------------------------------
class Dog5
@@ -125,7 +125,7 @@ class AboutClasses < EdgeCase::Koan
# THINK ABOUT IT:
# Why is this so?
end
def test_different_objects_have_difference_instance_variables
fido = Dog6.new("Fido")
rover = Dog6.new("Rover")
@@ -186,5 +186,5 @@ class AboutClasses < EdgeCase::Koan
assert_equal __, "STRING".to_s
assert_equal __, "STRING".inspect
end
end

87
koans/about_constants.rb Normal file
View File

@@ -0,0 +1,87 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
C = "top level"
class AboutConstants < EdgeCase::Koan
C = "nested"
def test_nested_constants_may_also_be_referenced_with_relative_paths
assert_equal __, C
end
def test_top_level_constants_are_referenced_by_double_colons
assert_equal __, ::C
end
def test_nested_constants_are_referenced_by_their_complete_path
assert_equal __, AboutConstants::C
assert_equal __, ::AboutConstants::C
end
# ------------------------------------------------------------------
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
class NestedAnimal
def legs_in_nested_animal
LEGS
end
end
end
def test_nested_classes_inherit_constants_from_enclosing_classes
assert_equal __, Animal::NestedAnimal.new.legs_in_nested_animal
end
# ------------------------------------------------------------------
class Reptile < Animal
def legs_in_reptile
LEGS
end
end
def test_subclasses_inherit_constants_from_parent_classes
assert_equal __, Reptile.new.legs_in_reptile
end
# ------------------------------------------------------------------
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
def test_who_wins_with_both_nested_and_inherited_constants
assert_equal __, MyAnimals::Bird.new.legs_in_bird
end
# QUESTION: Which has precedence: The constant in the lexical scope,
# or the constant from the inheritance heirarachy?
# ------------------------------------------------------------------
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
def test_who_wins_with_explicit_scoping_on_class_definition
assert_equal __, MyAnimals::Oyster.new.legs_in_oyster
end
# QUESTION: Now Which has precedence: The constant in the lexical
# scope, or the constant from the inheritance heirarachy? Why is it
# different than the previous answer?
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutControlStatements < EdgeCase::Koan
@@ -11,7 +11,7 @@ class AboutControlStatements < EdgeCase::Koan
assert_equal __, result
end
def test_if_then_else_statements
def test_if_then_statements
result = :default_value
if true
result = :true_value

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class DiceSet
attr_reader :values

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutExceptions < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutHashes < EdgeCase::Koan
def test_creating_hashes
@@ -48,7 +48,7 @@ class AboutHashes < EdgeCase::Koan
def test_hash_values
hash = { :one => "uno", :two => "dos" }
assert_equal __, hash.keys.size
assert_equal __, hash.values.size
assert_equal __, hash.values.include?("uno")
assert_equal __, hash.values.include?("dos")
assert_equal Array, hash.values.class

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutInheritance < EdgeCase::Koan
class Dog

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutIteration < EdgeCase::Koan

View File

@@ -1,28 +1,28 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutMessagePassing < EdgeCase::Koan
class MessageCatcher
def caught?
true
end
end
def test_methods_can_be_called_directly
mc = MessageCatcher.new
assert mc.caught?
assert mc.caught?
end
def test_methods_can_be_invoked_by_sending_the_message
mc = MessageCatcher.new
assert mc.send(:caught?)
end
def test_methods_can_be_invoked_more_dynamically
mc = MessageCatcher.new
assert mc.send("caught?")
assert mc.send("caught" + __ ) # What do you need to add to the first string?
assert mc.send("CAUGHT?".____ ) # What would you need to do to the string?
@@ -40,23 +40,22 @@ class AboutMessagePassing < EdgeCase::Koan
def test_classes_can_be_asked_if_they_know_how_to_respond
mc = MessageCatcher.new
assert_equal __, mc.respond_to?(:caught?)
assert_equal __, mc.respond_to?(:does_not_exist)
end
# ------------------------------------------------------------------
class MessageCatcher
def add_a_payload(*args)
return :empty unless args
args
end
end
def test_sending_a_message_with_arguments
mc = MessageCatcher.new
assert_equal __, mc.add_a_payload
assert_equal __, mc.send(:add_a_payload)
@@ -90,6 +89,18 @@ class AboutMessagePassing < EdgeCase::Koan
#
# If the method :method_missing causes the NoMethodError, then
# what would happen if we redefine method_missing?
#
# NOTE:
#
# In Ruby 1.8 the method_missing method is public and can be
# called as shown above. However, in Ruby 1.9 the method_missing
# method is private. We explicitly made it public in the testing
# framework so this example works in both versions of Ruby. Just
# keep in mind you can't call method_missing like that in Ruby
# 1.9. normally.
#
# Thanks. We now return you to your regularly schedule Ruby
# Koans.
end
# ------------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
def my_global_method(a,b)
a + b
@@ -10,14 +10,14 @@ class AboutMethods < EdgeCase::Koan
assert_equal __, my_global_method(2,3)
end
def test_calling_global_methods_without_parenthesis
def test_calling_global_methods_without_parentheses
result = my_global_method 2, 3
assert_equal __, result
end
# (NOTE: We are Using eval below because the example code is
# considered to be syntactically invalid).
def test_sometimes_missing_parenthesis_are_ambiguous
def test_sometimes_missing_parentheses_are_ambiguous
eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK
#
# Ruby doesn't know if you mean:

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutModules < EdgeCase::Koan
module Nameable

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutNil < EdgeCase::Koan
def test_nil_is_an_object

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutOpenClasses < EdgeCase::Koan
class Dog

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# Project: Create a Proxy Class
#

View File

@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutRegularExpressions < EdgeCase::Koan
def test_a_pattern_is_a_regular_expression
assert_equal Regexp, /pattern/.class
end
def test_a_regexp_can_search_a_string_for_matching_content
assert_equal "match", "some matching content"[/match/]
end
def test_a_failed_match_returns_nil
assert_equal __, "some matching content"[/missing/]
end
# ------------------------------------------------------------------
def test_question_mark_means_optional
assert_equal __, "abbcccddddeeeee"[/ab?/]
assert_equal __, "abbcccddddeeeee"[/az?/]
end
def test_plus_means_one_or_more
assert_equal __, "abbcccddddeeeee"[/bc+/]
end
def test_asterisk_means_zero_or_more
assert_equal __, "abbcccddddeeeee"[/ab*/]
assert_equal __, "abbcccddddeeeee"[/az*/]
assert_equal __, "abbcccddddeeeee"[/z*/]
# THINK ABOUT IT:
#
# When would * fail to match?
end
# THINK ABOUT IT:
#
# We say that the repetition operators above are "greedy."
#
# Why?
# ------------------------------------------------------------------
def test_the_left_most_match_wins
assert_equal __, "abbccc az"[/az*/]
end
# ------------------------------------------------------------------
def test_character_classes_give_options_for_a_character
animals = ["cat", "bat", "rat", "zat"]
assert_equal __, animals.select { |a| a[/[cbr]at/] }
end
def test_slash_d_is_a_shortcut_for_a_digit_character_class
assert_equal __, "the number is 42"[/[0123456789]+/]
assert_equal __, "the number is 42"[/\d+/]
end
def test_character_classes_can_include_ranges
assert_equal __, "the number is 42"[/[0-9]+/]
end
def test_slash_s_is_a_shortcut_for_a_whitespace_character_class
assert_equal __, "space: \t\n"[/\s+/]
end
def test_slash_w_is_a_shortcut_for_a_word_character_class
# NOTE: This is more like how a programmer might define a word.
assert_equal __, "variable_1 = 42"[/[a-zA-Z0-9_]+/]
assert_equal __, "variable_1 = 42"[/\w+/]
end
def test_period_is_a_shortcut_for_any_non_newline_character
assert_equal __, "abc\n123"[/a.+/]
end
def test_a_character_class_can_be_negated
assert_equal __, "the number is 42"[/[^0-9]+/]
end
def test_shortcut_character_classes_are_negated_with_capitals
assert_equal __, "the number is 42"[/\D+/]
assert_equal __, "space: \t\n"[/\S+/]
assert_equal __, "variable_1 = 42"[/\W+/]
end
# ------------------------------------------------------------------
def test_slash_a_anchors_to_the_start_of_the_string
assert_equal __, "start end"[/\Astart/]
assert_equal __, "start end"[/\Aend/]
end
def test_slash_z_anchors_to_the_end_of_the_string
assert_equal __, "start end"[/end\z/]
assert_equal __, "start end"[/start\z/]
end
def test_caret_anchors_to_the_start_of_lines
assert_equal __, "num 42\n2 lines"[/^\d+/]
end
def test_dollar_sign_anchors_to_the_end_of_lines
assert_equal __, "2 lines\nnum 42"[/\d+$/]
end
def test_slash_b_anchors_to_a_word_boundary
assert_equal __, "bovine vines"[/\bvine./]
end
# ------------------------------------------------------------------
def test_parentheses_group_contents
assert_equal __, "ahahaha"[/(ha)+/]
end
# ------------------------------------------------------------------
def test_parentheses_also_capture_matched_content_by_number
assert_equal __, "Gray, James"[/(\w+), (\w+)/, 1]
assert_equal __, "Gray, James"[/(\w+), (\w+)/, 2]
end
def test_variables_can_also_be_used_to_access_captures
assert_equal __, "Name: Gray, James"[/(\w+), (\w+)/]
assert_equal __, $1
assert_equal __, $2
end
# ------------------------------------------------------------------
def test_a_vertical_pipe_means_or
grays = /(James|Dana|Summer) Gray/
assert_equal __, "James Gray"[grays]
assert_equal __, "Summer Gray"[grays, 1]
assert_equal __, "Jim Gray"[grays, 1]
end
# THINK ABOUT IT:
#
# Explain the difference between a character class ([…]) and alternation (|).
# ------------------------------------------------------------------
def test_scan_is_like_find_all
assert_equal __, "one two-three".scan(/\w+/)
end
def test_sub_is_like_find_and_replace
assert_equal __, "one two-three".sub(/(t\w*)/) { $1[0, 1] }
end
def test_gsub_is_like_find_and_replace_all
assert_equal __, "one two-three".gsub(/(t\w*)/) { $1[0, 1] }
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutUsingBlocks < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutScope < EdgeCase::Koan
module Jims
@@ -28,7 +28,7 @@ class AboutScope < EdgeCase::Koan
rover = Joes::Dog.new
assert_equal __, fido.identify
assert_equal __, rover.identify
assert_not_equal fido.class, rover.class
assert_not_equal Jims::Dog, Joes::Dog
end
@@ -41,7 +41,7 @@ class AboutScope < EdgeCase::Koan
def test_bare_bones_class_names_assume_the_current_scope
assert_equal __, AboutScope::String == String
end
def test_nested_string_is_not_the_same_as_the_system_string
assert_equal __, String == "HI".class
end
@@ -74,6 +74,6 @@ class AboutScope < EdgeCase::Koan
def test_you_can_get_a_list_of_constants_for_any_class_or_module
assert_equal __, Jims.constants
assert_equal __, Object.constants.size
assert Object.constants.size > _n_
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# Greed is a dice game where you roll up to five dice to accumulate
# points. The following "score" function will be used calculate the

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutStrings < EdgeCase::Koan
def test_double_quoted_strings_are_strings
@@ -146,11 +146,20 @@ EOS
# Surprised?
end
def test_single_characters_are_represented_by_integers
assert_equal __, ?a
assert_equal __, ?a == 97
in_ruby_version("1.8") do
def test_in_ruby_1_8_single_characters_are_represented_by_integers
assert_equal __, ?a
assert_equal __, ?a == 97
assert_equal __, ?b == (?a + 1)
assert_equal __, ?b == (?a + 1)
end
end
in_ruby_version("1.9") do
def test_in_ruby_1_9_single_characters_are_represented_by_strings
assert_equal __, ?a
assert_equal __, ?a == 97
end
end
def test_strings_can_be_split
@@ -165,8 +174,8 @@ EOS
assert_equal [__, __, __, __], words
# NOTE: Patterns are formed from Regular Expressions. Ruby has a
# very powerful Regular Expression library. Unfortunately, time
# does not permit us to explore it in detail in Ruby 101.
# very powerful Regular Expression library. We will become
# enlightened about them soon.
end
def test_strings_can_be_joined

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'
@@ -9,6 +9,7 @@ class AboutTriangleAssignment2 < EdgeCase::Koan
def test_illegal_triangles_throw_exceptions
assert_raise(TriangleError) do triangle(0, 0, 0) end
assert_raise(TriangleError) do triangle(3, 4, -5) end
assert_raise(TriangleError) do triangle(1, 1, 3) end
assert_raise(TriangleError) do triangle(2, 4, 2) end
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutTrueAndFalse < EdgeCase::Koan
def truth_value(condition)

View File

@@ -0,0 +1,3 @@
Autotest.add_discovery do
"rubykoan" if File.exist? 'path_to_enlightenment.rb'
end

View File

@@ -0,0 +1,24 @@
require 'autotest'
class Autotest::Rubykoan < Autotest
def initialize
super
@exceptions = /\.txt|Rakefile|\.rdoc/
self.order = :alpha
self.add_mapping(/^about_.*rb$/) do |filename, _|
filename
end
end
def make_test_cmd files_to_test
"#{ruby} 'path_to_enlightenment.rb'"
end
# quiet test/unit chatter
def handle_results(results)
end
end

View File

@@ -1 +1 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')

View File

@@ -6,8 +6,24 @@ require 'test/unit/assertions'
class FillMeInError < StandardError
end
def __(value="FILL ME IN")
value
def in_ruby_version(version)
yield if RUBY_VERSION =~ /^#{version}/
end
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def ___(value=FillMeInError)
@@ -20,13 +36,56 @@ class Object
self.send(method)
end
end
in_ruby_version("1.9") do
public :method_missing
end
end
module EdgeCase
module Color
#shamelessly stolen (and modified) from redgreen
COLORS = {
:clear => 0, :black => 30, :red => 31,
:green => 32, :yellow => 33, :blue => 34,
:magenta => 35, :cyan => 36,
}
module_function
COLORS.each do |color, value|
module_eval "def #{color}(string); colorize(string, #{value}); end"
module_function color
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
color(color_value) + string + color(COLORS[:clear])
end
end
def color(color_value)
"\e[#{color_value}m"
end
end
class Sensei
attr_reader :failure, :failed_test
AssertionError = Test::Unit::AssertionFailedError
in_ruby_version("1.8") do
AssertionError = Test::Unit::AssertionFailedError
end
in_ruby_version("1.9") do
if defined?(MiniTest)
AssertionError = MiniTest::Assertion
else
AssertionError = Test::Unit::AssertionFailedError
end
end
def initialize
@pass_count = 0
@@ -37,9 +96,9 @@ module EdgeCase
def accumulate(test)
if test.passed?
@pass_count += 1
puts " #{test.name} has expanded your awareness."
puts Color.green(" #{test.name} has expanded your awareness.")
else
puts " #{test.name} has damaged your karma."
puts Color.red(" #{test.name} has damaged your karma.")
@failed_test = test
@failure = test.failure
throw :edgecase_exit
@@ -57,18 +116,19 @@ module EdgeCase
def report
if failed?
puts
puts "You have not yet reached enlightenment ..."
puts failure.message
puts Color.green("You have not yet reached enlightenment ...")
puts Color.red(failure.message)
puts
puts "Please meditate on the following code:"
puts Color.green("Please meditate on the following code:")
if assert_failed?
puts find_interesting_lines(failure.backtrace)
#puts find_interesting_lines(failure.backtrace)
puts find_interesting_lines(failure.backtrace).collect {|l| Color.red(l) }
else
puts failure.backtrace
puts Color.red(failure.backtrace)
end
puts
end
say_something_zenlike
puts Color.green(a_zenlike_statement)
end
def find_interesting_lines(backtrace)
@@ -79,28 +139,29 @@ module EdgeCase
# Hat's tip to Ara T. Howard for the zen statements from his
# metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html)
def say_something_zenlike
def a_zenlike_statement
puts
if !failed?
puts "Mountains are again merely mountains"
zen_statement = "Mountains are again merely mountains"
else
case (@pass_count % 10)
zen_statement = case (@pass_count % 10)
when 0
puts "mountains are merely mountains"
"mountains are merely mountains"
when 1, 2
puts "learn the rules so you know how to break them properly"
"learn the rules so you know how to break them properly"
when 3, 4
puts "remember that silence is sometimes the best answer"
"remember that silence is sometimes the best answer"
when 5, 6
puts "sleep is the best meditation"
"sleep is the best meditation"
when 7, 8
puts "when you lose, don't lose the lesson"
"when you lose, don't lose the lesson"
else
puts "things are not what they appear to be: nor are they otherwise"
"things are not what they appear to be: nor are they otherwise"
end
end
zen_statement
end
end
end
class Koan
include Test::Unit::Assertions
@@ -138,7 +199,7 @@ module EdgeCase
def run_tests(accumulator)
puts
puts "Thinking #{self}"
puts Color.green("Thinking #{self}")
testmethods.each do |m|
self.run_test(m, accumulator) if Koan.test_pattern =~ m.to_s
end
@@ -149,12 +210,12 @@ module EdgeCase
test.setup
begin
test.send(method)
rescue StandardError => ex
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
test.failed(ex)
ensure
begin
test.teardown
rescue StandardError => ex
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
test.failed(ex) if test.passed?
end
end
@@ -177,7 +238,7 @@ module EdgeCase
load(arg)
else
fail "Unknown command line argument '#{arg}'"
end
end
end
end
end

View File

@@ -1,12 +1,16 @@
# The path to Ruby Enlightenment starts with the following:
$LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
require 'about_strings'
require 'about_regular_expressions'
require 'about_methods'
require 'about_constants'
require 'about_control_statements'
require 'about_true_and_false'
require 'about_triangle_project'

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutArrayAssignment < EdgeCase::Koan
def test_non_parallel_assignment
@@ -35,4 +35,11 @@ class AboutArrayAssignment < EdgeCase::Koan
assert_equal __("John"), first_name
end
def test_swapping_with_parallel_assignment
first_name = "Roy"
last_name = "Rob"
first_name, last_name = last_name, first_name
assert_equal __('Rob'), first_name
assert_equal __('Roy'), last_name
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutArrays < EdgeCase::Koan
def test_creating_arrays

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env ruby
# -*- ruby -*-
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutAsserts < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutBlocks < EdgeCase::Koan
def method_with_block

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutClassMethods < EdgeCase::Koan
class Dog
@@ -19,11 +19,11 @@ class AboutClassMethods < EdgeCase::Koan
def test_objects_have_methods
fido = Dog.new
assert_equal __(44), fido.methods.size
assert fido.methods.size > _n_(30)
end
def test_classes_have_methods
assert_equal __(79), Dog.methods.size
assert Dog.methods.size > _n_(40)
end
def test_you_can_define_methods_on_individual_objects

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutClasses < EdgeCase::Koan
class Dog
@@ -22,7 +22,7 @@ class AboutClasses < EdgeCase::Koan
assert_equal __([]), fido.instance_variables
fido.set_name("Fido")
assert_equal __(["@name"]), fido.instance_variables
assert_equal __(["@name"], [:@name]), fido.instance_variables
end
def test_instance_variables_cannot_be_accessed_outside_the_class
@@ -43,7 +43,7 @@ class AboutClasses < EdgeCase::Koan
fido = Dog2.new
fido.set_name("Fido")
assert_equal __("Fido"), fido.instance_variable_get("@name")
assert_equal __("Fido"), fido.instance_variable_get("@name")
end
def test_you_can_rip_the_value_out_using_instance_eval
@@ -89,7 +89,7 @@ class AboutClasses < EdgeCase::Koan
assert_equal __("Fido"), fido.name
end
# ------------------------------------------------------------------
class Dog5
@@ -125,7 +125,7 @@ class AboutClasses < EdgeCase::Koan
# THINK ABOUT IT:
# Why is this so?
end
def test_different_objects_have_difference_instance_variables
fido = Dog6.new("Fido")
rover = Dog6.new("Rover")
@@ -180,11 +180,11 @@ class AboutClasses < EdgeCase::Koan
def test_all_objects_support_to_s_and_inspect
array = [1,2,3]
assert_equal __("123"), array.to_s
assert_equal __("123", "[1, 2, 3]"), array.to_s
assert_equal __("[1, 2, 3]"), array.inspect
assert_equal __("STRING"), "STRING".to_s
assert_equal __('"STRING"'), "STRING".inspect
end
end

87
src/about_constants.rb Normal file
View File

@@ -0,0 +1,87 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
C = "top level"
class AboutConstants < EdgeCase::Koan
C = "nested"
def test_nested_constants_may_also_be_referenced_with_relative_paths
assert_equal __("nested"), C
end
def test_top_level_constants_are_referenced_by_double_colons
assert_equal __("top level"), ::C
end
def test_nested_constants_are_referenced_by_their_complete_path
assert_equal __("nested"), AboutConstants::C
assert_equal __("nested"), ::AboutConstants::C
end
# ------------------------------------------------------------------
class Animal
LEGS = 4
def legs_in_animal
LEGS
end
class NestedAnimal
def legs_in_nested_animal
LEGS
end
end
end
def test_nested_classes_inherit_constants_from_enclosing_classes
assert_equal __(4), Animal::NestedAnimal.new.legs_in_nested_animal
end
# ------------------------------------------------------------------
class Reptile < Animal
def legs_in_reptile
LEGS
end
end
def test_subclasses_inherit_constants_from_parent_classes
assert_equal __(4), Reptile.new.legs_in_reptile
end
# ------------------------------------------------------------------
class MyAnimals
LEGS = 2
class Bird < Animal
def legs_in_bird
LEGS
end
end
end
def test_who_wins_with_both_nested_and_inherited_constants
assert_equal __(2), MyAnimals::Bird.new.legs_in_bird
end
# QUESTION: Which has precedence: The constant in the lexical scope,
# or the constant from the inheritance heirarachy?
# ------------------------------------------------------------------
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
def test_who_wins_with_explicit_scoping_on_class_definition
assert_equal __(4), MyAnimals::Oyster.new.legs_in_oyster
end
# QUESTION: Now Which has precedence: The constant in the lexical
# scope, or the constant from the inheritance heirarachy? Why is it
# different than the previous answer?
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutControlStatements < EdgeCase::Koan
@@ -8,10 +8,10 @@ class AboutControlStatements < EdgeCase::Koan
else
result = :false_value
end
assert_equal __, result
assert_equal __(:true_value), result
end
def test_if_then_else_statements
def test_if_then_statements
result = :default_value
if true
result = :true_value

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class DiceSet
attr_reader :values

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutExceptions < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutHashes < EdgeCase::Koan
def test_creating_hashes
@@ -48,7 +48,7 @@ class AboutHashes < EdgeCase::Koan
def test_hash_values
hash = { :one => "uno", :two => "dos" }
assert_equal __(2), hash.keys.size
assert_equal __(2), hash.values.size
assert_equal __(true), hash.values.include?("uno")
assert_equal __(true), hash.values.include?("dos")
assert_equal Array, hash.values.class

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutInheritance < EdgeCase::Koan
class Dog

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutIteration < EdgeCase::Koan

View File

@@ -1,28 +1,28 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutMessagePassing < EdgeCase::Koan
class MessageCatcher
def caught?
true
end
end
def test_methods_can_be_called_directly
mc = MessageCatcher.new
assert mc.caught?
assert mc.caught?
end
def test_methods_can_be_invoked_by_sending_the_message
mc = MessageCatcher.new
assert mc.send(:caught?)
end
def test_methods_can_be_invoked_more_dynamically
mc = MessageCatcher.new
assert mc.send("caught?")
assert mc.send("caught" + __("?") ) # What do you need to add to the first string?
assert mc.send("CAUGHT?".____(:downcase) ) # What would you need to do to the string?
@@ -40,23 +40,22 @@ class AboutMessagePassing < EdgeCase::Koan
def test_classes_can_be_asked_if_they_know_how_to_respond
mc = MessageCatcher.new
assert_equal __(true), mc.respond_to?(:caught?)
assert_equal __(false), mc.respond_to?(:does_not_exist)
end
# ------------------------------------------------------------------
class MessageCatcher
def add_a_payload(*args)
return :empty unless args
args
end
end
def test_sending_a_message_with_arguments
mc = MessageCatcher.new
assert_equal __([]), mc.add_a_payload
assert_equal __([]), mc.send(:add_a_payload)
@@ -90,6 +89,18 @@ class AboutMessagePassing < EdgeCase::Koan
#
# If the method :method_missing causes the NoMethodError, then
# what would happen if we redefine method_missing?
#
# NOTE:
#
# In Ruby 1.8 the method_missing method is public and can be
# called as shown above. However, in Ruby 1.9 the method_missing
# method is private. We explicitly made it public in the testing
# framework so this example works in both versions of Ruby. Just
# keep in mind you can't call method_missing like that in Ruby
# 1.9. normally.
#
# Thanks. We now return you to your regularly schedule Ruby
# Koans.
end
# ------------------------------------------------------------------

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
def my_global_method(a,b)
a + b
@@ -10,14 +10,14 @@ class AboutMethods < EdgeCase::Koan
assert_equal __(5), my_global_method(2,3)
end
def test_calling_global_methods_without_parenthesis
def test_calling_global_methods_without_parentheses
result = my_global_method 2, 3
assert_equal __(5), result
end
# (NOTE: We are Using eval below because the example code is
# considered to be syntactically invalid).
def test_sometimes_missing_parenthesis_are_ambiguous
def test_sometimes_missing_parentheses_are_ambiguous
#--
eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK
if false

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutModules < EdgeCase::Koan
module Nameable

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutNil < EdgeCase::Koan
def test_nil_is_an_object

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutOpenClasses < EdgeCase::Koan
class Dog

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# Project: Create a Proxy Class
#

View File

@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutRegularExpressions < EdgeCase::Koan
def test_a_pattern_is_a_regular_expression
assert_equal Regexp, /pattern/.class
end
def test_a_regexp_can_search_a_string_for_matching_content
assert_equal "match", "some matching content"[/match/]
end
def test_a_failed_match_returns_nil
assert_equal __(nil), "some matching content"[/missing/]
end
# ------------------------------------------------------------------
def test_question_mark_means_optional
assert_equal __("ab"), "abbcccddddeeeee"[/ab?/]
assert_equal __("a"), "abbcccddddeeeee"[/az?/]
end
def test_plus_means_one_or_more
assert_equal __("bccc"), "abbcccddddeeeee"[/bc+/]
end
def test_asterisk_means_zero_or_more
assert_equal __("abb"), "abbcccddddeeeee"[/ab*/]
assert_equal __("a"), "abbcccddddeeeee"[/az*/]
assert_equal __(""), "abbcccddddeeeee"[/z*/]
# THINK ABOUT IT:
#
# When would * fail to match?
end
# THINK ABOUT IT:
#
# We say that the repetition operators above are "greedy."
#
# Why?
# ------------------------------------------------------------------
def test_the_left_most_match_wins
assert_equal __("a"), "abbccc az"[/az*/]
end
# ------------------------------------------------------------------
def test_character_classes_give_options_for_a_character
animals = ["cat", "bat", "rat", "zat"]
assert_equal __(["cat", "bat", "rat"]), animals.select { |a| a[/[cbr]at/] }
end
def test_slash_d_is_a_shortcut_for_a_digit_character_class
assert_equal __("42"), "the number is 42"[/[0123456789]+/]
assert_equal __("42"), "the number is 42"[/\d+/]
end
def test_character_classes_can_include_ranges
assert_equal __("42"), "the number is 42"[/[0-9]+/]
end
def test_slash_s_is_a_shortcut_for_a_whitespace_character_class
assert_equal __(" \t\n"), "space: \t\n"[/\s+/]
end
def test_slash_w_is_a_shortcut_for_a_word_character_class
# NOTE: This is more like how a programmer might define a word.
assert_equal __("variable_1"), "variable_1 = 42"[/[a-zA-Z0-9_]+/]
assert_equal __("variable_1"), "variable_1 = 42"[/\w+/]
end
def test_period_is_a_shortcut_for_any_non_newline_character
assert_equal __("abc"), "abc\n123"[/a.+/]
end
def test_a_character_class_can_be_negated
assert_equal __("the number is "), "the number is 42"[/[^0-9]+/]
end
def test_shortcut_character_classes_are_negated_with_capitals
assert_equal __("the number is "), "the number is 42"[/\D+/]
assert_equal __("space:"), "space: \t\n"[/\S+/]
assert_equal __(" = "), "variable_1 = 42"[/\W+/]
end
# ------------------------------------------------------------------
def test_slash_a_anchors_to_the_start_of_the_string
assert_equal __("start"), "start end"[/\Astart/]
assert_equal __(nil), "start end"[/\Aend/]
end
def test_slash_z_anchors_to_the_end_of_the_string
assert_equal __("end"), "start end"[/end\z/]
assert_equal __(nil), "start end"[/start\z/]
end
def test_caret_anchors_to_the_start_of_lines
assert_equal __("2"), "num 42\n2 lines"[/^\d+/]
end
def test_dollar_sign_anchors_to_the_end_of_lines
assert_equal __("42"), "2 lines\nnum 42"[/\d+$/]
end
def test_slash_b_anchors_to_a_word_boundary
assert_equal __("vines"), "bovine vines"[/\bvine./]
end
# ------------------------------------------------------------------
def test_parentheses_group_contents
assert_equal __("hahaha"), "ahahaha"[/(ha)+/]
end
# ------------------------------------------------------------------
def test_parentheses_also_capture_matched_content_by_number
assert_equal __("Gray"), "Gray, James"[/(\w+), (\w+)/, 1]
assert_equal __("James"), "Gray, James"[/(\w+), (\w+)/, 2]
end
def test_variables_can_also_be_used_to_access_captures
assert_equal __("Gray, James"), "Name: Gray, James"[/(\w+), (\w+)/]
assert_equal __("Gray"), $1
assert_equal __("James"), $2
end
# ------------------------------------------------------------------
def test_a_vertical_pipe_means_or
grays = /(James|Dana|Summer) Gray/
assert_equal __("James Gray"), "James Gray"[grays]
assert_equal __("Summer"), "Summer Gray"[grays, 1]
assert_equal __(nil), "Jim Gray"[grays, 1]
end
# THINK ABOUT IT:
#
# Explain the difference between a character class ([…]) and alternation (|).
# ------------------------------------------------------------------
def test_scan_is_like_find_all
assert_equal __(["one", "two", "three"]), "one two-three".scan(/\w+/)
end
def test_sub_is_like_find_and_replace
assert_equal __("one t-three"), "one two-three".sub(/(t\w*)/) { $1[0, 1] }
end
def test_gsub_is_like_find_and_replace_all
assert_equal __("one t-t"), "one two-three".gsub(/(t\w*)/) { $1[0, 1] }
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutUsingBlocks < EdgeCase::Koan

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutScope < EdgeCase::Koan
module Jims
@@ -28,7 +28,7 @@ class AboutScope < EdgeCase::Koan
rover = Joes::Dog.new
assert_equal __(:jims_dog), fido.identify
assert_equal __(:joes_dog), rover.identify
assert_not_equal fido.class, rover.class
assert_not_equal Jims::Dog, Joes::Dog
end
@@ -41,7 +41,7 @@ class AboutScope < EdgeCase::Koan
def test_bare_bones_class_names_assume_the_current_scope
assert_equal __(true), AboutScope::String == String
end
def test_nested_string_is_not_the_same_as_the_system_string
assert_equal __(false), String == "HI".class
end
@@ -73,7 +73,7 @@ class AboutScope < EdgeCase::Koan
end
def test_you_can_get_a_list_of_constants_for_any_class_or_module
assert_equal __(["Dog"]), Jims.constants
assert_equal __(122), Object.constants.size
assert_equal __(["Dog"], [:Dog]), Jims.constants
assert Object.constants.size > _n_(10)
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# Greed is a dice game where you roll up to five dice to accumulate
# points. The following "score" function will be used calculate the

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutStrings < EdgeCase::Koan
def test_double_quoted_strings_are_strings
@@ -141,16 +141,25 @@ EOS
def test_you_can_get_a_single_character_from_a_string
string = "Bacon, lettuce and tomato"
assert_equal __(97), string[1]
assert_equal __(97, 'a'), string[1]
# Surprised?
end
def test_single_characters_are_represented_by_integers
assert_equal __(97), ?a
assert_equal __(true), ?a == 97
in_ruby_version("1.8") do
def test_in_ruby_1_8_single_characters_are_represented_by_integers
assert_equal __(97, 'a'), ?a
assert_equal __(true, false), ?a == 97
assert_equal __(true), ?b == (?a + 1)
assert_equal __(true), ?b == (?a + 1)
end
end
in_ruby_version("1.9") do
def test_in_ruby_1_9_single_characters_are_represented_by_strings
assert_equal __('a'), ?a
assert_equal __(false), ?a == 97
end
end
def test_strings_can_be_split
@@ -165,8 +174,8 @@ EOS
assert_equal [__("the"), __("rain"), __("in"), __("spain")], words
# NOTE: Patterns are formed from Regular Expressions. Ruby has a
# very powerful Regular Expression library. Unfortunately, time
# does not permit us to explore it in detail in Ruby 101.
# very powerful Regular Expression library. We will become
# enlightened about them soon.
end
def test_strings_can_be_joined

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'
@@ -9,6 +9,7 @@ class AboutTriangleAssignment2 < EdgeCase::Koan
def test_illegal_triangles_throw_exceptions
assert_raise(TriangleError) do triangle(0, 0, 0) end
assert_raise(TriangleError) do triangle(3, 4, -5) end
assert_raise(TriangleError) do triangle(1, 1, 3) end
assert_raise(TriangleError) do triangle(2, 4, 2) end
end
end

View File

@@ -1,4 +1,4 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutTrueAndFalse < EdgeCase::Koan
def truth_value(condition)

3
src/autotest/discover.rb Normal file
View File

@@ -0,0 +1,3 @@
Autotest.add_discovery do
"rubykoan" if File.exist? 'path_to_enlightenment.rb'
end

24
src/autotest/rubykoan.rb Normal file
View File

@@ -0,0 +1,24 @@
require 'autotest'
class Autotest::Rubykoan < Autotest
def initialize
super
@exceptions = /\.txt|Rakefile|\.rdoc/
self.order = :alpha
self.add_mapping(/^about_.*rb$/) do |filename, _|
filename
end
end
def make_test_cmd files_to_test
"#{ruby} 'path_to_enlightenment.rb'"
end
# quiet test/unit chatter
def handle_results(results)
end
end

View File

@@ -1 +1 @@
require 'edgecase'
require File.expand_path(File.dirname(__FILE__) + '/edgecase')

View File

@@ -6,8 +6,24 @@ require 'test/unit/assertions'
class FillMeInError < StandardError
end
def __(value="FILL ME IN")
value
def in_ruby_version(version)
yield if RUBY_VERSION =~ /^#{version}/
end
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def ___(value=FillMeInError)
@@ -20,13 +36,56 @@ class Object
self.send(method)
end
end
in_ruby_version("1.9") do
public :method_missing
end
end
module EdgeCase
module Color
#shamelessly stolen (and modified) from redgreen
COLORS = {
:clear => 0, :black => 30, :red => 31,
:green => 32, :yellow => 33, :blue => 34,
:magenta => 35, :cyan => 36,
}
module_function
COLORS.each do |color, value|
module_eval "def #{color}(string); colorize(string, #{value}); end"
module_function color
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
color(color_value) + string + color(COLORS[:clear])
end
end
def color(color_value)
"\e[#{color_value}m"
end
end
class Sensei
attr_reader :failure, :failed_test
AssertionError = Test::Unit::AssertionFailedError
in_ruby_version("1.8") do
AssertionError = Test::Unit::AssertionFailedError
end
in_ruby_version("1.9") do
if defined?(MiniTest)
AssertionError = MiniTest::Assertion
else
AssertionError = Test::Unit::AssertionFailedError
end
end
def initialize
@pass_count = 0
@@ -37,9 +96,9 @@ module EdgeCase
def accumulate(test)
if test.passed?
@pass_count += 1
puts " #{test.name} has expanded your awareness."
puts Color.green(" #{test.name} has expanded your awareness.")
else
puts " #{test.name} has damaged your karma."
puts Color.red(" #{test.name} has damaged your karma.")
@failed_test = test
@failure = test.failure
throw :edgecase_exit
@@ -57,18 +116,19 @@ module EdgeCase
def report
if failed?
puts
puts "You have not yet reached enlightenment ..."
puts failure.message
puts Color.green("You have not yet reached enlightenment ...")
puts Color.red(failure.message)
puts
puts "Please meditate on the following code:"
puts Color.green("Please meditate on the following code:")
if assert_failed?
puts find_interesting_lines(failure.backtrace)
#puts find_interesting_lines(failure.backtrace)
puts find_interesting_lines(failure.backtrace).collect {|l| Color.red(l) }
else
puts failure.backtrace
puts Color.red(failure.backtrace)
end
puts
end
say_something_zenlike
puts Color.green(a_zenlike_statement)
end
def find_interesting_lines(backtrace)
@@ -79,28 +139,29 @@ module EdgeCase
# Hat's tip to Ara T. Howard for the zen statements from his
# metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html)
def say_something_zenlike
def a_zenlike_statement
puts
if !failed?
puts "Mountains are again merely mountains"
zen_statement = "Mountains are again merely mountains"
else
case (@pass_count % 10)
zen_statement = case (@pass_count % 10)
when 0
puts "mountains are merely mountains"
"mountains are merely mountains"
when 1, 2
puts "learn the rules so you know how to break them properly"
"learn the rules so you know how to break them properly"
when 3, 4
puts "remember that silence is sometimes the best answer"
"remember that silence is sometimes the best answer"
when 5, 6
puts "sleep is the best meditation"
"sleep is the best meditation"
when 7, 8
puts "when you lose, don't lose the lesson"
"when you lose, don't lose the lesson"
else
puts "things are not what they appear to be: nor are they otherwise"
"things are not what they appear to be: nor are they otherwise"
end
end
zen_statement
end
end
end
class Koan
include Test::Unit::Assertions
@@ -138,7 +199,7 @@ module EdgeCase
def run_tests(accumulator)
puts
puts "Thinking #{self}"
puts Color.green("Thinking #{self}")
testmethods.each do |m|
self.run_test(m, accumulator) if Koan.test_pattern =~ m.to_s
end
@@ -149,12 +210,12 @@ module EdgeCase
test.setup
begin
test.send(method)
rescue StandardError => ex
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
test.failed(ex)
ensure
begin
test.teardown
rescue StandardError => ex
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
test.failed(ex) if test.passed?
end
end
@@ -177,7 +238,7 @@ module EdgeCase
load(arg)
else
fail "Unknown command line argument '#{arg}'"
end
end
end
end
end

View File

@@ -1,12 +1,16 @@
# The path to Ruby Enlightenment starts with the following:
$LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
require 'about_strings'
require 'about_regular_expressions'
require 'about_methods'
require 'about_constants'
require 'about_control_statements'
require 'about_true_and_false'
require 'about_triangle_project'