From 4b65b1f52d921bb8eb08aa07eb27bfe0e27d9cd4 Mon Sep 17 00:00:00 2001 From: Jonathan Lim Date: Wed, 28 Jan 2009 05:36:31 +0800 Subject: [PATCH 001/276] Fixing scores Signed-off-by: edgecase --- koans/about_scoring_project.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index 69aeae010..b5ac7fd3d 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -47,7 +47,7 @@ def test_score_of_a_single_roll_of_1_is_100 end def test_score_of_mulitple_1s_and_5s_is_the_sum - assert_equal 200, score([1,5,5,1]) + assert_equal 300, score([1,5,5,1]) end def test_score_of_single_2s_3s_4s_and_6s_are_zero @@ -67,7 +67,7 @@ def test_score_of_other_triples_is_100x end def test_score_of_mixed_is_sum - assert_equal 250, score([2,5,2,2,3]) + assert_equal 50, score([2,5,2,2,3]) assert_equal 550, score([5,5,5,5]) end From 9e799a71784e1112a048eb61b5a3acdf33418398 Mon Sep 17 00:00:00 2001 From: Jonathan Lim Date: Wed, 28 Jan 2009 06:46:11 +0800 Subject: [PATCH 002/276] Ensuring method names unique. Ensuring that later class method definitions don't mess with earlier tests. Renaming test to reflect that other objects are not affected by singleton methods on objects. Signed-off-by: edgecase --- koans/about_class_methods.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/koans/about_class_methods.rb b/koans/about_class_methods.rb index c3184032d..39ede9573 100644 --- a/koans/about_class_methods.rb +++ b/koans/about_class_methods.rb @@ -9,7 +9,7 @@ def test_objects_are_objects assert_equal __, fido.is_a?(Object) end - def test_classes_are_objects_too + def test_classes_are_classes assert_equal __, Dog.is_a?(Class) end @@ -34,7 +34,7 @@ def fido.wag assert_equal __, fido.wag end - def test_other_objects_are_affected_by_these_singleton_methods + def test_other_objects_are_not_affected_by_these_singleton_methods fido = Dog.new rover = Dog.new def fido.wag @@ -48,24 +48,24 @@ def fido.wag # ------------------------------------------------------------------ - def Dog.wag - :class_level_wag - end - - class Dog + class Dog2 def wag :instance_level_wag end end + def Dog2.wag + :class_level_wag + end + def test_since_classes_are_objects_you_can_define_singleton_methods_on_them_too - assert_equal __, Dog.a_class_method + assert_equal __, Dog2.wag end def test_class_methods_are_independent_of_instance_methods - fido = Dog.new + fido = Dog2.new assert_equal __, fido.wag - assert_equal __, Dog.wag + assert_equal __, Dog2.wag end # ------------------------------------------------------------------ From 77013b1afdabe9a4d5c6b7393d4342239dcb38f9 Mon Sep 17 00:00:00 2001 From: Caius Durling Date: Sat, 7 Feb 2009 02:13:34 +0000 Subject: [PATCH 003/276] Assigning a variable so the test passes when correct code is added. --- koans/about_message_passing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index d396c8034..9932e8fbd 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -72,7 +72,7 @@ class TypicalObject def test_sending_undefined_messages_to_a_typical_object_results_in_errors typical = TypicalObject.new - assert_raise(___) do + exception = assert_raise(___) do typical.foobar end assert_match(/foobar/, exception.message) From d8d1d4cc64a8d4620458f02782e7d7cd12abd96a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Mar 2009 21:38:05 -0400 Subject: [PATCH 004/276] Provided an alternative test_hash_keys_and_values function. Asserts on hash.keys or hash.values can not be relied on as the order is random (I had an expected values of [:two, :one] when I got to that test). --- koans/about_hashes.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 6208f3879..634323a90 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -38,10 +38,17 @@ def test_hash_is_unordered assert_equal hash1, hash2 end - def test_hash_keys_and_values + def test_hash_keys_and_values hash = { :one => "uno", :two => "dos" } - assert_equal __, hash.keys - assert_equal __, hash.values + + assert_equal __, hash.keys.size + assert_equal __, hash.has_key?(:one) + + # Why not just compare hash.keys to [:one, :two]? + # + # Clue: What was the name of the previous test again? + + assert_equal __, hash.values.sort end def test_combining_hashes From fcf5bd860dcc09180bfdc1cbbde674b33e636392 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Mar 2009 21:43:05 -0400 Subject: [PATCH 005/276] I renamed the class to AboutTriangleAssignment2 as this was messing with the testing order. Using the same class name as the other Triangle Assignment was affecting the testing order, causing this assignment to show up before about_exceptions. --- koans/about_triangle_project_2.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index f9e472815..a0f27166d 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.rb @@ -3,7 +3,7 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment < EdgeCase::Koan +class AboutTriangleAssignment2 < EdgeCase::Koan # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions From f9017915dcb1f9ce0a34403daff9b63e14400ee7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 17 Mar 2009 21:57:25 -0400 Subject: [PATCH 006/276] Cleanup of "cross method" test on the Bulldog, by removing the unfinished test and also Bulldog.growl method, which becomes obsolete. --- koans/about_inheritance.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/koans/about_inheritance.rb b/koans/about_inheritance.rb index 7bc3a1f99..01dde2c8e 100644 --- a/koans/about_inheritance.rb +++ b/koans/about_inheritance.rb @@ -60,10 +60,6 @@ class BullDog < Dog def bark super + ", GROWL" end - - def growl - super.bark + ", GROWL" - end end def test_subclasses_can_invoke_parent_behavior_via_super @@ -71,11 +67,6 @@ def test_subclasses_can_invoke_parent_behavior_via_super assert_equal __, ralph.bark end - def test_super_does_not_work_cross_method - ralph = BullDog.new("Ralph") - - end - # ------------------------------------------------------------------ class GreatDane < Dog From 17ac70bd4d46f9002543cfdc99b26584788e320f Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Thu, 8 Oct 2009 10:16:57 -0400 Subject: [PATCH 007/276] hash keys and values must assert against sorted arrays - thanks gregmalcolm --- koans/about_hashes.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 634323a90..e781896d4 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -38,16 +38,10 @@ def test_hash_is_unordered assert_equal hash1, hash2 end - def test_hash_keys_and_values + def test_hash_keys_and_values hash = { :one => "uno", :two => "dos" } - assert_equal __, hash.keys.size - assert_equal __, hash.has_key?(:one) - - # Why not just compare hash.keys to [:one, :two]? - # - # Clue: What was the name of the previous test again? - + assert_equal __, hash.keys.sort assert_equal __, hash.values.sort end From 41ef277f401bf04b96b68aaf27b053454f8a9769 Mon Sep 17 00:00:00 2001 From: capitalist Date: Tue, 10 Feb 2009 14:41:51 -0700 Subject: [PATCH 008/276] Fixed typo and faulty expectation. There are three twos = 200 and one five = 50 => so this should be 250 Also, here's my score method - I feel like I over complicated this: # def score(dice) # #count em up # results = dice.inject(Hash.new) {|h, die| h[die] = h[die] ? h[die] + 1 : 1; h } # # #convert to scores # score = results.keys.inject(0) do |s,k| # s += \ # case k # when 1 # results[k] >= 3 ? 1000 + (results[k]-3)*100 : results[k] * 100 # when 2..4,6 # results[k] >= 3 ? 100*k : 0 # when 5 # results[k] >= 3 ? 500 + (results[k]-3)*50 : results[k] * 50 # else # 0 # end # end # end --- koans/about_scoring_project.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index b5ac7fd3d..fcd4206f7 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -25,7 +25,7 @@ # score([3,4,5,3,3]) => 350 points # score([1,5,1,2,4]) => 250 points # -# More scoing examples are given in the tests below: +# More scoring examples are given in the tests below: # # Your goal is to write the score method. @@ -67,7 +67,7 @@ def test_score_of_other_triples_is_100x end def test_score_of_mixed_is_sum - assert_equal 50, score([2,5,2,2,3]) + assert_equal 250, score([2,5,2,2,3]) assert_equal 550, score([5,5,5,5]) end From e871052dd35d1b8b443941c93baebae24d0d77c3 Mon Sep 17 00:00:00 2001 From: capitalist Date: Tue, 10 Feb 2009 12:35:10 -0700 Subject: [PATCH 009/276] Fix typo --- koans/about_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_methods.rb b/koans/about_methods.rb index 187ad27dd..34d93fbbe 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -72,7 +72,7 @@ def test_calling_with_variable_arguments def method_with_explicit_return :a_non_return_value return :return_value - :anoher_non_return_value + :another_non_return_value end def test_method_with_explicit_return From dbaadf80b76bb242ce0446b7e8fb52ec56b9b83a Mon Sep 17 00:00:00 2001 From: Robert Osborne Date: Tue, 30 Jun 2009 22:21:26 -0400 Subject: [PATCH 010/276] Edited GREED_RULES --- koans/GREED_RULES.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/koans/GREED_RULES.txt b/koans/GREED_RULES.txt index f120604d5..bf237c0e1 100644 --- a/koans/GREED_RULES.txt +++ b/koans/GREED_RULES.txt @@ -1,12 +1,12 @@ = Playing Greed -Greed is a dice game played amoung 2 or more players, using 5 +Greed is a dice game played among 2 or more players, using 5 six-sided dice. == Playing Greed Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all six dice which are +On the first roll of the game, a player rolls all five dice which are scored according to the following: Three 1's => 1000 points @@ -37,7 +37,7 @@ final example. After a player rolls and the score is calculated, the scoring dice are removed and the player has the option of rolling again using only the -non-scoring dice. If there all no non-scoring dice), then the player +non-scoring dice. If all of the dice are scoring, then the player may roll all 5 dice in the next roll. The player may continue to roll as long as each roll scores points. If From b3226809ad89f1a4a87d5d19847b2dc6654dc9ca Mon Sep 17 00:00:00 2001 From: Robert Osborne Date: Mon, 29 Jun 2009 21:08:36 -0400 Subject: [PATCH 011/276] method name test_if_then_else_statements was duplicated, overwriting the first def. --- koans/about_control_statements.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index d2b75ad08..8ecf88ee2 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -11,7 +11,7 @@ def test_if_then_else_statements assert_equal __, result end - def test_if_then_else_statements + def test_if_then_statements result = :default_value if true result = :true_value From e225b1612c6813bb7f989083c67f31a30d0c9364 Mon Sep 17 00:00:00 2001 From: Robert Osborne Date: Sun, 28 Jun 2009 20:11:51 -0400 Subject: [PATCH 012/276] fixed typoo in def test_any_ruby_expression_my_be_interpolated --- koans/about_strings.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index db3289aad..48190dd7b 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -128,7 +128,7 @@ def test_single_quoted_strings_do_not_interpolate assert_equal __, string end - def test_any_ruby_expression_my_be_interpolated + def test_any_ruby_expression_may_be_interpolated string = "The square root of 5 is #{Math.sqrt(5)}" assert_equal __, string end From 73805b3e0e947abb407da40efab0daf9c4e187dd Mon Sep 17 00:00:00 2001 From: Robert Osborne Date: Sat, 27 Jun 2009 19:21:02 -0400 Subject: [PATCH 013/276] re-wrote a bit of explanation of red/green/refactor --- README.rdoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rdoc b/README.rdoc index 5fafe07dc..b85cebfd1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -59,8 +59,9 @@ Windows is the same thing 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 (refactor), make the test pass (green), then take a -moment and reflect upon the test to see what it is teaching you. +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). The very first time you run it you will see the following output: From 8de356c59897e34f020269f5614cdbecae3e093e Mon Sep 17 00:00:00 2001 From: RFelix Date: Sat, 22 Aug 2009 12:57:10 +0100 Subject: [PATCH 014/276] Removed duplicated array assignment tests from about_arrays.rb which are also in about_array_assignment.rb --- koans/about_arrays.rb | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb index 5fd016af5..998f7d90f 100644 --- a/koans/about_arrays.rb +++ b/koans/about_arrays.rb @@ -80,22 +80,4 @@ def test_shifting_arrays assert_equal __, array end - def test_parallel_assignments - first_name, last_name = ["John", "Smith"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_extra_values - first_name, last_name = ["John", "Smith", "III"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_extra_variables - first_name, last_name = ["Cher"] - assert_equal __, first_name - assert_equal __, last_name - end - end From 420013399e54ba4f8c608db88e288c9a98cf1d88 Mon Sep 17 00:00:00 2001 From: Corey Haines Date: Wed, 7 Oct 2009 13:47:15 -0500 Subject: [PATCH 015/276] fix url for tryruby --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index b85cebfd1..d24bfe60a 100644 --- a/README.rdoc +++ b/README.rdoc @@ -118,7 +118,7 @@ Meta Koans :: http://rubyquiz.com/quiz67.html == Other Resources The Ruby Language :: http://ruby-lang.org -Try Ruby in your browser :: http://tryruby.hobix.com/ +Try Ruby in your browser :: http://tryruby.sophrinix.com Dave Thomas' introduction to Ruby Programming Ruby (the Pick Axe) :: http://pragprog.com/titles/ruby/programming-ruby From 9563a4ef27fac483e9ded5a303773066d843fd42 Mon Sep 17 00:00:00 2001 From: Ken Barker Date: Fri, 9 Oct 2009 18:06:47 -0400 Subject: [PATCH 016/276] Add preceding bang to make first test fail Seems in-line with the other koans at this point to require the student remove the bang. --- koans/about_nil.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/koans/about_nil.rb b/koans/about_nil.rb index b007cc0c2..d9853e98e 100644 --- a/koans/about_nil.rb +++ b/koans/about_nil.rb @@ -2,7 +2,10 @@ class AboutNil < EdgeCase::Koan def test_nil_is_an_object - assert nil.is_a?(Object), "Unlike NULL in other languages" + # + # Hint: '!'s negate the response from what follows. + # + assert !nil.is_a?(Object), "Unlike NULL in other languages" end def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil From f3af22b96f0a1fa3a467b251f1478c932d43620a Mon Sep 17 00:00:00 2001 From: Bret Pettichord Date: Mon, 12 Oct 2009 23:46:33 -0500 Subject: [PATCH 017/276] rename file to match the name of its Koan class --- koans/{about_basics.rb => about_asserts.rb} | 0 koans/path_to_enlightenment.rb | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename koans/{about_basics.rb => about_asserts.rb} (100%) diff --git a/koans/about_basics.rb b/koans/about_asserts.rb similarity index 100% rename from koans/about_basics.rb rename to koans/about_asserts.rb diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index f8e323f95..79daa7955 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -1,6 +1,6 @@ # The path to Ruby Enlightenment starts with the following: -require 'about_basics' +require 'about_asserts' require 'about_nil' require 'about_arrays' require 'about_array_assignment' From 47c6c6f8dae1a7b6fd8987c34f2545d940c9b3a5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 15:03:20 -0500 Subject: [PATCH 018/276] Added src directory --- src/GREED_RULES.txt | 66 +++++++++ src/README | 38 ++++++ src/Rakefile | 12 ++ src/about_array_assignment.rb | 38 ++++++ src/about_arrays.rb | 85 ++++++++++++ src/about_asserts.rb | 40 ++++++ src/about_blocks.rb | 96 +++++++++++++ src/about_class_methods.rb | 167 +++++++++++++++++++++++ src/about_classes.rb | 190 ++++++++++++++++++++++++++ src/about_control_statements.rb | 116 ++++++++++++++++ src/about_dice_project.rb | 64 +++++++++ src/about_exceptions.rb | 60 +++++++++ src/about_extra_credit.rb | 8 ++ src/about_hashes.rb | 66 +++++++++ src/about_inheritance.rb | 85 ++++++++++++ src/about_iteration.rb | 93 +++++++++++++ src/about_message_passing.rb | 167 +++++++++++++++++++++++ src/about_methods.rb | 157 ++++++++++++++++++++++ src/about_modules.rb | 63 +++++++++ src/about_nil.rb | 38 ++++++ src/about_open_classes.rb | 45 +++++++ src/about_proxy_object_project.rb | 173 ++++++++++++++++++++++++ src/about_sandwich_code.rb | 113 ++++++++++++++++ src/about_scope.rb | 79 +++++++++++ src/about_scoring_project.rb | 95 +++++++++++++ src/about_strings.rb | 176 ++++++++++++++++++++++++ src/about_triangle_project.rb | 25 ++++ src/about_triangle_project_2.rb | 15 +++ src/about_true_and_false.rb | 33 +++++ src/array_test.rb | 47 +++++++ src/code_mash.rb | 1 + src/dist/rubykoans.tgz | Bin 0 -> 45 bytes src/edgecase.rb | 216 ++++++++++++++++++++++++++++++ src/example_file.txt | 4 + src/first_test.rb | 11 ++ src/path_to_enlightenment.rb | 28 ++++ src/test_helper.rb | 7 + src/triangle.rb | 28 ++++ 38 files changed, 2745 insertions(+) create mode 100644 src/GREED_RULES.txt create mode 100644 src/README create mode 100644 src/Rakefile create mode 100644 src/about_array_assignment.rb create mode 100644 src/about_arrays.rb create mode 100644 src/about_asserts.rb create mode 100644 src/about_blocks.rb create mode 100644 src/about_class_methods.rb create mode 100644 src/about_classes.rb create mode 100644 src/about_control_statements.rb create mode 100644 src/about_dice_project.rb create mode 100644 src/about_exceptions.rb create mode 100644 src/about_extra_credit.rb create mode 100644 src/about_hashes.rb create mode 100644 src/about_inheritance.rb create mode 100644 src/about_iteration.rb create mode 100644 src/about_message_passing.rb create mode 100644 src/about_methods.rb create mode 100644 src/about_modules.rb create mode 100644 src/about_nil.rb create mode 100644 src/about_open_classes.rb create mode 100644 src/about_proxy_object_project.rb create mode 100644 src/about_sandwich_code.rb create mode 100644 src/about_scope.rb create mode 100644 src/about_scoring_project.rb create mode 100644 src/about_strings.rb create mode 100644 src/about_triangle_project.rb create mode 100644 src/about_triangle_project_2.rb create mode 100644 src/about_true_and_false.rb create mode 100644 src/array_test.rb create mode 100644 src/code_mash.rb create mode 100644 src/dist/rubykoans.tgz create mode 100644 src/edgecase.rb create mode 100644 src/example_file.txt create mode 100644 src/first_test.rb create mode 100644 src/path_to_enlightenment.rb create mode 100644 src/test_helper.rb create mode 100644 src/triangle.rb diff --git a/src/GREED_RULES.txt b/src/GREED_RULES.txt new file mode 100644 index 000000000..f120604d5 --- /dev/null +++ b/src/GREED_RULES.txt @@ -0,0 +1,66 @@ += Playing Greed + +Greed is a dice game played amoung 2 or more players, using 5 +six-sided dice. + +== Playing Greed + +Each player takes a turn consisting of one or more rolls of the dice. +On the first roll of the game, a player rolls all six dice which are +scored according to the following: + + Three 1's => 1000 points + Three 6's => 600 points + Three 5's => 500 points + Three 4's => 400 points + Three 3's => 300 points + Three 2's => 200 points + One 1 => 100 points + One 5 => 50 points + +A single die can only be counted once in each roll. For example, +a "5" can only count as part of a triplet (contributing to the 500 +points) or as a single 50 points, but not both in the same roll. + +Example Scoring + + Throw Score + --------- ------------------ + 5 1 3 4 1 50 + 2 * 100 = 250 + 1 1 1 3 1 1000 + 100 = 1100 + 2 4 4 5 4 400 + 50 = 450 + +The dice not contributing to the score are called the non-scoring +dice. "3" and "4" are non-scoring dice in the first example. "3" is +a non-scoring die in the second, and "2" is a non-score die in the +final example. + +After a player rolls and the score is calculated, the scoring dice are +removed and the player has the option of rolling again using only the +non-scoring dice. If there all no non-scoring dice), then the player +may roll all 5 dice in the next roll. + +The player may continue to roll as long as each roll scores points. If +a roll has zero points, then the player loses not only their turn, but +also accumulated score for that turn. If a player decides to stop +rolling before rolling a zero-point roll, then the accumulated points +for the turn is added to his total score. + +== Getting "In The Game" + +Before a player is allowed to accumulate points, they must get at +least 300 points in a single turn. Once they have achieved 300 points +in a single turn, the points earned in that turn and each following +turn will be counted toward their total score. + +== End Game + +Once a player reaches 3000 (or more) points, the game enters the final +round where each of the other players gets one more turn. The winner +is the player with the highest score after the final round. + +== References + +Greed is described on Wikipedia at +http://en.wikipedia.org/wiki/Greed_(dice_game), however the rules are +a bit different from the rules given here. diff --git a/src/README b/src/README new file mode 100644 index 000000000..3dbdc716b --- /dev/null +++ b/src/README @@ -0,0 +1,38 @@ += 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 +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. + +== 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. + +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. + + +== The Path To Enlightenment + +In order to achieve enlightenment you need to follow the path_to_enlightenment. This +can be done in two ways + +*nix platforms, from the koans directory + + [koans] $ rake # runs the default target :walk_the_path + [koans] $ ruby path_to_enlightenment.rb # simply call the file directly + +Windows is the same thing + + c:\dev\koans\rake # runs the default target :walk_the_path + c:\dev\koans\ruby path_to_enlightenment.rb # simply call the file directly + diff --git a/src/Rakefile b/src/Rakefile new file mode 100644 index 000000000..1a2c7f26d --- /dev/null +++ b/src/Rakefile @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# -*- ruby -*- + +require 'rake/clean' +require 'rake/testtask' + +task :default => :test + +task :test do + ruby 'path_to_enlightenment.rb' +end + diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb new file mode 100644 index 000000000..0e7e118b2 --- /dev/null +++ b/src/about_array_assignment.rb @@ -0,0 +1,38 @@ +require 'edgecase' + +class AboutArrayAssignment < EdgeCase::Koan + def test_non_parallel_assignment + names = ["John", "Smith"] + assert_equal __(["John", "Smith"]), names + end + + def test_parallel_assignments + first_name, last_name = ["John", "Smith"] + assert_equal __("John"), first_name + assert_equal __("Smith"), last_name + end + + def test_parallel_assignments_with_extra_values + first_name, last_name = ["John", "Smith", "III"] + assert_equal __("John"), first_name + assert_equal __("Smith"), last_name + end + + def test_parallel_assignments_with_extra_variables + first_name, last_name = ["Cher"] + assert_equal __("Cher"), first_name + assert_equal __(nil), last_name + end + + def test_parallel_assignements_with_subarrays + first_name, last_name = [["Willie", "Rae"], "Johnson"] + assert_equal __(["Willie", "Rae"]), first_name + assert_equal __("Johnson"), last_name + end + + def test_parallel_assignment_with_one_variable + first_name, = ["John", "Smith"] + assert_equal __("John"), first_name + end + +end diff --git a/src/about_arrays.rb b/src/about_arrays.rb new file mode 100644 index 000000000..4eba6a971 --- /dev/null +++ b/src/about_arrays.rb @@ -0,0 +1,85 @@ +require 'edgecase' + +class AboutArrays < EdgeCase::Koan + def test_creating_arrays + empty_array = Array.new + assert_equal Array, empty_array.class + assert_equal __(0), empty_array.size + end + + def test_array_literals + array = Array.new + assert_equal [], array + + array[0] = 1 + assert_equal [1], array + + array[1] = 2 + assert_equal [1, __(2)], array + + array << 333 + assert_equal __([1, 2, 333]), array + end + + def test_accessing_array_elements + array = [:peanut, :butter, :and, :jelly] + + assert_equal __(:peanut), array[0] + assert_equal __(:peanut), array.first + assert_equal __(:jelly), array[3] + assert_equal __(:jelly), array.last + assert_equal __(:jelly), array[-1] + assert_equal __(:butter), array[-3] + end + + def test_slicing_arrays + array = [:peanut, :butter, :and, :jelly] + + assert_equal __([:peanut]), array[0,1] + assert_equal __([:peanut, :butter]), array[0,2] + assert_equal __([:and, :jelly]), array[2,2] + assert_equal __([:and, :jelly]), array[2,20] + assert_equal __([]), array[4,0] + assert_equal __([]), array[4,100] + assert_equal __(nil), array[5,0] + assert_equal __(nil), array[5,0] + end + + def test_arrays_and_ranges + assert_equal Range, (1..5).class + assert_not_equal [1,2,3,4,5], (1..5) + assert_equal [1,2,3,4,5], (1..5).to_a + assert_equal __([1,2,3,4]), (1...5).to_a + end + + def test_slicing_with_ranges + array = [:peanut, :butter, :and, :jelly] + + assert_equal __([:peanut, :butter, :and]), array[0..2] + assert_equal __([:peanut, :butter]), array[0...2] + assert_equal ([:and, :jelly]), array[2..-1] + end + + def test_pushing_and_popping_arrays + array = [1,2] + array.push(:last) + + assert_equal __([1, 2, :last]), array + + popped_value = array.pop + assert_equal __(:last), popped_value + assert_equal __([1, 2]), array + end + + def test_shifting_arrays + array = [1,2] + array.unshift(:first) + + assert_equal __([:first, 1, 2]), array + + shifted_value = array.shift + assert_equal __(:first), shifted_value + assert_equal __([1, 2]), array + end + +end diff --git a/src/about_asserts.rb b/src/about_asserts.rb new file mode 100644 index 000000000..9388a95fb --- /dev/null +++ b/src/about_asserts.rb @@ -0,0 +1,40 @@ +#!/usr/bin/env ruby +# -*- ruby -*- + +require 'edgecase' + +class AboutAsserts < EdgeCase::Koan + + # We shall contemplate truth by testing reality, via asserts. + def test_assert_truth + assert __(true) # This should be true + end + + # Enlightenment may be more easily achieved with appropriate + # messages. + def test_assert_with_message + assert __(true), "This should be true -- Please fix this" + end + + # To understand reality, we must compare our expectations against + # reality. + def test_assert_equality + expected_value = __(2) + actual_value = 1 + 1 + + assert expected_value == actual_value + end + + # Some ways of asserting equality are better than others. + def test_a_better_way_of_asserting_equality + expected_value = __(2) + actual_value = 1 + 1 + + assert_equal expected_value, actual_value + end + + # Sometimes we will ask you to fill in the values + def test_fill_in_values + assert_equal __(2), 1 + 1 + end +end diff --git a/src/about_blocks.rb b/src/about_blocks.rb new file mode 100644 index 000000000..c764af920 --- /dev/null +++ b/src/about_blocks.rb @@ -0,0 +1,96 @@ +require 'edgecase' + +class AboutBlocks < EdgeCase::Koan + def method_with_block + result = yield + result + end + + def test_methods_can_take_blocks + yielded_result = method_with_block { 1 + 2 } + assert_equal __(3), yielded_result + end + + def test_blocks_can_be_defined_with_do_end_too + yielded_result = method_with_block do 1 + 2 end + assert_equal __(3), yielded_result + end + + # ------------------------------------------------------------------ + + def method_with_block_arguments + yield("Jim") + end + + def test_blocks_can_take_arguments + result = method_with_block_arguments do |argument| + assert_equal __("Jim"), argument + end + end + + # ------------------------------------------------------------------ + + def many_yields + yield(:peanut) + yield(:butter) + yield(:and) + yield(:jelly) + end + + def test_methods_can_call_yield_many_times + result = [] + many_yields { |item| result << item } + assert_equal __([:peanut, :butter, :and, :jelly]), result + end + + # ------------------------------------------------------------------ + + def yield_tester + if block_given? + yield + else + :no_block + end + end + + def test_methods_can_see_if_they_have_been_called_with_a_block + assert_equal __(:with_block), yield_tester { :with_block } + assert_equal __(:no_block), yield_tester + end + + # ------------------------------------------------------------------ + + def test_block_can_effect_variables_in_the_code_where_they_are_created + value = :initial_value + method_with_block { value = :modified_in_a_block } + assert_equal __(:modified_in_a_block), value + end + + def test_blocks_can_be_assigned_to_variables_and_called_explicitly + add_one = lambda { |n| n + 1 } + assert_equal __(11), add_one.call(10) + + # Alternative calling sequence + assert_equal __(11), add_one[10] + end + + def test_stand_alone_blocks_can_be_passed_to_methods_expecting_blocks + make_upper = lambda { |n| n.upcase } + result = method_with_block_arguments(&make_upper) + assert_equal __("JIM"), result + end + + # ------------------------------------------------------------------ + + def method_with_explict_block(&block) + block.call(10) + end + + def test_methods_can_take_an_explicit_block_argument + assert_equal __(20), method_with_explict_block { |n| n * 2 } + + add_one = lambda { |n| n + 1 } + assert_equal __(11), method_with_explict_block(&add_one) + end + +end diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb new file mode 100644 index 000000000..9788ad4fc --- /dev/null +++ b/src/about_class_methods.rb @@ -0,0 +1,167 @@ +require 'edgecase' + +class AboutClassMethods < EdgeCase::Koan + class Dog + end + + def test_objects_are_objects + fido = Dog.new + assert_equal __(true), fido.is_a?(Object) + end + + def test_classes_are_classes + assert_equal __(true), Dog.is_a?(Class) + end + + def test_classes_are_objects_too + assert_equal __(true), Dog.is_a?(Object) + end + + def test_objects_have_methods + fido = Dog.new + assert_equal __(45), fido.methods.size + end + + def test_classes_have_methods + assert_equal __(80), Dog.methods.size + end + + def test_you_can_define_methods_on_individual_objects + fido = Dog.new + def fido.wag + :fidos_wag + end + assert_equal __(:fidos_wag), fido.wag + end + + def test_other_objects_are_unaffected_by_these_singleton_methods + fido = Dog.new + rover = Dog.new + + assert_raise(___(NoMethodError)) do + rover.wag + end + end + + # ------------------------------------------------------------------ + + def Dog.bark + :class_level_bark + end + + class Dog + def bark + :instance_level_bark + end + end + + def test_since_classes_are_objects_you_can_define_singleton_methods_on_them_too + assert_equal __(:class_level_bark), Dog.bark + end + + def test_class_methods_are_independent_of_instance_methods + fido = Dog.new + assert_equal __(:instance_level_bark), fido.bark + assert_equal __(:class_level_bark), Dog.bark + end + + # ------------------------------------------------------------------ + + class Dog + attr_accessor :name + end + + def Dog.name + @name + end + + def test_classes_and_instances_do_not_share_instance_variables + fido = Dog.new + fido.name = "Fido" + assert_equal __("Fido"), fido.name + assert_equal __(nil), Dog.name + end + + # ------------------------------------------------------------------ + + class Dog + def Dog.a_class_method + :dogs_class_method + end + end + + def test_you_can_define_class_methods_inside_the_class + assert_equal __(:dogs_class_method), Dog.a_class_method + end + + + # ------------------------------------------------------------------ + + LastExpressionInClassStatement = class Dog + 21 + end + + def test_class_statements_return_the_value_of_their_last_expression + assert_equal __(21), LastExpressionInClassStatement + end + + # ------------------------------------------------------------------ + + SelfInsideOfClassStatement = class Dog + self + end + + def test_self_while_inside_class_is_class_object_not_instance + assert_equal __(true), Dog == SelfInsideOfClassStatement + end + + # ------------------------------------------------------------------ + + class Dog + def self.class_method2 + :another_way_to_write_class_methods + end + end + + def test_you_can_use_self_instead_of_an_explicit_reference_to_dog + assert_equal __(:another_way_to_write_class_methods), Dog.class_method2 + end + + # ------------------------------------------------------------------ + + class Dog + class << self + def another_class_method + :still_another_way + end + end + end + + def test_heres_still_another_way_to_write_class_methods + assert_equal __(:still_another_way), Dog.another_class_method + end + + # THINK ABOUT IT: + # + # The two major ways to write class methods are: + # class Demo + # def self.method + # end + # + # class << self + # def class_methods + # end + # end + # end + # + # Which do you prefer and why? + # Are there times you might prefer the other way? + + # ------------------------------------------------------------------ + + def test_heres_an_easy_way_to_call_class_methods_from_instance_methods + fido = Dog.new + assert_equal __(:still_another_way), fido.class.another_class_method + end + +end diff --git a/src/about_classes.rb b/src/about_classes.rb new file mode 100644 index 000000000..11f253939 --- /dev/null +++ b/src/about_classes.rb @@ -0,0 +1,190 @@ +require 'edgecase' + +class AboutClasses < EdgeCase::Koan + class Dog + end + + def test_instances_of_classes_can_be_created_with_new + fido = Dog.new + assert_equal __(Dog), fido.class + end + + # ------------------------------------------------------------------ + + class Dog2 + def set_name(a_name) + @name = a_name + end + end + + def test_instance_variables_can_be_set_by_assigning_to_them + fido = Dog2.new + assert_equal __([]), fido.instance_variables + + fido.set_name("Fido") + assert_equal __(["@name"]), fido.instance_variables + end + + def test_instance_variables_cannot_be_accessed_outside_the_class + fido = Dog2.new + fido.set_name("Fido") + + assert_raise(___(NoMethodError)) do + fido.name + end + + assert_raise(___(SyntaxError)) do + eval "fido.@name" + # NOTE: Using eval because the above line is a syntax error. + end + end + + def test_you_can_politely_ask_for_instance_variable_values + fido = Dog2.new + fido.set_name("Fido") + + assert_equal __("Fido"), fido.instance_variable_get("@name") + end + + def test_you_can_rip_the_value_out_using_instance_eval + fido = Dog2.new + fido.set_name("Fido") + + assert_equal __("Fido"), fido.instance_eval("@name") # string version + assert_equal __("Fido"), fido.instance_eval { @name } # block version + end + + # ------------------------------------------------------------------ + + class Dog3 + def set_name(a_name) + @name = a_name + end + def name + @name + end + end + + def test_you_can_create_accessor_methods_to_return_instance_variables + fido = Dog3.new + fido.set_name("Fido") + + assert_equal __("Fido"), fido.name + end + + # ------------------------------------------------------------------ + + class Dog4 + attr_reader :name + + def set_name(a_name) + @name = a_name + end + end + + + def test_attr_reader_will_automatically_define_an_accessor + fido = Dog4.new + fido.set_name("Fido") + + assert_equal __("Fido"), fido.name + end + + # ------------------------------------------------------------------ + + class Dog5 + attr_accessor :name + end + + + def test_attr_accessor_will_automatically_define_both_read_and_write_accessors + fido = Dog5.new + + fido.name = "Fido" + assert_equal __("Fido"), fido.name + end + + # ------------------------------------------------------------------ + + class Dog6 + attr_reader :name + def initialize(initial_name) + @name = initial_name + end + end + + def test_initialize_provides_initial_values_for_instance_variables + fido = Dog6.new("Fido") + assert_equal __("Fido"), fido.name + end + + def test_args_to_new_must_match_initialize + assert_raise(___(ArgumentError)) do + Dog6.new + end + # THINK ABOUT IT: + # Why is this so? + end + + def test_different_objects_have_difference_instance_variables + fido = Dog6.new("Fido") + rover = Dog6.new("Rover") + + assert_not_equal rover.name, fido.name + end + + # ------------------------------------------------------------------ + + class Dog7 + attr_reader :name + + def initialize(initial_name) + @name = initial_name + end + + def get_self + self + end + + def to_s + __(@name) + end + + def inspect + "" + end + end + + def test_inside_a_method_self_refers_to_the_containing_object + fido = Dog7.new("Fido") + + fidos_self = fido.get_self + assert_equal __(fido), fidos_self + end + + def test_to_s_provides_a_string_version_of_the_object + fido = Dog7.new("Fido") + assert_equal "Fido", fido.to_s + end + + def test_to_s_is_used_in_string_interpolation + fido = Dog7.new("Fido") + assert_equal "My dog is Fido", "My dog is #{fido}" + end + + def test_inspect_provides_a_more_complete_string_version + fido = Dog7.new("Fido") + assert_equal __(""), fido.inspect + end + + def test_all_objects_support_to_s_and_inspect + array = [1,2,3] + + assert_equal __("123"), array.to_s + assert_equal __("[1, 2, 3]"), array.inspect + + assert_equal __("STRING"), "STRING".to_s + assert_equal __('"STRING"'), "STRING".inspect + end + +end diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb new file mode 100644 index 000000000..f470a8c5f --- /dev/null +++ b/src/about_control_statements.rb @@ -0,0 +1,116 @@ +require 'edgecase' + +class AboutControlStatements < EdgeCase::Koan + + def test_if_then_else_statements + if true + result = :true_value + else + result = :false_value + end + assert_equal __, result + end + + def test_if_then_else_statements + result = :default_value + if true + result = :true_value + end + assert_equal __(:true_value), result + end + + def test_if_statements_return_values + value = if true + :true_value + else + :false_value + end + assert_equal __(:true_value), value + + value = if false + :true_value + else + :false_value + end + assert_equal __(:false_value), value + + # NOTE: Actually, EVERY statement in Ruby will return a value, not + # just if statements. + end + + def test_if_statements_with_no_else_with_false_condition_return_value + value = if false + :true_value + end + assert_equal __(nil), value + end + + def test_condition_operators + assert_equal __(:true_value), (true ? :true_value : :false_value) + assert_equal __(:false_value), (false ? :true_value : :false_value) + end + + def test_if_statement_modifiers + result = :default_value + result = :true_value if true + + assert_equal __(:true_value), result + end + + def test_unless_statement + result = :default_value + unless false + result = :false_value + end + assert_equal __(:false_value), result + end + + def test_unless_statement_modifier + result = :default_value + result = :false_value unless false + + assert_equal __(:false_value), result + end + + def test_while_statement + i = 1 + result = 1 + while i <= 10 + result = result * i + i += 1 + end + assert_equal __(3628800), result + end + + def test_break_statement + i = 1 + result = 1 + while true + break unless i <= 10 + result = result * i + i += 1 + end + assert_equal __(3628800), result + end + + def test_next_statement + i = 0 + result = [] + while i < 10 + i += 1 + next if (i % 2) == 0 + result << i + end + assert_equal __([1, 3, 5, 7, 9]), result + end + + def test_for_statement + array = ["fish", "and", "chips"] + result = [] + for item in array + result << item.upcase + end + assert_equal [__("FISH"), __("AND"), __("CHIPS")], result + end + +end diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb new file mode 100644 index 000000000..c1fccb14c --- /dev/null +++ b/src/about_dice_project.rb @@ -0,0 +1,64 @@ +require 'edgecase' + +class DiceSet + attr_reader :values + def roll(n) + @values = (1..n).map { rand(6) + 1 } + end +end + +class AboutDiceSet < EdgeCase::Koan + def test_can_create_a_dice_set + dice = DiceSet.new + assert_not_nil dice + end + + def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6 + dice = DiceSet.new + + dice.roll(5) + assert dice.values.is_a?(Array), "should be an array" + assert_equal 5, dice.values.size + dice.values.each do |value| + assert value >= 1 && value <= 6, "value #{value} must be between 1 and 6" + end + end + + def test_dice_values_do_not_change_unless_explicitly_rolled + dice = DiceSet.new + dice.roll(5) + first_time = dice.values + second_time = dice.values + assert_equal first_time, second_time + end + + def test_dice_values_should_change_between_rolls + dice = DiceSet.new + + dice.roll(5) + first_time = dice.values + + dice.roll(5) + second_time = dice.values + + assert_not_equal first_time, second_time, + "Two rolls should not be equal" + + # THINK ABOUT IT: + # + # If the rolls are random, then it is possible (although not + # likely) that two consecutive rolls are equal. What would be a + # better way to test this. + end + + def test_you_can_roll_different_numbers_of_dice + dice = DiceSet.new + + dice.roll(3) + assert_equal 3, dice.values.size + + dice.roll(1) + assert_equal 1, dice.values.size + end + +end diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb new file mode 100644 index 000000000..936e00eda --- /dev/null +++ b/src/about_exceptions.rb @@ -0,0 +1,60 @@ +require 'edgecase' + +class AboutExceptions < EdgeCase::Koan + + class MySpecialError < RuntimeError + end + + def test_exceptions_inherit_from_Exception + assert_equal __(RuntimeError), MySpecialError.ancestors[1] + assert_equal __(StandardError), MySpecialError.ancestors[2] + assert_equal __(Exception), MySpecialError.ancestors[3] + assert_equal __(Object), MySpecialError.ancestors[4] + end + + def test_rescue_clause + result = nil + begin + fail "Oops" + rescue StandardError => ex + result = :exception_handled + end + + assert_equal __(:exception_handled), result + + assert ex.is_a?(StandardError), "Failure message." + assert ex.is_a?(RuntimeError), "Failure message." + + assert RuntimeError.ancestors.include?(StandardError), + "RuntimeError is a subclass of StandardError" + + assert_equal __("Oops"), ex.message + end + + def test_raising_a_particular_error + result = nil + begin + # 'raise' and 'fail' are synonyms + raise MySpecialError, "My Message" + rescue MySpecialError => ex + result = :exception_handled + end + + assert_equal __(:exception_handled), result + assert_equal __("My Message"), ex.message + end + + def test_ensure_clause + result = nil + begin + fail "Oops" + rescue StandardError => ex + # no code here + ensure + result = :always_run + end + + assert_equal __(:always_run), result + end + +end diff --git a/src/about_extra_credit.rb b/src/about_extra_credit.rb new file mode 100644 index 000000000..5012edf8c --- /dev/null +++ b/src/about_extra_credit.rb @@ -0,0 +1,8 @@ +# EXTRA CREDIT: +# +# Create a program that will play the Greed Game. +# Rules for the game are in GREED_RULES.TXT. +# +# You already have a DiceSet class and score function you can use. +# Write a player class and a Game class to complete the project. This +# is a free form assignment, so approach it however you desire. diff --git a/src/about_hashes.rb b/src/about_hashes.rb new file mode 100644 index 000000000..6e42372ce --- /dev/null +++ b/src/about_hashes.rb @@ -0,0 +1,66 @@ +require 'edgecase' + +class AboutHashes < EdgeCase::Koan + def test_creating_hashes + empty_hash = Hash.new + assert_equal Hash, empty_hash.class + assert_equal({}, empty_hash) + assert_equal __(0), empty_hash.size + end + + def test_hash_literals + hash = { :one => "uno", :two => "dos" } + assert_equal __(2), hash.size + end + + def test_accessing_hashes + hash = { :one => "uno", :two => "dos" } + assert_equal __("uno"), hash[:one] + assert_equal __("dos"), hash[:two] + assert_equal __(nil), hash[:doesnt_exist] + end + + def test_changing_hashes + hash = { :one => "uno", :two => "dos" } + hash[:one] = "eins" + + expected = { :one => __("eins"), :two => "dos" } + assert_equal expected, hash + + # Bonus Question: Why was "expected" broken out into a variable + # rather than used as a literal? + end + + def test_hash_is_unordered + hash1 = { :one => "uno", :two => "dos" } + hash2 = { :two => "dos", :one => "uno" } + + assert_equal hash1, hash2 + end + + def test_hash_keys + hash = { :one => "uno", :two => "dos" } + assert_equal __(2), hash.keys.size + assert_equal __(true), hash.keys.include?(:one) + assert_equal __(true), hash.keys.include?(:two) + assert_equal Array, hash.keys.class + end + + def test_hash_values + hash = { :one => "uno", :two => "dos" } + assert_equal __(2), hash.keys.size + assert_equal __(true), hash.values.include?("uno") + assert_equal __(true), hash.values.include?("dos") + assert_equal Array, hash.values.class + end + + def test_combining_hashes + hash = { "jim" => 53, "amy" => 20, "dan" => 23 } + new_hash = hash.merge({ "jim" => 54, "jenny" => 26 }) + + assert_not_equal hash, new_hash + + expected = { "jim" => __(54), "amy" => 20, "dan" => 23, "jenny" => __(26) } + assert_equal expected, new_hash + end +end diff --git a/src/about_inheritance.rb b/src/about_inheritance.rb new file mode 100644 index 000000000..4f950da3c --- /dev/null +++ b/src/about_inheritance.rb @@ -0,0 +1,85 @@ +require 'edgecase' + +class AboutInheritance < EdgeCase::Koan + class Dog + attr_reader :name + + def initialize(name) + @name = name + end + + def bark + "WOOF" + end + end + + class Chihuahua < Dog + def wag + :happy + end + + def bark + "yip" + end + end + + def test_subclasses_have_the_parent_as_an_ancestor + assert_equal __(true), Chihuahua.ancestors.include?(Dog) + end + + def test_all_classes_ultimately_inherit_from_object + assert_equal __(true), Chihuahua.ancestors.include?(Object) + end + + def test_subcases_inherit_behavior_from_parent_class + chico = Chihuahua.new("Chico") + assert_equal __("Chico"), chico.name + end + + def test_subclasses_add_new_behavior + chico = Chihuahua.new("Chico") + assert_equal __(:happy), chico.wag + + assert_raise(___(NoMethodError)) do + fido = Dog.new("Fido") + fido.wag + end + end + + def test_subclasses_can_modify_existing_behavior + chico = Chihuahua.new("Chico") + assert_equal __("yip"), chico.bark + + fido = Dog.new("Fido") + assert_equal __("WOOF"), fido.bark + end + + # ------------------------------------------------------------------ + + class BullDog < Dog + def bark + super + ", GROWL" + end + end + + def test_subclasses_can_invoke_parent_behavior_via_super + ralph = BullDog.new("Ralph") + assert_equal __("WOOF, GROWL"), ralph.bark + end + + # ------------------------------------------------------------------ + + class GreatDane < Dog + def growl + super.bark + ", GROWL" + end + end + + def test_super_does_not_work_cross_method + george = GreatDane.new("George") + assert_raise(___(NoMethodError)) do + george.growl + end + end + +end diff --git a/src/about_iteration.rb b/src/about_iteration.rb new file mode 100644 index 000000000..ccdad0d7b --- /dev/null +++ b/src/about_iteration.rb @@ -0,0 +1,93 @@ +require 'edgecase' + +class AboutIteration < EdgeCase::Koan + + def test_each_is_a_method_on_arrays + [].methods.include?("each") + end + + def test_iterating_with_each + array = [1, 2, 3] + sum = 0 + array.each do |item| + sum += item + end + assert_equal 6, sum + end + + def test_each_can_use_curly_brace_blocks_too + array = [1, 2, 3] + sum = 0 + array.each { |item| + sum += item + } + assert_equal __(6), sum + end + + def test_break_works_with_each_style_iterations + array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sum = 0 + array.each { |item| + break if item > 3 + sum += item + } + assert_equal __(6), sum + end + + def test_collect_transforms_elements_of_an_array + array = [1, 2, 3] + new_array = array.collect { |item| item + 10 } + assert_equal __([11, 12, 13]), new_array + + # NOTE: 'map' is another name for the 'collect' operation + another_array = array.map { |item| item + 10 } + assert_equal __([11, 12, 13]), another_array + end + + def test_select_selects_certain_items_from_an_array + array = [1, 2, 3, 4, 5, 6] + + even_numbers = array.select { |item| (item % 2) == 0 } + assert_equal __([2, 4, 6]), even_numbers + + # NOTE: 'find_all' is another name for the 'select' operation + more_even_numbers = array.find_all { |item| (item % 2) == 0 } + assert_equal __([2, 4, 6]), more_even_numbers + end + + def test_find_locates_the_first_element_matching_a_criteria + array = ["Jim", "Bill", "Clarence", "Doug", "Eli"] + + assert_equal __("Clarence"), array.find { |item| item.size > 4 } + end + + def test_inject_will_blow_your_mind + result = [2, 3, 4].inject(0) { |sum, item| sum + item } + assert_equal __(9), result + + result2 = [2, 3, 4].inject(1) { |sum, item| sum * item } + assert_equal __(24), result2 + + # Extra Credit: + # Describe in your own words what inject does. + end + + def test_all_iteration_methods_work_on_any_collection_not_just_arrays + # Ranges act like a collection + result = (1..3).map { |item| item + 10 } + assert_equal __([11, 12, 13]), result + + # Files act like a collection of lines + file = File.open("example_file.txt") + upcase_lines = file.map { |line| line.strip.upcase } + assert_equal __(["THIS", "IS", "A", "TEST"]), upcase_lines + + # NOTE: You can create your own collections that work with each, + # map, select, etc. + ensure + # Arg, this is ugly. + # We will figure out how to fix this later. + file.close if file + end + +end diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb new file mode 100644 index 000000000..59e305674 --- /dev/null +++ b/src/about_message_passing.rb @@ -0,0 +1,167 @@ +require '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? + 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? + end + + def test_send_with_underscores_will_also_send_messages + mc = MessageCatcher.new + + assert_equal __(true), mc.__send__(:caught?) + + # THINK ABOUT IT: + # + # Why does Ruby provide both send and __send__ ? + end + + 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) + + assert_equal __([3, 4, nil, 6]), mc.add_a_payload(3, 4, nil, 6) + assert_equal __([3, 4, nil, 6]), mc.send(:add_a_payload, 3, 4, nil, 6) + end + + # ------------------------------------------------------------------ + + class TypicalObject + end + + def test_sending_undefined_messages_to_a_typical_object_results_in_errors + typical = TypicalObject.new + + exception = assert_raise(___(NoMethodError)) do + typical.foobar + end + assert_match(/foobar/, exception.message) + end + + def test_calling_method_missing_causes_the_no_method_error + typical = TypicalObject.new + + exception = assert_raise(___(NoMethodError)) do + typical.method_missing(:foobar) + end + assert_match(/foobar/, exception.message) + + # THINK ABOUT IT: + # + # If the method :method_missing causes the NoMethodError, then + # what would happen if we redefine method_missing? + end + + # ------------------------------------------------------------------ + + class AllMessageCatcher + def method_missing(method_name, *args, &block) + "Someone called #{method_name} with <#{args.join(", ")}>" + end + end + + def test_all_messages_are_caught + catcher = AllMessageCatcher.new + + assert_equal __("Someone called foobar with <>"), catcher.foobar + assert_equal __("Someone called foobaz with <1>"), catcher.foobaz(1) + assert_equal __("Someone called sum with <1, 2, 3, 4, 5, 6>"), catcher.sum(1,2,3,4,5,6) + end + + def test_catching_messages_makes_respond_to_lie + catcher = AllMessageCatcher.new + + assert_nothing_raised(NoMethodError) do + catcher.any_method + end + assert_equal __(false), catcher.respond_to?(:any_method) + end + + # ------------------------------------------------------------------ + + class WellBehavedFooCatcher + def method_missing(method_name, *args, &block) + if method_name.to_s[0,3] == "foo" + "Foo to you too" + else + super(method_name, *args, &block) + end + end + end + + def test_foo_method_are_caught + catcher = WellBehavedFooCatcher.new + + assert_equal __("Foo to you too"), catcher.foo_bar + assert_equal __("Foo to you too"), catcher.foo_baz + end + + def test_non_foo_messages_are_treated_normally + catcher = WellBehavedFooCatcher.new + + assert_raise(___(NoMethodError)) do + catcher.normal_undefined_method + end + end + + # ------------------------------------------------------------------ + + # (note: just reopening class from above) + class WellBehavedFooCatcher + def respond_to?(method_name) + if method_name.to_s[0,3] == "foo" + true + else + super(method_name) + end + end + end + + def test_explicitly_implementing_respond_to_lets_objects_tell_the_truth + catcher = WellBehavedFooCatcher.new + + assert_equal __(true), catcher.respond_to?(:foo_bar) + assert_equal __(false), catcher.respond_to?(:something_else) + end + +end diff --git a/src/about_methods.rb b/src/about_methods.rb new file mode 100644 index 000000000..b289cac51 --- /dev/null +++ b/src/about_methods.rb @@ -0,0 +1,157 @@ +require 'edgecase' + +def my_global_method(a,b) + a + b +end + +class AboutMethods < EdgeCase::Koan + + def test_calling_global_methods + assert_equal __(5), my_global_method(2,3) + end + + def test_calling_global_methods_without_parenthesis + 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 + #-- + eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK + if false + #++ + eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK + #-- + end + #++ + # + # Ruby doesn't know if you mean: + # + # assert_equal(5, my_global_method(2), 3) + # or + # assert_equal(5, my_global_method(2, 3)) + # + # Rewrite the eval string to continue. + # + end + + # NOTE: wrong number of argument is not a SYNTAX error, but a + # runtime error. + def test_calling_global_methods_with_wrong_number_of_arguments + exception = assert_raise(___(ArgumentError)) do + my_global_method + end + assert_match(/#{__("wrong number of arguments")}/, exception.message) + + exception = assert_raise(___(ArgumentError)) do + my_global_method(1,2,3) + end + assert_match(/#{__("wrong number of arguments")}/, exception.message) + end + + # ------------------------------------------------------------------ + + def method_with_defaults(a, b=:default_value) + [a, b] + end + + def test_calling_with_default_values + assert_equal [1, __(:default_value)], method_with_defaults(1) + assert_equal [1, __(2)], method_with_defaults(1, 2) + end + + # ------------------------------------------------------------------ + + def method_with_var_args(*args) + args + end + + def test_calling_with_variable_arguments + assert_equal __([]), method_with_var_args + assert_equal __([:one]), method_with_var_args(:one) + assert_equal __([:one, :two]), method_with_var_args(:one, :two) + end + + # ------------------------------------------------------------------ + + def method_with_explicit_return + :a_non_return_value + return :return_value + :anoher_non_return_value + end + + def test_method_with_explicit_return + assert_equal __(:return_value), method_with_explicit_return + end + + # ------------------------------------------------------------------ + + def method_without_explicit_return + :a_non_return_value + :return_value + end + + def test_method_without_explicit_return + assert_equal __(:return_value), method_without_explicit_return + end + + # ------------------------------------------------------------------ + + def my_same_class_method(a, b) + a * b + end + + def test_calling_methods_in_same_class + assert_equal __(12), my_same_class_method(3,4) + end + + def test_calling_methods_in_same_class_with_explicit_receiver + assert_equal __(12), self.my_same_class_method(3,4) + end + + # ------------------------------------------------------------------ + + def my_private_method + "a secret" + end + private :my_private_method + + def test_calling_private_methods_without_receiver + assert_equal __("a secret"), my_private_method + end + + def test_calling_private_methods_with_an_explicit_receiver + exception = assert_raise(___(NoMethodError)) do + self.my_private_method + end + assert_match /#{__("private method `my_private_method' called ")}/, exception.message + end + + # ------------------------------------------------------------------ + + class Dog + def name + "Fido" + end + + private + + def tail + "tail" + end + end + + def test_calling_methods_in_other_objects_require_explicit_receiver + rover = Dog.new + assert_equal __("Fido"), rover.name + end + + def test_calling_private_methods_in_other_objects + rover = Dog.new + assert_raise(___(NoMethodError)) do + rover.tail + end + end +end diff --git a/src/about_modules.rb b/src/about_modules.rb new file mode 100644 index 000000000..1e8558dd3 --- /dev/null +++ b/src/about_modules.rb @@ -0,0 +1,63 @@ +require 'edgecase' + +class AboutModules < EdgeCase::Koan + module Nameable + def set_name(new_name) + @name = new_name + end + + def here + :in_module + end + end + + def test_cant_instantiate_modules + assert_raise(___(NoMethodError)) do + Nameable.new + end + end + + # ------------------------------------------------------------------ + + class Dog + include Nameable + + attr_reader :name + + def initialize + @name = "Fido" + end + + def bark + "WOOF" + end + + def here + :in_object + end + end + + def test_normal_methods_are_available_in_the_object + fido = Dog.new + assert_equal __("WOOF"), fido.bark + end + + def test_module_methods_are_also_availble_in_the_object + fido = Dog.new + assert_nothing_raised(Exception) do + fido.set_name("Rover") + end + end + + def test_module_methods_can_affect_instance_variables_in_the_object + fido = Dog.new + assert_equal __("Fido"), fido.name + fido.set_name("Rover") + assert_equal __("Rover"), fido.name + end + + def test_classes_can_override_module_methods + fido = Dog.new + assert_equal __(:in_object), fido.here + end +end diff --git a/src/about_nil.rb b/src/about_nil.rb new file mode 100644 index 000000000..070e109e5 --- /dev/null +++ b/src/about_nil.rb @@ -0,0 +1,38 @@ +require 'edgecase' + +class AboutNil < EdgeCase::Koan + def test_nil_is_an_object + assert_equal __(true), nil.is_a?(Object), "Unlike NULL in other languages" + end + + def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil + # What happens when you call a method that doesn't exist. The + # following begin/rescue/end code block captures the exception and + # make some assertions about it. + begin + nil.some_method_nil_doesnt_know_about + rescue Exception => ex + # What exception has been caught? + assert_equal __(NoMethodError), ex.class + + # What message was attached to the exception? + # (HINT: replace __ with part of the error message.) + assert_match(/#{__("undefined method")}/, ex.message) + end + end + + def test_nil_has_a_few_methods_defined_on_it + assert_equal __(true), nil.nil? + assert_equal __(""), nil.to_s + assert_equal __("nil"), nil.inspect + + # THINK ABOUT IT: + # + # Is it better to use + # obj.nil? + # or + # obj == nil + # Why? + end + +end diff --git a/src/about_open_classes.rb b/src/about_open_classes.rb new file mode 100644 index 000000000..17a76007f --- /dev/null +++ b/src/about_open_classes.rb @@ -0,0 +1,45 @@ +require 'edgecase' + +class AboutOpenClasses < EdgeCase::Koan + class Dog + def bark + "WOOF" + end + end + + def test_as_defined_dogs_do_bark + fido = Dog.new + assert_equal __("WOOF"), fido.bark + end + + # ------------------------------------------------------------------ + + # Open the existing Dog class and add a new method. + class Dog + def wag + "HAPPY" + end + end + + def test_after_reopening_dogs_can_both_wag_and_bark + fido = Dog.new + assert_equal __("HAPPY"), fido.wag + assert_equal __("WOOF"), fido.bark + end + + # ------------------------------------------------------------------ + + class ::Integer + def even? + (self % 2) == 0 + end + end + + def test_even_existing_built_in_classes_can_be_reopened + assert_equal __(false), 1.even? + assert_equal __(true), 2.even? + end + + # NOTE: To understand why we need the :: before Integer, you need to + # become enlightened about scope. +end diff --git a/src/about_proxy_object_project.rb b/src/about_proxy_object_project.rb new file mode 100644 index 000000000..842356007 --- /dev/null +++ b/src/about_proxy_object_project.rb @@ -0,0 +1,173 @@ +require 'edgecase' + +# Project: Create a Proxy Class +# +# In this assignment, create a proxy class (one is started for you +# below). You should be able to initialize the proxy object with any +# object. Any messages sent to the proxy object should be forwarded +# to the target object. As each message is sent, the proxy should +# record the name of the method send. +# +# The proxy class is started for you. You will need to add a method +# missing handler and any other supporting methods. The specification +# of the Proxy class is given in the AboutProxyObjectProject koan. + +class Proxy + def initialize(target_object) + @object = target_object + # ADD MORE CODE HERE + #-- + @messages = [] + #++ + end + + # WRITE CODE HERE + #-- + attr_reader :messages + + def method_missing(sym, *args, &block) + @messages << sym + @object.send(sym, *args, &block) + end + + def called?(method) + @messages.include?(method) + end + + def number_of_times_called(method) + @messages.select { |m| m == method }.size + end + #++ +end + +# The proxy object should pass the following Koan: +# +class AboutProxyObjectProject < EdgeCase::Koan + def test_proxy_method_returns_wrapped_object + # NOTE: The Television class is defined below + tv = Proxy.new(Television.new) + + assert tv.instance_of?(Proxy) + end + + def test_tv_methods_still_perform_their_function + tv = Proxy.new(Television.new) + + tv.channel = 10 + tv.power + + assert_equal 10, tv.channel + assert tv.on? + end + + def test_proxy_records_messages_sent_to_tv + tv = Proxy.new(Television.new) + + tv.power + tv.channel = 10 + + assert_equal [:power, :channel=], tv.messages + end + + def test_proxy_handles_invalid_messages + tv = Proxy.new(Television.new) + + assert_raise(NoMethodError) do + tv.no_such_method + end + end + + def test_proxy_reports_methods_have_been_called + tv = Proxy.new(Television.new) + + tv.power + tv.power + + assert tv.called?(:power) + assert ! tv.called?(:channel) + end + + def test_proxy_counts_method_calls + tv = Proxy.new(Television.new) + + tv.power + tv.channel = 48 + tv.power + + assert_equal 2, tv.number_of_times_called(:power) + assert_equal 1, tv.number_of_times_called(:channel=) + assert_equal 0, tv.number_of_times_called(:on?) + end + + def test_proxy_can_record_more_than_just_tv_objects + proxy = Proxy.new("Code Mash 2009") + + proxy.upcase! + result = proxy.split + + assert_equal ["CODE", "MASH", "2009"], result + assert_equal [:upcase!, :split], proxy.messages + end +end + + +# ==================================================================== +# The following code is to support the testing of the Proxy class. No +# changes should be necessary to anything below this comment. + +# Example class using in the proxy testing above. +class Television + attr_accessor :channel + + def power + if @power == :on + @power = :off + else + @power = :on + end + end + + def on? + @power == :on + end +end + +# Tests for the Television class. All of theses tests should pass. +class TelevisionTest < EdgeCase::Koan + def test_it_turns_on + tv = Television.new + + tv.power + assert tv.on? + end + + def test_it_also_turns_off + tv = Television.new + + tv.power + tv.power + + assert ! tv.on? + end + + def test_edge_case_on_off + tv = Television.new + + tv.power + tv.power + tv.power + + assert tv.on? + + tv.power + + assert ! tv.on? + end + + def test_can_set_the_channel + tv = Television.new + + tv.channel = 11 + assert_equal 11, tv.channel + end +end diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb new file mode 100644 index 000000000..1bbed9351 --- /dev/null +++ b/src/about_sandwich_code.rb @@ -0,0 +1,113 @@ +require 'edgecase' + +class AboutUsingBlocks < EdgeCase::Koan + + def count_lines(file_name) + file = open(file_name) + count = 0 + while line = file.gets + count += 1 + end + count + ensure + file.close if file + end + + def test_counting_lines + assert_equal __(4), count_lines("example_file.txt") + end + + # ------------------------------------------------------------------ + + def find_line(file_name) + file = open(file_name) + while line = file.gets + return line if line.match(/e/) + end + ensure + file.close if file + end + + def test_finding_lines + assert_equal __("test\n"), find_line("example_file.txt") + end + + # ------------------------------------------------------------------ + # THINK ABOUT IT: + # + # The count_lines and find_line are similar, and yet different. + # They both follow the pattern of "sandwich code". + # + # Sandwich code is code that comes in three parts: (1) the top slice + # of bread, (2) the meat, and (3) the bottom slice of bread. The + # the bread part of the sandwich almost always goes together, but + # the meat part changes all the time. + # + # Because the changing part of the sandwich code is in the middle, + # abstracting the top and bottom bread slices to a library can be + # difficult in many languages. + # + # (Aside for C++ programmers: The idiom of capturing allocated + # pointers in a smart pointer constructor is an attempt to deal with + # the problem of sandwich code for resource allocation.) + # + # Consider the following code: + # + + def file_sandwich(file_name) + file = open(file_name) + yield(file) + ensure + file.close if file + end + + # Now we write: + + def count_lines2(file_name) + file_sandwich(file_name) do |file| + count = 0 + while line = file.gets + count += 1 + end + count + end + end + + def test_counting_lines2 + assert_equal __(4), count_lines2("example_file.txt") + end + + # ------------------------------------------------------------------ + + def find_line2(file_name) + # Rewrite find_line using the file_sandwich library function. + #-- + file_sandwich(file_name) do |file| + file.each do |line| + return line if line =~ /e/ + end + end + #++ + end + + def test_finding_lines2 + assert_equal __("test\n"), find_line2("example_file.txt") + end + + # ------------------------------------------------------------------ + + def count_lines3(file_name) + open(file_name) do |file| + count = 0 + while line = file.gets + count += 1 + end + count + end + end + + def test_open_handles_the_file_sandwich_when_given_a_block + assert_equal __(4), count_lines3("example_file.txt") + end + +end diff --git a/src/about_scope.rb b/src/about_scope.rb new file mode 100644 index 000000000..11352a082 --- /dev/null +++ b/src/about_scope.rb @@ -0,0 +1,79 @@ +require 'edgecase' + +class AboutScope < EdgeCase::Koan + module Jims + class Dog + def identify + :jims_dog + end + end + end + + module Joes + class Dog + def identify + :joes_dog + end + end + end + + def test_dog_is_not_available_in_the_current_scope + assert_raise(___(NameError)) do + fido = Dog.new + end + end + + def test_you_can_reference_nested_classes_using_the_scope_operator + fido = Jims::Dog.new + 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 + + # ------------------------------------------------------------------ + + class String + end + + 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 + + def test_use_the_prefix_scope_operator_to_force_the_global_scope + assert_equal __(true), ::String == "HI".class + end + + # ------------------------------------------------------------------ + + PI = 3.1416 + + def test_constants_are_defined_with_an_initial_uppercase_letter + assert_equal __(3.1416), PI + end + + # ------------------------------------------------------------------ + + MyString = ::String + + def test_class_names_are_just_constants + assert_equal __(true), MyString == ::String + assert_equal __(true), MyString == "HI".class + end + + def test_constants_can_be_looked_up_explicitly + assert_equal __(true), PI == AboutScope.const_get("PI") + assert_equal __(true), MyString == AboutScope.const_get("MyString") + end + + def test_you_can_get_a_list_of_constants_for_any_class_or_module + assert_equal __(["Dog"]), Jims.constants + assert_equal __(121), Object.constants.size + end +end diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb new file mode 100644 index 000000000..c58078678 --- /dev/null +++ b/src/about_scoring_project.rb @@ -0,0 +1,95 @@ +require '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 +# score of a single roll of the dice. +# +# A greed roll is scored as follows: +# +# * A set of three ones is 1000 points +# +# * A set of three numbers (other than ones) is worth 100 times the +# number. (e.g. three fives is 500 points). +# +# * A one (that is not part of a set of three) is worth 100 points. +# +# * A five (that is not part of a set of three) is worth 50 points. +# +# * Everything else is worth 0 points. +# +# +# Examples: +# +# score([1,1,1,5,1]) => 1150 points +# score([2,3,4,6,2]) => 0 points +# score([3,4,5,3,3]) => 350 points +# score([1,5,1,2,4]) => 250 points +# +# More scoing examples are given in the tests below: +# +# Your goal is to write the score method. + +def score(dice) + # You need to write this method + #-- + result = 0 + (1..6).each do |face| + count = dice.select { |n| n == face }.size + while count > 0 + if count >= 3 + result += (face == 1) ? 1000 : 100 * face + count -= 3 + elsif face == 5 + result += count * 50 + count = 0 + elsif face == 1 + result += count * 100 + count = 0 + else + count = 0 + end + end + end + result + #++ +end + +class AboutScoringAssignment < EdgeCase::Koan + def test_score_of_an_empty_list_is_zero + assert_equal 0, score([]) + end + + def test_score_of_a_single_roll_of_5_is_50 + assert_equal 50, score([5]) + end + + def test_score_of_a_single_roll_of_1_is_100 + assert_equal 100, score([1]) + end + + def test_score_of_mulitple_1s_and_5s_is_the_sum + assert_equal 300, score([1,5,5,1]) + end + + def test_score_of_single_2s_3s_4s_and_6s_are_zero + assert_equal 0, score([2,3,4,6]) + end + + def test_score_of_a_triple_1_is_1000 + assert_equal 1000, score([1,1,1]) + end + + def test_score_of_other_triples_is_100x + assert_equal 200, score([2,2,2]) + assert_equal 300, score([3,3,3]) + assert_equal 400, score([4,4,4]) + assert_equal 500, score([5,5,5]) + assert_equal 600, score([6,6,6]) + end + + def test_score_of_mixed_is_sum + assert_equal 250, score([2,5,2,2,3]) + assert_equal 550, score([5,5,5,5]) + end + +end diff --git a/src/about_strings.rb b/src/about_strings.rb new file mode 100644 index 000000000..640bd508b --- /dev/null +++ b/src/about_strings.rb @@ -0,0 +1,176 @@ +require 'edgecase' + +class AboutStrings < EdgeCase::Koan + def test_double_quoted_strings_are_strings + string = "Hello, World" + assert_equal __(true), string.is_a?(String) + end + + def test_single_quoted_strings_are_also_strings + string = 'Goodbye, World' + assert_equal __(true), string.is_a?(String) + end + + def test_use_single_quotes_to_create_string_with_double_quotes + string = 'He said, "Go Away."' + assert_equal __('He said, "Go Away."'), string + end + + def test_use_double_quotes_to_create_strings_with_single_quotes + string = "Don't" + assert_equal __("Don't"), string + end + + def test_use_backslash_for_those_hard_cases + a = "He said, \"Don't\"" + b = 'He said, "Don\'t"' + assert_equal __(true), a == b + end + + def test_use_flexible_quoting_to_handle_really_hard_cases + a = %(flexible quotes can handle both ' and " characters) + b = %!flexible quotes can handle both ' and " characters! + c = %{flexible quotes can handle both ' and " characters} + assert_equal __(true), a == b + assert_equal __(true), a == c + end + + def test_flexible_quotes_can_handle_multiple_lines + long_string = %{ +It was the best of times, +It was the worst of times. +} + assert_equal __(54), long_string.size + end + + def test_here_documents_can_also_handle_multiple_lines + long_string = < ex + test.failed(ex) + ensure + begin + test.teardown + rescue StandardError => ex + test.failed(ex) if test.passed? + end + end + accumulator.accumulate(test) + end + + def end_of_enlightenment + @tests_disabled = true + end + + def command_line(args) + args.each do |arg| + case arg + when /^-n\/(.*)\/$/ + @test_pattern = Regexp.new($1) + when /^-n(.*)$/ + @test_pattern = Regexp.new(Regexp.quote($1)) + else + if File.exist?(arg) + load(arg) + else + fail "Unknown command line argument '#{arg}'" + end + end + end + end + + # Lazy initialize list of subclasses + def subclasses + @subclasses ||= [] + end + + # Lazy initialize list of test methods. + def testmethods + @test_methods ||= [] + end + + def tests_disabled? + @tests_disabled ||= false + end + + def test_pattern + @test_pattern ||= /^test_/ + end + + end + end +end + +END { + EdgeCase::Koan.command_line(ARGV) + zen_master = EdgeCase::Sensei.new + catch(:edgecase_exit) { + EdgeCase::Koan.subclasses.each do |sc| + sc.run_tests(zen_master) + end + } + zen_master.report +} diff --git a/src/example_file.txt b/src/example_file.txt new file mode 100644 index 000000000..ffe7cbd89 --- /dev/null +++ b/src/example_file.txt @@ -0,0 +1,4 @@ +this +is +a +test diff --git a/src/first_test.rb b/src/first_test.rb new file mode 100644 index 000000000..708baf17a --- /dev/null +++ b/src/first_test.rb @@ -0,0 +1,11 @@ +require 'test/unit' + +class TestSomething < Test::Unit::TestCase + def test_assert + assert true + assert_equal 1, 1 + assert_equal 1, 1.0 + end +end + + diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb new file mode 100644 index 000000000..a36f237b6 --- /dev/null +++ b/src/path_to_enlightenment.rb @@ -0,0 +1,28 @@ +# The path to Ruby Enlightenment starts with the following: + +require 'about_asserts' +require 'about_nil' +require 'about_arrays' +require 'about_array_assignment' +require 'about_hashes' +require 'about_strings' +require 'about_methods' +require 'about_control_statements' +require 'about_true_and_false' +require 'about_triangle_project' +require 'about_exceptions' +require 'about_triangle_project_2' +require 'about_iteration' +require 'about_blocks' +require 'about_sandwich_code' +require 'about_scoring_project' +require 'about_classes' +require 'about_open_classes' +require 'about_dice_project' +require 'about_inheritance' +require 'about_modules' +require 'about_scope' +require 'about_class_methods' +require 'about_message_passing' +require 'about_proxy_object_project' +require 'about_extra_credit' diff --git a/src/test_helper.rb b/src/test_helper.rb new file mode 100644 index 000000000..9accf96d8 --- /dev/null +++ b/src/test_helper.rb @@ -0,0 +1,7 @@ +require 'test/unit' + +def __ + "FILL ME IN" +end + +EdgeCase = Test::Unit diff --git a/src/triangle.rb b/src/triangle.rb new file mode 100644 index 000000000..ef4859bac --- /dev/null +++ b/src/triangle.rb @@ -0,0 +1,28 @@ +# Triangle Project Code. + +# Triangle analyzes the lengths of the sides of a triangle +# (represented by a, b and c) and returns the type of triangle. +# +# It returns: +# :equilateral if all sides are equal +# :isosceles if exactly 2 sides are equal +# :scalene if no sides are equal +# +# The tests for this method can be found in +# about_triangle_project.rb +# and +# about_triangle_project_2.rb +# +def triangle(a, b, c) + # WRITE THIS CODE + #-- + a, b, c = [a, b, c].sort + fail TriangleError if (a+b) <= c + sides = [a, b, c].uniq + [nil, :equilateral, :isosceles, :scalene][sides.size] + #++ +end + +# Error class used in part 2. No need to change this code. +class TriangleError < StandardError +end From 508a1d812ea3e6e1a7448fb1241ce1cea92e7a0e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 15:03:28 -0500 Subject: [PATCH 019/276] New Rakefile --- Rakefile | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/Rakefile b/Rakefile index 0c07899f0..07e7f3c75 100644 --- a/Rakefile +++ b/Rakefile @@ -1,14 +1,91 @@ -require 'rubygems' -require 'rake/rdoctask' +#!/usr/bin/env ruby +# -*- ruby -*- -task :default => :walk_the_path +require 'rake/clean' -task :walk_the_path do - cd 'koans' - ruby 'path_to_enlightenment.rb' +SRC_DIR = 'src' +PROB_DIR = 'koans' +SOLUTION_DIR = 'solution' +DIST_DIR = 'dist' + +SRC_FILES = FileList["#{SRC_DIR}/*"] +KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f") +SOLUTION_FILES = SRC_FILES.pathmap("#{SOLUTION_DIR}/%f") + +TAR_FILE = "#{DIST_DIR}/rubykoans.tgz" +ZIP_FILE = "#{DIST_DIR}/rubykoans.zip" + +CLOBBER.include(DIST_DIR) + +module Koans + def Koans.remove_solution(line) + line = line.gsub(/\b____\([^\)]+\)/, "____") + line = line.gsub(/\b___\([^\)]+\)/, "___") + line = line.gsub(/\b__\([^\)]+\)/, "__") + line = line.gsub(%r(/\#\{__\}/), "/__/") + line + end + + def Koans.make_koan_file(infile, outfile) + if infile =~ /edgecase/ + cp infile, outfile + else + open(infile) do |ins| + open(outfile, "w") do |outs| + state = :copy + ins.each do |line| + state = :skip if line =~ /^ *#--/ + case state + when :copy + outs.puts remove_solution(line) + else + # do nothing + end + state = :copy if line =~ /^ *#\+\+/ + end + end + end + end + end +end + +directory DIST_DIR +directory PROB_DIR +directory SOLUTION_DIR + +file ZIP_FILE => KOAN_FILES + [DIST_DIR] do + sh "zip #{ZIP_FILE} #{PROB_DIR}/*" +end + +file TAR_FILE => KOAN_FILES + [DIST_DIR] do + sh "tar zcvf #{TAR_FILE} #{PROB_DIR}" +end + +desc "Create packaged files for distribution" +task :package => [TAR_FILE, ZIP_FILE] + +desc "Upload the package files to the web server" +task :upload => [TAR_FILE, ZIP_FILE] do + sh "scp #{TAR_FILE} linode:sites/onestepback.org/download" + sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download" +end + +desc "Check that the require files match the about_* files" +task :check do + about_files = Dir['src/about_*.rb'].size + about_requires = `grep require src/path_to_enlightenment.rb | wc -l`.to_i + puts "# of about files: #{about_files}" + puts "# of about requires: #{about_requires}" +end + +task :regen => [:clobber_koans, :gen] +task :gen => KOAN_FILES +task :clobber_koans do + rm_r PROB_DIR end -Rake::RDocTask.new do |rd| - rd.main = "README.rdoc" - rd.rdoc_files.include("README.rdoc", "koans/*.rb") +SRC_FILES.each do |koan_src| + file koan_src.pathmap("#{PROB_DIR}/%f") => [PROB_DIR, koan_src] do |t| + Koans.make_koan_file koan_src, t.name + end end From c651dd5eba0afba9eb47976c54f150bc76b06390 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 15:07:03 -0500 Subject: [PATCH 020/276] Added back require rake/rdoctask --- Rakefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Rakefile b/Rakefile index 07e7f3c75..b4bce194e 100644 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,7 @@ # -*- ruby -*- require 'rake/clean' +require 'rake/rdoctask' SRC_DIR = 'src' PROB_DIR = 'koans' @@ -49,6 +50,18 @@ module Koans end end +task :default => :walk_the_path + +task :walk_the_path do + cd 'koans' + ruby 'path_to_enlightenment.rb' +end + +Rake::RDocTask.new do |rd| + rd.main = "README.rdoc" + rd.rdoc_files.include("README.rdoc", "koans/*.rb") +end + directory DIST_DIR directory PROB_DIR directory SOLUTION_DIR From f05d9ee1ac238279ca70b89fdec2ee052e9b6d7a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:17:32 -0500 Subject: [PATCH 021/276] Merged src directory with existing koans. --- koans/GREED_RULES.txt | 6 ++--- koans/about_arrays.rb | 1 + koans/about_asserts.rb | 6 ++--- koans/about_blocks.rb | 2 +- koans/about_control_statements.rb | 2 +- koans/about_exceptions.rb | 10 ++++----- koans/about_hashes.rb | 17 ++++++++++---- koans/about_message_passing.rb | 4 ++-- koans/about_methods.rb | 6 ++--- koans/about_nil.rb | 35 ++++++++++------------------- koans/about_proxy_object_project.rb | 3 +++ koans/code_mash.rb | 2 +- koans/edgecase.rb | 8 +++++++ koans/path_to_enlightenment.rb | 1 + src/about_arrays.rb | 3 +-- src/about_asserts.rb | 4 ++-- src/about_class_methods.rb | 31 +++++++++++++------------ src/about_methods.rb | 2 +- src/about_scoring_project.rb | 2 +- src/about_strings.rb | 2 +- src/about_triangle_project_2.rb | 2 +- 21 files changed, 81 insertions(+), 68 deletions(-) diff --git a/koans/GREED_RULES.txt b/koans/GREED_RULES.txt index bf237c0e1..f120604d5 100644 --- a/koans/GREED_RULES.txt +++ b/koans/GREED_RULES.txt @@ -1,12 +1,12 @@ = Playing Greed -Greed is a dice game played among 2 or more players, using 5 +Greed is a dice game played amoung 2 or more players, using 5 six-sided dice. == Playing Greed Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all five dice which are +On the first roll of the game, a player rolls all six dice which are scored according to the following: Three 1's => 1000 points @@ -37,7 +37,7 @@ final example. After a player rolls and the score is calculated, the scoring dice are removed and the player has the option of rolling again using only the -non-scoring dice. If all of the dice are scoring, then the player +non-scoring dice. If there all no non-scoring dice), then the player may roll all 5 dice in the next roll. The player may continue to roll as long as each roll scores points. If diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb index 998f7d90f..9b6b4a6c6 100644 --- a/koans/about_arrays.rb +++ b/koans/about_arrays.rb @@ -40,6 +40,7 @@ def test_slicing_arrays assert_equal __, array[2,2] assert_equal __, array[2,20] assert_equal __, array[4,0] + assert_equal __, array[4,100] assert_equal __, array[5,0] end diff --git a/koans/about_asserts.rb b/koans/about_asserts.rb index db0bfe373..e99bcf391 100644 --- a/koans/about_asserts.rb +++ b/koans/about_asserts.rb @@ -7,7 +7,7 @@ class AboutAsserts < EdgeCase::Koan # We shall contemplate truth by testing reality, via asserts. def test_assert_truth - assert false # This should be true + assert true # This should be true end # Enlightenment may be more easily achieved with appropriate @@ -19,7 +19,7 @@ def test_assert_with_message # To understand reality, we must compare our expectations against # reality. def test_assert_equality - expected_value = 3 + expected_value = __ actual_value = 1 + 1 assert expected_value == actual_value @@ -27,7 +27,7 @@ def test_assert_equality # Some ways of asserting equality are better than others. def test_a_better_way_of_asserting_equality - expected_value = 3 + expected_value = __ actual_value = 1 + 1 assert_equal expected_value, actual_value diff --git a/koans/about_blocks.rb b/koans/about_blocks.rb index df3a745d2..2c418c8db 100644 --- a/koans/about_blocks.rb +++ b/koans/about_blocks.rb @@ -77,7 +77,7 @@ def test_blocks_can_be_assigned_to_variables_and_called_explicitly def test_stand_alone_blocks_can_be_passed_to_methods_expecting_blocks make_upper = lambda { |n| n.upcase } result = method_with_block_arguments(&make_upper) - assert_equal __, result + assert_equal __, result end # ------------------------------------------------------------------ diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index 8ecf88ee2..d2b75ad08 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -11,7 +11,7 @@ def test_if_then_else_statements assert_equal __, result end - def test_if_then_statements + def test_if_then_else_statements result = :default_value if true result = :true_value diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index b2843b118..6604e6cac 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -6,10 +6,10 @@ class MySpecialError < RuntimeError end def test_exceptions_inherit_from_Exception - assert MySpecialError.ancestors.include?(RuntimeError) - assert MySpecialError.ancestors.include?(StandardError) - assert MySpecialError.ancestors.include?(Exception) - assert MySpecialError.ancestors.include?(Object) + assert_equal __, MySpecialError.ancestors[1] + assert_equal __, MySpecialError.ancestors[2] + assert_equal __, MySpecialError.ancestors[3] + assert_equal __, MySpecialError.ancestors[4] end def test_rescue_clause @@ -40,7 +40,7 @@ def test_raising_a_particular_error result = :exception_handled end - assert_equal __(:exception_handled), result + assert_equal __, result assert_equal __, ex.message end diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index e781896d4..e4bfc7826 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -35,14 +35,23 @@ def test_hash_is_unordered hash1 = { :one => "uno", :two => "dos" } hash2 = { :two => "dos", :one => "uno" } - assert_equal hash1, hash2 + assert_equal hash1, hash2 end - def test_hash_keys_and_values + def test_hash_keys hash = { :one => "uno", :two => "dos" } + assert_equal __, hash.keys.size + assert_equal __, hash.keys.include?(:one) + assert_equal __, hash.keys.include?(:two) + assert_equal Array, hash.keys.class + end - assert_equal __, hash.keys.sort - assert_equal __, hash.values.sort + def test_hash_values + hash = { :one => "uno", :two => "dos" } + assert_equal __, hash.keys.size + assert_equal __, hash.values.include?("uno") + assert_equal __, hash.values.include?("dos") + assert_equal Array, hash.values.class end def test_combining_hashes diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index 9932e8fbd..251e3621d 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -25,7 +25,7 @@ def test_methods_can_be_invoked_more_dynamically 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? + assert mc.send("CAUGHT?".____ ) # What would you need to do to the string? end def test_send_with_underscores_will_also_send_messages @@ -96,7 +96,7 @@ def test_calling_method_missing_causes_the_no_method_error class AllMessageCatcher def method_missing(method_name, *args, &block) - "Someone called #{method_name} with (#{args.join(", ")})" + "Someone called #{method_name} with <#{args.join(", ")}>" end end diff --git a/koans/about_methods.rb b/koans/about_methods.rb index 34d93fbbe..7f5c4871e 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -18,7 +18,7 @@ def test_calling_global_methods_without_parenthesis # (NOTE: We are Using eval below because the example code is # considered to be syntactically invalid). def test_sometimes_missing_parenthesis_are_ambiguous - eval "assert_equal 5, my_global_method 2, 3" + eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK # # Ruby doesn't know if you mean: # @@ -36,12 +36,12 @@ def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___) do my_global_method end - assert_equal __, exception.message + assert_match(/__/, exception.message) exception = assert_raise(___) do my_global_method(1,2,3) end - assert_equal __, exception.message + assert_match(/__/, exception.message) end # ------------------------------------------------------------------ diff --git a/koans/about_nil.rb b/koans/about_nil.rb index d9853e98e..af092e21d 100644 --- a/koans/about_nil.rb +++ b/koans/about_nil.rb @@ -2,34 +2,23 @@ class AboutNil < EdgeCase::Koan def test_nil_is_an_object - # - # Hint: '!'s negate the response from what follows. - # - assert !nil.is_a?(Object), "Unlike NULL in other languages" + assert_equal __, nil.is_a?(Object), "Unlike NULL in other languages" end def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil - # - # What is the Exception that is thrown when you call a method that - # does not exist? - # - # Hint: launch irb and try the code in the block below. - # - # Don't be confused by the code below yet. It's using blocks - # which are explained later on in about_blocks.rb. For now, - # think about it like running nil.some_method_nil_doesnt_know_about - # in a sandbox and catching the error class into the exception - # variable. - # - exception = assert_raise(___) do + # What happens when you call a method that doesn't exist. The + # following begin/rescue/end code block captures the exception and + # make some assertions about it. + begin nil.some_method_nil_doesnt_know_about + rescue Exception => ex + # What exception has been caught? + assert_equal __, ex.class + + # What message was attached to the exception? + # (HINT: replace __ with part of the error message.) + assert_match(/__/, ex.message) end - - # - # What is the error message itself? What substring or pattern could - # you test against in order to have a good idea what the string is? - # - assert_match /__/, exception.message end def test_nil_has_a_few_methods_defined_on_it diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index dad63d7a2..f3d2a65bc 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -15,7 +15,10 @@ class Proxy def initialize(target_object) @object = target_object + # ADD MORE CODE HERE end + + # WRITE CODE HERE end # The proxy object should pass the following Koan: diff --git a/koans/code_mash.rb b/koans/code_mash.rb index fe089a5ef..1157de930 100644 --- a/koans/code_mash.rb +++ b/koans/code_mash.rb @@ -1 +1 @@ -require 'edgecase' \ No newline at end of file +require 'edgecase' diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 7ab429e9d..91d838f7c 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -14,6 +14,14 @@ def ___(value=FillMeInError) value end +class Object + def ____(method=nil) + if method + self.send(method) + end + end +end + module EdgeCase class Sensei attr_reader :failure, :failed_test diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index 79daa7955..a36f237b6 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -17,6 +17,7 @@ require 'about_sandwich_code' require 'about_scoring_project' require 'about_classes' +require 'about_open_classes' require 'about_dice_project' require 'about_inheritance' require 'about_modules' diff --git a/src/about_arrays.rb b/src/about_arrays.rb index 4eba6a971..680717bd2 100644 --- a/src/about_arrays.rb +++ b/src/about_arrays.rb @@ -42,7 +42,6 @@ def test_slicing_arrays assert_equal __([]), array[4,0] assert_equal __([]), array[4,100] assert_equal __(nil), array[5,0] - assert_equal __(nil), array[5,0] end def test_arrays_and_ranges @@ -57,7 +56,7 @@ def test_slicing_with_ranges assert_equal __([:peanut, :butter, :and]), array[0..2] assert_equal __([:peanut, :butter]), array[0...2] - assert_equal ([:and, :jelly]), array[2..-1] + assert_equal __([:and, :jelly]), array[2..-1] end def test_pushing_and_popping_arrays diff --git a/src/about_asserts.rb b/src/about_asserts.rb index 9388a95fb..55fb420ad 100644 --- a/src/about_asserts.rb +++ b/src/about_asserts.rb @@ -7,13 +7,13 @@ class AboutAsserts < EdgeCase::Koan # We shall contemplate truth by testing reality, via asserts. def test_assert_truth - assert __(true) # This should be true + assert true # This should be true end # Enlightenment may be more easily achieved with appropriate # messages. def test_assert_with_message - assert __(true), "This should be true -- Please fix this" + assert false, "This should be true -- Please fix this" end # To understand reality, we must compare our expectations against diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index 9788ad4fc..f8bc9b132 100644 --- a/src/about_class_methods.rb +++ b/src/about_class_methods.rb @@ -19,11 +19,11 @@ def test_classes_are_objects_too def test_objects_have_methods fido = Dog.new - assert_equal __(45), fido.methods.size + assert_equal __(44), fido.methods.size end def test_classes_have_methods - assert_equal __(80), Dog.methods.size + assert_equal __(79), Dog.methods.size end def test_you_can_define_methods_on_individual_objects @@ -34,9 +34,12 @@ def fido.wag assert_equal __(:fidos_wag), fido.wag end - def test_other_objects_are_unaffected_by_these_singleton_methods + def test_other_objects_are_not_affected_by_these_singleton_methods fido = Dog.new rover = Dog.new + def fido.wag + :fidos_wag + end assert_raise(___(NoMethodError)) do rover.wag @@ -45,24 +48,24 @@ def test_other_objects_are_unaffected_by_these_singleton_methods # ------------------------------------------------------------------ - def Dog.bark - :class_level_bark + class Dog2 + def wag + :instance_level_wag + end end - class Dog - def bark - :instance_level_bark - end + def Dog2.wag + :class_level_wag end def test_since_classes_are_objects_you_can_define_singleton_methods_on_them_too - assert_equal __(:class_level_bark), Dog.bark + assert_equal __(:class_level_wag), Dog2.wag end def test_class_methods_are_independent_of_instance_methods - fido = Dog.new - assert_equal __(:instance_level_bark), fido.bark - assert_equal __(:class_level_bark), Dog.bark + fido = Dog2.new + assert_equal __(:instance_level_wag), fido.wag + assert_equal __(:class_level_wag), Dog2.wag end # ------------------------------------------------------------------ @@ -155,7 +158,7 @@ def test_heres_still_another_way_to_write_class_methods # end # # Which do you prefer and why? - # Are there times you might prefer the other way? + # Are there times you might prefer one over the other? # ------------------------------------------------------------------ diff --git a/src/about_methods.rb b/src/about_methods.rb index b289cac51..b8d108591 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -79,7 +79,7 @@ def test_calling_with_variable_arguments def method_with_explicit_return :a_non_return_value return :return_value - :anoher_non_return_value + :another_non_return_value end def test_method_with_explicit_return diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index c58078678..cbfd26a20 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -25,7 +25,7 @@ # score([3,4,5,3,3]) => 350 points # score([1,5,1,2,4]) => 250 points # -# More scoing examples are given in the tests below: +# More scoring examples are given in the tests below: # # Your goal is to write the score method. diff --git a/src/about_strings.rb b/src/about_strings.rb index 640bd508b..6f1797a5c 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -128,7 +128,7 @@ def test_single_quoted_strings_do_not_interpolate assert_equal __('The value is #{value}'), string end - def test_any_ruby_expression_my_be_interpolated + def test_any_ruby_expression_may_be_interpolated string = "The square root of 5 is #{Math.sqrt(5)}" assert_equal __("The square root of 5 is 2.23606797749979"), string end diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index f9e472815..a0f27166d 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -3,7 +3,7 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment < EdgeCase::Koan +class AboutTriangleAssignment2 < EdgeCase::Koan # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions From 4fdf06036025ef3c99fe6b54ffd493f6170080fd Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:30:07 -0500 Subject: [PATCH 022/276] Ignoring the dist directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1521c8b76 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dist From 0b58d57399401ff147bc44ccb5632f8c40c41966 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:30:50 -0500 Subject: [PATCH 023/276] Updated Rakfile to copy the main readme into the koan directory. Removed SOURCE directory reference. --- Rakefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index b4bce194e..e8641e78a 100644 --- a/Rakefile +++ b/Rakefile @@ -6,12 +6,10 @@ require 'rake/rdoctask' SRC_DIR = 'src' PROB_DIR = 'koans' -SOLUTION_DIR = 'solution' DIST_DIR = 'dist' SRC_FILES = FileList["#{SRC_DIR}/*"] KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f") -SOLUTION_FILES = SRC_FILES.pathmap("#{SOLUTION_DIR}/%f") TAR_FILE = "#{DIST_DIR}/rubykoans.tgz" ZIP_FILE = "#{DIST_DIR}/rubykoans.zip" @@ -64,7 +62,6 @@ end directory DIST_DIR directory PROB_DIR -directory SOLUTION_DIR file ZIP_FILE => KOAN_FILES + [DIST_DIR] do sh "zip #{ZIP_FILE} #{PROB_DIR}/*" @@ -92,11 +89,15 @@ task :check do end task :regen => [:clobber_koans, :gen] -task :gen => KOAN_FILES +task :gen => KOAN_FILES + [PROB_DIR + "/README.rdoc"] task :clobber_koans do rm_r PROB_DIR end +file PROB_DIR + "/README.rdoc" => "README.rdoc" do |t| + cp "README.rdoc", t.name +end + SRC_FILES.each do |koan_src| file koan_src.pathmap("#{PROB_DIR}/%f") => [PROB_DIR, koan_src] do |t| Koans.make_koan_file koan_src, t.name From e9e079e2622b5efcbee6f122ee5c3075e48a247b Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:31:11 -0500 Subject: [PATCH 024/276] Cleaned up src directory --- src/README | 38 -------------------------------------- src/dist/rubykoans.tgz | Bin 45 -> 0 bytes 2 files changed, 38 deletions(-) delete mode 100644 src/README delete mode 100644 src/dist/rubykoans.tgz diff --git a/src/README b/src/README deleted file mode 100644 index 3dbdc716b..000000000 --- a/src/README +++ /dev/null @@ -1,38 +0,0 @@ -= 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 -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. - -== 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. - -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. - - -== The Path To Enlightenment - -In order to achieve enlightenment you need to follow the path_to_enlightenment. This -can be done in two ways - -*nix platforms, from the koans directory - - [koans] $ rake # runs the default target :walk_the_path - [koans] $ ruby path_to_enlightenment.rb # simply call the file directly - -Windows is the same thing - - c:\dev\koans\rake # runs the default target :walk_the_path - c:\dev\koans\ruby path_to_enlightenment.rb # simply call the file directly - diff --git a/src/dist/rubykoans.tgz b/src/dist/rubykoans.tgz deleted file mode 100644 index a24413becaa500d3fbe0c93a156f04be27021405..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45 vcmb2|=3v- Date: Mon, 21 Dec 2009 16:31:42 -0500 Subject: [PATCH 025/276] Added Main readme to koan directory. --- koans/README.rdoc | 133 ++++++++++++++++++++++++++++++++++++++++++++++ koans/Rakefile | 12 +++++ 2 files changed, 145 insertions(+) create mode 100644 koans/README.rdoc create mode 100644 koans/Rakefile diff --git a/koans/README.rdoc b/koans/README.rdoc new file mode 100644 index 000000000..d24bfe60a --- /dev/null +++ b/koans/README.rdoc @@ -0,0 +1,133 @@ += 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 +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. + +== 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. + +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. + +== 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 +installed. To check the installations simply type: + +*nix platforms from any terminal window: + + [~] $ ruby --version + [~] $ rake --version + +Windows from the command prompt (cmd.exe) + + 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. + +== The Path To Enlightenment + +You can run the tests through rake or by calling the file itself (rake is the +recommended way to run them as we might build more functionality into this task). + +*nix platforms, from the koans directory + + [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 +moment and reflect upon the test to see what it is teaching you and improve the +code to better communicate its intent (refactor). + +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 ... + is not true. + + Please meditate on the following code: + ./about_basics.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_basics.rb:10:in `test_assert_truth' + path_to_enlightenment.rb:27 + +We then open up the about_basics.rb file and look at the first test: + + # We shall contemplate truth by testing reality, via asserts. + def test_assert_truth + assert false # This should be true + end + +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+ +method, it will either ensure it is +true+ and continue on, or fail if in fact +the statement is +false+. + +== Inspiration + +A special thanks to Mike Clark and Ara Howard for inspiring this project. Mike Clark +wrote an excellent blog post about learning Ruby through unit testing. This sparked +an idea that has taken a bit to solidify, that of bringing new rubyists into the +community through testing. Ara Howard then gave us the idea for the Koans in his +ruby quiz entry an Meta Koans (a must for any rubyist wanting to improve their skills). + +Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 +Meta Koans :: http://rubyquiz.com/quiz67.html + +== Other Resources + +The Ruby Language :: http://ruby-lang.org +Try Ruby in your browser :: http://tryruby.sophrinix.com + +Dave Thomas' introduction to Ruby Programming Ruby (the Pick Axe) :: http://pragprog.com/titles/ruby/programming-ruby + +Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: http://pragprog.com/titles/bmsft/everyday-scripting-with-ruby + += Other stuff + +Author:: Jim Weirich +Author:: Joe O'Brien +Requires:: Ruby 1.8.x or later and Rake (any version) + + diff --git a/koans/Rakefile b/koans/Rakefile new file mode 100644 index 000000000..1a2c7f26d --- /dev/null +++ b/koans/Rakefile @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# -*- ruby -*- + +require 'rake/clean' +require 'rake/testtask' + +task :default => :test + +task :test do + ruby 'path_to_enlightenment.rb' +end + From 4fb9f8fb9f7508f63088f0358ee7c6e282c719cf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:36:48 -0500 Subject: [PATCH 026/276] Fixed broken assert in src, so that it is still broken in koan --- src/about_asserts.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/about_asserts.rb b/src/about_asserts.rb index 55fb420ad..8304f714b 100644 --- a/src/about_asserts.rb +++ b/src/about_asserts.rb @@ -13,7 +13,14 @@ def test_assert_truth # Enlightenment may be more easily achieved with appropriate # messages. def test_assert_with_message + #-- + assert true, "This should be true -- Please fix this" + if false + #++ assert false, "This should be true -- Please fix this" + #-- + end + #++ end # To understand reality, we must compare our expectations against From a7382f394069c849f6efe66c669a15dd64625e70 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:37:06 -0500 Subject: [PATCH 027/276] Changed minor constant count change. --- src/about_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_scope.rb b/src/about_scope.rb index 11352a082..4f116d5f1 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -74,6 +74,6 @@ def test_constants_can_be_looked_up_explicitly def test_you_can_get_a_list_of_constants_for_any_class_or_module assert_equal __(["Dog"]), Jims.constants - assert_equal __(121), Object.constants.size + assert_equal __(122), Object.constants.size end end From ac6f38a8046d00dd88ea9e0acd13e18f33fd7db5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:45:33 -0500 Subject: [PATCH 028/276] Fixed rules typos. --- src/GREED_RULES.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GREED_RULES.txt b/src/GREED_RULES.txt index f120604d5..58b5a9cb6 100644 --- a/src/GREED_RULES.txt +++ b/src/GREED_RULES.txt @@ -1,12 +1,12 @@ = Playing Greed -Greed is a dice game played amoung 2 or more players, using 5 +Greed is a dice game played among 2 or more players, using 5 six-sided dice. == Playing Greed Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all six dice which are +On the first roll of the game, a player rolls all five dice which are scored according to the following: Three 1's => 1000 points @@ -37,8 +37,8 @@ final example. After a player rolls and the score is calculated, the scoring dice are removed and the player has the option of rolling again using only the -non-scoring dice. If there all no non-scoring dice), then the player -may roll all 5 dice in the next roll. +non-scoring dice. If all of the thrown dice are scoring, then the +player may roll all 5 dice in the next roll. The player may continue to roll as long as each roll scores points. If a roll has zero points, then the player loses not only their turn, but From 5a68c779e43d5b299193852c531ccff3284b02ef Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 21 Dec 2009 16:57:46 -0500 Subject: [PATCH 029/276] Added ref to Little Lisper. --- README.rdoc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index d24bfe60a..5378cbc32 100644 --- a/README.rdoc +++ b/README.rdoc @@ -110,10 +110,13 @@ A special thanks to Mike Clark and Ara Howard for inspiring this project. Mike wrote an excellent blog post about learning Ruby through unit testing. This sparked an idea that has taken a bit to solidify, that of bringing new rubyists into the community through testing. Ara Howard then gave us the idea for the Koans in his -ruby quiz entry an Meta Koans (a must for any rubyist wanting to improve their skills). +ruby quiz entry an Meta Koans (a must for any rubyist wanting to +improve their skills). Also, "The Little Lisper" taught us all the +value of the short questions/simple answers style of learning. Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 Meta Koans :: http://rubyquiz.com/quiz67.html +The Little Lisper :: http://www.amazon.com/Little-LISPer-Third-Daniel-Friedman/dp/0023397632 == Other Resources From 26639d58eccaf00b6e4a809d66fde64bede70d9e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 22 Dec 2009 22:25:47 -0500 Subject: [PATCH 030/276] Fixed typos in Greed Rules. --- koans/GREED_RULES.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/koans/GREED_RULES.txt b/koans/GREED_RULES.txt index f120604d5..58b5a9cb6 100644 --- a/koans/GREED_RULES.txt +++ b/koans/GREED_RULES.txt @@ -1,12 +1,12 @@ = Playing Greed -Greed is a dice game played amoung 2 or more players, using 5 +Greed is a dice game played among 2 or more players, using 5 six-sided dice. == Playing Greed Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all six dice which are +On the first roll of the game, a player rolls all five dice which are scored according to the following: Three 1's => 1000 points @@ -37,8 +37,8 @@ final example. After a player rolls and the score is calculated, the scoring dice are removed and the player has the option of rolling again using only the -non-scoring dice. If there all no non-scoring dice), then the player -may roll all 5 dice in the next roll. +non-scoring dice. If all of the thrown dice are scoring, then the +player may roll all 5 dice in the next roll. The player may continue to roll as long as each roll scores points. If a roll has zero points, then the player loses not only their turn, but From 690ca4c022d6d5e6b530f0a093fbd4ab90409f24 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 22 Dec 2009 22:26:04 -0500 Subject: [PATCH 031/276] Updated Readme with ref to about_asserts. --- README.rdoc | 6 +++--- koans/README.rdoc | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/README.rdoc b/README.rdoc index 5378cbc32..0ae3ab956 100644 --- a/README.rdoc +++ b/README.rdoc @@ -76,7 +76,7 @@ The very first time you run it you will see the following output: is not true. Please meditate on the following code: - ./about_basics.rb:10:in `test_assert_truth' + ./about_asserts.rb:10:in `test_assert_truth' path_to_enlightenment.rb:27 mountains are merely mountains @@ -85,10 +85,10 @@ You have come to your first stage. If you notice it is telling you where to look the first solution: Please meditate on the following code: - ./about_basics.rb:10:in `test_assert_truth' + ./about_asserts.rb:10:in `test_assert_truth' path_to_enlightenment.rb:27 -We then open up the about_basics.rb file and look at the first test: +We then open up the about_asserts.rb file and look at the first test: # We shall contemplate truth by testing reality, via asserts. def test_assert_truth diff --git a/koans/README.rdoc b/koans/README.rdoc index d24bfe60a..0ae3ab956 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -76,7 +76,7 @@ The very first time you run it you will see the following output: is not true. Please meditate on the following code: - ./about_basics.rb:10:in `test_assert_truth' + ./about_asserts.rb:10:in `test_assert_truth' path_to_enlightenment.rb:27 mountains are merely mountains @@ -85,10 +85,10 @@ You have come to your first stage. If you notice it is telling you where to look the first solution: Please meditate on the following code: - ./about_basics.rb:10:in `test_assert_truth' + ./about_asserts.rb:10:in `test_assert_truth' path_to_enlightenment.rb:27 -We then open up the about_basics.rb file and look at the first test: +We then open up the about_asserts.rb file and look at the first test: # We shall contemplate truth by testing reality, via asserts. def test_assert_truth @@ -110,10 +110,13 @@ A special thanks to Mike Clark and Ara Howard for inspiring this project. Mike wrote an excellent blog post about learning Ruby through unit testing. This sparked an idea that has taken a bit to solidify, that of bringing new rubyists into the community through testing. Ara Howard then gave us the idea for the Koans in his -ruby quiz entry an Meta Koans (a must for any rubyist wanting to improve their skills). +ruby quiz entry an Meta Koans (a must for any rubyist wanting to +improve their skills). Also, "The Little Lisper" taught us all the +value of the short questions/simple answers style of learning. Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 Meta Koans :: http://rubyquiz.com/quiz67.html +The Little Lisper :: http://www.amazon.com/Little-LISPer-Third-Daniel-Friedman/dp/0023397632 == Other Resources From 3958b3c9e5b4c31c37a48b44f8d98b1d843f8fcf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 22 Dec 2009 22:31:55 -0500 Subject: [PATCH 032/276] Updated first test to properly fail on the first run. --- koans/about_asserts.rb | 2 +- src/about_asserts.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/koans/about_asserts.rb b/koans/about_asserts.rb index e99bcf391..53a42aa66 100644 --- a/koans/about_asserts.rb +++ b/koans/about_asserts.rb @@ -7,7 +7,7 @@ class AboutAsserts < EdgeCase::Koan # We shall contemplate truth by testing reality, via asserts. def test_assert_truth - assert true # This should be true + assert false # This should be true end # Enlightenment may be more easily achieved with appropriate diff --git a/src/about_asserts.rb b/src/about_asserts.rb index 8304f714b..37253d431 100644 --- a/src/about_asserts.rb +++ b/src/about_asserts.rb @@ -7,7 +7,14 @@ class AboutAsserts < EdgeCase::Koan # We shall contemplate truth by testing reality, via asserts. def test_assert_truth + #-- assert true # This should be true + if false + #++ + assert false # This should be true + #-- + end + #++ end # Enlightenment may be more easily achieved with appropriate From a0ff4e58f780a4d908a04e8a23ff472d6c67ced6 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 24 Dec 2009 02:27:02 -0500 Subject: [PATCH 033/276] Fixed typo in tribute to Ara Howard. --- README.rdoc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.rdoc b/README.rdoc index 0ae3ab956..94cb2a07c 100644 --- a/README.rdoc +++ b/README.rdoc @@ -106,13 +106,14 @@ the statement is +false+. == Inspiration -A special thanks to Mike Clark and Ara Howard for inspiring this project. Mike Clark -wrote an excellent blog post about learning Ruby through unit testing. This sparked -an idea that has taken a bit to solidify, that of bringing new rubyists into the -community through testing. Ara Howard then gave us the idea for the Koans in his -ruby quiz entry an Meta Koans (a must for any rubyist wanting to -improve their skills). Also, "The Little Lisper" taught us all the -value of the short questions/simple answers style of learning. +A special thanks to Mike Clark and Ara Howard for inspiring this +project. Mike Clark wrote an excellent blog post about learning Ruby +through unit testing. This sparked an idea that has taken a bit to +solidify, that of bringing new rubyists into the community through +testing. Ara Howard then gave us the idea for the Koans in his ruby +quiz entry on Meta Koans (a must for any rubyist wanting to improve +their skills). Also, "The Little Lisper" taught us all the value of +the short questions/simple answers style of learning. Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 Meta Koans :: http://rubyquiz.com/quiz67.html From 2a116925a0717fa92d94e3c37dfc02137ecb4ee6 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 24 Dec 2009 02:33:08 -0500 Subject: [PATCH 034/276] Updated tryruby link to tryruby.org. --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 94cb2a07c..6f4b1e359 100644 --- a/README.rdoc +++ b/README.rdoc @@ -122,7 +122,7 @@ The Little Lisper :: http://www.amazon.com/Little-LISPer-Third-Daniel-Friedman/ == Other Resources The Ruby Language :: http://ruby-lang.org -Try Ruby in your browser :: http://tryruby.sophrinix.com +Try Ruby in your browser :: http://tryruby.org Dave Thomas' introduction to Ruby Programming Ruby (the Pick Axe) :: http://pragprog.com/titles/ruby/programming-ruby From eaccb51af6f8db15045fc7bb6e1adb52da1a926f Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 31 Dec 2009 13:37:51 -0500 Subject: [PATCH 035/276] Added tracker information to readme. --- README.rdoc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.rdoc b/README.rdoc index 6f4b1e359..307a4a9f7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -130,8 +130,7 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: = Other stuff -Author:: Jim Weirich -Author:: Joe O'Brien -Requires:: Ruby 1.8.x or later and Rake (any version) - - +Author :: Jim Weirich +Author :: Joe O'Brien +Issue Tracker :: http://www.pivotaltracker.com/projects/48111 +Requires :: Ruby 1.8.x or later and Rake (any recent version) From e639fb315ffde36ac0831cb5267ae40430f4f800 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:20:54 -0500 Subject: [PATCH 036/276] Added pivotal tracker address to readme. --- koans/README.rdoc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/koans/README.rdoc b/koans/README.rdoc index 0ae3ab956..da95c5860 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -129,8 +129,7 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: = Other stuff -Author:: Jim Weirich -Author:: Joe O'Brien -Requires:: Ruby 1.8.x or later and Rake (any version) - - +Author :: Jim Weirich +Author :: Joe O'Brien +Issue Tracker :: http://www.pivotaltracker.com/projects/48111 +Requires :: Ruby 1.8.x or later and Rake (any recent version) From f68bd3ca8fe9790ecc8201508118bad1be6d178d Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:21:12 -0500 Subject: [PATCH 037/276] Updated try ruby link --- koans/README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/README.rdoc b/koans/README.rdoc index da95c5860..ae19ed0d5 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -121,7 +121,7 @@ The Little Lisper :: http://www.amazon.com/Little-LISPer-Third-Daniel-Friedman/ == Other Resources The Ruby Language :: http://ruby-lang.org -Try Ruby in your browser :: http://tryruby.sophrinix.com +Try Ruby in your browser :: http://tryruby.org Dave Thomas' introduction to Ruby Programming Ruby (the Pick Axe) :: http://pragprog.com/titles/ruby/programming-ruby From a22b5fe9dc39a8f93ccb073641bfd13c7aeaf314 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:21:33 -0500 Subject: [PATCH 038/276] Some minor reformatting. --- koans/README.rdoc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/koans/README.rdoc b/koans/README.rdoc index ae19ed0d5..307a4a9f7 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -106,13 +106,14 @@ the statement is +false+. == Inspiration -A special thanks to Mike Clark and Ara Howard for inspiring this project. Mike Clark -wrote an excellent blog post about learning Ruby through unit testing. This sparked -an idea that has taken a bit to solidify, that of bringing new rubyists into the -community through testing. Ara Howard then gave us the idea for the Koans in his -ruby quiz entry an Meta Koans (a must for any rubyist wanting to -improve their skills). Also, "The Little Lisper" taught us all the -value of the short questions/simple answers style of learning. +A special thanks to Mike Clark and Ara Howard for inspiring this +project. Mike Clark wrote an excellent blog post about learning Ruby +through unit testing. This sparked an idea that has taken a bit to +solidify, that of bringing new rubyists into the community through +testing. Ara Howard then gave us the idea for the Koans in his ruby +quiz entry on Meta Koans (a must for any rubyist wanting to improve +their skills). Also, "The Little Lisper" taught us all the value of +the short questions/simple answers style of learning. Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 Meta Koans :: http://rubyquiz.com/quiz67.html From 2483665fb96f133f02115caf5d0ed5557057844d Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:21:49 -0500 Subject: [PATCH 039/276] Addd comments to gen and regen tasks. --- Rakefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Rakefile b/Rakefile index e8641e78a..cb81bba39 100644 --- a/Rakefile +++ b/Rakefile @@ -88,7 +88,10 @@ task :check do puts "# of about requires: #{about_requires}" end +desc "Generate the Koans from the source files from scratch." task :regen => [:clobber_koans, :gen] + +desc "Generate the Koans from the changed source files." task :gen => KOAN_FILES + [PROB_DIR + "/README.rdoc"] task :clobber_koans do rm_r PROB_DIR From e21e46bdf9c2ee0472be7594e8652d88c8ab29fb Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:22:24 -0500 Subject: [PATCH 040/276] Renamed test (http://www.pivotaltracker.com/story/show/2072574) --- koans/about_scoring_project.rb | 2 +- src/about_scoring_project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index fcd4206f7..bb5470186 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -46,7 +46,7 @@ def test_score_of_a_single_roll_of_1_is_100 assert_equal 100, score([1]) end - def test_score_of_mulitple_1s_and_5s_is_the_sum + def test_score_of_mulitple_1s_and_5s_is_the_sum_of_individual_scores assert_equal 300, score([1,5,5,1]) end diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index cbfd26a20..9c4ce40e4 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -67,7 +67,7 @@ def test_score_of_a_single_roll_of_1_is_100 assert_equal 100, score([1]) end - def test_score_of_mulitple_1s_and_5s_is_the_sum + def test_score_of_mulitple_1s_and_5s_is_the_sum_of_individual_scores assert_equal 300, score([1,5,5,1]) end From bdc9e2a772fe6eb8ee9cbf54e946ddfcebf3ccba Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 2 Jan 2010 22:25:05 -0500 Subject: [PATCH 041/276] Renamed explict to explicit (http://www.pivotaltracker.com/story/show/2070657) --- koans/about_blocks.rb | 6 +++--- src/about_blocks.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/koans/about_blocks.rb b/koans/about_blocks.rb index 2c418c8db..08458f575 100644 --- a/koans/about_blocks.rb +++ b/koans/about_blocks.rb @@ -82,15 +82,15 @@ def test_stand_alone_blocks_can_be_passed_to_methods_expecting_blocks # ------------------------------------------------------------------ - def method_with_explict_block(&block) + def method_with_explicit_block(&block) block.call(10) end def test_methods_can_take_an_explicit_block_argument - assert_equal __, method_with_explict_block { |n| n * 2 } + assert_equal __, method_with_explicit_block { |n| n * 2 } add_one = lambda { |n| n + 1 } - assert_equal __, method_with_explict_block(&add_one) + assert_equal __, method_with_explicit_block(&add_one) end end diff --git a/src/about_blocks.rb b/src/about_blocks.rb index c764af920..eead2a79d 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -82,15 +82,15 @@ def test_stand_alone_blocks_can_be_passed_to_methods_expecting_blocks # ------------------------------------------------------------------ - def method_with_explict_block(&block) + def method_with_explicit_block(&block) block.call(10) end def test_methods_can_take_an_explicit_block_argument - assert_equal __(20), method_with_explict_block { |n| n * 2 } + assert_equal __(20), method_with_explicit_block { |n| n * 2 } add_one = lambda { |n| n + 1 } - assert_equal __(11), method_with_explict_block(&add_one) + assert_equal __(11), method_with_explicit_block(&add_one) end end From 425fd41fbca0208f63000c1a38391d0bb96fb097 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 3 Jan 2010 06:27:59 -0500 Subject: [PATCH 042/276] Fixed misspelling of "multiple" (http://www.pivotaltracker.com/story/show/2072574) --- koans/about_scoring_project.rb | 2 +- src/about_scoring_project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index bb5470186..e71423f3c 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -46,7 +46,7 @@ def test_score_of_a_single_roll_of_1_is_100 assert_equal 100, score([1]) end - def test_score_of_mulitple_1s_and_5s_is_the_sum_of_individual_scores + def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores assert_equal 300, score([1,5,5,1]) end diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 9c4ce40e4..0e78eb839 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -67,7 +67,7 @@ def test_score_of_a_single_roll_of_1_is_100 assert_equal 100, score([1]) end - def test_score_of_mulitple_1s_and_5s_is_the_sum_of_individual_scores + def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores assert_equal 300, score([1,5,5,1]) end From 6052c776bc273fcf86d26e4f933298f3b844e447 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 14 Jan 2010 14:31:30 -0500 Subject: [PATCH 043/276] Use .values rather than .keys in values test (http://www.pivotaltracker.com/story/show/2177802) --- koans/about_hashes.rb | 2 +- src/about_hashes.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index e4bfc7826..05af65a4f 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -48,7 +48,7 @@ def test_hash_keys 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 diff --git a/src/about_hashes.rb b/src/about_hashes.rb index 6e42372ce..ae85292d7 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -48,7 +48,7 @@ def test_hash_keys 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 From 6c69bcb0ef2d682822d34841e87c3233324352e5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 15 Jan 2010 09:39:48 -0500 Subject: [PATCH 044/276] Added [1,1,3] case for triangles. --- src/about_triangle_project_2.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index a0f27166d..34f748246 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.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 From ec6458e17482342bd17f34db8b7c9eec38db19cf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 15 Jan 2010 09:46:17 -0500 Subject: [PATCH 045/276] Renamed if test to avoid method name conflict. --- src/about_control_statements.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index f470a8c5f..7e2ca6f74 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -8,10 +8,10 @@ def test_if_then_else_statements 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 From d4c9150453ffcda5df96a6739cddf9479dcfc9ee Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 15 Jan 2010 09:51:50 -0500 Subject: [PATCH 046/276] Added swap example to parallel assignments --- src/about_array_assignment.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 0e7e118b2..063c241b8 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -35,4 +35,11 @@ def test_parallel_assignment_with_one_variable 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 From 1d1ab85777e573fcb96f3dac671cfed0d76a52bb Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 15 Jan 2010 09:53:28 -0500 Subject: [PATCH 047/276] Generated new koans directory. --- koans/about_array_assignment.rb | 7 +++++++ koans/about_control_statements.rb | 2 +- koans/about_triangle_project_2.rb | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/koans/about_array_assignment.rb b/koans/about_array_assignment.rb index 37b1068c5..4e6cfeef1 100644 --- a/koans/about_array_assignment.rb +++ b/koans/about_array_assignment.rb @@ -35,4 +35,11 @@ def test_parallel_assignment_with_one_variable 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 diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index d2b75ad08..8ecf88ee2 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -11,7 +11,7 @@ def test_if_then_else_statements assert_equal __, result end - def test_if_then_else_statements + def test_if_then_statements result = :default_value if true result = :true_value diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index a0f27166d..34f748246 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.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 From 110ff38b3fcd51f95cfb1db900d18c2470ac44d8 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:16:55 -0400 Subject: [PATCH 048/276] Added a numeric fill in method (_n_) --- src/edgecase.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/edgecase.rb b/src/edgecase.rb index 91d838f7c..acb032b5b 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -10,6 +10,10 @@ def __(value="FILL ME IN") value end +def _n_(value=999999) + value +end + def ___(value=FillMeInError) value end From 3b824d0e8614f62d173cc5ef54f901a29333498e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:17:24 -0400 Subject: [PATCH 049/276] Modified to be less dependent on exact method and constant counts. --- src/about_class_methods.rb | 4 ++-- src/about_scope.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index f8bc9b132..0728c4743 100644 --- a/src/about_class_methods.rb +++ b/src/about_class_methods.rb @@ -19,11 +19,11 @@ def test_classes_are_objects_too 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 diff --git a/src/about_scope.rb b/src/about_scope.rb index 4f116d5f1..e322f17f0 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -74,6 +74,6 @@ def test_constants_can_be_looked_up_explicitly 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 Object.constants.size > _n_(10) end end From f0b1560f344a0724291cade21fc610656152bf65 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:17:34 -0400 Subject: [PATCH 050/276] Added about_constants --- koans/about_constants.rb | 87 ++++++++++++++++++++++++++++++++++++ src/about_constants.rb | 87 ++++++++++++++++++++++++++++++++++++ src/path_to_enlightenment.rb | 1 + 3 files changed, 175 insertions(+) create mode 100644 koans/about_constants.rb create mode 100644 src/about_constants.rb diff --git a/koans/about_constants.rb b/koans/about_constants.rb new file mode 100644 index 000000000..ae270edc6 --- /dev/null +++ b/koans/about_constants.rb @@ -0,0 +1,87 @@ +require '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? +end diff --git a/src/about_constants.rb b/src/about_constants.rb new file mode 100644 index 000000000..b0913a7d7 --- /dev/null +++ b/src/about_constants.rb @@ -0,0 +1,87 @@ +require '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? +end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index a36f237b6..6a87bcb8f 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -7,6 +7,7 @@ require 'about_hashes' require 'about_strings' require 'about_methods' +require 'about_constants' require 'about_control_statements' require 'about_true_and_false' require 'about_triangle_project' From c40424e9a47e0e91e3eb8f22fb1fe2a2fad52e65 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:25:19 -0400 Subject: [PATCH 051/276] Updates source to be consistent with the _n_ changes. --- koans/about_class_methods.rb | 4 ++-- koans/about_scope.rb | 2 +- koans/edgecase.rb | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/koans/about_class_methods.rb b/koans/about_class_methods.rb index 39ede9573..c768b00d0 100644 --- a/koans/about_class_methods.rb +++ b/koans/about_class_methods.rb @@ -19,11 +19,11 @@ def test_classes_are_objects_too def test_objects_have_methods fido = Dog.new - assert_equal __, fido.methods.size + assert fido.methods.size > _n_(30) end def test_classes_have_methods - assert_equal __, Dog.methods.size + assert Dog.methods.size > _n_(40) end def test_you_can_define_methods_on_individual_objects diff --git a/koans/about_scope.rb b/koans/about_scope.rb index 968c360cf..e616ae01d 100644 --- a/koans/about_scope.rb +++ b/koans/about_scope.rb @@ -74,6 +74,6 @@ def test_constants_can_be_looked_up_explicitly 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_(10) end end diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 91d838f7c..acb032b5b 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -10,6 +10,10 @@ def __(value="FILL ME IN") value end +def _n_(value=999999) + value +end + def ___(value=FillMeInError) value end From 308ad5d9c5912b50ad98f43b4e408ef9219442b2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:26:18 -0400 Subject: [PATCH 052/276] Added constants to koans path to enlightenment. --- koans/path_to_enlightenment.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index a36f237b6..6a87bcb8f 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -7,6 +7,7 @@ require 'about_hashes' require 'about_strings' require 'about_methods' +require 'about_constants' require 'about_control_statements' require 'about_true_and_false' require 'about_triangle_project' From 56206e0a41fbb7b2b88b0c2ee7b91ace046438ea Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 20 Apr 2010 16:26:57 -0400 Subject: [PATCH 053/276] Removed unneeded check for no args. --- koans/about_message_passing.rb | 1 - src/about_message_passing.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index 251e3621d..26e7b66f1 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -49,7 +49,6 @@ def test_classes_can_be_asked_if_they_know_how_to_respond class MessageCatcher def add_a_payload(*args) - return :empty unless args args end end diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 59e305674..047f52dcb 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -49,7 +49,6 @@ def test_classes_can_be_asked_if_they_know_how_to_respond class MessageCatcher def add_a_payload(*args) - return :empty unless args args end end From fbd36f6b0d317045f8f371c3ab6fdb335b8f42aa Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 13:59:58 -0400 Subject: [PATCH 054/276] Reworded question. --- src/about_constants.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/about_constants.rb b/src/about_constants.rb index b0913a7d7..5e1395997 100644 --- a/src/about_constants.rb +++ b/src/about_constants.rb @@ -20,7 +20,7 @@ def test_nested_constants_are_referenced_by_their_complete_path end # ------------------------------------------------------------------ - + class Animal LEGS = 4 def legs_in_animal @@ -33,25 +33,25 @@ def legs_in_nested_animal end end end - + def test_nested_classes_inherit_constants_from_enclosing_classes - assert_equal __(4), Animal::NestedAnimal.new.legs_in_nested_animal + 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 @@ -61,16 +61,16 @@ def legs_in_bird 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 @@ -83,5 +83,5 @@ def test_who_wins_with_explicit_scoping_on_class_definition # QUESTION: Now Which has precedence: The constant in the lexical # scope, or the constant from the inheritance heirarachy? Why is it - # different? + # different than the previous answer? end From 2c3b65ec79f6e458ee6bc724a667537c35842c5a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 14:40:37 -0400 Subject: [PATCH 055/276] Updated require with yucky File.dirname(__FILE__) hacks. --- src/about_array_assignment.rb | 2 +- src/about_arrays.rb | 2 +- src/about_asserts.rb | 2 +- src/about_blocks.rb | 2 +- src/about_class_methods.rb | 2 +- src/about_classes.rb | 2 +- src/about_constants.rb | 2 +- src/about_control_statements.rb | 2 +- src/about_dice_project.rb | 2 +- src/about_exceptions.rb | 2 +- src/about_hashes.rb | 2 +- src/about_inheritance.rb | 2 +- src/about_iteration.rb | 2 +- src/about_message_passing.rb | 2 +- src/about_methods.rb | 2 +- src/about_modules.rb | 2 +- src/about_nil.rb | 2 +- src/about_open_classes.rb | 2 +- src/about_proxy_object_project.rb | 2 +- src/about_sandwich_code.rb | 2 +- src/about_scope.rb | 2 +- src/about_scoring_project.rb | 2 +- src/about_strings.rb | 2 +- src/about_triangle_project.rb | 2 +- src/about_triangle_project_2.rb | 2 +- src/about_true_and_false.rb | 2 +- src/code_mash.rb | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 063c241b8..659ce6b26 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutArrayAssignment < EdgeCase::Koan def test_non_parallel_assignment diff --git a/src/about_arrays.rb b/src/about_arrays.rb index 680717bd2..7782ab9bd 100644 --- a/src/about_arrays.rb +++ b/src/about_arrays.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutArrays < EdgeCase::Koan def test_creating_arrays diff --git a/src/about_asserts.rb b/src/about_asserts.rb index 37253d431..5ac6b551f 100644 --- a/src/about_asserts.rb +++ b/src/about_asserts.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # -*- ruby -*- -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutAsserts < EdgeCase::Koan diff --git a/src/about_blocks.rb b/src/about_blocks.rb index eead2a79d..7330ca039 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutBlocks < EdgeCase::Koan def method_with_block diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index 0728c4743..930345d6a 100644 --- a/src/about_class_methods.rb +++ b/src/about_class_methods.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutClassMethods < EdgeCase::Koan class Dog diff --git a/src/about_classes.rb b/src/about_classes.rb index 11f253939..350c11295 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutClasses < EdgeCase::Koan class Dog diff --git a/src/about_constants.rb b/src/about_constants.rb index 5e1395997..ad780c698 100644 --- a/src/about_constants.rb +++ b/src/about_constants.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') C = "top level" diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index 7e2ca6f74..53ac6d891 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutControlStatements < EdgeCase::Koan diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index c1fccb14c..28066c527 100644 --- a/src/about_dice_project.rb +++ b/src/about_dice_project.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class DiceSet attr_reader :values diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index 936e00eda..e65ed82f4 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutExceptions < EdgeCase::Koan diff --git a/src/about_hashes.rb b/src/about_hashes.rb index ae85292d7..e74793fdf 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutHashes < EdgeCase::Koan def test_creating_hashes diff --git a/src/about_inheritance.rb b/src/about_inheritance.rb index 4f950da3c..f516cd602 100644 --- a/src/about_inheritance.rb +++ b/src/about_inheritance.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutInheritance < EdgeCase::Koan class Dog diff --git a/src/about_iteration.rb b/src/about_iteration.rb index ccdad0d7b..4c4daa6c2 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutIteration < EdgeCase::Koan diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 047f52dcb..389bd65e5 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutMessagePassing < EdgeCase::Koan diff --git a/src/about_methods.rb b/src/about_methods.rb index b8d108591..a31d37341 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') def my_global_method(a,b) a + b diff --git a/src/about_modules.rb b/src/about_modules.rb index 1e8558dd3..9e26d00aa 100644 --- a/src/about_modules.rb +++ b/src/about_modules.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutModules < EdgeCase::Koan module Nameable diff --git a/src/about_nil.rb b/src/about_nil.rb index 070e109e5..1e670a079 100644 --- a/src/about_nil.rb +++ b/src/about_nil.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutNil < EdgeCase::Koan def test_nil_is_an_object diff --git a/src/about_open_classes.rb b/src/about_open_classes.rb index 17a76007f..bef7effde 100644 --- a/src/about_open_classes.rb +++ b/src/about_open_classes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutOpenClasses < EdgeCase::Koan class Dog diff --git a/src/about_proxy_object_project.rb b/src/about_proxy_object_project.rb index 842356007..1d64f0f28 100644 --- a/src/about_proxy_object_project.rb +++ b/src/about_proxy_object_project.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') # Project: Create a Proxy Class # diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb index 1bbed9351..f3f4c9a34 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutUsingBlocks < EdgeCase::Koan diff --git a/src/about_scope.rb b/src/about_scope.rb index e322f17f0..097ffd3a4 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutScope < EdgeCase::Koan module Jims diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 0e78eb839..21b1d2856 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -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 diff --git a/src/about_strings.rb b/src/about_strings.rb index 6f1797a5c..f61d533b0 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -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 diff --git a/src/about_triangle_project.rb b/src/about_triangle_project.rb index 5c1855cf1..085113b84 100644 --- a/src/about_triangle_project.rb +++ b/src/about_triangle_project.rb @@ -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' diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index 34f748246..f9f39766f 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -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' diff --git a/src/about_true_and_false.rb b/src/about_true_and_false.rb index 724e825fc..4c99d99aa 100644 --- a/src/about_true_and_false.rb +++ b/src/about_true_and_false.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutTrueAndFalse < EdgeCase::Koan def truth_value(condition) diff --git a/src/code_mash.rb b/src/code_mash.rb index fe089a5ef..8fbf61788 100644 --- a/src/code_mash.rb +++ b/src/code_mash.rb @@ -1 +1 @@ -require 'edgecase' \ No newline at end of file +require File.expand_path(File.dirname(__FILE__) + '/edgecase') From 138bc7c9bcd6d2850c5bbda4cab78b050a0007df Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 14:59:04 -0400 Subject: [PATCH 056/276] Minor change to comment about regular expressions. --- src/about_strings.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_strings.rb b/src/about_strings.rb index f61d533b0..97a3877d9 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -166,7 +166,7 @@ def test_strings_can_be_split_with_different_patterns # 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. + # does not permit us to explore it in detail now. end def test_strings_can_be_joined From e8456fa3215439db68c3588dc6fda557dfdba996 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 15:03:44 -0400 Subject: [PATCH 057/276] Added current directory to rake runner. --- src/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rakefile b/src/Rakefile index 1a2c7f26d..171fffeb4 100644 --- a/src/Rakefile +++ b/src/Rakefile @@ -7,6 +7,6 @@ require 'rake/testtask' task :default => :test task :test do - ruby 'path_to_enlightenment.rb' + ruby '-I.', 'path_to_enlightenment.rb' end From 70462943437e1deee8e38ed13a49114abb8c594e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 15:05:20 -0400 Subject: [PATCH 058/276] Answers now Ruby 1.9 compliant --- src/about_classes.rb | 12 ++++++------ src/about_scope.rb | 6 +++--- src/about_strings.rb | 19 ++++++++++++++----- src/edgecase.rb | 24 ++++++++++++++++++------ 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/about_classes.rb b/src/about_classes.rb index 350c11295..30a2ca9ea 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -22,7 +22,7 @@ def test_instance_variables_can_be_set_by_assigning_to_them 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 @@ def test_you_can_politely_ask_for_instance_variable_values 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 @@ def test_attr_reader_will_automatically_define_an_accessor assert_equal __("Fido"), fido.name end - + # ------------------------------------------------------------------ class Dog5 @@ -125,7 +125,7 @@ def test_args_to_new_must_match_initialize # 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 @@ def test_inspect_provides_a_more_complete_string_version 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 diff --git a/src/about_scope.rb b/src/about_scope.rb index 097ffd3a4..796ff029b 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -28,7 +28,7 @@ def test_you_can_reference_nested_classes_using_the_scope_operator 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 String 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 @@ def test_constants_can_be_looked_up_explicitly end def test_you_can_get_a_list_of_constants_for_any_class_or_module - assert_equal __(["Dog"]), Jims.constants + assert_equal __(["Dog"], [:Dog]), Jims.constants assert Object.constants.size > _n_(10) end end diff --git a/src/about_strings.rb b/src/about_strings.rb index 97a3877d9..3dd0725bb 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -141,16 +141,25 @@ def test_you_can_get_a_substring_from_a_string 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_8_single_characters_are_represented_by_strings + assert_equal __('a'), ?a + assert_equal __(false), ?a == 97 + end end def test_strings_can_be_split diff --git a/src/edgecase.rb b/src/edgecase.rb index acb032b5b..0f92a6ba3 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -6,12 +6,24 @@ class FillMeInError < StandardError end -def __(value="FILL ME IN") - value +def in_ruby_version(version) + yield if RUBY_VERSION =~ /^#{version}/ end -def _n_(value=999999) - value +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) @@ -104,7 +116,7 @@ def say_something_zenlike end end end - end + end class Koan include Test::Unit::Assertions @@ -181,7 +193,7 @@ def command_line(args) load(arg) else fail "Unknown command line argument '#{arg}'" - end + end end end end From 8ef93f1d3ac5e067f904765c7668327661bb377d Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 15:06:12 -0400 Subject: [PATCH 059/276] UPdated koans to match latest source. --- koans/Rakefile | 2 +- koans/about_array_assignment.rb | 2 +- koans/about_arrays.rb | 2 +- koans/about_asserts.rb | 2 +- koans/about_blocks.rb | 2 +- koans/about_class_methods.rb | 2 +- koans/about_classes.rb | 10 +++++----- koans/about_constants.rb | 26 +++++++++++++------------- koans/about_control_statements.rb | 2 +- koans/about_dice_project.rb | 2 +- koans/about_exceptions.rb | 2 +- koans/about_hashes.rb | 2 +- koans/about_inheritance.rb | 2 +- koans/about_iteration.rb | 2 +- koans/about_message_passing.rb | 2 +- koans/about_methods.rb | 2 +- koans/about_modules.rb | 2 +- koans/about_nil.rb | 2 +- koans/about_open_classes.rb | 2 +- koans/about_proxy_object_project.rb | 2 +- koans/about_sandwich_code.rb | 2 +- koans/about_scope.rb | 6 +++--- koans/about_scoring_project.rb | 2 +- koans/about_strings.rb | 21 +++++++++++++++------ koans/about_triangle_project.rb | 2 +- koans/about_triangle_project_2.rb | 2 +- koans/about_true_and_false.rb | 2 +- koans/code_mash.rb | 2 +- koans/edgecase.rb | 24 ++++++++++++++++++------ 29 files changed, 78 insertions(+), 57 deletions(-) diff --git a/koans/Rakefile b/koans/Rakefile index 1a2c7f26d..171fffeb4 100644 --- a/koans/Rakefile +++ b/koans/Rakefile @@ -7,6 +7,6 @@ require 'rake/testtask' task :default => :test task :test do - ruby 'path_to_enlightenment.rb' + ruby '-I.', 'path_to_enlightenment.rb' end diff --git a/koans/about_array_assignment.rb b/koans/about_array_assignment.rb index 4e6cfeef1..12733fb29 100644 --- a/koans/about_array_assignment.rb +++ b/koans/about_array_assignment.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutArrayAssignment < EdgeCase::Koan def test_non_parallel_assignment diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb index 9b6b4a6c6..8dc4dfcbc 100644 --- a/koans/about_arrays.rb +++ b/koans/about_arrays.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutArrays < EdgeCase::Koan def test_creating_arrays diff --git a/koans/about_asserts.rb b/koans/about_asserts.rb index 53a42aa66..e1c34d44e 100644 --- a/koans/about_asserts.rb +++ b/koans/about_asserts.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # -*- ruby -*- -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutAsserts < EdgeCase::Koan diff --git a/koans/about_blocks.rb b/koans/about_blocks.rb index 08458f575..1bd2d133d 100644 --- a/koans/about_blocks.rb +++ b/koans/about_blocks.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutBlocks < EdgeCase::Koan def method_with_block diff --git a/koans/about_class_methods.rb b/koans/about_class_methods.rb index c768b00d0..8072166c5 100644 --- a/koans/about_class_methods.rb +++ b/koans/about_class_methods.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutClassMethods < EdgeCase::Koan class Dog diff --git a/koans/about_classes.rb b/koans/about_classes.rb index d576e4bbb..08858b88f 100644 --- a/koans/about_classes.rb +++ b/koans/about_classes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutClasses < EdgeCase::Koan class Dog @@ -43,7 +43,7 @@ def test_you_can_politely_ask_for_instance_variable_values 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 @@ def test_attr_reader_will_automatically_define_an_accessor assert_equal __, fido.name end - + # ------------------------------------------------------------------ class Dog5 @@ -125,7 +125,7 @@ def test_args_to_new_must_match_initialize # 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 @@ def test_all_objects_support_to_s_and_inspect assert_equal __, "STRING".to_s assert_equal __, "STRING".inspect end - + end diff --git a/koans/about_constants.rb b/koans/about_constants.rb index ae270edc6..0beccdcea 100644 --- a/koans/about_constants.rb +++ b/koans/about_constants.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') C = "top level" @@ -20,7 +20,7 @@ def test_nested_constants_are_referenced_by_their_complete_path end # ------------------------------------------------------------------ - + class Animal LEGS = 4 def legs_in_animal @@ -33,25 +33,25 @@ def legs_in_nested_animal end end end - + def test_nested_classes_inherit_constants_from_enclosing_classes - assert_equal __, Animal::NestedAnimal.new.legs_in_nested_animal + 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 @@ -61,16 +61,16 @@ def legs_in_bird 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 @@ -83,5 +83,5 @@ def test_who_wins_with_explicit_scoping_on_class_definition # QUESTION: Now Which has precedence: The constant in the lexical # scope, or the constant from the inheritance heirarachy? Why is it - # different? + # different than the previous answer? end diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index 8ecf88ee2..768dace43 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutControlStatements < EdgeCase::Koan diff --git a/koans/about_dice_project.rb b/koans/about_dice_project.rb index c1fccb14c..28066c527 100644 --- a/koans/about_dice_project.rb +++ b/koans/about_dice_project.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class DiceSet attr_reader :values diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index 6604e6cac..33b538a5c 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutExceptions < EdgeCase::Koan diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 05af65a4f..d491f6d06 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutHashes < EdgeCase::Koan def test_creating_hashes diff --git a/koans/about_inheritance.rb b/koans/about_inheritance.rb index 01dde2c8e..cafec3463 100644 --- a/koans/about_inheritance.rb +++ b/koans/about_inheritance.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutInheritance < EdgeCase::Koan class Dog diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 01808dcdb..608f1e924 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutIteration < EdgeCase::Koan diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index 26e7b66f1..d6c0bc4e3 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutMessagePassing < EdgeCase::Koan diff --git a/koans/about_methods.rb b/koans/about_methods.rb index 7f5c4871e..ecf72403d 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') def my_global_method(a,b) a + b diff --git a/koans/about_modules.rb b/koans/about_modules.rb index c18c81e30..c528c32fb 100644 --- a/koans/about_modules.rb +++ b/koans/about_modules.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutModules < EdgeCase::Koan module Nameable diff --git a/koans/about_nil.rb b/koans/about_nil.rb index af092e21d..5e1e28bfa 100644 --- a/koans/about_nil.rb +++ b/koans/about_nil.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutNil < EdgeCase::Koan def test_nil_is_an_object diff --git a/koans/about_open_classes.rb b/koans/about_open_classes.rb index 233cef507..afef1f956 100644 --- a/koans/about_open_classes.rb +++ b/koans/about_open_classes.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutOpenClasses < EdgeCase::Koan class Dog diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index f3d2a65bc..a959a8075 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') # Project: Create a Proxy Class # diff --git a/koans/about_sandwich_code.rb b/koans/about_sandwich_code.rb index 37f0c5fee..689e9014f 100644 --- a/koans/about_sandwich_code.rb +++ b/koans/about_sandwich_code.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutUsingBlocks < EdgeCase::Koan diff --git a/koans/about_scope.rb b/koans/about_scope.rb index e616ae01d..77fe668e5 100644 --- a/koans/about_scope.rb +++ b/koans/about_scope.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutScope < EdgeCase::Koan module Jims @@ -28,7 +28,7 @@ def test_you_can_reference_nested_classes_using_the_scope_operator 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 String 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 diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index e71423f3c..2e9c2070b 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -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 diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 48190dd7b..3d9037b6c 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -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 @@ def test_you_can_get_a_single_character_from_a_string # 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_8_single_characters_are_represented_by_strings + assert_equal __, ?a + assert_equal __, ?a == 97 + end end def test_strings_can_be_split @@ -166,7 +175,7 @@ def test_strings_can_be_split_with_different_patterns # 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. + # does not permit us to explore it in detail now. end def test_strings_can_be_joined diff --git a/koans/about_triangle_project.rb b/koans/about_triangle_project.rb index 5c1855cf1..085113b84 100644 --- a/koans/about_triangle_project.rb +++ b/koans/about_triangle_project.rb @@ -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' diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index 34f748246..f9f39766f 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.rb @@ -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' diff --git a/koans/about_true_and_false.rb b/koans/about_true_and_false.rb index 51922516e..d58564449 100644 --- a/koans/about_true_and_false.rb +++ b/koans/about_true_and_false.rb @@ -1,4 +1,4 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutTrueAndFalse < EdgeCase::Koan def truth_value(condition) diff --git a/koans/code_mash.rb b/koans/code_mash.rb index 1157de930..8fbf61788 100644 --- a/koans/code_mash.rb +++ b/koans/code_mash.rb @@ -1 +1 @@ -require 'edgecase' +require File.expand_path(File.dirname(__FILE__) + '/edgecase') diff --git a/koans/edgecase.rb b/koans/edgecase.rb index acb032b5b..0f92a6ba3 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -6,12 +6,24 @@ class FillMeInError < StandardError end -def __(value="FILL ME IN") - value +def in_ruby_version(version) + yield if RUBY_VERSION =~ /^#{version}/ end -def _n_(value=999999) - value +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) @@ -104,7 +116,7 @@ def say_something_zenlike end end end - end + end class Koan include Test::Unit::Assertions @@ -181,7 +193,7 @@ def command_line(args) load(arg) else fail "Unknown command line argument '#{arg}'" - end + end end end end From ee9a03740bfea903ce0580d5555c8ee4c709022e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 15:39:46 -0400 Subject: [PATCH 060/276] Setup load path in path_to_enlightenment, so -I not needed in Rakefile. --- src/Rakefile | 2 +- src/path_to_enlightenment.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Rakefile b/src/Rakefile index 171fffeb4..1a2c7f26d 100644 --- a/src/Rakefile +++ b/src/Rakefile @@ -7,6 +7,6 @@ require 'rake/testtask' task :default => :test task :test do - ruby '-I.', 'path_to_enlightenment.rb' + ruby 'path_to_enlightenment.rb' end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index 6a87bcb8f..ee57759e8 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -1,5 +1,7 @@ # The path to Ruby Enlightenment starts with the following: +$LOAD_PATH << File.dirname(__FILE__) + require 'about_asserts' require 'about_nil' require 'about_arrays' From c4549eb24b98590bae9e56230d2943bf9a87ad7d Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 15:40:54 -0400 Subject: [PATCH 061/276] Make method_missing public in the test framework for Ruby 1.9. --- src/about_message_passing.rb | 36 ++++++++++++++++++++++++------------ src/edgecase.rb | 4 ++++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 389bd65e5..c2b871501 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -1,28 +1,28 @@ 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,11 +40,11 @@ def test_send_with_underscores_will_also_send_messages 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 @@ -52,10 +52,10 @@ def add_a_payload(*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) @@ -89,6 +89,18 @@ def test_calling_method_missing_causes_the_no_method_error # # 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 # ------------------------------------------------------------------ diff --git a/src/edgecase.rb b/src/edgecase.rb index 0f92a6ba3..d0aa616fd 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -36,6 +36,10 @@ def ____(method=nil) self.send(method) end end + + in_ruby_version("1.9") do + public :method_missing + end end module EdgeCase From f2ac27f52e1d259366c1cdad474cd7ffeec8e770 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 16:53:56 -0400 Subject: [PATCH 062/276] Added support for minitest under Ruby 1.9. --- src/edgecase.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index d0aa616fd..a0c782c97 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -46,7 +46,13 @@ module EdgeCase 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 + AssertionError = MiniTest::Assertion + end def initialize @pass_count = 0 @@ -169,12 +175,12 @@ def run_test(method, accumulator) 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 From 6365c8d61d4f63affc1f6a6f82d4230a60e263e3 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 16:56:42 -0400 Subject: [PATCH 063/276] Now supporting Test::Unit as well under Ruby 1.9. --- src/edgecase.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index a0c782c97..71a70b91c 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -51,7 +51,11 @@ class Sensei end in_ruby_version("1.9") do - AssertionError = MiniTest::Assertion + if defined?(MiniTest) + AssertionError = MiniTest::Assertion + else + AssertionError = Test::Unit::AssertionFailedError + end end def initialize From eee3429394da62cc440a353c8dffa2c6f6c2cb0a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 16 Aug 2010 16:57:13 -0400 Subject: [PATCH 064/276] Updated the koans directory. --- koans/Rakefile | 2 +- koans/about_message_passing.rb | 36 ++++++++++++++++++++++------------ koans/edgecase.rb | 20 ++++++++++++++++--- koans/path_to_enlightenment.rb | 2 ++ 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/koans/Rakefile b/koans/Rakefile index 171fffeb4..1a2c7f26d 100644 --- a/koans/Rakefile +++ b/koans/Rakefile @@ -7,6 +7,6 @@ require 'rake/testtask' task :default => :test task :test do - ruby '-I.', 'path_to_enlightenment.rb' + ruby 'path_to_enlightenment.rb' end diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index d6c0bc4e3..45541a015 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -1,28 +1,28 @@ 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,11 +40,11 @@ def test_send_with_underscores_will_also_send_messages 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 @@ -52,10 +52,10 @@ def add_a_payload(*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) @@ -89,6 +89,18 @@ def test_calling_method_missing_causes_the_no_method_error # # 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 # ------------------------------------------------------------------ diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 0f92a6ba3..71a70b91c 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -36,13 +36,27 @@ def ____(method=nil) self.send(method) end end + + in_ruby_version("1.9") do + public :method_missing + end end module EdgeCase 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 @@ -165,12 +179,12 @@ def run_test(method, accumulator) 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 diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index 6a87bcb8f..ee57759e8 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -1,5 +1,7 @@ # The path to Ruby Enlightenment starts with the following: +$LOAD_PATH << File.dirname(__FILE__) + require 'about_asserts' require 'about_nil' require 'about_arrays' From 028e4a0c75cc513febca5faa634f6ce700f7dc7a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 17 Aug 2010 08:41:18 -0400 Subject: [PATCH 065/276] Updated README (tweeks words, whitespace cleanup) --- README.rdoc | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/README.rdoc b/README.rdoc index 307a4a9f7..f1e0f8e4a 100644 --- a/README.rdoc +++ b/README.rdoc @@ -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 ... 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 From 7c52931392923b866dab0a47e52781adb081374c Mon Sep 17 00:00:00 2001 From: Jonathan Castello Date: Sat, 21 Aug 2010 01:33:13 -0700 Subject: [PATCH 066/276] 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.) --- koans/about_strings.rb | 2 +- src/about_strings.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 3d9037b6c..87bb4ec0a 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -156,7 +156,7 @@ def test_in_ruby_1_8_single_characters_are_represented_by_integers end in_ruby_version("1.9") do - def test_in_ruby_1_8_single_characters_are_represented_by_strings + def test_in_ruby_1_9_single_characters_are_represented_by_strings assert_equal __, ?a assert_equal __, ?a == 97 end diff --git a/src/about_strings.rb b/src/about_strings.rb index 3dd0725bb..106ba7962 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -156,7 +156,7 @@ def test_in_ruby_1_8_single_characters_are_represented_by_integers end in_ruby_version("1.9") do - def test_in_ruby_1_8_single_characters_are_represented_by_strings + def test_in_ruby_1_9_single_characters_are_represented_by_strings assert_equal __('a'), ?a assert_equal __(false), ?a == 97 end From 7db19b5e922aa0db9524021657c2323305cd4f80 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 21 Aug 2010 09:01:10 -0400 Subject: [PATCH 067/276] White space fixes --- koans/README.rdoc | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/koans/README.rdoc b/koans/README.rdoc index 307a4a9f7..f1e0f8e4a 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -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 ... 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 From a5180d9ea17c3b8b46e9fad8904cce601c87fbb7 Mon Sep 17 00:00:00 2001 From: Jonathan Castello Date: Sat, 21 Aug 2010 11:32:57 -0700 Subject: [PATCH 068/276] Typo fix: changed "parenthesis" to "parentheses" --- koans/about_methods.rb | 4 ++-- src/about_methods.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/koans/about_methods.rb b/koans/about_methods.rb index ecf72403d..cbebd3049 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -10,14 +10,14 @@ def test_calling_global_methods 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: diff --git a/src/about_methods.rb b/src/about_methods.rb index a31d37341..3b6ad5748 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -10,14 +10,14 @@ def test_calling_global_methods 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 From e1ada6ca9f7e04c69592d7101e6fcf92ee9c2b61 Mon Sep 17 00:00:00 2001 From: James Edward Gray II Date: Sat, 21 Aug 2010 15:34:54 -0500 Subject: [PATCH 069/276] Fixing a bug that was causing some number Koans to be presolved. --- Rakefile | 1 + koans/about_class_methods.rb | 4 ++-- koans/about_scope.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index cb81bba39..614aad63d 100644 --- a/Rakefile +++ b/Rakefile @@ -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 diff --git a/koans/about_class_methods.rb b/koans/about_class_methods.rb index 8072166c5..ddd32bd51 100644 --- a/koans/about_class_methods.rb +++ b/koans/about_class_methods.rb @@ -19,11 +19,11 @@ def test_classes_are_objects_too def test_objects_have_methods fido = Dog.new - assert fido.methods.size > _n_(30) + assert fido.methods.size > _n_ end def test_classes_have_methods - assert Dog.methods.size > _n_(40) + assert Dog.methods.size > _n_ end def test_you_can_define_methods_on_individual_objects diff --git a/koans/about_scope.rb b/koans/about_scope.rb index 77fe668e5..edbe87662 100644 --- a/koans/about_scope.rb +++ b/koans/about_scope.rb @@ -74,6 +74,6 @@ def test_constants_can_be_looked_up_explicitly def test_you_can_get_a_list_of_constants_for_any_class_or_module assert_equal __, Jims.constants - assert Object.constants.size > _n_(10) + assert Object.constants.size > _n_ end end From 9a459a7eb30ed6f676e4a6e7311b11b73bd16f56 Mon Sep 17 00:00:00 2001 From: James Edward Gray II Date: Sat, 21 Aug 2010 22:11:06 -0500 Subject: [PATCH 070/276] Adding Regular Expression koans. --- koans/about_regular_expressions.rb | 158 +++++++++++++++++++++++++++++ koans/about_strings.rb | 4 +- koans/path_to_enlightenment.rb | 1 + src/about_regular_expressions.rb | 158 +++++++++++++++++++++++++++++ src/about_strings.rb | 4 +- src/path_to_enlightenment.rb | 1 + 6 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 koans/about_regular_expressions.rb create mode 100644 src/about_regular_expressions.rb diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb new file mode 100644 index 000000000..417cca528 --- /dev/null +++ b/koans/about_regular_expressions.rb @@ -0,0 +1,158 @@ +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 repition 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 diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 87bb4ec0a..f26e69995 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -174,8 +174,8 @@ def test_strings_can_be_split_with_different_patterns 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 now. + # very powerful Regular Expression library. We will become + # enlightened about them soon. end def test_strings_can_be_joined diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index ee57759e8..2e12c4643 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -8,6 +8,7 @@ require 'about_array_assignment' require 'about_hashes' require 'about_strings' +require 'about_regular_expressions' require 'about_methods' require 'about_constants' require 'about_control_statements' diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb new file mode 100644 index 000000000..967bc6ab2 --- /dev/null +++ b/src/about_regular_expressions.rb @@ -0,0 +1,158 @@ +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 repition 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 diff --git a/src/about_strings.rb b/src/about_strings.rb index 106ba7962..94211a996 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -174,8 +174,8 @@ def test_strings_can_be_split_with_different_patterns 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 now. + # very powerful Regular Expression library. We will become + # enlightened about them soon. end def test_strings_can_be_joined diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index ee57759e8..2e12c4643 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -8,6 +8,7 @@ require 'about_array_assignment' require 'about_hashes' require 'about_strings' +require 'about_regular_expressions' require 'about_methods' require 'about_constants' require 'about_control_statements' From 3aa75e86aa0101fd7020b157d43a2a07298bf2b5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 22 Aug 2010 01:55:02 -0400 Subject: [PATCH 071/276] Fixed spelling of repetition. --- src/about_regular_expressions.rb | 73 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb index 967bc6ab2..5c5f8fa63 100644 --- a/src/about_regular_expressions.rb +++ b/src/about_regular_expressions.rb @@ -1,34 +1,35 @@ +# -*- 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? @@ -36,101 +37,101 @@ def test_asterisk_means_zero_or_more # THINK ABOUT IT: # - # We say that the repition operators above are "greedy." - # + # 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] @@ -141,17 +142,17 @@ def test_a_vertical_pipe_means_or # 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 From 1b31a5b4dce22fa11c080b8e9508617df152f80b Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 22 Aug 2010 02:03:17 -0400 Subject: [PATCH 072/276] Updated koans from new regex section. --- koans/about_regular_expressions.rb | 73 +++++++++++++++--------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb index 417cca528..941b5e632 100644 --- a/koans/about_regular_expressions.rb +++ b/koans/about_regular_expressions.rb @@ -1,34 +1,35 @@ +# -*- 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? @@ -36,101 +37,101 @@ def test_asterisk_means_zero_or_more # THINK ABOUT IT: # - # We say that the repition operators above are "greedy." - # + # 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] @@ -141,17 +142,17 @@ def test_a_vertical_pipe_means_or # 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 From 05d5ab9a5edc857e4e95482f5ce581a240556050 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 26 Aug 2010 07:45:31 -0400 Subject: [PATCH 073/276] Added colors to output (based on renemendoza's patch). --- src/edgecase.rb | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 71a70b91c..3da9435f3 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -43,6 +43,18 @@ def ____(method=nil) end module EdgeCase + + module Color + #shamelessly stolen from redgreen + COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } + def self.method_missing(color_name, *args) + color(color_name) + args.first + color(:clear) + end + def self.color(color) + "\e[#{COLORS[color.to_sym]}m" + end + end + class Sensei attr_reader :failure, :failed_test @@ -67,9 +79,9 @@ def initialize 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 @@ -87,18 +99,19 @@ def assert_failed? 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(say_something_zenlike) end def find_interesting_lines(backtrace) @@ -112,23 +125,24 @@ def find_interesting_lines(backtrace) def say_something_zenlike 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 @@ -168,7 +182,7 @@ def method_added(name) 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 From f88e9f1dfc1f88f2a52e159d6ba818cf405706cc Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 26 Aug 2010 07:53:22 -0400 Subject: [PATCH 074/276] Removed method missing from color module. --- src/edgecase.rb | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 3da9435f3..27180326f 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -47,12 +47,18 @@ module EdgeCase module Color #shamelessly stolen from redgreen COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } - def self.method_missing(color_name, *args) - color(color_name) + args.first + color(:clear) - end - def self.color(color) - "\e[#{COLORS[color.to_sym]}m" - end + + COLORS.each do |color, value| + class_eval "def self.#{color}(string); colorize(string, #{value}); end" + end + + def self.colorize(string, color_value) + color(color_value) + string + color(COLORS[:clear]) + end + + def self.color(color_value) + "\e[#{color_value}m" + end end class Sensei From d17cc7b45704091447bf2c20e5475a879bb74e24 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 26 Aug 2010 07:55:04 -0400 Subject: [PATCH 075/276] Disable colorization when the NO_COLOR env variable is defined. --- src/edgecase.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 27180326f..33cb88912 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -53,7 +53,11 @@ module Color end def self.colorize(string, color_value) - color(color_value) + string + color(COLORS[:clear]) + if ENV['NO_COLOR'] + string + else + color(color_value) + string + color(COLORS[:clear]) + end end def self.color(color_value) From bc558539838b8a615c477e15f609e8c8a6191069 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 26 Aug 2010 07:57:28 -0400 Subject: [PATCH 076/276] Updated comment --- src/edgecase.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 33cb88912..add1aa746 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -45,7 +45,7 @@ def ____(method=nil) module EdgeCase module Color - #shamelessly stolen from redgreen + #shamelessly stolen (and modified) from redgreen COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } COLORS.each do |color, value| From 36f93c6c636789339353f012da1a1b65fd000fbd Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 26 Aug 2010 07:58:28 -0400 Subject: [PATCH 077/276] Updated koans with changed from src. --- koans/edgecase.rb | 58 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 71a70b91c..add1aa746 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -43,6 +43,28 @@ def ____(method=nil) end module EdgeCase + + module Color + #shamelessly stolen (and modified) from redgreen + COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } + + COLORS.each do |color, value| + class_eval "def self.#{color}(string); colorize(string, #{value}); end" + end + + def self.colorize(string, color_value) + if ENV['NO_COLOR'] + string + else + color(color_value) + string + color(COLORS[:clear]) + end + end + + def self.color(color_value) + "\e[#{color_value}m" + end + end + class Sensei attr_reader :failure, :failed_test @@ -67,9 +89,9 @@ def initialize 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 @@ -87,18 +109,19 @@ def assert_failed? 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(say_something_zenlike) end def find_interesting_lines(backtrace) @@ -112,23 +135,24 @@ def find_interesting_lines(backtrace) def say_something_zenlike 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 @@ -168,7 +192,7 @@ def method_added(name) 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 From e6fc8f64346ac0f57aef78f7476023fe2c5f3a23 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 27 Aug 2010 09:11:51 -0400 Subject: [PATCH 078/276] Renamed method --- src/edgecase.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index add1aa746..3c9a94954 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -121,7 +121,7 @@ def report end puts end - puts Color.green(say_something_zenlike) + puts Color.green(a_zenlike_statement) end def find_interesting_lines(backtrace) @@ -132,7 +132,7 @@ def find_interesting_lines(backtrace) # 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? zen_statement = "Mountains are again merely mountains" From bc1a20a31043b4f3776b9dd80dd8fe595e528385 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 27 Aug 2010 09:25:10 -0400 Subject: [PATCH 079/276] Tweeks on the color module --- src/edgecase.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 3c9a94954..99cefc7f2 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -46,13 +46,20 @@ module EdgeCase module Color #shamelessly stolen (and modified) from redgreen - COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } + COLORS = { + :clear => 0, :black => 30, :red => 31, + :green => 32, :yellow => 33, :blue => 34, + :magenta => 35, :cyan => 36, + } + + module_function COLORS.each do |color, value| - class_eval "def self.#{color}(string); colorize(string, #{value}); end" + module_eval "def #{color}(string); colorize(string, #{value}); end" + module_function color end - def self.colorize(string, color_value) + def colorize(string, color_value) if ENV['NO_COLOR'] string else @@ -60,7 +67,7 @@ def self.colorize(string, color_value) end end - def self.color(color_value) + def color(color_value) "\e[#{color_value}m" end end From 06c47eb2842d3bbea9909f2d55d5f3fb66b3c27e Mon Sep 17 00:00:00 2001 From: Rene Mendoza Date: Wed, 25 Aug 2010 17:58:14 -0500 Subject: [PATCH 080/276] Added autotest support and added colorized output of tests --- koans/autotest/discover.rb | 3 +++ koans/autotest/rubykoan.rb | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 koans/autotest/discover.rb create mode 100644 koans/autotest/rubykoan.rb diff --git a/koans/autotest/discover.rb b/koans/autotest/discover.rb new file mode 100644 index 000000000..31a7804b2 --- /dev/null +++ b/koans/autotest/discover.rb @@ -0,0 +1,3 @@ +Autotest.add_discovery do + "rubykoan" if File.exist? 'path_to_enlightenment.rb' +end diff --git a/koans/autotest/rubykoan.rb b/koans/autotest/rubykoan.rb new file mode 100644 index 000000000..d43dc9112 --- /dev/null +++ b/koans/autotest/rubykoan.rb @@ -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 + From 1f6c0e03a5678fcfafc032c4a9c58bfa8c6f14a9 Mon Sep 17 00:00:00 2001 From: Rene Mendoza Date: Thu, 26 Aug 2010 20:01:37 -0500 Subject: [PATCH 081/276] Color support for Ruby Koans --- koans/autotest/discover.rb | 3 --- koans/autotest/rubykoan.rb | 24 ------------------------ koans/edgecase.rb | 37 +++++++++++++++++-------------------- 3 files changed, 17 insertions(+), 47 deletions(-) delete mode 100644 koans/autotest/discover.rb delete mode 100644 koans/autotest/rubykoan.rb diff --git a/koans/autotest/discover.rb b/koans/autotest/discover.rb deleted file mode 100644 index 31a7804b2..000000000 --- a/koans/autotest/discover.rb +++ /dev/null @@ -1,3 +0,0 @@ -Autotest.add_discovery do - "rubykoan" if File.exist? 'path_to_enlightenment.rb' -end diff --git a/koans/autotest/rubykoan.rb b/koans/autotest/rubykoan.rb deleted file mode 100644 index d43dc9112..000000000 --- a/koans/autotest/rubykoan.rb +++ /dev/null @@ -1,24 +0,0 @@ -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 - diff --git a/koans/edgecase.rb b/koans/edgecase.rb index add1aa746..8cf180bfa 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -43,7 +43,6 @@ def ____(method=nil) end module EdgeCase - module Color #shamelessly stolen (and modified) from redgreen COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } @@ -89,9 +88,9 @@ def initialize def accumulate(test) if test.passed? @pass_count += 1 - puts Color.green(" #{test.name} has expanded your awareness.") + puts " #{test.name} has expanded your awareness." else - puts Color.red(" #{test.name} has damaged your karma.") + puts " #{test.name} has damaged your karma." @failed_test = test @failure = test.failure throw :edgecase_exit @@ -109,19 +108,18 @@ def assert_failed? def report if failed? puts - puts Color.green("You have not yet reached enlightenment ...") - puts Color.red(failure.message) + puts "You have not yet reached enlightenment ..." + puts failure.message puts - puts Color.green("Please meditate on the following code:") + puts "Please meditate on the following code:" if assert_failed? - #puts find_interesting_lines(failure.backtrace) - puts find_interesting_lines(failure.backtrace).collect {|l| Color.red(l) } + puts find_interesting_lines(failure.backtrace) else - puts Color.red(failure.backtrace) + puts failure.backtrace end puts end - puts Color.green(say_something_zenlike) + say_something_zenlike end def find_interesting_lines(backtrace) @@ -135,24 +133,23 @@ def find_interesting_lines(backtrace) def say_something_zenlike puts if !failed? - zen_statement = "Mountains are again merely mountains" + puts "Mountains are again merely mountains" else - zen_statement = case (@pass_count % 10) + case (@pass_count % 10) when 0 - "mountains are merely mountains" + puts "mountains are merely mountains" when 1, 2 - "learn the rules so you know how to break them properly" + puts "learn the rules so you know how to break them properly" when 3, 4 - "remember that silence is sometimes the best answer" + puts "remember that silence is sometimes the best answer" when 5, 6 - "sleep is the best meditation" + puts "sleep is the best meditation" when 7, 8 - "when you lose, don't lose the lesson" + puts "when you lose, don't lose the lesson" else - "things are not what they appear to be: nor are they otherwise" + puts "things are not what they appear to be: nor are they otherwise" end end - zen_statement end end @@ -192,7 +189,7 @@ def method_added(name) def run_tests(accumulator) puts - puts Color.green("Thinking #{self}") + puts "Thinking #{self}" testmethods.each do |m| self.run_test(m, accumulator) if Koan.test_pattern =~ m.to_s end From ed2ef0f4392398ddd4a9acea4a35565639401763 Mon Sep 17 00:00:00 2001 From: Rene Mendoza Date: Thu, 26 Aug 2010 20:14:26 -0500 Subject: [PATCH 082/276] Added autotest support to RubyKoans --- Rakefile | 2 ++ src/autotest/discover.rb | 3 +++ src/autotest/rubykoan.rb | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 src/autotest/discover.rb create mode 100644 src/autotest/rubykoan.rb diff --git a/Rakefile b/Rakefile index 614aad63d..8fccbbd6d 100644 --- a/Rakefile +++ b/Rakefile @@ -29,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| diff --git a/src/autotest/discover.rb b/src/autotest/discover.rb new file mode 100644 index 000000000..31a7804b2 --- /dev/null +++ b/src/autotest/discover.rb @@ -0,0 +1,3 @@ +Autotest.add_discovery do + "rubykoan" if File.exist? 'path_to_enlightenment.rb' +end diff --git a/src/autotest/rubykoan.rb b/src/autotest/rubykoan.rb new file mode 100644 index 000000000..d43dc9112 --- /dev/null +++ b/src/autotest/rubykoan.rb @@ -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 + From b0a01786f42bfd26da6eea5709a8fc7938e4f80f Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 27 Aug 2010 09:44:10 -0400 Subject: [PATCH 083/276] Updated koan directory from src. --- koans/autotest/discover.rb | 3 +++ koans/autotest/rubykoan.rb | 24 +++++++++++++++++ koans/edgecase.rb | 54 ++++++++++++++++++++++---------------- 3 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 koans/autotest/discover.rb create mode 100644 koans/autotest/rubykoan.rb diff --git a/koans/autotest/discover.rb b/koans/autotest/discover.rb new file mode 100644 index 000000000..31a7804b2 --- /dev/null +++ b/koans/autotest/discover.rb @@ -0,0 +1,3 @@ +Autotest.add_discovery do + "rubykoan" if File.exist? 'path_to_enlightenment.rb' +end diff --git a/koans/autotest/rubykoan.rb b/koans/autotest/rubykoan.rb new file mode 100644 index 000000000..d43dc9112 --- /dev/null +++ b/koans/autotest/rubykoan.rb @@ -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 + diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 8cf180bfa..99cefc7f2 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -43,15 +43,23 @@ def ____(method=nil) end module EdgeCase + module Color #shamelessly stolen (and modified) from redgreen - COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33, :blue => 34, :magenta => 35, :cyan => 36 } + COLORS = { + :clear => 0, :black => 30, :red => 31, + :green => 32, :yellow => 33, :blue => 34, + :magenta => 35, :cyan => 36, + } + + module_function COLORS.each do |color, value| - class_eval "def self.#{color}(string); colorize(string, #{value}); end" + module_eval "def #{color}(string); colorize(string, #{value}); end" + module_function color end - def self.colorize(string, color_value) + def colorize(string, color_value) if ENV['NO_COLOR'] string else @@ -59,7 +67,7 @@ def self.colorize(string, color_value) end end - def self.color(color_value) + def color(color_value) "\e[#{color_value}m" end end @@ -88,9 +96,9 @@ def initialize 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 @@ -108,18 +116,19 @@ def assert_failed? 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) @@ -130,26 +139,27 @@ def find_interesting_lines(backtrace) # 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 @@ -189,7 +199,7 @@ def method_added(name) 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 From b0e34a90e093733ad84c3fe90c32e0e7de2a36dd Mon Sep 17 00:00:00 2001 From: Greg Mefford Date: Sun, 12 Sep 2010 17:07:22 -0400 Subject: [PATCH 084/276] Cleaned up some messy File housekeeping. --- koans/about_iteration.rb | 9 +++------ src/about_iteration.rb | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 608f1e924..83b5a28d5 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -78,16 +78,13 @@ def test_all_iteration_methods_work_on_any_collection_not_just_arrays assert_equal __, result # Files act like a collection of lines - file = File.open("example_file.txt") - upcase_lines = file.map { |line| line.strip.upcase } + upcase_lines = File.open("example_file.txt") do |file| + file.map { |line| line.strip.upcase } + end assert_equal __, upcase_lines # NOTE: You can create your own collections that work with each, # map, select, etc. - ensure - # Arg, this is ugly. - # We will figure out how to fix this later. - file.close if file end end diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 4c4daa6c2..e995a5e01 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -78,16 +78,13 @@ def test_all_iteration_methods_work_on_any_collection_not_just_arrays assert_equal __([11, 12, 13]), result # Files act like a collection of lines - file = File.open("example_file.txt") - upcase_lines = file.map { |line| line.strip.upcase } + upcase_lines = File.open("example_file.txt") do |file| + file.map { |line| line.strip.upcase } + end assert_equal __(["THIS", "IS", "A", "TEST"]), upcase_lines # NOTE: You can create your own collections that work with each, # map, select, etc. - ensure - # Arg, this is ugly. - # We will figure out how to fix this later. - file.close if file end end From 28eec8cc419defd26db41cfbfafecac4a6e3a41b Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:25:42 -0400 Subject: [PATCH 085/276] Ignoring project env rc file. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1521c8b76..1487603e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ dist +.project_env.rc From 0c18e9742f719770d5f277e1e13743e1ad08c84c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:26:49 -0400 Subject: [PATCH 086/276] Simplified file read example. --- src/about_iteration.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index e995a5e01..8a738ab6e 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -78,10 +78,10 @@ def test_all_iteration_methods_work_on_any_collection_not_just_arrays assert_equal __([11, 12, 13]), result # Files act like a collection of lines - upcase_lines = File.open("example_file.txt") do |file| - file.map { |line| line.strip.upcase } + File.open("example_file.txt") do |file| + upcase_lines = file.map { |line| line.strip.upcase } + assert_equal __(["THIS", "IS", "A", "TEST"]), upcase_lines end - assert_equal __(["THIS", "IS", "A", "TEST"]), upcase_lines # NOTE: You can create your own collections that work with each, # map, select, etc. From 8d8287365b8ab8541797ccb91866605357f278a2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:27:01 -0400 Subject: [PATCH 087/276] Added bonus question about the file read. --- src/about_iteration.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 8a738ab6e..08071baf3 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -87,4 +87,17 @@ def test_all_iteration_methods_work_on_any_collection_not_just_arrays # map, select, etc. end + # Bonus Question: In the previous koan, we saw the construct: + # + # File.open(filename) do |file| + # # code to read 'file' + # end + # + # Why did we do it that way instead of the following? + # + # file = File.open(filename) + # # code to read 'file' + # + # When you get to the "AboutSandwichCode" koan, recheck your answer. + end From ad99c372c32408daee9f5c95d38f2ad736bce621 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:27:22 -0400 Subject: [PATCH 088/276] Normalized file name and koan category name. --- src/about_dice_project.rb | 2 +- src/about_sandwich_code.rb | 4 ++-- src/about_scoring_project.rb | 4 ++-- src/about_triangle_project.rb | 4 ++-- src/about_triangle_project_2.rb | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index 28066c527..a01236a66 100644 --- a/src/about_dice_project.rb +++ b/src/about_dice_project.rb @@ -7,7 +7,7 @@ def roll(n) end end -class AboutDiceSet < EdgeCase::Koan +class AboutDiceProject < EdgeCase::Koan def test_can_create_a_dice_set dice = DiceSet.new assert_not_nil dice diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb index f3f4c9a34..07be3fcc9 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -1,6 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') -class AboutUsingBlocks < EdgeCase::Koan +class AboutSandwichCode < EdgeCase::Koan def count_lines(file_name) file = open(file_name) @@ -93,7 +93,7 @@ def find_line2(file_name) def test_finding_lines2 assert_equal __("test\n"), find_line2("example_file.txt") end - + # ------------------------------------------------------------------ def count_lines3(file_name) diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 21b1d2856..124c38744 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -7,7 +7,7 @@ # A greed roll is scored as follows: # # * A set of three ones is 1000 points -# +# # * A set of three numbers (other than ones) is worth 100 times the # number. (e.g. three fives is 500 points). # @@ -54,7 +54,7 @@ def score(dice) #++ end -class AboutScoringAssignment < EdgeCase::Koan +class AboutScoringProject < EdgeCase::Koan def test_score_of_an_empty_list_is_zero assert_equal 0, score([]) end diff --git a/src/about_triangle_project.rb b/src/about_triangle_project.rb index 085113b84..da23bbd78 100644 --- a/src/about_triangle_project.rb +++ b/src/about_triangle_project.rb @@ -3,7 +3,7 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment < EdgeCase::Koan +class AboutTriangleProject < EdgeCase::Koan def test_equilateral_triangles_have_equal_sides assert_equal :equilateral, triangle(2, 2, 2) assert_equal :equilateral, triangle(10, 10, 10) @@ -22,4 +22,4 @@ def test_scalene_triangles_have_no_equal_sides assert_equal :scalene, triangle(5, 4, 2) end end - + diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index f9f39766f..c48c3cb68 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -3,14 +3,14 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment2 < EdgeCase::Koan +class AboutTriangleProject2 < EdgeCase::Koan # The first assignment did not talk about how to handle errors. # Let's handle that part now. 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 + assert_raise(TriangleError) do triangle(2, 4, 2) end end end - + From 0794235441f37421030f91fc9551919a55965468 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:32:55 -0400 Subject: [PATCH 089/276] Removed utf-8 character in comments. --- src/about_regular_expressions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb index 5c5f8fa63..01e39f2cd 100644 --- a/src/about_regular_expressions.rb +++ b/src/about_regular_expressions.rb @@ -141,7 +141,7 @@ def test_a_vertical_pipe_means_or # THINK ABOUT IT: # - # Explain the difference between a character class ([…]) and alternation (|). + # Explain the difference between a character class ([...]) and alternation (|). # ------------------------------------------------------------------ From 57f0f4f1788f4c7ee5d7708c2720993feb4df399 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 12 Sep 2010 21:33:11 -0400 Subject: [PATCH 090/276] Updated koans from source. --- koans/about_dice_project.rb | 2 +- koans/about_iteration.rb | 19 ++++++++++++++++--- koans/about_regular_expressions.rb | 2 +- koans/about_sandwich_code.rb | 4 ++-- koans/about_scoring_project.rb | 4 ++-- koans/about_triangle_project.rb | 4 ++-- koans/about_triangle_project_2.rb | 6 +++--- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/koans/about_dice_project.rb b/koans/about_dice_project.rb index 28066c527..a01236a66 100644 --- a/koans/about_dice_project.rb +++ b/koans/about_dice_project.rb @@ -7,7 +7,7 @@ def roll(n) end end -class AboutDiceSet < EdgeCase::Koan +class AboutDiceProject < EdgeCase::Koan def test_can_create_a_dice_set dice = DiceSet.new assert_not_nil dice diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 83b5a28d5..1b64cbe46 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -78,13 +78,26 @@ def test_all_iteration_methods_work_on_any_collection_not_just_arrays assert_equal __, result # Files act like a collection of lines - upcase_lines = File.open("example_file.txt") do |file| - file.map { |line| line.strip.upcase } + File.open("example_file.txt") do |file| + upcase_lines = file.map { |line| line.strip.upcase } + assert_equal __, upcase_lines end - assert_equal __, upcase_lines # NOTE: You can create your own collections that work with each, # map, select, etc. end + # Bonus Question: In the previous koan, we saw the construct: + # + # File.open(filename) do |file| + # # code to read 'file' + # end + # + # Why did we do it that way instead of the following? + # + # file = File.open(filename) + # # code to read 'file' + # + # When you get to the "AboutSandwichCode" koan, recheck your answer. + end diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb index 941b5e632..c35d757d7 100644 --- a/koans/about_regular_expressions.rb +++ b/koans/about_regular_expressions.rb @@ -141,7 +141,7 @@ def test_a_vertical_pipe_means_or # THINK ABOUT IT: # - # Explain the difference between a character class ([…]) and alternation (|). + # Explain the difference between a character class ([...]) and alternation (|). # ------------------------------------------------------------------ diff --git a/koans/about_sandwich_code.rb b/koans/about_sandwich_code.rb index 689e9014f..614a3740b 100644 --- a/koans/about_sandwich_code.rb +++ b/koans/about_sandwich_code.rb @@ -1,6 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') -class AboutUsingBlocks < EdgeCase::Koan +class AboutSandwichCode < EdgeCase::Koan def count_lines(file_name) file = open(file_name) @@ -86,7 +86,7 @@ def find_line2(file_name) def test_finding_lines2 assert_equal __, find_line2("example_file.txt") end - + # ------------------------------------------------------------------ def count_lines3(file_name) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index 2e9c2070b..3c8e0274a 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -7,7 +7,7 @@ # A greed roll is scored as follows: # # * A set of three ones is 1000 points -# +# # * A set of three numbers (other than ones) is worth 100 times the # number. (e.g. three fives is 500 points). # @@ -33,7 +33,7 @@ def score(dice) # You need to write this method end -class AboutScoringAssignment < EdgeCase::Koan +class AboutScoringProject < EdgeCase::Koan def test_score_of_an_empty_list_is_zero assert_equal 0, score([]) end diff --git a/koans/about_triangle_project.rb b/koans/about_triangle_project.rb index 085113b84..da23bbd78 100644 --- a/koans/about_triangle_project.rb +++ b/koans/about_triangle_project.rb @@ -3,7 +3,7 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment < EdgeCase::Koan +class AboutTriangleProject < EdgeCase::Koan def test_equilateral_triangles_have_equal_sides assert_equal :equilateral, triangle(2, 2, 2) assert_equal :equilateral, triangle(10, 10, 10) @@ -22,4 +22,4 @@ def test_scalene_triangles_have_no_equal_sides assert_equal :scalene, triangle(5, 4, 2) end end - + diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index f9f39766f..c48c3cb68 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.rb @@ -3,14 +3,14 @@ # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleAssignment2 < EdgeCase::Koan +class AboutTriangleProject2 < EdgeCase::Koan # The first assignment did not talk about how to handle errors. # Let's handle that part now. 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 + assert_raise(TriangleError) do triangle(2, 4, 2) end end end - + From 1597b2f912dbd60b8ef81400ddacbb472929eadf Mon Sep 17 00:00:00 2001 From: Erik Ogan Date: Sun, 19 Sep 2010 16:52:26 -0700 Subject: [PATCH 091/276] minor grammar nit --- koans/about_blocks.rb | 2 +- src/about_blocks.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_blocks.rb b/koans/about_blocks.rb index 1bd2d133d..0abee8f9b 100644 --- a/koans/about_blocks.rb +++ b/koans/about_blocks.rb @@ -60,7 +60,7 @@ def test_methods_can_see_if_they_have_been_called_with_a_block # ------------------------------------------------------------------ - def test_block_can_effect_variables_in_the_code_where_they_are_created + def test_block_can_affect_variables_in_the_code_where_they_are_created value = :initial_value method_with_block { value = :modified_in_a_block } assert_equal __, value diff --git a/src/about_blocks.rb b/src/about_blocks.rb index 7330ca039..7fefcd907 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -60,7 +60,7 @@ def test_methods_can_see_if_they_have_been_called_with_a_block # ------------------------------------------------------------------ - def test_block_can_effect_variables_in_the_code_where_they_are_created + def test_block_can_affect_variables_in_the_code_where_they_are_created value = :initial_value method_with_block { value = :modified_in_a_block } assert_equal __(:modified_in_a_block), value From 18cccf33fb2beaba9760a7e9d3bb612015cdf93a Mon Sep 17 00:00:00 2001 From: Matt Yoho Date: Tue, 21 Sep 2010 11:52:47 -0400 Subject: [PATCH 092/276] Add about_symbols koan --- koans/about_symbols.rb | 68 ++++++++++++++++++++++++++++++++++ koans/path_to_enlightenment.rb | 1 + src/about_symbols.rb | 68 ++++++++++++++++++++++++++++++++++ src/path_to_enlightenment.rb | 1 + 4 files changed, 138 insertions(+) create mode 100644 koans/about_symbols.rb create mode 100644 src/about_symbols.rb diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb new file mode 100644 index 000000000..978a0e041 --- /dev/null +++ b/koans/about_symbols.rb @@ -0,0 +1,68 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutSymbols < EdgeCase::Koan + def test_symbols_are_symbols + symbol = :ruby + assert_equal __, symbol.is_a?(Symbol) + end + + def test_symbols_are_not_strings + symbol = :ruby + assert_equal __, symbol.is_a?(String) + assert_equal __, symbol.eql?("ruby") + end + + def test_symbols_have_unique_identity + symbol1 = :identity + symbol2 = :identity + symbol3 = :something_else + + assert symbol1 == __ + assert symbol1 != __ + end + + def test_identical_symbols_are_represented_by_a_single_internal_object + symbol1 = :identity + symbol2 = :identity + + assert symbol1.equal?(__) + assert_equal __, symbol2.object_id + end + + def test_method_names_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal __, all_symbols.include?(:test_method_names_are_symbols) + end + + RubyConstant = "This string is assigned to a constant." + def test_constants_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal true, all_symbols.include?(__) + end + + def test_symbols_can_be_made_from_strings + string = "catsAndDogs" + assert_equal __, string.to_sym + end + + def test_symbols_with_spaces_can_by_built + symbol = :"cats and dogs" + + assert_equal symbol, __.to_sym + end + + def test_interpolated_symbols_become_strings + symbol = :cats + string = "It is raining #{symbol} and dogs." + + assert_equal __, string + end + + def test_symbols_cannot_be_concatenated + assert_raise(__) do + :cats + :dogs + end + end +end diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index 2e12c4643..f7e0773ec 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -8,6 +8,7 @@ require 'about_array_assignment' require 'about_hashes' require 'about_strings' +require 'about_symbols' require 'about_regular_expressions' require 'about_methods' require 'about_constants' diff --git a/src/about_symbols.rb b/src/about_symbols.rb new file mode 100644 index 000000000..65cd44960 --- /dev/null +++ b/src/about_symbols.rb @@ -0,0 +1,68 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutSymbols < EdgeCase::Koan + def test_symbols_are_symbols + symbol = :ruby + assert_equal __(true), symbol.is_a?(Symbol) + end + + def test_symbols_are_not_strings + symbol = :ruby + assert_equal __(false), symbol.is_a?(String) + assert_equal __(false), symbol.eql?("ruby") + end + + def test_symbols_have_unique_identity + symbol1 = :identity + symbol2 = :identity + symbol3 = :something_else + + assert symbol1 == __(symbol2) + assert symbol1 != __(symbol2) + end + + def test_identical_symbols_are_represented_by_a_single_internal_object + symbol1 = :identity + symbol2 = :identity + + assert symbol1.equal?(__(symbol2)) + assert_equal __(symbol1.object_id), symbol2.object_id + end + + def test_method_names_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal __(true), all_symbols.include?(:test_method_names_are_symbols) + end + + RubyConstant = "This string is assigned to a constant." + def test_constants_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal true, all_symbols.include?(__(:RubyConstant)) + end + + def test_symbols_can_be_made_from_strings + string = "catsAndDogs" + assert_equal __(:catsAndDogs), string.to_sym + end + + def test_symbols_with_spaces_can_by_built + symbol = :"cats and dogs" + + assert_equal symbol, __("cats and dogs").to_sym + end + + def test_interpolated_symbols_become_strings + symbol = :cats + string = "It is raining #{symbol} and dogs." + + assert_equal __('It is raining cats and dogs.'), string + end + + def test_symbols_cannot_be_concatenated + assert_raise(__(NoMethodError)) do + :cats + :dogs + end + end +end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index 2e12c4643..f7e0773ec 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -8,6 +8,7 @@ require 'about_array_assignment' require 'about_hashes' require 'about_strings' +require 'about_symbols' require 'about_regular_expressions' require 'about_methods' require 'about_constants' From a36c3b7a4db14d669ba3608318f5d389f0c0b7ac Mon Sep 17 00:00:00 2001 From: Daniel Parker Date: Tue, 21 Sep 2010 17:41:09 +0100 Subject: [PATCH 093/276] Fixed typo --- koans/about_symbols.rb | 2 +- src/about_symbols.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 978a0e041..6e45f16c1 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -47,7 +47,7 @@ def test_symbols_can_be_made_from_strings assert_equal __, string.to_sym end - def test_symbols_with_spaces_can_by_built + def test_symbols_with_spaces_can_be_built symbol = :"cats and dogs" assert_equal symbol, __.to_sym diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 65cd44960..1b01168d2 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -47,7 +47,7 @@ def test_symbols_can_be_made_from_strings assert_equal __(:catsAndDogs), string.to_sym end - def test_symbols_with_spaces_can_by_built + def test_symbols_with_spaces_can_be_built symbol = :"cats and dogs" assert_equal symbol, __("cats and dogs").to_sym From aa09d1763096bc8a52163d877ff5ac22d63741ef Mon Sep 17 00:00:00 2001 From: Matt Yoho Date: Tue, 21 Sep 2010 15:29:21 -0400 Subject: [PATCH 094/276] Clean up about_koans and add another example --- koans/about_symbols.rb | 37 +++++++++++++++++++++++-------------- src/about_symbols.rb | 39 ++++++++++++++++++++++++--------------- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 6e45f16c1..2aad1940e 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -6,24 +6,18 @@ def test_symbols_are_symbols assert_equal __, symbol.is_a?(Symbol) end - def test_symbols_are_not_strings - symbol = :ruby - assert_equal __, symbol.is_a?(String) - assert_equal __, symbol.eql?("ruby") - end - - def test_symbols_have_unique_identity - symbol1 = :identity - symbol2 = :identity + def test_symbols_can_be_compared + symbol1 = :a_symbol + symbol2 = :a_symbol symbol3 = :something_else assert symbol1 == __ assert symbol1 != __ end - def test_identical_symbols_are_represented_by_a_single_internal_object - symbol1 = :identity - symbol2 = :identity + def test_identical_symbols_are_a_single_internal_object + symbol1 = :a_symbol + symbol2 = :a_symbol assert symbol1.equal?(__) assert_equal __, symbol2.object_id @@ -35,7 +29,7 @@ def test_method_names_become_symbols assert_equal __, all_symbols.include?(:test_method_names_are_symbols) end - RubyConstant = "This string is assigned to a constant." + RubyConstant = "What is the sound of one hand clapping?" def test_constants_become_symbols all_symbols = Symbol.all_symbols @@ -53,14 +47,29 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __.to_sym end - def test_interpolated_symbols_become_strings + def test_to_s_is_called_on_interpolated_symbols symbol = :cats string = "It is raining #{symbol} and dogs." assert_equal __, string end + def test_symbols_are_not_strings + symbol = :ruby + assert_equal __, symbol.is_a?(String) + assert_equal __, symbol.eql?("ruby") + end + + def test_symbols_do_not_have_string_methods + symbol = :not_a_string + assert_equal __, symbol.respond_to?(:each_char) + assert_equal __, symbol.respond_to?(:reverse) + end + # It's important to realize that symbols are not "immutable + # strings", though they are immutable. None of the + # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated + # Exceptions will be pondered further father down the path assert_raise(__) do :cats + :dogs end diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 1b01168d2..cf1b8b011 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -6,24 +6,18 @@ def test_symbols_are_symbols assert_equal __(true), symbol.is_a?(Symbol) end - def test_symbols_are_not_strings - symbol = :ruby - assert_equal __(false), symbol.is_a?(String) - assert_equal __(false), symbol.eql?("ruby") - end - - def test_symbols_have_unique_identity - symbol1 = :identity - symbol2 = :identity + def test_symbols_can_be_compared + symbol1 = :a_symbol + symbol2 = :a_symbol symbol3 = :something_else assert symbol1 == __(symbol2) - assert symbol1 != __(symbol2) + assert symbol1 != __(symbol3) end - def test_identical_symbols_are_represented_by_a_single_internal_object - symbol1 = :identity - symbol2 = :identity + def test_identical_symbols_are_a_single_internal_object + symbol1 = :a_symbol + symbol2 = :a_symbol assert symbol1.equal?(__(symbol2)) assert_equal __(symbol1.object_id), symbol2.object_id @@ -35,7 +29,7 @@ def test_method_names_become_symbols assert_equal __(true), all_symbols.include?(:test_method_names_are_symbols) end - RubyConstant = "This string is assigned to a constant." + RubyConstant = "What is the sound of one hand clapping?" def test_constants_become_symbols all_symbols = Symbol.all_symbols @@ -53,14 +47,29 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __("cats and dogs").to_sym end - def test_interpolated_symbols_become_strings + def test_to_s_is_called_on_interpolated_symbols symbol = :cats string = "It is raining #{symbol} and dogs." assert_equal __('It is raining cats and dogs.'), string end + def test_symbols_are_not_strings + symbol = :ruby + assert_equal __(false), symbol.is_a?(String) + assert_equal __(false), symbol.eql?("ruby") + end + + def test_symbols_do_not_have_string_methods + symbol = :not_a_string + assert_equal __(false), symbol.respond_to?(:each_char) + assert_equal __(false), symbol.respond_to?(:reverse) + end + # It's important to realize that symbols are not "immutable + # strings", though they are immutable. None of the + # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated + # Exceptions will be pondered further father down the path assert_raise(__(NoMethodError)) do :cats + :dogs end From 3ed32b45346c2e6a452748a272e8fde5e382cd0a Mon Sep 17 00:00:00 2001 From: Matt Yoho Date: Tue, 21 Sep 2010 15:32:43 -0400 Subject: [PATCH 095/276] Use correct method for exception fill-in blank --- koans/about_symbols.rb | 2 +- src/about_symbols.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 2aad1940e..e78c65ab9 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -70,7 +70,7 @@ def test_symbols_do_not_have_string_methods # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated # Exceptions will be pondered further father down the path - assert_raise(__) do + assert_raise(___) do :cats + :dogs end end diff --git a/src/about_symbols.rb b/src/about_symbols.rb index cf1b8b011..17dfa81df 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -70,7 +70,7 @@ def test_symbols_do_not_have_string_methods # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated # Exceptions will be pondered further father down the path - assert_raise(__(NoMethodError)) do + assert_raise(___(NoMethodError)) do :cats + :dogs end end From 9b5dfb4e4290c1ad34439d7030ca3cb30e97afc3 Mon Sep 17 00:00:00 2001 From: Matt Yoho Date: Tue, 21 Sep 2010 17:12:50 -0400 Subject: [PATCH 096/276] Add koan on asserting exceptions --- koans/about_exceptions.rb | 8 ++++++++ src/about_exceptions.rb | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index 33b538a5c..c44833e5e 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -57,4 +57,12 @@ def test_ensure_clause assert_equal __, result end + # Sometimes, we must know about the unknown + def test_asserting_an_error_is_raised + # A do-end is a block, a topic to explore more later + assert_raise(___) do + raise MySpecialError.new("New instances can be raised directly.") + end + end + end diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index e65ed82f4..296055231 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -57,4 +57,12 @@ def test_ensure_clause assert_equal __(:always_run), result end + # Sometimes, we must know about the unknown + def test_asserting_an_error_is_raised + # A do-end is a block, a topic to explore more later + assert_raise(___(MySpecialError)) do + raise MySpecialError.new("New instances can be raised directly.") + end + end + end From 1bc1b8e50c5e107a87d712b0c44d06f59fb1d088 Mon Sep 17 00:00:00 2001 From: Matt Yoho Date: Tue, 21 Sep 2010 17:48:30 -0400 Subject: [PATCH 097/276] Add timestamps to package output --- Rakefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 8fccbbd6d..de5d5be2b 100644 --- a/Rakefile +++ b/Rakefile @@ -11,8 +11,9 @@ DIST_DIR = 'dist' SRC_FILES = FileList["#{SRC_DIR}/*"] KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f") -TAR_FILE = "#{DIST_DIR}/rubykoans.tgz" -ZIP_FILE = "#{DIST_DIR}/rubykoans.zip" +today = Time.now.strftime("%Y-%m-%d") +TAR_FILE = "#{DIST_DIR}/rubykoans-#{today}.tgz" +ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip" CLOBBER.include(DIST_DIR) From 493300b24d85e708eb4ad3bd5a5e985752c46a6a Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Wed, 22 Sep 2010 14:08:38 -0400 Subject: [PATCH 098/276] end screen with koans logo ascii art --- .gitignore | 1 + src/edgecase.rb | 244 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 188 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 1487603e6..c92368f0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dist .project_env.rc +.path_progress diff --git a/src/edgecase.rb b/src/edgecase.rb index 99cefc7f2..9d31ea67b 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -73,7 +73,7 @@ def color(color_value) end class Sensei - attr_reader :failure, :failed_test + attr_reader :failure, :failed_test, :pass_count in_ruby_version("1.8") do AssertionError = Test::Unit::AssertionFailedError @@ -91,16 +91,41 @@ def initialize @pass_count = 0 @failure = nil @failed_test = nil + @observations = [] end - def accumulate(test) - if test.passed? + PROGRESS_FILE_NAME = '.path_progress' + + def add_progress(prog) + @_contents = nil + exists = File.exists?(PROGRESS_FILE_NAME) + File.open(PROGRESS_FILE_NAME,'a+') do |f| + f.print "#{',' if exists}#{prog}" + end + end + + def progress + if @_contents.nil? + if File.exists?(PROGRESS_FILE_NAME) + File.open(PROGRESS_FILE_NAME,'r') do |f| + @_contents = f.read.to_s.gsub(/\s/,'').split(',') + end + end + end + @_contents + end + + def observe(step) + if step.passed? @pass_count += 1 - puts Color.green(" #{test.name} has expanded your awareness.") + if @pass_count > progress.last.to_i + @observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.") + end else - puts Color.red(" #{test.name} has damaged your karma.") - @failed_test = test - @failure = test.failure + @failed_test = step + @failure = step.failure + add_progress(@pass_count) + @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.") throw :edgecase_exit end end @@ -113,22 +138,115 @@ def assert_failed? failure.is_a?(AssertionError) end - def report + def instruct + if failed? + @observations.each{|c| puts c } + encourage + guide_through_error + a_zenlike_statement + show_progress + else + end_screen + end + end + + def show_progress + bar_width = 50 + total_tests = EdgeCase::Koan.total_tests + scale = bar_width.to_f/total_tests + print Color.green("your path thus far [") + happy_steps = (pass_count*scale).to_i + happy_steps = 1 if happy_steps == 0 && pass_count > 0 + print Color.green('.'*happy_steps) if failed? - puts - puts Color.green("You have not yet reached enlightenment ...") - puts Color.red(failure.message) - puts - puts Color.green("Please meditate on the following code:") - if assert_failed? - #puts find_interesting_lines(failure.backtrace) - puts find_interesting_lines(failure.backtrace).collect {|l| Color.red(l) } + print Color.red('X') + print Color.blue('_'*(bar_width-1-happy_steps)) + end + print Color.green(']') + print " #{pass_count}/#{total_tests}" + puts + end + + def end_screen + completed = <<-ENDTEXT + ,, , ,, + : ::::, :::, + , ,,: :::::::::::::,, :::: : , + , ,,, ,:::::::::::::::::::, ,: ,: ,, + :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: + : : ::, ,:::::::: ::, ,:::: + , ,::::: :,:::::::,::::, + ,: , ,:,,: ::::::::::::: + ::,: ,,:::, ,::::::::::::, + ,:::, :,,::: ::::::::::::, + ,::: :::::::, Mountains are again merely mountains ,:::::::::::: + :::,,,:::::: :::::::::::: + ,:::::::::::, ::::::::::::, + :::::::::::, ,:::::::::::: + ::::::::::::: ,:::::::::::: +,:::::::::::: Ruby Koans ::::::::::::, +::::::::::::: ,::::::::::::, +,:::::::::::, , :::::::::::: + ,:::::::::::::, brought to you by ,,::::::::::::, + :::::::::::::: ,:::::::::::: + ::::::::::::::, ::::::::::::: + ::::::::::::, EdgeCase Software Artisans , :::::::::::: + :,::::::::: :::: ::::::::::::: + ,::::::::::: ,: ,,:::::::::::::, + :::::::::::: ,::::::::::::::, + :::::::::::::::::, :::::::::::::::: + :::::::::::::::::::, :::::::::::::::: + ::::::::::::::::::::::, ,::::,:, , ::::,::: + :::::::::::::::::::::::, ::,: ::,::, ,,: :::: + ,:::::::::::::::::::: ::,, , ,, ,:::: + ,:::::::::::::::: ::,, , ,:::, + ,:::: , ,, + ,,, +ENDTEXT + puts completed + end + + def encourage + puts + puts "The Master says:" + puts Color.blue(" You have not yet reached enlightenment.") + if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1) + puts Color.blue(" I sense frustration. Do not be afraid to ask for help.") + elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1 + puts Color.blue(" Do not lose hope.") + elsif progress.last.to_i > 0 + puts Color.blue(" You are progressing. Excellent. #{progress.last} completed.") + end + end + + def guide_through_error + puts + puts "The answers you seek..." + puts Color.red(indent(failure.message).join) + puts + puts "Please meditate on the following code:" + if assert_failed? + puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace))) + else + puts embolden_first_line_only(indent(failure.backtrace)) + end + puts + end + + def embolden_first_line_only(text) + first_line = true + text.collect { |t| + if first_line + first_line = false + Color.red(t) else - puts Color.red(failure.backtrace) + Color.blue(t) end - puts - end - puts Color.green(a_zenlike_statement) + } + end + + def indent(text) + text.collect{|t| " #{t}"} end def find_interesting_lines(backtrace) @@ -140,7 +258,6 @@ def find_interesting_lines(backtrace) # Hat's tip to Ara T. Howard for the zen statements from his # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html) def a_zenlike_statement - puts if !failed? zen_statement = "Mountains are again merely mountains" else @@ -159,18 +276,21 @@ def a_zenlike_statement "things are not what they appear to be: nor are they otherwise" end end - zen_statement + puts Color.green(zen_statement) end end class Koan include Test::Unit::Assertions - attr_reader :name, :failure + attr_reader :name, :failure, :koan_count, :step_count, :koan_file - def initialize(name) + def initialize(name, koan_file=nil, koan_count=0, step_count=0) @name = name @failure = nil + @koan_count = koan_count + @step_count = step_count + @koan_file = koan_file end def passed? @@ -187,6 +307,22 @@ def setup def teardown end + def meditate + setup + begin + send(name) + rescue StandardError, EdgeCase::Sensei::AssertionError => ex + failed(ex) + ensure + begin + teardown + rescue StandardError, EdgeCase::Sensei::AssertionError => ex + failed(ex) if passed? + end + end + self + end + # Class methods for the EdgeCase test suite. class << self def inherited(subclass) @@ -194,32 +330,7 @@ def inherited(subclass) end def method_added(name) - testmethods << name unless tests_disabled? - end - - def run_tests(accumulator) - puts - puts Color.green("Thinking #{self}") - testmethods.each do |m| - self.run_test(m, accumulator) if Koan.test_pattern =~ m.to_s - end - end - - def run_test(method, accumulator) - test = self.new(method) - test.setup - begin - test.send(method) - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - test.failed(ex) - ensure - begin - test.teardown - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - test.failed(ex) if test.passed? - end - end - accumulator.accumulate(test) + testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s end def end_of_enlightenment @@ -261,17 +372,36 @@ def test_pattern @test_pattern ||= /^test_/ end + def total_tests + self.subclasses.inject(0){|total, k| total + k.testmethods.size } + end + end + end + + class ThePath + def walk + sensei = EdgeCase::Sensei.new + each_step do |step| + sensei.observe(step.meditate) + end + sensei.instruct + end + + def each_step + catch(:edgecase_exit) { + step_count = 0 + EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index| + koan.testmethods.each do |method_name| + step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1) + yield step + end + end + } end end end END { EdgeCase::Koan.command_line(ARGV) - zen_master = EdgeCase::Sensei.new - catch(:edgecase_exit) { - EdgeCase::Koan.subclasses.each do |sc| - sc.run_tests(zen_master) - end - } - zen_master.report + EdgeCase::ThePath.new.walk } From 1492d7003a8ece942abc7e9157e71debeb3e19c8 Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Wed, 22 Sep 2010 14:10:34 -0400 Subject: [PATCH 099/276] regen for updated koans/edgecase.rb --- koans/edgecase.rb | 244 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 187 insertions(+), 57 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 99cefc7f2..9d31ea67b 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -73,7 +73,7 @@ def color(color_value) end class Sensei - attr_reader :failure, :failed_test + attr_reader :failure, :failed_test, :pass_count in_ruby_version("1.8") do AssertionError = Test::Unit::AssertionFailedError @@ -91,16 +91,41 @@ def initialize @pass_count = 0 @failure = nil @failed_test = nil + @observations = [] end - def accumulate(test) - if test.passed? + PROGRESS_FILE_NAME = '.path_progress' + + def add_progress(prog) + @_contents = nil + exists = File.exists?(PROGRESS_FILE_NAME) + File.open(PROGRESS_FILE_NAME,'a+') do |f| + f.print "#{',' if exists}#{prog}" + end + end + + def progress + if @_contents.nil? + if File.exists?(PROGRESS_FILE_NAME) + File.open(PROGRESS_FILE_NAME,'r') do |f| + @_contents = f.read.to_s.gsub(/\s/,'').split(',') + end + end + end + @_contents + end + + def observe(step) + if step.passed? @pass_count += 1 - puts Color.green(" #{test.name} has expanded your awareness.") + if @pass_count > progress.last.to_i + @observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.") + end else - puts Color.red(" #{test.name} has damaged your karma.") - @failed_test = test - @failure = test.failure + @failed_test = step + @failure = step.failure + add_progress(@pass_count) + @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.") throw :edgecase_exit end end @@ -113,22 +138,115 @@ def assert_failed? failure.is_a?(AssertionError) end - def report + def instruct + if failed? + @observations.each{|c| puts c } + encourage + guide_through_error + a_zenlike_statement + show_progress + else + end_screen + end + end + + def show_progress + bar_width = 50 + total_tests = EdgeCase::Koan.total_tests + scale = bar_width.to_f/total_tests + print Color.green("your path thus far [") + happy_steps = (pass_count*scale).to_i + happy_steps = 1 if happy_steps == 0 && pass_count > 0 + print Color.green('.'*happy_steps) if failed? - puts - puts Color.green("You have not yet reached enlightenment ...") - puts Color.red(failure.message) - puts - puts Color.green("Please meditate on the following code:") - if assert_failed? - #puts find_interesting_lines(failure.backtrace) - puts find_interesting_lines(failure.backtrace).collect {|l| Color.red(l) } + print Color.red('X') + print Color.blue('_'*(bar_width-1-happy_steps)) + end + print Color.green(']') + print " #{pass_count}/#{total_tests}" + puts + end + + def end_screen + completed = <<-ENDTEXT + ,, , ,, + : ::::, :::, + , ,,: :::::::::::::,, :::: : , + , ,,, ,:::::::::::::::::::, ,: ,: ,, + :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: + : : ::, ,:::::::: ::, ,:::: + , ,::::: :,:::::::,::::, + ,: , ,:,,: ::::::::::::: + ::,: ,,:::, ,::::::::::::, + ,:::, :,,::: ::::::::::::, + ,::: :::::::, Mountains are again merely mountains ,:::::::::::: + :::,,,:::::: :::::::::::: + ,:::::::::::, ::::::::::::, + :::::::::::, ,:::::::::::: + ::::::::::::: ,:::::::::::: +,:::::::::::: Ruby Koans ::::::::::::, +::::::::::::: ,::::::::::::, +,:::::::::::, , :::::::::::: + ,:::::::::::::, brought to you by ,,::::::::::::, + :::::::::::::: ,:::::::::::: + ::::::::::::::, ::::::::::::: + ::::::::::::, EdgeCase Software Artisans , :::::::::::: + :,::::::::: :::: ::::::::::::: + ,::::::::::: ,: ,,:::::::::::::, + :::::::::::: ,::::::::::::::, + :::::::::::::::::, :::::::::::::::: + :::::::::::::::::::, :::::::::::::::: + ::::::::::::::::::::::, ,::::,:, , ::::,::: + :::::::::::::::::::::::, ::,: ::,::, ,,: :::: + ,:::::::::::::::::::: ::,, , ,, ,:::: + ,:::::::::::::::: ::,, , ,:::, + ,:::: , ,, + ,,, +ENDTEXT + puts completed + end + + def encourage + puts + puts "The Master says:" + puts Color.blue(" You have not yet reached enlightenment.") + if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1) + puts Color.blue(" I sense frustration. Do not be afraid to ask for help.") + elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1 + puts Color.blue(" Do not lose hope.") + elsif progress.last.to_i > 0 + puts Color.blue(" You are progressing. Excellent. #{progress.last} completed.") + end + end + + def guide_through_error + puts + puts "The answers you seek..." + puts Color.red(indent(failure.message).join) + puts + puts "Please meditate on the following code:" + if assert_failed? + puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace))) + else + puts embolden_first_line_only(indent(failure.backtrace)) + end + puts + end + + def embolden_first_line_only(text) + first_line = true + text.collect { |t| + if first_line + first_line = false + Color.red(t) else - puts Color.red(failure.backtrace) + Color.blue(t) end - puts - end - puts Color.green(a_zenlike_statement) + } + end + + def indent(text) + text.collect{|t| " #{t}"} end def find_interesting_lines(backtrace) @@ -140,7 +258,6 @@ def find_interesting_lines(backtrace) # Hat's tip to Ara T. Howard for the zen statements from his # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html) def a_zenlike_statement - puts if !failed? zen_statement = "Mountains are again merely mountains" else @@ -159,18 +276,21 @@ def a_zenlike_statement "things are not what they appear to be: nor are they otherwise" end end - zen_statement + puts Color.green(zen_statement) end end class Koan include Test::Unit::Assertions - attr_reader :name, :failure + attr_reader :name, :failure, :koan_count, :step_count, :koan_file - def initialize(name) + def initialize(name, koan_file=nil, koan_count=0, step_count=0) @name = name @failure = nil + @koan_count = koan_count + @step_count = step_count + @koan_file = koan_file end def passed? @@ -187,6 +307,22 @@ def setup def teardown end + def meditate + setup + begin + send(name) + rescue StandardError, EdgeCase::Sensei::AssertionError => ex + failed(ex) + ensure + begin + teardown + rescue StandardError, EdgeCase::Sensei::AssertionError => ex + failed(ex) if passed? + end + end + self + end + # Class methods for the EdgeCase test suite. class << self def inherited(subclass) @@ -194,32 +330,7 @@ def inherited(subclass) end def method_added(name) - testmethods << name unless tests_disabled? - end - - def run_tests(accumulator) - puts - puts Color.green("Thinking #{self}") - testmethods.each do |m| - self.run_test(m, accumulator) if Koan.test_pattern =~ m.to_s - end - end - - def run_test(method, accumulator) - test = self.new(method) - test.setup - begin - test.send(method) - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - test.failed(ex) - ensure - begin - test.teardown - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - test.failed(ex) if test.passed? - end - end - accumulator.accumulate(test) + testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s end def end_of_enlightenment @@ -261,17 +372,36 @@ def test_pattern @test_pattern ||= /^test_/ end + def total_tests + self.subclasses.inject(0){|total, k| total + k.testmethods.size } + end + end + end + + class ThePath + def walk + sensei = EdgeCase::Sensei.new + each_step do |step| + sensei.observe(step.meditate) + end + sensei.instruct + end + + def each_step + catch(:edgecase_exit) { + step_count = 0 + EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index| + koan.testmethods.each do |method_name| + step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1) + yield step + end + end + } end end end END { EdgeCase::Koan.command_line(ARGV) - zen_master = EdgeCase::Sensei.new - catch(:edgecase_exit) { - EdgeCase::Koan.subclasses.each do |sc| - sc.run_tests(zen_master) - end - } - zen_master.report + EdgeCase::ThePath.new.walk } From 754a7694ad3455f44f5e15bd35b313dade4f190b Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 22 Sep 2010 14:50:25 -0400 Subject: [PATCH 100/276] Added else clause if progress file is not there. --- src/edgecase.rb | 68 +++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 9d31ea67b..def4accf6 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -110,6 +110,8 @@ def progress File.open(PROGRESS_FILE_NAME,'r') do |f| @_contents = f.read.to_s.gsub(/\s/,'').split(',') end + else + @_contents = [] end end @_contents @@ -169,39 +171,39 @@ def show_progress def end_screen completed = <<-ENDTEXT - ,, , ,, - : ::::, :::, - , ,,: :::::::::::::,, :::: : , - , ,,, ,:::::::::::::::::::, ,: ,: ,, - :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: - : : ::, ,:::::::: ::, ,:::: - , ,::::: :,:::::::,::::, - ,: , ,:,,: ::::::::::::: - ::,: ,,:::, ,::::::::::::, - ,:::, :,,::: ::::::::::::, - ,::: :::::::, Mountains are again merely mountains ,:::::::::::: - :::,,,:::::: :::::::::::: - ,:::::::::::, ::::::::::::, - :::::::::::, ,:::::::::::: - ::::::::::::: ,:::::::::::: -,:::::::::::: Ruby Koans ::::::::::::, -::::::::::::: ,::::::::::::, -,:::::::::::, , :::::::::::: - ,:::::::::::::, brought to you by ,,::::::::::::, - :::::::::::::: ,:::::::::::: - ::::::::::::::, ::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: - :,::::::::: :::: ::::::::::::: - ,::::::::::: ,: ,,:::::::::::::, - :::::::::::: ,::::::::::::::, - :::::::::::::::::, :::::::::::::::: - :::::::::::::::::::, :::::::::::::::: - ::::::::::::::::::::::, ,::::,:, , ::::,::: - :::::::::::::::::::::::, ::,: ::,::, ,,: :::: - ,:::::::::::::::::::: ::,, , ,, ,:::: - ,:::::::::::::::: ::,, , ,:::, - ,:::: , ,, - ,,, + ,, , ,, + : ::::, :::, + , ,,: :::::::::::::,, :::: : , + , ,,, ,:::::::::::::::::::, ,: ,: ,, + :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: + : : ::, ,:::::::: ::, ,:::: + , ,::::: :,:::::::,::::, + ,: , ,:,,: ::::::::::::: + ::,: ,,:::, ,::::::::::::, + ,:::, :,,::: ::::::::::::, + ,::: :::::::, Mountains are again merely mountains ,:::::::::::: + :::,,,:::::: :::::::::::: + ,:::::::::::, ::::::::::::, + :::::::::::, ,:::::::::::: + ::::::::::::: ,:::::::::::: +,:::::::::::: Ruby Koans ::::::::::::, +::::::::::::: ,::::::::::::, +,:::::::::::, , :::::::::::: + ,:::::::::::::, brought to you by ,,::::::::::::, + :::::::::::::: ,:::::::::::: + ::::::::::::::, ::::::::::::: + ::::::::::::, EdgeCase Software Artisans , :::::::::::: + :,::::::::: :::: ::::::::::::: + ,::::::::::: ,: ,,:::::::::::::, + :::::::::::: ,::::::::::::::, + :::::::::::::::::, :::::::::::::::: + :::::::::::::::::::, :::::::::::::::: + ::::::::::::::::::::::, ,::::,:, , ::::,::: + :::::::::::::::::::::::, ::,: ::,::, ,,: :::: + ,:::::::::::::::::::: ::,, , ,, ,:::: + ,:::::::::::::::: ::,, , ,:::, + ,:::: , ,, + ,,, ENDTEXT puts completed end From b4e907e30e6a8f6c52da16e120146b63b60dbd34 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 22 Sep 2010 14:54:42 -0400 Subject: [PATCH 101/276] Updated Koans directory --- koans/edgecase.rb | 68 ++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 9d31ea67b..def4accf6 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -110,6 +110,8 @@ def progress File.open(PROGRESS_FILE_NAME,'r') do |f| @_contents = f.read.to_s.gsub(/\s/,'').split(',') end + else + @_contents = [] end end @_contents @@ -169,39 +171,39 @@ def show_progress def end_screen completed = <<-ENDTEXT - ,, , ,, - : ::::, :::, - , ,,: :::::::::::::,, :::: : , - , ,,, ,:::::::::::::::::::, ,: ,: ,, - :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: - : : ::, ,:::::::: ::, ,:::: - , ,::::: :,:::::::,::::, - ,: , ,:,,: ::::::::::::: - ::,: ,,:::, ,::::::::::::, - ,:::, :,,::: ::::::::::::, - ,::: :::::::, Mountains are again merely mountains ,:::::::::::: - :::,,,:::::: :::::::::::: - ,:::::::::::, ::::::::::::, - :::::::::::, ,:::::::::::: - ::::::::::::: ,:::::::::::: -,:::::::::::: Ruby Koans ::::::::::::, -::::::::::::: ,::::::::::::, -,:::::::::::, , :::::::::::: - ,:::::::::::::, brought to you by ,,::::::::::::, - :::::::::::::: ,:::::::::::: - ::::::::::::::, ::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: - :,::::::::: :::: ::::::::::::: - ,::::::::::: ,: ,,:::::::::::::, - :::::::::::: ,::::::::::::::, - :::::::::::::::::, :::::::::::::::: - :::::::::::::::::::, :::::::::::::::: - ::::::::::::::::::::::, ,::::,:, , ::::,::: - :::::::::::::::::::::::, ::,: ::,::, ,,: :::: - ,:::::::::::::::::::: ::,, , ,, ,:::: - ,:::::::::::::::: ::,, , ,:::, - ,:::: , ,, - ,,, + ,, , ,, + : ::::, :::, + , ,,: :::::::::::::,, :::: : , + , ,,, ,:::::::::::::::::::, ,: ,: ,, + :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: + : : ::, ,:::::::: ::, ,:::: + , ,::::: :,:::::::,::::, + ,: , ,:,,: ::::::::::::: + ::,: ,,:::, ,::::::::::::, + ,:::, :,,::: ::::::::::::, + ,::: :::::::, Mountains are again merely mountains ,:::::::::::: + :::,,,:::::: :::::::::::: + ,:::::::::::, ::::::::::::, + :::::::::::, ,:::::::::::: + ::::::::::::: ,:::::::::::: +,:::::::::::: Ruby Koans ::::::::::::, +::::::::::::: ,::::::::::::, +,:::::::::::, , :::::::::::: + ,:::::::::::::, brought to you by ,,::::::::::::, + :::::::::::::: ,:::::::::::: + ::::::::::::::, ::::::::::::: + ::::::::::::, EdgeCase Software Artisans , :::::::::::: + :,::::::::: :::: ::::::::::::: + ,::::::::::: ,: ,,:::::::::::::, + :::::::::::: ,::::::::::::::, + :::::::::::::::::, :::::::::::::::: + :::::::::::::::::::, :::::::::::::::: + ::::::::::::::::::::::, ,::::,:, , ::::,::: + :::::::::::::::::::::::, ::,: ::,::, ,,: :::: + ,:::::::::::::::::::: ::,, , ,, ,:::: + ,:::::::::::::::: ::,, , ,:::, + ,:::: , ,, + ,,, ENDTEXT puts completed end From 15551eaf530e44b301144c9b4143ffa137742017 Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Wed, 22 Sep 2010 15:09:08 -0400 Subject: [PATCH 102/276] 80 char limit to end screen --- koans/edgecase.rb | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 9d31ea67b..80116aace 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -169,39 +169,39 @@ def show_progress def end_screen completed = <<-ENDTEXT - ,, , ,, - : ::::, :::, - , ,,: :::::::::::::,, :::: : , - , ,,, ,:::::::::::::::::::, ,: ,: ,, - :, ::, , , :, ,:::::::::::::::::::, ::: ,:::: - : : ::, ,:::::::: ::, ,:::: - , ,::::: :,:::::::,::::, - ,: , ,:,,: ::::::::::::: - ::,: ,,:::, ,::::::::::::, - ,:::, :,,::: ::::::::::::, - ,::: :::::::, Mountains are again merely mountains ,:::::::::::: - :::,,,:::::: :::::::::::: - ,:::::::::::, ::::::::::::, - :::::::::::, ,:::::::::::: - ::::::::::::: ,:::::::::::: -,:::::::::::: Ruby Koans ::::::::::::, -::::::::::::: ,::::::::::::, -,:::::::::::, , :::::::::::: - ,:::::::::::::, brought to you by ,,::::::::::::, - :::::::::::::: ,:::::::::::: - ::::::::::::::, ::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: - :,::::::::: :::: ::::::::::::: - ,::::::::::: ,: ,,:::::::::::::, - :::::::::::: ,::::::::::::::, - :::::::::::::::::, :::::::::::::::: - :::::::::::::::::::, :::::::::::::::: - ::::::::::::::::::::::, ,::::,:, , ::::,::: - :::::::::::::::::::::::, ::,: ::,::, ,,: :::: - ,:::::::::::::::::::: ::,, , ,, ,:::: - ,:::::::::::::::: ::,, , ,:::, - ,:::: , ,, - ,,, + ,, , ,, + : ::::, :::, + , ,,: :::::::::::::,, :::: : , + , ,,, ,:::::::::::::::::::, ,: ,: ,, + :, ::, , , :, ,::::::::::::::::::, ::: ,:::: + : : ::, ,:::::::: ::, ,:::: + , ,::::: :,:::::::,::::, + ,: , ,:,,: ::::::::::::: + ::,: ,,:::, ,::::::::::::, + ,:::, :,,::: ::::::::::::, + ,::: :::::::, Mountains are again merely mountains ,:::::::::::: + :::,,,:::::: :::::::::::: + ,:::::::::::, ::::::::::::, + :::::::::::, ,:::::::::::: +::::::::::::: ,:::::::::::: +:::::::::::: Ruby Koans ::::::::::::, +:::::::::::: ,::::::::::::, +:::::::::::, , :::::::::::: +,:::::::::::::, brought to you by ,,::::::::::::, +:::::::::::::: ,:::::::::::: + ::::::::::::::, ,::::::::::::: + ::::::::::::, EdgeCase Software Artisans , :::::::::::: + :,::::::::: :::: ::::::::::::: + ,::::::::::: ,: ,,:::::::::::::, + :::::::::::: ,::::::::::::::, + :::::::::::::::::, :::::::::::::::: + :::::::::::::::::::, :::::::::::::::: + ::::::::::::::::::::::, ,::::,:, , ::::,::: + :::::::::::::::::::::::, ::,: ::,::, ,,: :::: + ,:::::::::::::::::::: ::,, , ,, ,:::: + ,:::::::::::::::: ::,, , ,:::, + ,:::: , ,, + ,,, ENDTEXT puts completed end From b2c47e0c0f8156e7bb4dea0504a8faf6a5d8925c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 10:37:35 -0400 Subject: [PATCH 103/276] Switch blue color to cyan for better contrast on dark terminals. --- koans/edgecase.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 96617f928..6ee835eb3 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -162,7 +162,7 @@ def show_progress print Color.green('.'*happy_steps) if failed? print Color.red('X') - print Color.blue('_'*(bar_width-1-happy_steps)) + print Color.cyan('_'*(bar_width-1-happy_steps)) end print Color.green(']') print " #{pass_count}/#{total_tests}" @@ -211,13 +211,13 @@ def end_screen def encourage puts puts "The Master says:" - puts Color.blue(" You have not yet reached enlightenment.") + puts Color.cyan(" You have not yet reached enlightenment.") if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1) - puts Color.blue(" I sense frustration. Do not be afraid to ask for help.") + puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.") elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1 - puts Color.blue(" Do not lose hope.") + puts Color.cyan(" Do not lose hope.") elsif progress.last.to_i > 0 - puts Color.blue(" You are progressing. Excellent. #{progress.last} completed.") + puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.") end end @@ -242,7 +242,7 @@ def embolden_first_line_only(text) first_line = false Color.red(t) else - Color.blue(t) + Color.cyan(t) end } end From 584b26e532a41ff28e22a5e6b05b2f01d585090a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 10:44:58 -0400 Subject: [PATCH 104/276] Updated for JRuby --- src/about_methods.rb | 10 +++++----- src/about_symbols.rb | 35 +++++++++++++++++++++++++++++------ src/edgecase.rb | 23 +++++++++++++++-------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/about_methods.rb b/src/about_methods.rb index 3b6ad5748..42a06cfd7 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -3,7 +3,7 @@ def my_global_method(a,b) a + b end - + class AboutMethods < EdgeCase::Koan def test_calling_global_methods @@ -36,19 +36,19 @@ def test_sometimes_missing_parentheses_are_ambiguous # Rewrite the eval string to continue. # end - + # NOTE: wrong number of argument is not a SYNTAX error, but a # runtime error. def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___(ArgumentError)) do my_global_method end - assert_match(/#{__("wrong number of arguments")}/, exception.message) + assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message) exception = assert_raise(___(ArgumentError)) do my_global_method(1,2,3) end - assert_match(/#{__("wrong number of arguments")}/, exception.message) + assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message) end # ------------------------------------------------------------------ @@ -142,7 +142,7 @@ def tail "tail" end end - + def test_calling_methods_in_other_objects_require_explicit_receiver rover = Dog.new assert_equal __("Fido"), rover.name diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 17dfa81df..e265df851 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -25,15 +25,21 @@ def test_identical_symbols_are_a_single_internal_object def test_method_names_become_symbols all_symbols = Symbol.all_symbols - - assert_equal __(true), all_symbols.include?(:test_method_names_are_symbols) + assert_equal __(true), all_symbols.include?(:test_method_names_become_symbols) end - RubyConstant = "What is the sound of one hand clapping?" - def test_constants_become_symbols - all_symbols = Symbol.all_symbols + # THINK ABOUT IT: + # + # Why do we capture the list of symbols before we check for the + # method name? - assert_equal true, all_symbols.include?(__(:RubyConstant)) + in_ruby_version("mri") do + RubyConstant = "What is the sound of one hand clapping?" + def test_constants_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal __(true), all_symbols.include?(__(:RubyConstant)) + end end def test_symbols_can_be_made_from_strings @@ -47,6 +53,13 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __("cats and dogs").to_sym end + def test_symbols_with_spaces_can_be_built + value = "and" + symbol = :"cats #{value} dogs" + + assert_equal symbol, __("cats and dogs").to_sym + end + def test_to_s_is_called_on_interpolated_symbols symbol = :cats string = "It is raining #{symbol} and dogs." @@ -65,13 +78,23 @@ def test_symbols_do_not_have_string_methods assert_equal __(false), symbol.respond_to?(:each_char) assert_equal __(false), symbol.respond_to?(:reverse) end + # It's important to realize that symbols are not "immutable # strings", though they are immutable. None of the # interesting string operations are available on symbols. + def test_symbols_cannot_be_concatenated # Exceptions will be pondered further father down the path assert_raise(___(NoMethodError)) do :cats + :dogs end end + + def test_symbols_can_be_dynamically_created + assert_equal __(:catsdogs), ("cats" + "dogs").to_sym + end + + # THINK ABOUT IT: + # + # Why is it not a good idea to dynamically create a lot of symbols? end diff --git a/src/edgecase.rb b/src/edgecase.rb index 96617f928..1a5b882f0 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -6,8 +6,14 @@ class FillMeInError < StandardError end -def in_ruby_version(version) - yield if RUBY_VERSION =~ /^#{version}/ +def ruby_version?(version) + RUBY_VERSION =~ /^#{version}/ || + (version == 'jruby' && defined?(JRUBY_VERSION)) || + (version == 'mri' && ! defined?(JRUBY_VERSION)) +end + +def in_ruby_version(*versions) + yield if versions.any? { |v| ruby_version?(v) } end def __(value="FILL ME IN", value19=:mu) @@ -162,7 +168,7 @@ def show_progress print Color.green('.'*happy_steps) if failed? print Color.red('X') - print Color.blue('_'*(bar_width-1-happy_steps)) + print Color.cyan('_'*(bar_width-1-happy_steps)) end print Color.green(']') print " #{pass_count}/#{total_tests}" @@ -211,13 +217,13 @@ def end_screen def encourage puts puts "The Master says:" - puts Color.blue(" You have not yet reached enlightenment.") + puts Color.cyan(" You have not yet reached enlightenment.") if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1) - puts Color.blue(" I sense frustration. Do not be afraid to ask for help.") + puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.") elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1 - puts Color.blue(" Do not lose hope.") + puts Color.cyan(" Do not lose hope.") elsif progress.last.to_i > 0 - puts Color.blue(" You are progressing. Excellent. #{progress.last} completed.") + puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.") end end @@ -242,12 +248,13 @@ def embolden_first_line_only(text) first_line = false Color.red(t) else - Color.blue(t) + Color.cyan(t) end } end def indent(text) + text = text.split(/\n/) if text.is_a?(String) text.collect{|t| " #{t}"} end From 9caf7a950a40de64f867d984a04dc49c8b892452 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 10:50:29 -0400 Subject: [PATCH 105/276] Updated koans from source directory. --- koans/about_methods.rb | 10 +++++----- koans/about_symbols.rb | 35 +++++++++++++++++++++++++++++------ koans/edgecase.rb | 11 +++++++++-- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/koans/about_methods.rb b/koans/about_methods.rb index cbebd3049..fde97e987 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -3,7 +3,7 @@ def my_global_method(a,b) a + b end - + class AboutMethods < EdgeCase::Koan def test_calling_global_methods @@ -29,19 +29,19 @@ def test_sometimes_missing_parentheses_are_ambiguous # Rewrite the eval string to continue. # end - + # NOTE: wrong number of argument is not a SYNTAX error, but a # runtime error. def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___) do my_global_method end - assert_match(/__/, exception.message) + assert_match(/#{__ of arguments")}/, exception.message) exception = assert_raise(___) do my_global_method(1,2,3) end - assert_match(/__/, exception.message) + assert_match(/#{__ of arguments")}/, exception.message) end # ------------------------------------------------------------------ @@ -135,7 +135,7 @@ def tail "tail" end end - + def test_calling_methods_in_other_objects_require_explicit_receiver rover = Dog.new assert_equal __, rover.name diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index e78c65ab9..b94c3b8ab 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -25,15 +25,21 @@ def test_identical_symbols_are_a_single_internal_object def test_method_names_become_symbols all_symbols = Symbol.all_symbols - - assert_equal __, all_symbols.include?(:test_method_names_are_symbols) + assert_equal __, all_symbols.include?(:test_method_names_become_symbols) end - RubyConstant = "What is the sound of one hand clapping?" - def test_constants_become_symbols - all_symbols = Symbol.all_symbols + # THINK ABOUT IT: + # + # Why do we capture the list of symbols before we check for the + # method name? - assert_equal true, all_symbols.include?(__) + in_ruby_version("mri") do + RubyConstant = "What is the sound of one hand clapping?" + def test_constants_become_symbols + all_symbols = Symbol.all_symbols + + assert_equal __, all_symbols.include?(__) + end end def test_symbols_can_be_made_from_strings @@ -47,6 +53,13 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __.to_sym end + def test_symbols_with_spaces_can_be_built + value = "and" + symbol = :"cats #{value} dogs" + + assert_equal symbol, __.to_sym + end + def test_to_s_is_called_on_interpolated_symbols symbol = :cats string = "It is raining #{symbol} and dogs." @@ -65,13 +78,23 @@ def test_symbols_do_not_have_string_methods assert_equal __, symbol.respond_to?(:each_char) assert_equal __, symbol.respond_to?(:reverse) end + # It's important to realize that symbols are not "immutable # strings", though they are immutable. None of the # interesting string operations are available on symbols. + def test_symbols_cannot_be_concatenated # Exceptions will be pondered further father down the path assert_raise(___) do :cats + :dogs end end + + def test_symbols_can_be_dynamically_created + assert_equal __, ("cats" + "dogs").to_sym + end + + # THINK ABOUT IT: + # + # Why is it not a good idea to dynamically create a lot of symbols? end diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 6ee835eb3..1a5b882f0 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -6,8 +6,14 @@ class FillMeInError < StandardError end -def in_ruby_version(version) - yield if RUBY_VERSION =~ /^#{version}/ +def ruby_version?(version) + RUBY_VERSION =~ /^#{version}/ || + (version == 'jruby' && defined?(JRUBY_VERSION)) || + (version == 'mri' && ! defined?(JRUBY_VERSION)) +end + +def in_ruby_version(*versions) + yield if versions.any? { |v| ruby_version?(v) } end def __(value="FILL ME IN", value19=:mu) @@ -248,6 +254,7 @@ def embolden_first_line_only(text) end def indent(text) + text = text.split(/\n/) if text.is_a?(String) text.collect{|t| " #{t}"} end From fe2ee8617268b6081fbde68b82b67dfbc4a5fc8e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 11:36:00 -0400 Subject: [PATCH 106/276] Added Koan on basic objects --- koans/about_objects.rb | 56 ++++++++++++++++++++++++++++++++++ koans/path_to_enlightenment.rb | 1 + src/about_objects.rb | 56 ++++++++++++++++++++++++++++++++++ src/path_to_enlightenment.rb | 1 + 4 files changed, 114 insertions(+) create mode 100644 koans/about_objects.rb create mode 100644 src/about_objects.rb diff --git a/koans/about_objects.rb b/koans/about_objects.rb new file mode 100644 index 000000000..05c44de0c --- /dev/null +++ b/koans/about_objects.rb @@ -0,0 +1,56 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutObjects < EdgeCase::Koan + def test_everything_is_an_object + assert_equal __, 1.is_a?(Object) + assert_equal __, 1.5.is_a?(Object) + assert_equal __, "string".is_a?(Object) + assert_equal __, nil.is_a?(Object) + assert_equal __, Object.is_a?(Object) + end + + def test_objects_can_be_converted_to_strings + assert_equal __, 123.to_s + assert_equal __, nil.to_s + end + + def test_objects_can_be_inspected + assert_equal __, 123.inspect + assert_equal __, nil.inspect + end + + def test_every_object_has_an_id + obj = Object.new + assert_equal __, obj.object_id.class + end + + def test_every_object_has_different_id + obj = Object.new + another_obj = Object.new + assert_equal __, obj.object_id != another_obj.object_id + end + + def test_some_system_objects_always_have_the_same_id + assert_equal __, false.object_id + assert_equal __, true.object_id + assert_equal __, nil.object_id + end + + def test_small_integers_have_fixed_ids + assert_equal __, 0.object_id + assert_equal __, 1.object_id + assert_equal __, 2.object_id + assert_equal __, 100.object_id + + # THINK ABOUT IT: + # What pattern do the object IDs for small integers follow? + end + + def test_clone_creates_a_different_object + obj = Object.new + copy = obj.clone + + assert_equal __, obj != copy + assert_equal __, obj.object_id != copy.object_id + end +end diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index f7e0773ec..f8b09c7e4 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -4,6 +4,7 @@ require 'about_asserts' require 'about_nil' +require 'about_objects' require 'about_arrays' require 'about_array_assignment' require 'about_hashes' diff --git a/src/about_objects.rb b/src/about_objects.rb new file mode 100644 index 000000000..1faf0a0eb --- /dev/null +++ b/src/about_objects.rb @@ -0,0 +1,56 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutObjects < EdgeCase::Koan + def test_everything_is_an_object + assert_equal __(true), 1.is_a?(Object) + assert_equal __(true), 1.5.is_a?(Object) + assert_equal __(true), "string".is_a?(Object) + assert_equal __(true), nil.is_a?(Object) + assert_equal __(true), Object.is_a?(Object) + end + + def test_objects_can_be_converted_to_strings + assert_equal __("123"), 123.to_s + assert_equal __(""), nil.to_s + end + + def test_objects_can_be_inspected + assert_equal __("123"), 123.inspect + assert_equal __("nil"), nil.inspect + end + + def test_every_object_has_an_id + obj = Object.new + assert_equal __(Fixnum), obj.object_id.class + end + + def test_every_object_has_different_id + obj = Object.new + another_obj = Object.new + assert_equal __(true), obj.object_id != another_obj.object_id + end + + def test_some_system_objects_always_have_the_same_id + assert_equal __(0), false.object_id + assert_equal __(2), true.object_id + assert_equal __(4), nil.object_id + end + + def test_small_integers_have_fixed_ids + assert_equal __(1), 0.object_id + assert_equal __(3), 1.object_id + assert_equal __(5), 2.object_id + assert_equal __(201), 100.object_id + + # THINK ABOUT IT: + # What pattern do the object IDs for small integers follow? + end + + def test_clone_creates_a_different_object + obj = Object.new + copy = obj.clone + + assert_equal __(true), obj != copy + assert_equal __(true), obj.object_id != copy.object_id + end +end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index f7e0773ec..f8b09c7e4 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -4,6 +4,7 @@ require 'about_asserts' require 'about_nil' +require 'about_objects' require 'about_arrays' require 'about_array_assignment' require 'about_hashes' From ece35b2539058b45e2765f86757d21995f03a777 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 11:36:38 -0400 Subject: [PATCH 107/276] Added symbol & string identity tests. --- koans/about_strings.rb | 8 ++++++++ koans/about_symbols.rb | 4 ++-- src/about_strings.rb | 8 ++++++++ src/about_symbols.rb | 4 ++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index f26e69995..509d26c3a 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -182,4 +182,12 @@ def test_strings_can_be_joined words = ["Now", "is", "the", "time"] assert_equal __, words.join(" ") end + + def test_strings_are_not_unique_objects + a = "a string" + b = "a string" + + assert_equal __, a == b + assert_equal __, a.object_id == b.object_id + end end diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index b94c3b8ab..a8b7f38b0 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -19,8 +19,8 @@ def test_identical_symbols_are_a_single_internal_object symbol1 = :a_symbol symbol2 = :a_symbol - assert symbol1.equal?(__) - assert_equal __, symbol2.object_id + assert_equal __, symbol1 == symbol2 + assert_equal __, symbol1.object_id == symbol2.object_id end def test_method_names_become_symbols diff --git a/src/about_strings.rb b/src/about_strings.rb index 94211a996..deba2c830 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -182,4 +182,12 @@ def test_strings_can_be_joined words = ["Now", "is", "the", "time"] assert_equal __("Now is the time"), words.join(" ") end + + def test_strings_are_not_unique_objects + a = "a string" + b = "a string" + + assert_equal __(true), a == b + assert_equal __(false), a.object_id == b.object_id + end end diff --git a/src/about_symbols.rb b/src/about_symbols.rb index e265df851..7a2e19a7d 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -19,8 +19,8 @@ def test_identical_symbols_are_a_single_internal_object symbol1 = :a_symbol symbol2 = :a_symbol - assert symbol1.equal?(__(symbol2)) - assert_equal __(symbol1.object_id), symbol2.object_id + assert_equal __(true), symbol1 == symbol2 + assert_equal __(true), symbol1.object_id == symbol2.object_id end def test_method_names_become_symbols From 012cb20bb3984ec03c91099b53e94e5878a1131e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 13:38:22 -0400 Subject: [PATCH 108/276] Moved checks into a separate rake file. --- rakelib/checks.rake | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 rakelib/checks.rake diff --git a/rakelib/checks.rake b/rakelib/checks.rake new file mode 100644 index 000000000..9ef619901 --- /dev/null +++ b/rakelib/checks.rake @@ -0,0 +1,31 @@ +namespace "check" do + + desc "Check that the require files match the about_* files" + task :abouts do + about_files = Dir['src/about_*.rb'].size + about_requires = `grep require src/path_to_enlightenment.rb | wc -l`.to_i + puts "Checking path_to_enlightenment completeness" + puts "# of about files: #{about_files}" + puts "# of about requires: #{about_requires}" + if about_files > about_requires + puts "*** There seems to be requires missing in the path to enlightenment" + else + puts "OK" + end + puts + end + + task :asserts do + puts "Checking for asserts missing the replacement text:" + begin + sh "egrep -n 'assert( |_)' src/about_* | egrep -v '__|_n_|project|about_assert' | egrep -v ' *#'" + puts + puts "Examine the above lines for missing __ replacements" + rescue RuntimeError => ex + puts "OK" + end + puts + end +end + +task :check => ["check:abouts", "check:asserts"] From 17fb071814758be5d9072cfaca8736c556c0cd43 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 13:38:50 -0400 Subject: [PATCH 109/276] Evaluated each assert line without a replacement test specified. --- Rakefile | 13 +++++-------- koans/about_arrays.rb | 2 +- src/about_arrays.rb | 12 ++++++------ src/about_classes.rb | 6 +++--- src/about_exceptions.rb | 10 +++++----- src/about_hashes.rb | 18 +++++++++--------- src/about_iteration.rb | 2 +- src/about_message_passing.rb | 12 ++++++------ src/about_methods.rb | 4 ++-- src/about_modules.rb | 4 ++-- src/about_regular_expressions.rb | 4 ++-- src/about_scope.rb | 4 ++-- src/edgecase.rb | 9 +++++++++ 13 files changed, 53 insertions(+), 47 deletions(-) diff --git a/Rakefile b/Rakefile index de5d5be2b..e42cd8c4d 100644 --- a/Rakefile +++ b/Rakefile @@ -18,12 +18,17 @@ ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip" CLOBBER.include(DIST_DIR) module Koans + # Remove solution info from source + # __(a,b) => __ + # _n_(number) => __ + # # __ => def Koans.remove_solution(line) line = line.gsub(/\b____\([^\)]+\)/, "____") line = line.gsub(/\b___\([^\)]+\)/, "___") line = line.gsub(/\b__\([^\)]+\)/, "__") line = line.gsub(/\b_n_\([^\)]+\)/, "_n_") line = line.gsub(%r(/\#\{__\}/), "/__/") + line = line.gsub(/\s*#\s*__\s*$/, '') line end @@ -84,14 +89,6 @@ task :upload => [TAR_FILE, ZIP_FILE] do sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download" end -desc "Check that the require files match the about_* files" -task :check do - about_files = Dir['src/about_*.rb'].size - about_requires = `grep require src/path_to_enlightenment.rb | wc -l`.to_i - puts "# of about files: #{about_files}" - puts "# of about requires: #{about_requires}" -end - desc "Generate the Koans from the source files from scratch." task :regen => [:clobber_koans, :gen] diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb index 8dc4dfcbc..2ed3181ee 100644 --- a/koans/about_arrays.rb +++ b/koans/about_arrays.rb @@ -3,7 +3,7 @@ class AboutArrays < EdgeCase::Koan def test_creating_arrays empty_array = Array.new - assert_equal Array, empty_array.class + assert_equal __, empty_array.class assert_equal __, empty_array.size end diff --git a/src/about_arrays.rb b/src/about_arrays.rb index 7782ab9bd..35c951d64 100644 --- a/src/about_arrays.rb +++ b/src/about_arrays.rb @@ -3,16 +3,16 @@ class AboutArrays < EdgeCase::Koan def test_creating_arrays empty_array = Array.new - assert_equal Array, empty_array.class + assert_equal __(Array), empty_array.class assert_equal __(0), empty_array.size end def test_array_literals array = Array.new - assert_equal [], array + assert_equal [], array # __ array[0] = 1 - assert_equal [1], array + assert_equal [1], array # __ array[1] = 2 assert_equal [1, __(2)], array @@ -45,9 +45,9 @@ def test_slicing_arrays end def test_arrays_and_ranges - assert_equal Range, (1..5).class - assert_not_equal [1,2,3,4,5], (1..5) - assert_equal [1,2,3,4,5], (1..5).to_a + assert_equal __(Range), (1..5).class + assert_not_equal [1,2,3,4,5], (1..5) # __ + assert_equal __([1,2,3,4,5]), (1..5).to_a assert_equal __([1,2,3,4]), (1...5).to_a end diff --git a/src/about_classes.rb b/src/about_classes.rb index 30a2ca9ea..b8b67ea12 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -130,7 +130,7 @@ def test_different_objects_have_difference_instance_variables fido = Dog6.new("Fido") rover = Dog6.new("Rover") - assert_not_equal rover.name, fido.name + assert_equal __(true), rover.name != fido.name end # ------------------------------------------------------------------ @@ -164,12 +164,12 @@ def test_inside_a_method_self_refers_to_the_containing_object def test_to_s_provides_a_string_version_of_the_object fido = Dog7.new("Fido") - assert_equal "Fido", fido.to_s + assert_equal __("Fido"), fido.to_s end def test_to_s_is_used_in_string_interpolation fido = Dog7.new("Fido") - assert_equal "My dog is Fido", "My dog is #{fido}" + assert_equal __("My dog is Fido"), "My dog is #{fido}" end def test_inspect_provides_a_more_complete_string_version diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index 296055231..a2efbb3a7 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -22,12 +22,12 @@ def test_rescue_clause assert_equal __(:exception_handled), result - assert ex.is_a?(StandardError), "Failure message." - assert ex.is_a?(RuntimeError), "Failure message." + assert ex.is_a?(___(StandardError)), "Failure message." + assert ex.is_a?(___(RuntimeError)), "Failure message." - assert RuntimeError.ancestors.include?(StandardError), + assert RuntimeError.ancestors.include?(StandardError), # __ "RuntimeError is a subclass of StandardError" - + assert_equal __("Oops"), ex.message end @@ -58,7 +58,7 @@ def test_ensure_clause end # Sometimes, we must know about the unknown - def test_asserting_an_error_is_raised + def test_asserting_an_error_is_raised # __ # A do-end is a block, a topic to explore more later assert_raise(___(MySpecialError)) do raise MySpecialError.new("New instances can be raised directly.") diff --git a/src/about_hashes.rb b/src/about_hashes.rb index e74793fdf..49b393915 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -3,8 +3,8 @@ class AboutHashes < EdgeCase::Koan def test_creating_hashes empty_hash = Hash.new - assert_equal Hash, empty_hash.class - assert_equal({}, empty_hash) + assert_equal __(Hash), empty_hash.class + assert_equal({}, empty_hash) # __ assert_equal __(0), empty_hash.size end @@ -25,7 +25,7 @@ def test_changing_hashes hash[:one] = "eins" expected = { :one => __("eins"), :two => "dos" } - assert_equal expected, hash + assert_equal __(true), expected == hash # Bonus Question: Why was "expected" broken out into a variable # rather than used as a literal? @@ -35,7 +35,7 @@ def test_hash_is_unordered hash1 = { :one => "uno", :two => "dos" } hash2 = { :two => "dos", :one => "uno" } - assert_equal hash1, hash2 + assert_equal __(true), hash1 == hash2 end def test_hash_keys @@ -43,7 +43,7 @@ def test_hash_keys assert_equal __(2), hash.keys.size assert_equal __(true), hash.keys.include?(:one) assert_equal __(true), hash.keys.include?(:two) - assert_equal Array, hash.keys.class + assert_equal __(Array), hash.keys.class end def test_hash_values @@ -51,16 +51,16 @@ def test_hash_values 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 + assert_equal __(Array), hash.values.class end def test_combining_hashes hash = { "jim" => 53, "amy" => 20, "dan" => 23 } new_hash = hash.merge({ "jim" => 54, "jenny" => 26 }) - assert_not_equal hash, new_hash - + assert_equal __(true), hash != new_hash + expected = { "jim" => __(54), "amy" => 20, "dan" => 23, "jenny" => __(26) } - assert_equal expected, new_hash + assert_equal __(true), expected == new_hash end end diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 08071baf3..324a116f8 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -12,7 +12,7 @@ def test_iterating_with_each array.each do |item| sum += item end - assert_equal 6, sum + assert_equal __(6), sum end def test_each_can_use_curly_brace_blocks_too diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index c2b871501..37126f252 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -11,19 +11,19 @@ def caught? 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?) + assert mc.send(:caught?) # __ end def test_methods_can_be_invoked_more_dynamically mc = MessageCatcher.new - assert mc.send("caught?") + 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? end @@ -74,7 +74,7 @@ def test_sending_undefined_messages_to_a_typical_object_results_in_errors exception = assert_raise(___(NoMethodError)) do typical.foobar end - assert_match(/foobar/, exception.message) + assert_match(/foobar/, exception.message) # __ end def test_calling_method_missing_causes_the_no_method_error @@ -83,7 +83,7 @@ def test_calling_method_missing_causes_the_no_method_error exception = assert_raise(___(NoMethodError)) do typical.method_missing(:foobar) end - assert_match(/foobar/, exception.message) + assert_match(/foobar/, exception.message) # __ # THINK ABOUT IT: # @@ -122,7 +122,7 @@ def test_all_messages_are_caught def test_catching_messages_makes_respond_to_lie catcher = AllMessageCatcher.new - assert_nothing_raised(NoMethodError) do + assert_nothing_raised(NoMethodError) do # __ catcher.any_method end assert_equal __(false), catcher.respond_to?(:any_method) diff --git a/src/about_methods.rb b/src/about_methods.rb index 42a06cfd7..78ed5b697 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -19,10 +19,10 @@ def test_calling_global_methods_without_parentheses # considered to be syntactically invalid). def test_sometimes_missing_parentheses_are_ambiguous #-- - eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK + eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK # __ if false #++ - eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK + eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK # __ #-- end #++ diff --git a/src/about_modules.rb b/src/about_modules.rb index 9e26d00aa..261746a58 100644 --- a/src/about_modules.rb +++ b/src/about_modules.rb @@ -44,8 +44,8 @@ def test_normal_methods_are_available_in_the_object def test_module_methods_are_also_availble_in_the_object fido = Dog.new - assert_nothing_raised(Exception) do - fido.set_name("Rover") + assert_nothing_raised(Exception) do # __ + fido.set_name("Rover") end end diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb index 01e39f2cd..55b85f678 100644 --- a/src/about_regular_expressions.rb +++ b/src/about_regular_expressions.rb @@ -3,11 +3,11 @@ class AboutRegularExpressions < EdgeCase::Koan def test_a_pattern_is_a_regular_expression - assert_equal Regexp, /pattern/.class + assert_equal __(Regexp), /pattern/.class end def test_a_regexp_can_search_a_string_for_matching_content - assert_equal "match", "some matching content"[/match/] + assert_equal __("match"), "some matching content"[/match/] end def test_a_failed_match_returns_nil diff --git a/src/about_scope.rb b/src/about_scope.rb index 796ff029b..f6843c870 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -29,8 +29,8 @@ def test_you_can_reference_nested_classes_using_the_scope_operator 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 + assert_equal __(true), fido.class != rover.class + assert_equal __(true), Jims::Dog != Joes::Dog end # ------------------------------------------------------------------ diff --git a/src/edgecase.rb b/src/edgecase.rb index 1a5b882f0..1d7ef5fb9 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -3,6 +3,10 @@ require 'test/unit/assertions' +# -------------------------------------------------------------------- +# Support code for the Ruby Koans. +# -------------------------------------------------------------------- + class FillMeInError < StandardError end @@ -16,6 +20,8 @@ def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end +# Standard, generic replacement value. +# If value19 is given, it is used inplace of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) if RUBY_VERSION < "1.9" value @@ -24,6 +30,7 @@ def __(value="FILL ME IN", value19=:mu) end end +# Numeric replacement value. def _n_(value=999999, value19=:mu) if RUBY_VERSION < "1.9" value @@ -32,10 +39,12 @@ def _n_(value=999999, value19=:mu) end end +# Error object replacement value. def ___(value=FillMeInError) value end +# Method name replacement. class Object def ____(method=nil) if method From beb7fe591ecf0fd8b386b1ee8d4d13a6a51d7faf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 13:46:21 -0400 Subject: [PATCH 110/276] Added rake task for running koans against several rubies. --- rakelib/run.rake | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 rakelib/run.rake diff --git a/rakelib/run.rake b/rakelib/run.rake new file mode 100644 index 000000000..6d52f6196 --- /dev/null +++ b/rakelib/run.rake @@ -0,0 +1,7 @@ +RUBIES = ENV['KOAN_RUBIES'] || %w(ruby-1.8.7-p299,ruby-1.9.2-p0,jruby-1.5.2,jruby-head) + +task :runall do + chdir('src') do + sh "rvm #{RUBIES} path_to_enlightenment.rb" + end +end From 91f15dc69000bbc593ebd3d819513bb05c9253da Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 14:09:38 -0400 Subject: [PATCH 111/276] Simplified output for running against multiple rubies. --- rakelib/run.rake | 1 + src/edgecase.rb | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/rakelib/run.rake b/rakelib/run.rake index 6d52f6196..a21917833 100644 --- a/rakelib/run.rake +++ b/rakelib/run.rake @@ -2,6 +2,7 @@ RUBIES = ENV['KOAN_RUBIES'] || %w(ruby-1.8.7-p299,ruby-1.9.2-p0,jruby-1.5.2,jrub task :runall do chdir('src') do + ENV['SIMPLE_KOAN_OUTPUT'] = 'true' sh "rvm #{RUBIES} path_to_enlightenment.rb" end end diff --git a/src/edgecase.rb b/src/edgecase.rb index 1d7ef5fb9..424e159a9 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -58,6 +58,11 @@ def ____(method=nil) end module EdgeCase + class << self + def simple_output + ENV['SIMPLE_KOAN_OUTPUT'] == 'true' + end + end module Color #shamelessly stolen (and modified) from redgreen @@ -185,6 +190,18 @@ def show_progress end def end_screen + if EdgeCase.simple_output + boring_end_screen + else + artistic_end_screen + end + end + + def boring_end_screen + puts "Mountains are again merely mountains" + end + + def artistic_end_screen completed = <<-ENDTEXT ,, , ,, : ::::, :::, From 322ca38767683bacca28431b5f7d3ab2e1d99587 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 14:15:59 -0400 Subject: [PATCH 112/276] Minitest lines in backtrace are no longer interesting. --- src/edgecase.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index 424e159a9..e8ff9a16d 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -286,7 +286,7 @@ def indent(text) def find_interesting_lines(backtrace) backtrace.reject { |line| - line =~ /test\/unit\/|edgecase\.rb/ + line =~ /test\/unit\/|edgecase\.rb|minitest/ } end From 8436b46c1a123e6756ae1d131a493e9817627619 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 27 Sep 2010 14:36:38 -0400 Subject: [PATCH 113/276] Added Ruby version information to the output. --- src/edgecase.rb | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index e8ff9a16d..658da2e8b 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -57,6 +57,19 @@ def ____(method=nil) end end +class String + def side_padding(width) + extra = width - self.size + if width < 0 + self + else + left_padding = extra / 2 + right_padding = (extra+1)/2 + (" " * left_padding) + self + (" " *right_padding) + end + end +end + module EdgeCase class << self def simple_output @@ -202,6 +215,9 @@ def boring_end_screen end def artistic_end_screen + "JRuby 1.9.x Koans" + ruby_version = "(in #{'J' if defined?(JRUBY_VERSION)}Ruby #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION})" + ruby_version = ruby_version.side_padding(54) completed = <<-ENDTEXT ,, , ,, : ::::, :::, @@ -218,8 +234,8 @@ def artistic_end_screen ,:::::::::::, ::::::::::::, :::::::::::, ,:::::::::::: ::::::::::::: ,:::::::::::: -:::::::::::: Ruby Koans ::::::::::::, -:::::::::::: ,::::::::::::, +:::::::::::: Ruby Koans ::::::::::::, +::::::::::::#{ ruby_version },::::::::::::, :::::::::::, , :::::::::::: ,:::::::::::::, brought to you by ,,::::::::::::, :::::::::::::: ,:::::::::::: From 45523c03c021e7d782394749a346f90a2c5bc554 Mon Sep 17 00:00:00 2001 From: Marc Peabody + Jim Weirich Date: Mon, 27 Sep 2010 16:54:10 -0400 Subject: [PATCH 114/276] More class conflict examples. --- src/about_java_interop.rb | 89 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/about_java_interop.rb diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb new file mode 100644 index 000000000..b4fdbd5d7 --- /dev/null +++ b/src/about_java_interop.rb @@ -0,0 +1,89 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +include Java + +# Concepts +# * Pull in a java class +# * calling a method, Camel vs snake +# * Resovling module/class name conflicts +# * Showing what gets returned +# * Ruby Strings VS Java Strings +# * Calling custom java class +# * Calling Ruby from java??? + +class AboutJavaInterop < EdgeCase::Koan + def test_using_a_java_library_class + java_array = java.util.ArrayList.new + assert_equal __(Java::JavaUtil::ArrayList), java_array.class + end + + def test_java_class_can_be_referenced_using_both_ruby_and_java_like_syntax + assert_equal __(true), Java::JavaUtil::ArrayList == java.util.ArrayList + end + + def test_include_class_includes_class_in_module_scope + assert_nil defined?(TreeSet) # __ + include_class "java.util.TreeSet" + assert_equal __("constant"), defined?(TreeSet) + end + + # THINK ABOUT IT: + # + # What if we use: + # + # include_class "java.lang.String" + # + # What would be the value of the String constant after this + # include_class is run? Would it be useful to provide a way of + # aliasing java classes to different names? + + JString = java.lang.String + def test_also_java_class_can_be_given_ruby_aliases + java_string = JString.new("A Java String") + assert_equal __(java.lang.String), java_string.class + assert_equal __(java.lang.String), JString + end + + def test_can_directly_call_java_methods_on_java_objects + java_string = JString.new("A Java String") + assert_equal __("a java string"), java_string.toLowerCase + end + + def test_jruby_provides_snake_case_versions_of_java_methods + java_string = JString.new("A Java String") + assert_equal __("a java string"), java_string.to_lower_case + end + + def test_jruby_provides_question_mark_versions_of_boolean_methods + java_string = JString.new("A Java String") + assert_equal __(true), java_string.endsWith("String") + assert_equal __(true), java_string.ends_with("String") + assert_equal __(true), java_string.ends_with?("String") + end + + def test_java_string_are_not_ruby_strings + ruby_string = "A Java String" + java_string = java.lang.String.new(ruby_string) + assert_equal __(true), java_string.is_a?(java.lang.String) + assert_equal __(false), java_string.is_a?(String) + end + + def test_java_strings_can_be_compared_to_ruby_strings_maybe + ruby_string = "A Java String" + java_string = java.lang.String.new(ruby_string) + assert_equal __(false), ruby_string == java_string + assert_equal __(true), java_string == ruby_string + + # THINK ABOUT IT: + # Is there any possible way for this to be more wrong? + end + + def test_however_most_methods_returning_strings_return_ruby_strings + java_array = java.util.ArrayList.new + assert_equal __("[]"), java_array.toString + assert_equal __(true), java_array.toString.is_a?(String) + assert_equal __(false), java_array.toString.is_a?(java.lang.String) + end + + +end From 1dcd9babd4fe285accf3998d94f8f95117cbda2d Mon Sep 17 00:00:00 2001 From: Marc Peabody + Jim Weirich Date: Mon, 27 Sep 2010 18:24:25 -0400 Subject: [PATCH 115/276] Added more think about its to the ruby/java string comparisons. --- src/about_java_interop.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index b4fdbd5d7..2bc9628a4 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -75,7 +75,17 @@ def test_java_strings_can_be_compared_to_ruby_strings_maybe assert_equal __(true), java_string == ruby_string # THINK ABOUT IT: + # # Is there any possible way for this to be more wrong? + # + # SERIOUSLY, THINK ABOUT IT: + # + # Why do you suppose that Ruby and Java strings compare like that? + # + # ADVANCED THINK ABOUT IT: + # + # Is there a way to make Ruby/Java string comparisons commutative? + # How would you do it? end def test_however_most_methods_returning_strings_return_ruby_strings @@ -85,5 +95,4 @@ def test_however_most_methods_returning_strings_return_ruby_strings assert_equal __(false), java_array.toString.is_a?(java.lang.String) end - end From 6fb8e3c3afa90ca1cab69fbf2abed3722d7b173c Mon Sep 17 00:00:00 2001 From: Srdjan Pejic Date: Thu, 23 Sep 2010 21:06:40 -0400 Subject: [PATCH 116/276] Cool test; Still can't believe there is no standard implementation of first/rest --- src/about_array_assignment.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 659ce6b26..035d5bbb0 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -12,6 +12,12 @@ def test_parallel_assignments assert_equal __("Smith"), last_name end + def test_parallel_assigments_with_splat_operator + first_name, *last_name = ["John", "Smith", "III"] + assert_equal "John", first_name + assert_equal ["Smith","III"], last_name + end + def test_parallel_assignments_with_extra_values first_name, last_name = ["John", "Smith", "III"] assert_equal __("John"), first_name From c0bbe773d9c396a6033e735719f97b9931bf4087 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:15:08 -0400 Subject: [PATCH 117/276] Moved splat example to later + several typo corrections. --- src/about_array_assignment.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 035d5bbb0..ce3b09395 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -5,32 +5,32 @@ def test_non_parallel_assignment names = ["John", "Smith"] assert_equal __(["John", "Smith"]), names end - + def test_parallel_assignments first_name, last_name = ["John", "Smith"] assert_equal __("John"), first_name assert_equal __("Smith"), last_name end - def test_parallel_assigments_with_splat_operator - first_name, *last_name = ["John", "Smith", "III"] - assert_equal "John", first_name - assert_equal ["Smith","III"], last_name - end - def test_parallel_assignments_with_extra_values first_name, last_name = ["John", "Smith", "III"] assert_equal __("John"), first_name assert_equal __("Smith"), last_name end - def test_parallel_assignments_with_extra_variables + def test_parallel_assignments_with_splat_operator + first_name, *last_name = ["John", "Smith", "III"] + assert_equal "John", first_name + assert_equal ["Smith","III"], last_name + end + + def test_parallel_assignments_with_too_few_variables first_name, last_name = ["Cher"] assert_equal __("Cher"), first_name assert_equal __(nil), last_name end - def test_parallel_assignements_with_subarrays + def test_parallel_assignments_with_subarrays first_name, last_name = [["Willie", "Rae"], "Johnson"] assert_equal __(["Willie", "Rae"]), first_name assert_equal __("Johnson"), last_name From b41d6167b433ed5c27e65e8f838a33fd80b0e5e2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:17:46 -0400 Subject: [PATCH 118/276] Updated koans from src. --- koans/about_array_assignment.rb | 12 +++- koans/about_arrays.rb | 4 +- koans/about_classes.rb | 6 +- koans/about_exceptions.rb | 6 +- koans/about_hashes.rb | 16 ++--- koans/about_iteration.rb | 2 +- koans/about_java_interop.rb | 98 ++++++++++++++++++++++++++++++ koans/about_modules.rb | 2 +- koans/about_regular_expressions.rb | 4 +- koans/about_scope.rb | 4 +- koans/edgecase.rb | 48 ++++++++++++++- 11 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 koans/about_java_interop.rb diff --git a/koans/about_array_assignment.rb b/koans/about_array_assignment.rb index 12733fb29..71efb1613 100644 --- a/koans/about_array_assignment.rb +++ b/koans/about_array_assignment.rb @@ -5,7 +5,7 @@ def test_non_parallel_assignment names = ["John", "Smith"] assert_equal __, names end - + def test_parallel_assignments first_name, last_name = ["John", "Smith"] assert_equal __, first_name @@ -18,13 +18,19 @@ def test_parallel_assignments_with_extra_values assert_equal __, last_name end - def test_parallel_assignments_with_extra_variables + def test_parallel_assignments_with_splat_operator + first_name, *last_name = ["John", "Smith", "III"] + assert_equal "John", first_name + assert_equal ["Smith","III"], last_name + end + + def test_parallel_assignments_with_too_few_variables first_name, last_name = ["Cher"] assert_equal __, first_name assert_equal __, last_name end - def test_parallel_assignements_with_subarrays + def test_parallel_assignments_with_subarrays first_name, last_name = [["Willie", "Rae"], "Johnson"] assert_equal __, first_name assert_equal __, last_name diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb index 2ed3181ee..9f27b5aaa 100644 --- a/koans/about_arrays.rb +++ b/koans/about_arrays.rb @@ -45,9 +45,9 @@ def test_slicing_arrays end def test_arrays_and_ranges - assert_equal Range, (1..5).class + assert_equal __, (1..5).class assert_not_equal [1,2,3,4,5], (1..5) - assert_equal [1,2,3,4,5], (1..5).to_a + assert_equal __, (1..5).to_a assert_equal __, (1...5).to_a end diff --git a/koans/about_classes.rb b/koans/about_classes.rb index 08858b88f..fce0be084 100644 --- a/koans/about_classes.rb +++ b/koans/about_classes.rb @@ -130,7 +130,7 @@ def test_different_objects_have_difference_instance_variables fido = Dog6.new("Fido") rover = Dog6.new("Rover") - assert_not_equal rover.name, fido.name + assert_equal __, rover.name != fido.name end # ------------------------------------------------------------------ @@ -164,12 +164,12 @@ def test_inside_a_method_self_refers_to_the_containing_object def test_to_s_provides_a_string_version_of_the_object fido = Dog7.new("Fido") - assert_equal "Fido", fido.to_s + assert_equal __, fido.to_s end def test_to_s_is_used_in_string_interpolation fido = Dog7.new("Fido") - assert_equal "My dog is Fido", "My dog is #{fido}" + assert_equal __, "My dog is #{fido}" end def test_inspect_provides_a_more_complete_string_version diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index c44833e5e..32708b6aa 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -22,12 +22,12 @@ def test_rescue_clause assert_equal __, result - assert ex.is_a?(StandardError), "Failure message." - assert ex.is_a?(RuntimeError), "Failure message." + assert ex.is_a?(___), "Failure message." + assert ex.is_a?(___), "Failure message." assert RuntimeError.ancestors.include?(StandardError), "RuntimeError is a subclass of StandardError" - + assert_equal __, ex.message end diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index d491f6d06..3e4e62c89 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -3,7 +3,7 @@ class AboutHashes < EdgeCase::Koan def test_creating_hashes empty_hash = Hash.new - assert_equal Hash, empty_hash.class + assert_equal __, empty_hash.class assert_equal({}, empty_hash) assert_equal __, empty_hash.size end @@ -25,7 +25,7 @@ def test_changing_hashes hash[:one] = "eins" expected = { :one => __, :two => "dos" } - assert_equal expected, hash + assert_equal __, expected == hash # Bonus Question: Why was "expected" broken out into a variable # rather than used as a literal? @@ -35,7 +35,7 @@ def test_hash_is_unordered hash1 = { :one => "uno", :two => "dos" } hash2 = { :two => "dos", :one => "uno" } - assert_equal hash1, hash2 + assert_equal __, hash1 == hash2 end def test_hash_keys @@ -43,7 +43,7 @@ def test_hash_keys assert_equal __, hash.keys.size assert_equal __, hash.keys.include?(:one) assert_equal __, hash.keys.include?(:two) - assert_equal Array, hash.keys.class + assert_equal __, hash.keys.class end def test_hash_values @@ -51,16 +51,16 @@ def test_hash_values assert_equal __, hash.values.size assert_equal __, hash.values.include?("uno") assert_equal __, hash.values.include?("dos") - assert_equal Array, hash.values.class + assert_equal __, hash.values.class end def test_combining_hashes hash = { "jim" => 53, "amy" => 20, "dan" => 23 } new_hash = hash.merge({ "jim" => 54, "jenny" => 26 }) - assert_not_equal hash, new_hash - + assert_equal __, hash != new_hash + expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ } - assert_equal expected, new_hash + assert_equal __, expected == new_hash end end diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 1b64cbe46..591b869b1 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -12,7 +12,7 @@ def test_iterating_with_each array.each do |item| sum += item end - assert_equal 6, sum + assert_equal __, sum end def test_each_can_use_curly_brace_blocks_too diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb new file mode 100644 index 000000000..0bdd18377 --- /dev/null +++ b/koans/about_java_interop.rb @@ -0,0 +1,98 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +include Java + +# Concepts +# * Pull in a java class +# * calling a method, Camel vs snake +# * Resovling module/class name conflicts +# * Showing what gets returned +# * Ruby Strings VS Java Strings +# * Calling custom java class +# * Calling Ruby from java??? + +class AboutJavaInterop < EdgeCase::Koan + def test_using_a_java_library_class + java_array = java.util.ArrayList.new + assert_equal __, java_array.class + end + + def test_java_class_can_be_referenced_using_both_ruby_and_java_like_syntax + assert_equal __, Java::JavaUtil::ArrayList == java.util.ArrayList + end + + def test_include_class_includes_class_in_module_scope + assert_nil defined?(TreeSet) + include_class "java.util.TreeSet" + assert_equal __, defined?(TreeSet) + end + + # THINK ABOUT IT: + # + # What if we use: + # + # include_class "java.lang.String" + # + # What would be the value of the String constant after this + # include_class is run? Would it be useful to provide a way of + # aliasing java classes to different names? + + JString = java.lang.String + def test_also_java_class_can_be_given_ruby_aliases + java_string = JString.new("A Java String") + assert_equal __, java_string.class + assert_equal __, JString + end + + def test_can_directly_call_java_methods_on_java_objects + java_string = JString.new("A Java String") + assert_equal __, java_string.toLowerCase + end + + def test_jruby_provides_snake_case_versions_of_java_methods + java_string = JString.new("A Java String") + assert_equal __, java_string.to_lower_case + end + + def test_jruby_provides_question_mark_versions_of_boolean_methods + java_string = JString.new("A Java String") + assert_equal __, java_string.endsWith("String") + assert_equal __, java_string.ends_with("String") + assert_equal __, java_string.ends_with?("String") + end + + def test_java_string_are_not_ruby_strings + ruby_string = "A Java String" + java_string = java.lang.String.new(ruby_string) + assert_equal __, java_string.is_a?(java.lang.String) + assert_equal __, java_string.is_a?(String) + end + + def test_java_strings_can_be_compared_to_ruby_strings_maybe + ruby_string = "A Java String" + java_string = java.lang.String.new(ruby_string) + assert_equal __, ruby_string == java_string + assert_equal __, java_string == ruby_string + + # THINK ABOUT IT: + # + # Is there any possible way for this to be more wrong? + # + # SERIOUSLY, THINK ABOUT IT: + # + # Why do you suppose that Ruby and Java strings compare like that? + # + # ADVANCED THINK ABOUT IT: + # + # Is there a way to make Ruby/Java string comparisons commutative? + # How would you do it? + end + + def test_however_most_methods_returning_strings_return_ruby_strings + java_array = java.util.ArrayList.new + assert_equal __, java_array.toString + assert_equal __, java_array.toString.is_a?(String) + assert_equal __, java_array.toString.is_a?(java.lang.String) + end + +end diff --git a/koans/about_modules.rb b/koans/about_modules.rb index c528c32fb..cd967a949 100644 --- a/koans/about_modules.rb +++ b/koans/about_modules.rb @@ -45,7 +45,7 @@ def test_normal_methods_are_available_in_the_object def test_module_methods_are_also_availble_in_the_object fido = Dog.new assert_nothing_raised(Exception) do - fido.set_name("Rover") + fido.set_name("Rover") end end diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb index c35d757d7..83449112c 100644 --- a/koans/about_regular_expressions.rb +++ b/koans/about_regular_expressions.rb @@ -3,11 +3,11 @@ class AboutRegularExpressions < EdgeCase::Koan def test_a_pattern_is_a_regular_expression - assert_equal Regexp, /pattern/.class + assert_equal __, /pattern/.class end def test_a_regexp_can_search_a_string_for_matching_content - assert_equal "match", "some matching content"[/match/] + assert_equal __, "some matching content"[/match/] end def test_a_failed_match_returns_nil diff --git a/koans/about_scope.rb b/koans/about_scope.rb index edbe87662..d07d2af18 100644 --- a/koans/about_scope.rb +++ b/koans/about_scope.rb @@ -29,8 +29,8 @@ def test_you_can_reference_nested_classes_using_the_scope_operator assert_equal __, fido.identify assert_equal __, rover.identify - assert_not_equal fido.class, rover.class - assert_not_equal Jims::Dog, Joes::Dog + assert_equal __, fido.class != rover.class + assert_equal __, Jims::Dog != Joes::Dog end # ------------------------------------------------------------------ diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 1a5b882f0..658da2e8b 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -3,6 +3,10 @@ require 'test/unit/assertions' +# -------------------------------------------------------------------- +# Support code for the Ruby Koans. +# -------------------------------------------------------------------- + class FillMeInError < StandardError end @@ -16,6 +20,8 @@ def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end +# Standard, generic replacement value. +# If value19 is given, it is used inplace of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) if RUBY_VERSION < "1.9" value @@ -24,6 +30,7 @@ def __(value="FILL ME IN", value19=:mu) end end +# Numeric replacement value. def _n_(value=999999, value19=:mu) if RUBY_VERSION < "1.9" value @@ -32,10 +39,12 @@ def _n_(value=999999, value19=:mu) end end +# Error object replacement value. def ___(value=FillMeInError) value end +# Method name replacement. class Object def ____(method=nil) if method @@ -48,7 +57,25 @@ def ____(method=nil) end end +class String + def side_padding(width) + extra = width - self.size + if width < 0 + self + else + left_padding = extra / 2 + right_padding = (extra+1)/2 + (" " * left_padding) + self + (" " *right_padding) + end + end +end + module EdgeCase + class << self + def simple_output + ENV['SIMPLE_KOAN_OUTPUT'] == 'true' + end + end module Color #shamelessly stolen (and modified) from redgreen @@ -176,6 +203,21 @@ def show_progress end def end_screen + if EdgeCase.simple_output + boring_end_screen + else + artistic_end_screen + end + end + + def boring_end_screen + puts "Mountains are again merely mountains" + end + + def artistic_end_screen + "JRuby 1.9.x Koans" + ruby_version = "(in #{'J' if defined?(JRUBY_VERSION)}Ruby #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION})" + ruby_version = ruby_version.side_padding(54) completed = <<-ENDTEXT ,, , ,, : ::::, :::, @@ -192,8 +234,8 @@ def end_screen ,:::::::::::, ::::::::::::, :::::::::::, ,:::::::::::: ::::::::::::: ,:::::::::::: -:::::::::::: Ruby Koans ::::::::::::, -:::::::::::: ,::::::::::::, +:::::::::::: Ruby Koans ::::::::::::, +::::::::::::#{ ruby_version },::::::::::::, :::::::::::, , :::::::::::: ,:::::::::::::, brought to you by ,,::::::::::::, :::::::::::::: ,:::::::::::: @@ -260,7 +302,7 @@ def indent(text) def find_interesting_lines(backtrace) backtrace.reject { |line| - line =~ /test\/unit\/|edgecase\.rb/ + line =~ /test\/unit\/|edgecase\.rb|minitest/ } end From 4789e831df8757a013bf3600a23899b7b9122778 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:43:03 -0400 Subject: [PATCH 119/276] Added enumerable collections and open java classes to jruby koan. --- src/about_java_interop.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index 2bc9628a4..39a93b797 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -95,4 +95,30 @@ def test_however_most_methods_returning_strings_return_ruby_strings assert_equal __(false), java_array.toString.is_a?(java.lang.String) end + def test_java_collections_are_enumerable + java_array = java.util.ArrayList.new + java_array << "one" << "two" << "three" + assert_equal __(["ONE", "TWO", "THREE"]), java_array.map { |item| item.upcase } + end + + # ------------------------------------------------------------------ + + # Open the Java ArrayList class and add a new method. + class Java::JavaUtil::ArrayList + def multiply_all + result = 1 + each do |item| + result *= item + end + result + end + end + + def test_java_class_are_open_from_ruby + java_array = java.util.ArrayList.new + java_array.add_all([1,2,3,4,5]) + + assert_equal __(120), java_array.multiply_all + end + end From e24d94eeffbb72e20935a1f60d95db7a84449cdd Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:43:34 -0400 Subject: [PATCH 120/276] Updated koans from source. --- koans/about_java_interop.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb index 0bdd18377..20a40c7b3 100644 --- a/koans/about_java_interop.rb +++ b/koans/about_java_interop.rb @@ -95,4 +95,30 @@ def test_however_most_methods_returning_strings_return_ruby_strings assert_equal __, java_array.toString.is_a?(java.lang.String) end + def test_java_collections_are_enumerable + java_array = java.util.ArrayList.new + java_array << "one" << "two" << "three" + assert_equal __, java_array.map { |item| item.upcase } + end + + # ------------------------------------------------------------------ + + # Open the Java ArrayList class and add a new method. + class Java::JavaUtil::ArrayList + def multiply_all + result = 1 + each do |item| + result *= item + end + result + end + end + + def test_java_class_are_open_from_ruby + java_array = java.util.ArrayList.new + java_array.add_all([1,2,3,4,5]) + + assert_equal __, java_array.multiply_all + end + end From 7dee146a8c2087247bf8562d7d8e9727e3021758 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:49:06 -0400 Subject: [PATCH 121/276] Added missing __ replacements --- koans/about_array_assignment.rb | 4 ++-- src/about_array_assignment.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/koans/about_array_assignment.rb b/koans/about_array_assignment.rb index 71efb1613..21a64bb81 100644 --- a/koans/about_array_assignment.rb +++ b/koans/about_array_assignment.rb @@ -20,8 +20,8 @@ def test_parallel_assignments_with_extra_values def test_parallel_assignments_with_splat_operator first_name, *last_name = ["John", "Smith", "III"] - assert_equal "John", first_name - assert_equal ["Smith","III"], last_name + assert_equal __, first_name + assert_equal __, last_name end def test_parallel_assignments_with_too_few_variables diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index ce3b09395..35af856a2 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -20,8 +20,8 @@ def test_parallel_assignments_with_extra_values def test_parallel_assignments_with_splat_operator first_name, *last_name = ["John", "Smith", "III"] - assert_equal "John", first_name - assert_equal ["Smith","III"], last_name + assert_equal __("John"), first_name + assert_equal __(["Smith","III"]), last_name end def test_parallel_assignments_with_too_few_variables From 5b483df29bf49fd90b761cb1b0458002c0406b74 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:49:20 -0400 Subject: [PATCH 122/276] Added descriptions to rake tasks. --- rakelib/checks.rake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rakelib/checks.rake b/rakelib/checks.rake index 9ef619901..287020269 100644 --- a/rakelib/checks.rake +++ b/rakelib/checks.rake @@ -15,6 +15,7 @@ namespace "check" do puts end + desc "Check that asserts have __ replacements" task :asserts do puts "Checking for asserts missing the replacement text:" begin @@ -28,4 +29,5 @@ namespace "check" do end end +desc "Run some simple consistancy checks" task :check => ["check:abouts", "check:asserts"] From fdb8774c958d38fa2d254df975b35dc9427a0c40 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 28 Sep 2010 14:49:43 -0400 Subject: [PATCH 123/276] Added Java Interop koans if running jruby. --- koans/path_to_enlightenment.rb | 3 +++ src/path_to_enlightenment.rb | 3 +++ 2 files changed, 6 insertions(+) diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index f8b09c7e4..641559ab0 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -31,4 +31,7 @@ require 'about_class_methods' require 'about_message_passing' require 'about_proxy_object_project' +in_ruby_version("jruby") do + require 'about_java_interop' +end require 'about_extra_credit' diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index f8b09c7e4..641559ab0 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -31,4 +31,7 @@ require 'about_class_methods' require 'about_message_passing' require 'about_proxy_object_project' +in_ruby_version("jruby") do + require 'about_java_interop' +end require 'about_extra_credit' From e5843f64fd98ed74e24fac4d8fe1ba688698bb77 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 1 Oct 2010 11:05:25 -0400 Subject: [PATCH 124/276] Fixed bug where some koans were not generated properly. --- koans/about_methods.rb | 4 ++-- src/about_methods.rb | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/koans/about_methods.rb b/koans/about_methods.rb index fde97e987..d36e9ab38 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -36,12 +36,12 @@ def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___) do my_global_method end - assert_match(/#{__ of arguments")}/, exception.message) + assert_match(/__/, exception.message) exception = assert_raise(___) do my_global_method(1,2,3) end - assert_match(/#{__ of arguments")}/, exception.message) + assert_match(/__/, exception.message) end # ------------------------------------------------------------------ diff --git a/src/about_methods.rb b/src/about_methods.rb index 78ed5b697..1497f9ba2 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -43,12 +43,15 @@ def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___(ArgumentError)) do my_global_method end - assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message) + #-- + pattern = "wrong (number|#) of arguments" + #++ + assert_match(/#{__(pattern)}/, exception.message) exception = assert_raise(___(ArgumentError)) do my_global_method(1,2,3) end - assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message) + assert_match(/#{__(pattern)}/, exception.message) end # ------------------------------------------------------------------ From e26666280ccf8c1f45fbbdd70d1d4e82ae18735d Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Sat, 2 Oct 2010 10:11:18 -0400 Subject: [PATCH 125/276] java coercion --- koans/about_java_interop.rb | 15 +++++++++++++++ src/about_java_interop.rb | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb index 20a40c7b3..fb2669339 100644 --- a/koans/about_java_interop.rb +++ b/koans/about_java_interop.rb @@ -95,6 +95,21 @@ def test_however_most_methods_returning_strings_return_ruby_strings assert_equal __, java_array.toString.is_a?(java.lang.String) end + def test_some_ruby_objects_can_be_coerced_to_java + assert_equal __, "ruby string".to_java.class + assert_equal __, 1.to_java.class + assert_equal __, 9.32.to_java.class + assert_equal __, false.to_java.class + end + + def test_some_ruby_objects_can_NOT_be_coerced_to_java + [[], {}, Object.new].each do |ruby_object| + assert_raise(___) do + ruby_object.to_java_class + end + end + end + def test_java_collections_are_enumerable java_array = java.util.ArrayList.new java_array << "one" << "two" << "three" diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index 39a93b797..bb63a5fc4 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -95,6 +95,21 @@ def test_however_most_methods_returning_strings_return_ruby_strings assert_equal __(false), java_array.toString.is_a?(java.lang.String) end + def test_some_ruby_objects_can_be_coerced_to_java + assert_equal __(Java::JavaLang::String), "ruby string".to_java.class + assert_equal __(Java::JavaLang::Long), 1.to_java.class + assert_equal __(Java::JavaLang::Double), 9.32.to_java.class + assert_equal __(Java::JavaLang::Boolean), false.to_java.class + end + + def test_some_ruby_objects_can_NOT_be_coerced_to_java + [[], {}, Object.new].each do |ruby_object| + assert_raise(___(NoMethodError)) do + ruby_object.to_java_class + end + end + end + def test_java_collections_are_enumerable java_array = java.util.ArrayList.new java_array << "one" << "two" << "three" From cfd5b6bbe10dfa3a998bb219e130ac0b63433ec4 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 21 Oct 2010 07:02:10 -0400 Subject: [PATCH 126/276] Fixed test_symbols_with_spaces_can_be_built method name collision. --- src/about_symbols.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 7a2e19a7d..705c2e37e 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -53,7 +53,7 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __("cats and dogs").to_sym end - def test_symbols_with_spaces_can_be_built + def test_symbols_with_interpolation_can_be_built value = "and" symbol = :"cats #{value} dogs" From 1864c9c3463032c418fe35ddb2b33fb08dfbe190 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 21 Oct 2010 07:04:54 -0400 Subject: [PATCH 127/276] Updated koans for about_symbols fix --- koans/about_symbols.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index a8b7f38b0..c38539f27 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -53,7 +53,7 @@ def test_symbols_with_spaces_can_be_built assert_equal symbol, __.to_sym end - def test_symbols_with_spaces_can_be_built + def test_symbols_with_interpolation_can_be_built value = "and" symbol = :"cats #{value} dogs" From 71f670ac1d9ca1cf590b394d9ff789630e14e5da Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 21 Oct 2010 07:05:06 -0400 Subject: [PATCH 128/276] Disabled colored output on windows. --- koans/edgecase.rb | 19 ++++++++++++++++--- src/edgecase.rb | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 658da2e8b..c024438f4 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -93,16 +93,29 @@ module Color end def colorize(string, color_value) - if ENV['NO_COLOR'] - string - else + if use_colors? color(color_value) + string + color(COLORS[:clear]) + else + string end end def color(color_value) "\e[#{color_value}m" end + + def use_colors? + return false if ENV['NO_COLOR'] + if ENV['ANSI_COLOR'].nil? + ! using_windows? + else + ENV['ANSI_COLOR'] =~ /^(t|y)/i + end + end + + def using_windows? + File::ALT_SEPARATOR + end end class Sensei diff --git a/src/edgecase.rb b/src/edgecase.rb index 658da2e8b..c024438f4 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -93,16 +93,29 @@ module Color end def colorize(string, color_value) - if ENV['NO_COLOR'] - string - else + if use_colors? color(color_value) + string + color(COLORS[:clear]) + else + string end end def color(color_value) "\e[#{color_value}m" end + + def use_colors? + return false if ENV['NO_COLOR'] + if ENV['ANSI_COLOR'].nil? + ! using_windows? + else + ENV['ANSI_COLOR'] =~ /^(t|y)/i + end + end + + def using_windows? + File::ALT_SEPARATOR + end end class Sensei From 9291f534c6ce9a3ae7d6f22a052090f26a2e0b8f Mon Sep 17 00:00:00 2001 From: Luke Pearce Date: Mon, 29 Nov 2010 13:24:40 +0000 Subject: [PATCH 129/276] Fixed exceptions typo --- koans/about_exceptions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index 32708b6aa..d228e48de 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -22,8 +22,8 @@ def test_rescue_clause assert_equal __, result - assert ex.is_a?(___), "Failure message." - assert ex.is_a?(___), "Failure message." + assert ex.is_a?(__) + assert_equal __, ex.message assert RuntimeError.ancestors.include?(StandardError), "RuntimeError is a subclass of StandardError" From d3ce64a7685e3e0f1ffe7e616d9f243d19f23785 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 29 Nov 2010 09:02:22 -0500 Subject: [PATCH 130/276] Updatd exception koan to be clearer about StandardError VS RuntimeError --- koans/about_exceptions.rb | 4 ++-- src/about_exceptions.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb index d228e48de..d745f961b 100644 --- a/koans/about_exceptions.rb +++ b/koans/about_exceptions.rb @@ -22,8 +22,8 @@ def test_rescue_clause assert_equal __, result - assert ex.is_a?(__) - assert_equal __, ex.message + assert_equal __, ex.is_a?(StandardError), "Should be a Standard Error" + assert_equal __, ex.is_a?(RuntimeError), "Should be a Runtime Error" assert RuntimeError.ancestors.include?(StandardError), "RuntimeError is a subclass of StandardError" diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index a2efbb3a7..f24398249 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -22,8 +22,8 @@ def test_rescue_clause assert_equal __(:exception_handled), result - assert ex.is_a?(___(StandardError)), "Failure message." - assert ex.is_a?(___(RuntimeError)), "Failure message." + assert_equal __(true), ex.is_a?(StandardError), "Should be a Standard Error" + assert_equal __(true), ex.is_a?(RuntimeError), "Should be a Runtime Error" assert RuntimeError.ancestors.include?(StandardError), # __ "RuntimeError is a subclass of StandardError" From 0b9727f2998a7e3a369bc777e5ada6519a1aa649 Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Tue, 14 Dec 2010 09:12:16 -0500 Subject: [PATCH 131/276] fix mistake in about_symbols.rb --- koans/about_symbols.rb | 3 +-- src/about_symbols.rb | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index c38539f27..0c8a78b5d 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -24,8 +24,7 @@ def test_identical_symbols_are_a_single_internal_object end def test_method_names_become_symbols - all_symbols = Symbol.all_symbols - assert_equal __, all_symbols.include?(:test_method_names_become_symbols) + assert_equal __, Symbol.all_symbols.include?("test_method_names_become_symbols".to_sym) end # THINK ABOUT IT: diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 705c2e37e..0e05bdb3c 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -24,8 +24,7 @@ def test_identical_symbols_are_a_single_internal_object end def test_method_names_become_symbols - all_symbols = Symbol.all_symbols - assert_equal __(true), all_symbols.include?(:test_method_names_become_symbols) + assert_equal __(true), Symbol.all_symbols.include?("test_method_names_become_symbols".to_sym) end # THINK ABOUT IT: From 3dab146b8dd49c974dc3fb35dad3f86c3bd61fa5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 09:26:55 -0500 Subject: [PATCH 132/276] Added --/++ markers around the dice class. --- koans/about_dice_project.rb | 11 +++++------ src/about_dice_project.rb | 8 ++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/koans/about_dice_project.rb b/koans/about_dice_project.rb index a01236a66..ce817155e 100644 --- a/koans/about_dice_project.rb +++ b/koans/about_dice_project.rb @@ -1,11 +1,10 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') -class DiceSet - attr_reader :values - def roll(n) - @values = (1..n).map { rand(6) + 1 } - end -end +# Implement a DiceSet Class here: +# +# class DiceSet +# code ... +# end class AboutDiceProject < EdgeCase::Koan def test_can_create_a_dice_set diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index a01236a66..65c21dfe7 100644 --- a/src/about_dice_project.rb +++ b/src/about_dice_project.rb @@ -1,5 +1,12 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') +# Implement a DiceSet Class here: +# +# class DiceSet +# code ... +# end + +#-- class DiceSet attr_reader :values def roll(n) @@ -7,6 +14,7 @@ def roll(n) end end +#++ class AboutDiceProject < EdgeCase::Koan def test_can_create_a_dice_set dice = DiceSet.new From 297cfde6a31b58a8c3272e36fc2dbac0b2eb5ab7 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 10:16:34 -0500 Subject: [PATCH 133/276] [7439987] Changed symbol inclusion test to use strings. --- koans/about_symbols.rb | 7 ++++--- src/about_symbols.rb | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 0c8a78b5d..2a7f4a35a 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -24,13 +24,14 @@ def test_identical_symbols_are_a_single_internal_object end def test_method_names_become_symbols - assert_equal __, Symbol.all_symbols.include?("test_method_names_become_symbols".to_sym) + symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } + assert_equal __, symbols_as_strings.include?("test_method_names_become_symbols") end # THINK ABOUT IT: # - # Why do we capture the list of symbols before we check for the - # method name? + # Why do we convert the list of symbols to strings and then compare + # against the string value rather than against symbols? in_ruby_version("mri") do RubyConstant = "What is the sound of one hand clapping?" diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 0e05bdb3c..e06f5e197 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -24,13 +24,14 @@ def test_identical_symbols_are_a_single_internal_object end def test_method_names_become_symbols - assert_equal __(true), Symbol.all_symbols.include?("test_method_names_become_symbols".to_sym) + symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } + assert_equal __(true), symbols_as_strings.include?("test_method_names_become_symbols") end # THINK ABOUT IT: # - # Why do we capture the list of symbols before we check for the - # method name? + # Why do we convert the list of symbols to strings and then compare + # against the string value rather than against symbols? in_ruby_version("mri") do RubyConstant = "What is the sound of one hand clapping?" From 9b9eb640f86a4d3994609a86af5063465961f9ad Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 11:29:39 -0500 Subject: [PATCH 134/276] Added cruise task --- Rakefile | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Rakefile b/Rakefile index e42cd8c4d..a85b4781c 100644 --- a/Rakefile +++ b/Rakefile @@ -57,6 +57,28 @@ module Koans end end +module RubyImpls + # Calculate the list of relevant Ruby implementations. + def self.find_ruby_impls + rubys = `rvm list`.gsub(/=>/,'').split(/\n/).sort + expected.map { |impl| + puts "DBG: impl=#{impl.inspect}" + last = rubys.grep(Regexp.new(Regexp.quote(impl))).last + last ? last.split.first : nil + }.compact + end + + # Return a (cached) list of relevant Ruby implementations. + def self.list + @list ||= find_ruby_impls + end + + # List of expected ruby implementations. + def self.expected + %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree) + end +end + task :default => :walk_the_path task :walk_the_path do @@ -107,3 +129,38 @@ SRC_FILES.each do |koan_src| Koans.make_koan_file koan_src, t.name end end + +task :run do + puts 'koans' + Dir.chdir("src") do + puts "in #{Dir.pwd}" + sh "ruby path_to_enlightenment.rb" + end +end + + +desc "Pre-checkin tests (=> run_all)" +task :cruise => :run_all + +desc "Run the completed koans againts a list of relevant Ruby Implementations" +task :run_all do + results = {} + RubyImpls.list.each do |impl| + puts "=" * 40 + puts "On Ruby #{impl}" + res = sh "rvm #{impl} rake run" + results[impl] = res + puts + end + puts "=" * 40 + puts "Summary:" + puts + results.each do |impl, res| + puts "#{impl} => RAN" + end + puts + RubyImpls.expected.each do |requested_impl| + impl_pattern = Regexp.new(Regexp.quote(requested_impl)) + puts "No Results for #{requested_impl}" if results.keys.grep(impl_pattern).empty? + end +end From ccfa664b485cb3fa8c16e9f31204ea5b554f2016 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 11:45:46 -0500 Subject: [PATCH 135/276] [5553333] Updated java interop on to_java method. --- koans/about_java_interop.rb | 8 +++----- src/about_java_interop.rb | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb index fb2669339..66f79c41c 100644 --- a/koans/about_java_interop.rb +++ b/koans/about_java_interop.rb @@ -103,11 +103,9 @@ def test_some_ruby_objects_can_be_coerced_to_java end def test_some_ruby_objects_can_NOT_be_coerced_to_java - [[], {}, Object.new].each do |ruby_object| - assert_raise(___) do - ruby_object.to_java_class - end - end + assert_equal __, [].to_java.class == Java::JavaUtil::ArrayList + assert_equal __, {}.to_java.class == Java::JavaUtil::HashMap + assert_equal __, Object.new.to_java.class == Java::JavaLang::Object end def test_java_collections_are_enumerable diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index bb63a5fc4..56035db4d 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -103,11 +103,9 @@ def test_some_ruby_objects_can_be_coerced_to_java end def test_some_ruby_objects_can_NOT_be_coerced_to_java - [[], {}, Object.new].each do |ruby_object| - assert_raise(___(NoMethodError)) do - ruby_object.to_java_class - end - end + assert_equal __(false), [].to_java.class == Java::JavaUtil::ArrayList + assert_equal __(false), {}.to_java.class == Java::JavaUtil::HashMap + assert_equal __(false), Object.new.to_java.class == Java::JavaLang::Object end def test_java_collections_are_enumerable From 5e9083e75404184d483a085d315bcd554ba9a930 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 11:48:15 -0500 Subject: [PATCH 136/276] Remove dbgs from Rakefile --- Rakefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Rakefile b/Rakefile index a85b4781c..2eec08dbe 100644 --- a/Rakefile +++ b/Rakefile @@ -62,7 +62,6 @@ module RubyImpls def self.find_ruby_impls rubys = `rvm list`.gsub(/=>/,'').split(/\n/).sort expected.map { |impl| - puts "DBG: impl=#{impl.inspect}" last = rubys.grep(Regexp.new(Regexp.quote(impl))).last last ? last.split.first : nil }.compact From b733076165aa9fdbcab617f5c030c3650c42860c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 11:48:40 -0500 Subject: [PATCH 137/276] Added .rbc to ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c92368f0b..f15e83aba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ dist .project_env.rc .path_progress +*.rbc From 325ad5bce3d7e837f4dbf5e32ba5f0818043c119 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 11:54:41 -0500 Subject: [PATCH 138/276] Result summary now in order of running. --- Rakefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index 2eec08dbe..686fb6fc3 100644 --- a/Rakefile +++ b/Rakefile @@ -143,12 +143,12 @@ task :cruise => :run_all desc "Run the completed koans againts a list of relevant Ruby Implementations" task :run_all do - results = {} + results = [] RubyImpls.list.each do |impl| puts "=" * 40 puts "On Ruby #{impl}" - res = sh "rvm #{impl} rake run" - results[impl] = res + sh "rvm #{impl} rake run" + results << [impl, "RAN"] puts end puts "=" * 40 @@ -160,6 +160,6 @@ task :run_all do puts RubyImpls.expected.each do |requested_impl| impl_pattern = Regexp.new(Regexp.quote(requested_impl)) - puts "No Results for #{requested_impl}" if results.keys.grep(impl_pattern).empty? + puts "No Results for #{requested_impl}" unless results.detect { |x| x.first =~ impl_pattern } end end From 204cd44ea98b6879c774a8a73be1ec1ba9fd14b5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 12:08:03 -0500 Subject: [PATCH 139/276] [5462710] Fixed equality koan on symbols. --- koans/about_symbols.rb | 4 ++-- src/about_symbols.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 2a7f4a35a..6133faaa4 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -11,8 +11,8 @@ def test_symbols_can_be_compared symbol2 = :a_symbol symbol3 = :something_else - assert symbol1 == __ - assert symbol1 != __ + assert_equal __, symbol1 == symbol2 + assert_equal __, symbol1 == symbol3 end def test_identical_symbols_are_a_single_internal_object diff --git a/src/about_symbols.rb b/src/about_symbols.rb index e06f5e197..d618e7cc7 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -11,8 +11,8 @@ def test_symbols_can_be_compared symbol2 = :a_symbol symbol3 = :something_else - assert symbol1 == __(symbol2) - assert symbol1 != __(symbol3) + assert_equal __(true), symbol1 == symbol2 + assert_equal __(false), symbol1 == symbol3 end def test_identical_symbols_are_a_single_internal_object From c8b4c3e6c5ad691639f73533a511d3aadcf16211 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 12:28:24 -0500 Subject: [PATCH 140/276] [5458710] Added koans about to_str --- koans/about_to_str.rb | 54 ++++++++++++++++++++++++++++++++++ koans/path_to_enlightenment.rb | 1 + src/about_to_str.rb | 54 ++++++++++++++++++++++++++++++++++ src/path_to_enlightenment.rb | 1 + 4 files changed, 110 insertions(+) create mode 100644 koans/about_to_str.rb create mode 100644 src/about_to_str.rb diff --git a/koans/about_to_str.rb b/koans/about_to_str.rb new file mode 100644 index 000000000..964850dc2 --- /dev/null +++ b/koans/about_to_str.rb @@ -0,0 +1,54 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutToStr < EdgeCase::Koan + + class CanNotBeTreatedAsString + def to_s + "non-string-like" + end + end + + def test_to_s_returns_a_string_representation + not_like_a_string = CanNotBeTreatedAsString.new + assert_equal __, not_like_a_string.to_s + end + + def test_normally_objects_cannot_be_used_where_strings_are_expected + assert_raise(___) do + File.exist?(CanNotBeTreatedAsString.new) + end + end + + # ------------------------------------------------------------------ + + class CanBeTreatedAsString + def to_s + "string-like" + end + + def to_str + to_s + end + end + + def test_to_str_also_returns_a_string_representation + like_a_string = CanBeTreatedAsString.new + assert_equal __, like_a_string.to_str + end + + def test_to_str_allows_objects_to_be_treated_as_strings + assert_equal __, File.exist?(CanBeTreatedAsString.new) + end + + # ------------------------------------------------------------------ + + def acts_like_a_string?(string) + string = string.to_str if string.respond_to?(:to_str) + string.is_a?(String) + end + + def test_user_defined_code_can_check_for_to_str + assert_equal __, acts_like_a_string?(CanNotBeTreatedAsString.new) + assert_equal __, acts_like_a_string?(CanBeTreatedAsString.new) + end +end diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb index 641559ab0..64621bf4f 100644 --- a/koans/path_to_enlightenment.rb +++ b/koans/path_to_enlightenment.rb @@ -31,6 +31,7 @@ require 'about_class_methods' require 'about_message_passing' require 'about_proxy_object_project' +require 'about_to_str' in_ruby_version("jruby") do require 'about_java_interop' end diff --git a/src/about_to_str.rb b/src/about_to_str.rb new file mode 100644 index 000000000..68c40b258 --- /dev/null +++ b/src/about_to_str.rb @@ -0,0 +1,54 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutToStr < EdgeCase::Koan + + class CanNotBeTreatedAsString + def to_s + "non-string-like" + end + end + + def test_to_s_returns_a_string_representation + not_like_a_string = CanNotBeTreatedAsString.new + assert_equal __("non-string-like"), not_like_a_string.to_s + end + + def test_normally_objects_cannot_be_used_where_strings_are_expected + assert_raise(___(TypeError)) do + File.exist?(CanNotBeTreatedAsString.new) + end + end + + # ------------------------------------------------------------------ + + class CanBeTreatedAsString + def to_s + "string-like" + end + + def to_str + to_s + end + end + + def test_to_str_also_returns_a_string_representation + like_a_string = CanBeTreatedAsString.new + assert_equal __("string-like"), like_a_string.to_str + end + + def test_to_str_allows_objects_to_be_treated_as_strings + assert_equal __(false), File.exist?(CanBeTreatedAsString.new) + end + + # ------------------------------------------------------------------ + + def acts_like_a_string?(string) + string = string.to_str if string.respond_to?(:to_str) + string.is_a?(String) + end + + def test_user_defined_code_can_check_for_to_str + assert_equal __(false), acts_like_a_string?(CanNotBeTreatedAsString.new) + assert_equal __(true), acts_like_a_string?(CanBeTreatedAsString.new) + end +end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index 641559ab0..64621bf4f 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -31,6 +31,7 @@ require 'about_class_methods' require 'about_message_passing' require 'about_proxy_object_project' +require 'about_to_str' in_ruby_version("jruby") do require 'about_java_interop' end From 1a0d82a402af136a2be570c6aa060736ef7b73eb Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 12:28:39 -0500 Subject: [PATCH 141/276] Added .rbc to clean list. --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index 686fb6fc3..19b3bc18c 100644 --- a/Rakefile +++ b/Rakefile @@ -15,6 +15,7 @@ today = Time.now.strftime("%Y-%m-%d") TAR_FILE = "#{DIST_DIR}/rubykoans-#{today}.tgz" ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip" +CLEAN.include("**/*.rbc") CLOBBER.include(DIST_DIR) module Koans From db3bbdcf45980f16f7620498a75bf86646ffc8ac Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 23 Dec 2010 15:04:16 -0500 Subject: [PATCH 142/276] Better test name in the java interop koan --- koans/about_java_interop.rb | 2 +- src/about_java_interop.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb index 66f79c41c..2a58e40dc 100644 --- a/koans/about_java_interop.rb +++ b/koans/about_java_interop.rb @@ -102,7 +102,7 @@ def test_some_ruby_objects_can_be_coerced_to_java assert_equal __, false.to_java.class end - def test_some_ruby_objects_can_NOT_be_coerced_to_java + def test_some_ruby_objects_are_not_coerced_to_what_you_might_expect assert_equal __, [].to_java.class == Java::JavaUtil::ArrayList assert_equal __, {}.to_java.class == Java::JavaUtil::HashMap assert_equal __, Object.new.to_java.class == Java::JavaLang::Object diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index 56035db4d..52f03ebcf 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -102,7 +102,7 @@ def test_some_ruby_objects_can_be_coerced_to_java assert_equal __(Java::JavaLang::Boolean), false.to_java.class end - def test_some_ruby_objects_can_NOT_be_coerced_to_java + def test_some_ruby_objects_are_not_coerced_to_what_you_might_expect assert_equal __(false), [].to_java.class == Java::JavaUtil::ArrayList assert_equal __(false), {}.to_java.class == Java::JavaUtil::HashMap assert_equal __(false), Object.new.to_java.class == Java::JavaLang::Object From 3ce23a8ee09f276e778aeab0c7b477b2e7b5a8ab Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sat, 25 Dec 2010 08:11:31 -0500 Subject: [PATCH 143/276] Updated with Rubinius Support --- Rakefile | 2 +- src/about_methods.rb | 2 +- src/about_objects.rb | 30 ++++++++++++++++-------------- src/edgecase.rb | 9 +++++++-- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Rakefile b/Rakefile index 19b3bc18c..d60dfd243 100644 --- a/Rakefile +++ b/Rakefile @@ -75,7 +75,7 @@ module RubyImpls # List of expected ruby implementations. def self.expected - %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree) + %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree rbx) end end diff --git a/src/about_methods.rb b/src/about_methods.rb index 1497f9ba2..0bdb399d0 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -44,7 +44,7 @@ def test_calling_global_methods_with_wrong_number_of_arguments my_global_method end #-- - pattern = "wrong (number|#) of arguments" + pattern = "wrong (number|#) of arguments|given \\d+, expected \\d+" #++ assert_match(/#{__(pattern)}/, exception.message) diff --git a/src/about_objects.rb b/src/about_objects.rb index 1faf0a0eb..64f39eefc 100644 --- a/src/about_objects.rb +++ b/src/about_objects.rb @@ -30,20 +30,22 @@ def test_every_object_has_different_id assert_equal __(true), obj.object_id != another_obj.object_id end - def test_some_system_objects_always_have_the_same_id - assert_equal __(0), false.object_id - assert_equal __(2), true.object_id - assert_equal __(4), nil.object_id - end - - def test_small_integers_have_fixed_ids - assert_equal __(1), 0.object_id - assert_equal __(3), 1.object_id - assert_equal __(5), 2.object_id - assert_equal __(201), 100.object_id - - # THINK ABOUT IT: - # What pattern do the object IDs for small integers follow? + not_in_ruby_version('rbx') do + def test_some_system_objects_always_have_the_same_id + assert_equal __(0), false.object_id + assert_equal __(2), true.object_id + assert_equal __(4), nil.object_id + end + + def test_small_integers_have_fixed_ids + assert_equal __(1), 0.object_id + assert_equal __(3), 1.object_id + assert_equal __(5), 2.object_id + assert_equal __(201), 100.object_id + + # THINK ABOUT IT: + # What pattern do the object IDs for small integers follow? + end end def test_clone_creates_a_different_object diff --git a/src/edgecase.rb b/src/edgecase.rb index c024438f4..37dc4a9b6 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -13,13 +13,18 @@ class FillMeInError < StandardError def ruby_version?(version) RUBY_VERSION =~ /^#{version}/ || (version == 'jruby' && defined?(JRUBY_VERSION)) || - (version == 'mri' && ! defined?(JRUBY_VERSION)) + (version == 'mri' && (! defined?(JRUBY_VERSION) && ! defined?(Rubinius))) || + (version == 'rbx' && defined?(Rubinius)) end def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end +def not_in_ruby_version(*versions) + yield unless versions.any? { |v| ruby_version?(v) } +end + # Standard, generic replacement value. # If value19 is given, it is used inplace of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) @@ -52,7 +57,7 @@ def ____(method=nil) end end - in_ruby_version("1.9") do + in_ruby_version("1.9", "rbx") do public :method_missing end end From 71ce39368363910d6ade67ec6d4e671e8d4087ea Mon Sep 17 00:00:00 2001 From: Chris Kimpton Date: Sun, 9 Jan 2011 09:40:29 +0000 Subject: [PATCH 144/276] add a hint --- koans/about_proxy_object_project.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index a959a8075..31799c996 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -33,7 +33,8 @@ def test_proxy_method_returns_wrapped_object def test_tv_methods_still_perform_their_function tv = Proxy.new(Television.new) - + + # HINT Proxy class is defined above, may need tweaking... tv.channel = 10 tv.power From 14792b8ce049be6c795102740ff5964b7d559efd Mon Sep 17 00:00:00 2001 From: Chris Kimpton Date: Sun, 9 Jan 2011 11:31:10 +0000 Subject: [PATCH 145/276] add hint/link to related stack overflow problem --- koans/about_triangle_project_2.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index c48c3cb68..fc90ba181 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.rb @@ -11,6 +11,7 @@ def test_illegal_triangles_throw_exceptions 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 + #HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions end end From ac3de6debdfc4b24cfec4e9d2cbacb9068acc0cb Mon Sep 17 00:00:00 2001 From: Chris Kimpton Date: Sun, 9 Jan 2011 11:37:38 +0000 Subject: [PATCH 146/276] fix typo --- koans/about_inheritance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_inheritance.rb b/koans/about_inheritance.rb index cafec3463..712daca55 100644 --- a/koans/about_inheritance.rb +++ b/koans/about_inheritance.rb @@ -31,7 +31,7 @@ def test_all_classes_ultimately_inherit_from_object assert_equal __, Chihuahua.ancestors.include?(Object) end - def test_subcases_inherit_behavior_from_parent_class + def test_subclasses_inherit_behavior_from_parent_class chico = Chihuahua.new("Chico") assert_equal __, chico.name end From b7c27f5b01e31813252fe5bde28f3f15927a0fe3 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 12 Jan 2011 08:29:57 -0500 Subject: [PATCH 147/276] Added keynote slides --- keynote/RubyKoans.key | Bin 0 -> 385680 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 keynote/RubyKoans.key diff --git a/keynote/RubyKoans.key b/keynote/RubyKoans.key new file mode 100644 index 0000000000000000000000000000000000000000..a9f00ac95393f34da2880cfd7962454abdffcade GIT binary patch literal 385680 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 literal 0 HcmV?d00001 From 670101783b72d00c39bec258cdefe378aec6fa35 Mon Sep 17 00:00:00 2001 From: Marc Peabody Date: Wed, 12 Jan 2011 15:37:38 -0500 Subject: [PATCH 148/276] Revert "Updated with Rubinius Support" This reverts commit 3ce23a8ee09f276e778aeab0c7b477b2e7b5a8ab. --- Rakefile | 2 +- src/about_methods.rb | 2 +- src/about_objects.rb | 30 ++++++++++++++---------------- src/edgecase.rb | 9 ++------- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/Rakefile b/Rakefile index d60dfd243..19b3bc18c 100644 --- a/Rakefile +++ b/Rakefile @@ -75,7 +75,7 @@ module RubyImpls # List of expected ruby implementations. def self.expected - %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree rbx) + %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree) end end diff --git a/src/about_methods.rb b/src/about_methods.rb index 0bdb399d0..1497f9ba2 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -44,7 +44,7 @@ def test_calling_global_methods_with_wrong_number_of_arguments my_global_method end #-- - pattern = "wrong (number|#) of arguments|given \\d+, expected \\d+" + pattern = "wrong (number|#) of arguments" #++ assert_match(/#{__(pattern)}/, exception.message) diff --git a/src/about_objects.rb b/src/about_objects.rb index 64f39eefc..1faf0a0eb 100644 --- a/src/about_objects.rb +++ b/src/about_objects.rb @@ -30,22 +30,20 @@ def test_every_object_has_different_id assert_equal __(true), obj.object_id != another_obj.object_id end - not_in_ruby_version('rbx') do - def test_some_system_objects_always_have_the_same_id - assert_equal __(0), false.object_id - assert_equal __(2), true.object_id - assert_equal __(4), nil.object_id - end - - def test_small_integers_have_fixed_ids - assert_equal __(1), 0.object_id - assert_equal __(3), 1.object_id - assert_equal __(5), 2.object_id - assert_equal __(201), 100.object_id - - # THINK ABOUT IT: - # What pattern do the object IDs for small integers follow? - end + def test_some_system_objects_always_have_the_same_id + assert_equal __(0), false.object_id + assert_equal __(2), true.object_id + assert_equal __(4), nil.object_id + end + + def test_small_integers_have_fixed_ids + assert_equal __(1), 0.object_id + assert_equal __(3), 1.object_id + assert_equal __(5), 2.object_id + assert_equal __(201), 100.object_id + + # THINK ABOUT IT: + # What pattern do the object IDs for small integers follow? end def test_clone_creates_a_different_object diff --git a/src/edgecase.rb b/src/edgecase.rb index 37dc4a9b6..c024438f4 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -13,18 +13,13 @@ class FillMeInError < StandardError def ruby_version?(version) RUBY_VERSION =~ /^#{version}/ || (version == 'jruby' && defined?(JRUBY_VERSION)) || - (version == 'mri' && (! defined?(JRUBY_VERSION) && ! defined?(Rubinius))) || - (version == 'rbx' && defined?(Rubinius)) + (version == 'mri' && ! defined?(JRUBY_VERSION)) end def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end -def not_in_ruby_version(*versions) - yield unless versions.any? { |v| ruby_version?(v) } -end - # Standard, generic replacement value. # If value19 is given, it is used inplace of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) @@ -57,7 +52,7 @@ def ____(method=nil) end end - in_ruby_version("1.9", "rbx") do + in_ruby_version("1.9") do public :method_missing end end From 70eae5b30619d211a774e9ebabe721c7e00ddd5b Mon Sep 17 00:00:00 2001 From: Jeff Casimir Date: Wed, 12 Jan 2011 14:12:15 -0500 Subject: [PATCH 149/276] Fix minor typo in method name: strings ARE unique objects --- koans/about_strings.rb | 2 +- src/about_strings.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 509d26c3a..27ccf7203 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -183,7 +183,7 @@ def test_strings_can_be_joined assert_equal __, words.join(" ") end - def test_strings_are_not_unique_objects + def test_strings_are_unique_objects a = "a string" b = "a string" diff --git a/src/about_strings.rb b/src/about_strings.rb index deba2c830..65738fcac 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -183,7 +183,7 @@ def test_strings_can_be_joined assert_equal __("Now is the time"), words.join(" ") end - def test_strings_are_not_unique_objects + def test_strings_are_unique_objects a = "a string" b = "a string" From c350469e9379b2fafad75a8c4ba64dee8027570c Mon Sep 17 00:00:00 2001 From: Andy Lindeman Date: Sat, 22 Jan 2011 19:37:45 -0600 Subject: [PATCH 150/276] Remove trailing whitespace --- koans/about_true_and_false.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_true_and_false.rb b/koans/about_true_and_false.rb index d58564449..1138fb96e 100644 --- a/koans/about_true_and_false.rb +++ b/koans/about_true_and_false.rb @@ -10,7 +10,7 @@ def truth_value(condition) end def test_true_is_treated_as_true - assert_equal __, truth_value(true) + assert_equal __, truth_value(true) end def test_false_is_treated_as_false From a05d7b8980412a099b3848343b098461dd75c58c Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 23 Jan 2011 19:44:58 +0100 Subject: [PATCH 151/276] Add koan on break statements --- koans/about_control_statements.rb | 10 ++++++++++ src/about_control_statements.rb | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index 768dace43..f243ac85b 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -93,6 +93,16 @@ def test_break_statement assert_equal __, result end + def test_break_statement_returns_values + i = 1 + result = while i <= 10 + break i if i % 2 == 0 + i += 1 + end + + assert_equal __, result + end + def test_next_statement i = 0 result = [] diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index 53ac6d891..319bde005 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -93,6 +93,16 @@ def test_break_statement assert_equal __(3628800), result end + def test_break_statement_returns_values + i = 1 + result = while i <= 10 + break i if i % 2 == 0 + i += 1 + end + + assert_equal __(2), result + end + def test_next_statement i = 0 result = [] From 0447d69a6d508368d8ee3ea46f484128c593b43b Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 3 Feb 2011 15:23:25 -0800 Subject: [PATCH 152/276] my_same_class_method => my_method_in_the_same_class for clarity --- koans/about_methods.rb | 6 +++--- src/about_methods.rb | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/koans/about_methods.rb b/koans/about_methods.rb index d36e9ab38..a4df4b8e5 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -92,16 +92,16 @@ def test_method_without_explicit_return # ------------------------------------------------------------------ - def my_same_class_method(a, b) + def my_method_in_the_same_class(a, b) a * b end def test_calling_methods_in_same_class - assert_equal __, my_same_class_method(3,4) + assert_equal __, my_method_in_the_same_class(3,4) end def test_calling_methods_in_same_class_with_explicit_receiver - assert_equal __, self.my_same_class_method(3,4) + assert_equal __, self.my_method_in_the_same_class(3,4) end # ------------------------------------------------------------------ diff --git a/src/about_methods.rb b/src/about_methods.rb index 1497f9ba2..9e7af3744 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -102,16 +102,16 @@ def test_method_without_explicit_return # ------------------------------------------------------------------ - def my_same_class_method(a, b) + def my_method_in_the_same_class(a, b) a * b end def test_calling_methods_in_same_class - assert_equal __(12), my_same_class_method(3,4) + assert_equal __(12), my_method_in_the_same_class(3,4) end def test_calling_methods_in_same_class_with_explicit_receiver - assert_equal __(12), self.my_same_class_method(3,4) + assert_equal __(12), self.my_method_in_the_same_class(3,4) end # ------------------------------------------------------------------ From caceba4d233447f9aea0f1e8356bcc63de336d60 Mon Sep 17 00:00:00 2001 From: Potapov Sergey Date: Tue, 8 Feb 2011 00:50:39 +0200 Subject: [PATCH 153/276] Added test for Hash default value. Developers often forget about using it. --- koans/about_hashes.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 3e4e62c89..2324b0460 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -63,4 +63,18 @@ def test_combining_hashes expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ } assert_equal __, expected == new_hash end + + def test_default_value + hash1 = Hash.new + hash1[:one] = 1 + + assert_equal __, hash1[:one] + assert_equal __, hash1[:two] + + hash2 = Hash.new("dos") + hash2[:one] = 1 + + assert_equal __, hash2[:one] + assert_equal __, hash2[:two] + end end From ef1536eda07573b87f5fe34c8368f3c92a0ea374 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sat, 12 Feb 2011 10:43:27 -0800 Subject: [PATCH 154/276] Fix a typo in a method name. --- koans/about_modules.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_modules.rb b/koans/about_modules.rb index cd967a949..8b56b65c0 100644 --- a/koans/about_modules.rb +++ b/koans/about_modules.rb @@ -42,7 +42,7 @@ def test_normal_methods_are_available_in_the_object assert_equal __, fido.bark end - def test_module_methods_are_also_availble_in_the_object + def test_module_methods_are_also_available_in_the_object fido = Dog.new assert_nothing_raised(Exception) do fido.set_name("Rover") From 34cc5c406959b305748097a63d7ff281f9e5966c Mon Sep 17 00:00:00 2001 From: Skilldrick Date: Sun, 20 Feb 2011 11:26:27 +0000 Subject: [PATCH 155/276] Fix some typos. --- koans/about_constants.rb | 6 +++--- koans/about_iteration.rb | 2 +- koans/about_message_passing.rb | 2 +- koans/about_modules.rb | 2 +- koans/about_proxy_object_project.rb | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/koans/about_constants.rb b/koans/about_constants.rb index 0beccdcea..41d3f0126 100644 --- a/koans/about_constants.rb +++ b/koans/about_constants.rb @@ -67,7 +67,7 @@ def test_who_wins_with_both_nested_and_inherited_constants end # QUESTION: Which has precedence: The constant in the lexical scope, - # or the constant from the inheritance heirarachy? + # or the constant from the inheritance hierarchy? # ------------------------------------------------------------------ @@ -81,7 +81,7 @@ 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 + # QUESTION: Now which has precedence: The constant in the lexical + # scope, or the constant from the inheritance hierarchy? Why is it # different than the previous answer? end diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 591b869b1..5c5a2b044 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -65,7 +65,7 @@ def test_inject_will_blow_your_mind result = [2, 3, 4].inject(0) { |sum, item| sum + item } assert_equal __, result - result2 = [2, 3, 4].inject(1) { |sum, item| sum * item } + result2 = [2, 3, 4].inject(1) { |product, item| product * item } assert_equal __, result2 # Extra Credit: diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb index 45541a015..a978ddec4 100644 --- a/koans/about_message_passing.rb +++ b/koans/about_message_passing.rb @@ -99,7 +99,7 @@ def test_calling_method_missing_causes_the_no_method_error # 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 + # Thanks. We now return you to your regularly scheduled Ruby # Koans. end diff --git a/koans/about_modules.rb b/koans/about_modules.rb index cd967a949..8b56b65c0 100644 --- a/koans/about_modules.rb +++ b/koans/about_modules.rb @@ -42,7 +42,7 @@ def test_normal_methods_are_available_in_the_object assert_equal __, fido.bark end - def test_module_methods_are_also_availble_in_the_object + def test_module_methods_are_also_available_in_the_object fido = Dog.new assert_nothing_raised(Exception) do fido.set_name("Rover") diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index a959a8075..1c1a8e725 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -6,7 +6,7 @@ # below). You should be able to initialize the proxy object with any # object. Any messages sent to the proxy object should be forwarded # to the target object. As each message is sent, the proxy should -# record the name of the method send. +# record the name of the method sent. # # The proxy class is started for you. You will need to add a method # missing handler and any other supporting methods. The specification From e338fff35a6158a7ab632b6c655cc4fe2062ba93 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 9 Mar 2011 10:56:58 -0500 Subject: [PATCH 156/276] Switched from MIT to CC by-nc-sa license. --- MIT-LICENSE | 20 -------------------- README.rdoc | 13 +++++++++++-- 2 files changed, 11 insertions(+), 22 deletions(-) delete mode 100644 MIT-LICENSE diff --git a/MIT-LICENSE b/MIT-LICENSE deleted file mode 100644 index b243e8cf6..000000000 --- a/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009 EdgeCase - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.rdoc b/README.rdoc index f1e0f8e4a..1d916b136 100644 --- a/README.rdoc +++ b/README.rdoc @@ -130,7 +130,16 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: = Other stuff -Author :: Jim Weirich -Author :: Joe O'Brien +Author :: Jim Weirich +Author :: Joe O'Brien Issue Tracker :: http://www.pivotaltracker.com/projects/48111 Requires :: Ruby 1.8.x or later and Rake (any recent version) + += License + + + +GitImmersion is release under a Creative +Commons, Attribution-NonCommercial-ShareAlike, Version 3.0 +License. From ea5841d1f78d3d626c197f525edd92dfe176da99 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 9 Mar 2011 10:58:25 -0500 Subject: [PATCH 157/276] Fixed links in license. --- README.rdoc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.rdoc b/README.rdoc index 1d916b136..ab8e825a1 100644 --- a/README.rdoc +++ b/README.rdoc @@ -137,9 +137,8 @@ Requires :: Ruby 1.8.x or later and Rake (any recent version) = License - +http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png GitImmersion is release under a Creative -Commons, Attribution-NonCommercial-ShareAlike, Version 3.0 +"http://creativecommons.org/licenses/by-nc-sa/3.0/":CreativeCommons, Attribution-NonCommercial-ShareAlike, Version 3.0 License. From d8b4865d84d74a73fe06c83f9b93b0f0a4ec36db Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 9 Mar 2011 10:59:23 -0500 Subject: [PATCH 158/276] Another link fix --- README.rdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rdoc b/README.rdoc index ab8e825a1..74685f4c9 100644 --- a/README.rdoc +++ b/README.rdoc @@ -139,6 +139,6 @@ Requires :: Ruby 1.8.x or later and Rake (any recent version) http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png -GitImmersion is release under a Date: Wed, 9 Mar 2011 11:00:07 -0500 Subject: [PATCH 159/276] Final attempt on license link. --- README.rdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rdoc b/README.rdoc index 74685f4c9..e717b78c6 100644 --- a/README.rdoc +++ b/README.rdoc @@ -139,6 +139,6 @@ Requires :: Ruby 1.8.x or later and Rake (any recent version) http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png -GitImmersion is release under a -http://creativecommons.org/licenses/by-nc-sa/3.0/:"Creative Commons, Attribution-NonCommercial-ShareAlike, Version 3.0" -License. +GitImmersion is release under a Creative Commons, +Attribution-NonCommercial-ShareAlike, Version 3.0 +(http://creativecommons.org/licenses/by-nc-sa/3.0/) License. From 3fd8d9da79d721ecd0992bf1372f484d7a567443 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 9 Mar 2011 11:01:03 -0500 Subject: [PATCH 160/276] Now that the links are ok, fix the wording. --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index e717b78c6..b3eef11d4 100644 --- a/README.rdoc +++ b/README.rdoc @@ -139,6 +139,6 @@ Requires :: Ruby 1.8.x or later and Rake (any recent version) http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png -GitImmersion is release under a Creative Commons, +RubyKoans is released under a Creative Commons, Attribution-NonCommercial-ShareAlike, Version 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/) License. From a46642e192844a312c344d43147a81ecf43f438b Mon Sep 17 00:00:00 2001 From: Jeffrey Murray Date: Fri, 11 Mar 2011 17:34:59 -0800 Subject: [PATCH 161/276] Fixed test_you_can_get_a_single_character_from_a_string for multiple rubies (1.8, 1.9) --- koans/about_strings.rb | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 27ccf7203..48dfa2d16 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -139,13 +139,6 @@ def test_you_can_get_a_substring_from_a_string assert_equal __, string[7..9] end - def test_you_can_get_a_single_character_from_a_string - string = "Bacon, lettuce and tomato" - assert_equal __, string[1] - - # Surprised? - end - in_ruby_version("1.8") do def test_in_ruby_1_8_single_characters_are_represented_by_integers assert_equal __, ?a @@ -162,6 +155,26 @@ def test_in_ruby_1_9_single_characters_are_represented_by_strings end end +in_ruby_version("1.8") do + def test_in_ruby_1_8_you_can_get_a_single_character_from_a_string + string = "Bacon, lettuce and tomato" + assert_equal __, string[1] + + # Surprised? + end + end + + in_ruby_version("1.9") do + + def test_in_ruby_1_9_you_can_get_a_single_character_from_a_string + string = "Bacon, lettuce and tomato" + assert_equal "a", string[1] + + # Surprised? + end + end + + def test_strings_can_be_split string = "Sausage Egg Cheese" words = string.split From eb3403b0ff3d6d3a433498d129bd117c4d373b91 Mon Sep 17 00:00:00 2001 From: Jeffrey Murray Date: Fri, 11 Mar 2011 17:50:39 -0800 Subject: [PATCH 162/276] Fixed missed test case. --- koans/about_strings.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 48dfa2d16..771ff8ba8 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -168,7 +168,7 @@ def test_in_ruby_1_8_you_can_get_a_single_character_from_a_string def test_in_ruby_1_9_you_can_get_a_single_character_from_a_string string = "Bacon, lettuce and tomato" - assert_equal "a", string[1] + assert_equal "__", string[1] # Surprised? end From 434016150e49611dc2779ce79c48baf0598fa44c Mon Sep 17 00:00:00 2001 From: Daniel Hedrick Date: Mon, 21 Mar 2011 19:24:38 -0500 Subject: [PATCH 163/276] Fix typo of subclasses (from subcases) --- koans/about_inheritance.rb | 2 +- src/about_inheritance.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_inheritance.rb b/koans/about_inheritance.rb index cafec3463..712daca55 100644 --- a/koans/about_inheritance.rb +++ b/koans/about_inheritance.rb @@ -31,7 +31,7 @@ def test_all_classes_ultimately_inherit_from_object assert_equal __, Chihuahua.ancestors.include?(Object) end - def test_subcases_inherit_behavior_from_parent_class + def test_subclasses_inherit_behavior_from_parent_class chico = Chihuahua.new("Chico") assert_equal __, chico.name end diff --git a/src/about_inheritance.rb b/src/about_inheritance.rb index f516cd602..73030c6ef 100644 --- a/src/about_inheritance.rb +++ b/src/about_inheritance.rb @@ -31,7 +31,7 @@ def test_all_classes_ultimately_inherit_from_object assert_equal __(true), Chihuahua.ancestors.include?(Object) end - def test_subcases_inherit_behavior_from_parent_class + def test_subclasses_inherit_behavior_from_parent_class chico = Chihuahua.new("Chico") assert_equal __("Chico"), chico.name end From d6f69b5b260bd10851d0e0dc87c034ab4fec85c5 Mon Sep 17 00:00:00 2001 From: Aviv Ben-Yosef Date: Sat, 26 Mar 2011 19:14:30 +0200 Subject: [PATCH 164/276] fixing typo --- koans/about_proxy_object_project.rb | 2 +- src/about_proxy_object_project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index a959a8075..1c1a8e725 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -6,7 +6,7 @@ # below). You should be able to initialize the proxy object with any # object. Any messages sent to the proxy object should be forwarded # to the target object. As each message is sent, the proxy should -# record the name of the method send. +# record the name of the method sent. # # The proxy class is started for you. You will need to add a method # missing handler and any other supporting methods. The specification diff --git a/src/about_proxy_object_project.rb b/src/about_proxy_object_project.rb index 1d64f0f28..483a7d7c0 100644 --- a/src/about_proxy_object_project.rb +++ b/src/about_proxy_object_project.rb @@ -6,7 +6,7 @@ # below). You should be able to initialize the proxy object with any # object. Any messages sent to the proxy object should be forwarded # to the target object. As each message is sent, the proxy should -# record the name of the method send. +# record the name of the method sent. # # The proxy class is started for you. You will need to add a method # missing handler and any other supporting methods. The specification From 39d556d66ee08b268ecca9486557bb38e820aaf6 Mon Sep 17 00:00:00 2001 From: Mani Tadayon Date: Tue, 29 Mar 2011 11:11:09 -0700 Subject: [PATCH 165/276] Fix one letter typo in comments --- koans/about_symbols.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index 6133faaa4..f4a431968 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -84,7 +84,7 @@ def test_symbols_do_not_have_string_methods # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated - # Exceptions will be pondered further father down the path + # Exceptions will be pondered further farther down the path assert_raise(___) do :cats + :dogs end From 6dc43a1ab08dd1a1701b92ef8e3a78d363cc2e98 Mon Sep 17 00:00:00 2001 From: Mani Tadayon Date: Tue, 29 Mar 2011 15:14:06 -0700 Subject: [PATCH 166/276] Correct spelling: "heirarachy" => "hierarchy" --- koans/about_constants.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_constants.rb b/koans/about_constants.rb index 0beccdcea..006f1c08a 100644 --- a/koans/about_constants.rb +++ b/koans/about_constants.rb @@ -67,7 +67,7 @@ def test_who_wins_with_both_nested_and_inherited_constants end # QUESTION: Which has precedence: The constant in the lexical scope, - # or the constant from the inheritance heirarachy? + # or the constant from the inheritance hierarchy? # ------------------------------------------------------------------ From bb8d835ad4c78a8f4a84055ed7ee6b0e211b59e8 Mon Sep 17 00:00:00 2001 From: Mani Tadayon Date: Tue, 29 Mar 2011 17:11:33 -0700 Subject: [PATCH 167/276] Fix typo in about_modules.rb --- koans/about_modules.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_modules.rb b/koans/about_modules.rb index cd967a949..8b56b65c0 100644 --- a/koans/about_modules.rb +++ b/koans/about_modules.rb @@ -42,7 +42,7 @@ def test_normal_methods_are_available_in_the_object assert_equal __, fido.bark end - def test_module_methods_are_also_availble_in_the_object + def test_module_methods_are_also_available_in_the_object fido = Dog.new assert_nothing_raised(Exception) do fido.set_name("Rover") From d78e284e55ce63ae9c1cf59d7972d7dfeb42d970 Mon Sep 17 00:00:00 2001 From: nazgob Date: Wed, 13 Apr 2011 06:49:58 -0700 Subject: [PATCH 168/276] fixed typo -> Issue #39 --- src/about_scoring_project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 124c38744..60b468226 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -1,7 +1,7 @@ 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 +# points. The following "score" function will be used to calculate the # score of a single roll of the dice. # # A greed roll is scored as follows: From 3d18d339e4da12942222da96dc454b7405a2f6cd Mon Sep 17 00:00:00 2001 From: nazgob Date: Wed, 13 Apr 2011 06:50:17 -0700 Subject: [PATCH 169/276] fixed typo -> Issue #39 --- koans/about_scoring_project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb index 3c8e0274a..bc617854e 100644 --- a/koans/about_scoring_project.rb +++ b/koans/about_scoring_project.rb @@ -1,7 +1,7 @@ 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 +# points. The following "score" function will be used to calculate the # score of a single roll of the dice. # # A greed roll is scored as follows: From 6c8fe055076bae93c451daef73e60248396f9c6c Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Mon, 16 May 2011 23:48:53 +0200 Subject: [PATCH 170/276] Adding missing assert in iteration test. Also checking against symbol rather than string. --- koans/about_iteration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 5c5a2b044..b48c27813 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -3,7 +3,7 @@ class AboutIteration < EdgeCase::Koan def test_each_is_a_method_on_arrays - [].methods.include?("each") + assert_equal __, [].methods.include?(:each) end def test_iterating_with_each From 561a74d8093cf398e2300a5005d70abe7ca224b3 Mon Sep 17 00:00:00 2001 From: "R.T. Lechow" Date: Thu, 2 Jun 2011 17:46:41 -0400 Subject: [PATCH 171/276] Typos. --- koans/about_java_interop.rb | 2 +- koans/edgecase.rb | 2 +- rakelib/checks.rake | 2 +- src/about_java_interop.rb | 2 +- src/edgecase.rb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb index 2a58e40dc..4d35d5dd4 100644 --- a/koans/about_java_interop.rb +++ b/koans/about_java_interop.rb @@ -5,7 +5,7 @@ # Concepts # * Pull in a java class # * calling a method, Camel vs snake -# * Resovling module/class name conflicts +# * Resolving module/class name conflicts # * Showing what gets returned # * Ruby Strings VS Java Strings # * Calling custom java class diff --git a/koans/edgecase.rb b/koans/edgecase.rb index c024438f4..ba49956de 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -21,7 +21,7 @@ def in_ruby_version(*versions) end # Standard, generic replacement value. -# If value19 is given, it is used inplace of value for Ruby 1.9. +# If value19 is given, it is used in place of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) if RUBY_VERSION < "1.9" value diff --git a/rakelib/checks.rake b/rakelib/checks.rake index 287020269..fa5aaf7e0 100644 --- a/rakelib/checks.rake +++ b/rakelib/checks.rake @@ -29,5 +29,5 @@ namespace "check" do end end -desc "Run some simple consistancy checks" +desc "Run some simple consistency checks" task :check => ["check:abouts", "check:asserts"] diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index 52f03ebcf..c2d2142ce 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -5,7 +5,7 @@ # Concepts # * Pull in a java class # * calling a method, Camel vs snake -# * Resovling module/class name conflicts +# * Resolving module/class name conflicts # * Showing what gets returned # * Ruby Strings VS Java Strings # * Calling custom java class diff --git a/src/edgecase.rb b/src/edgecase.rb index c024438f4..ba49956de 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -21,7 +21,7 @@ def in_ruby_version(*versions) end # Standard, generic replacement value. -# If value19 is given, it is used inplace of value for Ruby 1.9. +# If value19 is given, it is used in place of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) if RUBY_VERSION < "1.9" value From 3e6d01a15b4ac9199b8cdb0b58e703cb80577c88 Mon Sep 17 00:00:00 2001 From: tjkirch Date: Sun, 6 Mar 2011 12:29:15 +0000 Subject: [PATCH 172/276] Clarify string length versus line count --- koans/about_strings.rb | 6 ++++-- src/about_strings.rb | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/koans/about_strings.rb b/koans/about_strings.rb index 771ff8ba8..aa427d48f 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -40,7 +40,8 @@ def test_flexible_quotes_can_handle_multiple_lines It was the best of times, It was the worst of times. } - assert_equal __, long_string.size + assert_equal __, long_string.length + assert_equal __, long_string.lines.count end def test_here_documents_can_also_handle_multiple_lines @@ -48,7 +49,8 @@ def test_here_documents_can_also_handle_multiple_lines It was the best of times, It was the worst of times. EOS - assert_equal __, long_string.size + assert_equal __, long_string.length + assert_equal __, long_string.lines.count end def test_plus_will_concatenate_two_strings diff --git a/src/about_strings.rb b/src/about_strings.rb index 65738fcac..dd13fecfd 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -40,7 +40,8 @@ def test_flexible_quotes_can_handle_multiple_lines It was the best of times, It was the worst of times. } - assert_equal __(54), long_string.size + assert_equal __(54), long_string.length + assert_equal __(3), long_string.lines.count end def test_here_documents_can_also_handle_multiple_lines @@ -48,7 +49,8 @@ def test_here_documents_can_also_handle_multiple_lines It was the best of times, It was the worst of times. EOS - assert_equal __(53), long_string.size + assert_equal __(53), long_string.length + assert_equal __(2), long_string.lines.count end def test_plus_will_concatenate_two_strings From 3d8391174b0d7897b82fa64b760e6f5049afef9c Mon Sep 17 00:00:00 2001 From: Matt Darby Date: Fri, 3 Jun 2011 11:21:25 -0700 Subject: [PATCH 173/276] Added a note on how to (optionally) install rake. --- README.rdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rdoc b/README.rdoc index b3eef11d4..fb6abb159 100644 --- a/README.rdoc +++ b/README.rdoc @@ -36,6 +36,8 @@ Windows from the command prompt (cmd.exe) c:\ruby --version c:\rake --version +If you don't have rake installed, just run `gem install rake` + 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. From 0ae75e0dbd7032e1d96061b49e27f4cf59071ce3 Mon Sep 17 00:00:00 2001 From: Connor Montgomery Date: Thu, 18 Aug 2011 02:21:03 -0500 Subject: [PATCH 174/276] Fixed a typo. --- src/about_message_passing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 37126f252..882716ecc 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -99,7 +99,7 @@ def test_calling_method_missing_causes_the_no_method_error # 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 + # Thanks. We now return you to your regularly scheduled Ruby # Koans. end From 6fd8668b7029b34b6c6354b58e217ede44bc415e Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Tue, 23 Aug 2011 02:24:10 +0200 Subject: [PATCH 175/276] using windows32console gem for colors --- koans/edgecase.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index ba49956de..8d9646b66 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -107,7 +107,9 @@ def color(color_value) def use_colors? return false if ENV['NO_COLOR'] if ENV['ANSI_COLOR'].nil? - ! using_windows? + if using_windows? + using_win32console + end else ENV['ANSI_COLOR'] =~ /^(t|y)/i end @@ -116,6 +118,13 @@ def use_colors? def using_windows? File::ALT_SEPARATOR end + def using_win32console + begin + !! Win32::Console::ANSI + rescue + return false + end + end end class Sensei From 4be16207596f41f0eaccd7fdf2252a706419179a Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Tue, 23 Aug 2011 02:34:01 +0200 Subject: [PATCH 176/276] forgot requires --- koans/edgecase.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 8d9646b66..091dbdaae 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -2,7 +2,8 @@ # -*- ruby -*- require 'test/unit/assertions' - +require 'rubygems' +require 'win32console' # -------------------------------------------------------------------- # Support code for the Ruby Koans. # -------------------------------------------------------------------- From 0032cee9a6a037408282058af3a44e8ee1265651 Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Tue, 23 Aug 2011 14:28:00 +0200 Subject: [PATCH 177/276] Edited koans/edgecase.rb via GitHub --- koans/edgecase.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 091dbdaae..82159baa6 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -2,7 +2,6 @@ # -*- ruby -*- require 'test/unit/assertions' -require 'rubygems' require 'win32console' # -------------------------------------------------------------------- # Support code for the Ruby Koans. From 0a4f89cae38d24a5e293c85e58c7f97dfa5f27be Mon Sep 17 00:00:00 2001 From: Daemian Mack Date: Mon, 29 Aug 2011 17:34:35 -0300 Subject: [PATCH 178/276] Edited src/about_nil.rb via GitHub --- src/about_nil.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_nil.rb b/src/about_nil.rb index 1e670a079..9df4f9bf8 100644 --- a/src/about_nil.rb +++ b/src/about_nil.rb @@ -8,7 +8,7 @@ def test_nil_is_an_object def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil # What happens when you call a method that doesn't exist. The # following begin/rescue/end code block captures the exception and - # make some assertions about it. + # makes some assertions about it. begin nil.some_method_nil_doesnt_know_about rescue Exception => ex From 75d1505a44e1c6d14c0b053e508c52910326a5da Mon Sep 17 00:00:00 2001 From: Daemian Mack Date: Mon, 29 Aug 2011 21:44:30 -0300 Subject: [PATCH 179/276] Edited src/about_symbols.rb via GitHub --- src/about_symbols.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_symbols.rb b/src/about_symbols.rb index d618e7cc7..95cdffd03 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -84,7 +84,7 @@ def test_symbols_do_not_have_string_methods # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated - # Exceptions will be pondered further father down the path + # Exceptions will be pondered further down the path assert_raise(___(NoMethodError)) do :cats + :dogs end From 3371a31885902dbd07c459bb7c81e15156926c1a Mon Sep 17 00:00:00 2001 From: Daemian Mack Date: Wed, 31 Aug 2011 18:02:16 -0300 Subject: [PATCH 180/276] Fix typo. --- src/about_modules.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_modules.rb b/src/about_modules.rb index 261746a58..334b175d6 100644 --- a/src/about_modules.rb +++ b/src/about_modules.rb @@ -42,7 +42,7 @@ def test_normal_methods_are_available_in_the_object assert_equal __("WOOF"), fido.bark end - def test_module_methods_are_also_availble_in_the_object + def test_module_methods_are_also_available_in_the_object fido = Dog.new assert_nothing_raised(Exception) do # __ fido.set_name("Rover") From db594e16fd87f886f9ea10e7ffd915ebd13b39db Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 8 Sep 2011 16:23:01 +0300 Subject: [PATCH 181/276] tweak for a more enlightened Regexp koan --- koans/about_regular_expressions.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb index 83449112c..790bea324 100644 --- a/koans/about_regular_expressions.rb +++ b/koans/about_regular_expressions.rb @@ -84,6 +84,8 @@ def test_a_character_class_can_be_negated def test_shortcut_character_classes_are_negated_with_capitals assert_equal __, "the number is 42"[/\D+/] assert_equal __, "space: \t\n"[/\S+/] + # ... a programmer would most likely do + assert_equal __, "variable_1 = 42"[/[^a-zA-Z0-9_]+/] assert_equal __, "variable_1 = 42"[/\W+/] end From 7c34268f848a359132874a285acc54cb704216c9 Mon Sep 17 00:00:00 2001 From: Dan Dorman Date: Thu, 8 Sep 2011 09:46:02 -0600 Subject: [PATCH 182/276] Add koan addressing Hash#fetch. --- koans/about_hashes.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 2324b0460..766248867 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -20,6 +20,18 @@ def test_accessing_hashes assert_equal __, hash[:doesnt_exist] end + def test_accessing_hashes_with_fetch + hash = { :one => "uno" } + assert_equal "uno", hash.fetch(:one) + assert_raise(___) do + hash.fetch(:doesnt_exist) + end + + # THINK ABOUT IT: + # + # Why might you want to use #fetch instead of #[] when accessing hash keys? + end + def test_changing_hashes hash = { :one => "uno", :two => "dos" } hash[:one] = "eins" From 6acc65ac9294e89a35b70e8ee0efc31594cee551 Mon Sep 17 00:00:00 2001 From: Dan Dorman Date: Thu, 8 Sep 2011 09:48:41 -0600 Subject: [PATCH 183/276] Add koans addressing passing a block to Hash#initialize. --- koans/about_hashes.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb index 2324b0460..511caa631 100644 --- a/koans/about_hashes.rb +++ b/koans/about_hashes.rb @@ -77,4 +77,28 @@ def test_default_value assert_equal __, hash2[:one] assert_equal __, hash2[:two] end + + def test_default_value_is_the_same_object + hash = Hash.new([]) + + hash[:one] << "uno" + hash[:two] << "dos" + + assert_equal __, hash[:one] + assert_equal __, hash[:two] + assert_equal __, hash[:three] + + assert_equal __, hash[:one].object_id == hash[:two].object_id + end + + def test_default_value_with_block + hash = Hash.new {|hash, key| hash[key] = [] } + + hash[:one] << "uno" + hash[:two] << "dos" + + assert_equal __, hash[:one] + assert_equal __, hash[:two] + assert_equal __, hash[:three] + end end From c160ee8b034582d1245dd4dd0cff89d7cb87fd56 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Fri, 9 Sep 2011 00:16:21 +0300 Subject: [PATCH 184/276] few more enlightening tweaks --- koans/about_control_statements.rb | 10 +++++++++- koans/about_methods.rb | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index f243ac85b..71a7af0e4 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -59,12 +59,20 @@ def test_if_statement_modifiers def test_unless_statement result = :default_value - unless false + unless false # same as saying 'if !false', which evaluates as 'if true' result = :false_value end assert_equal __, result end + def test_unless_statement_evaluate_true + result = :default_value + unless true # same as saying 'if !true', which evaluates as 'if false' + result = :true_value + end + assert_equal __, result + end + def test_unless_statement_modifier result = :default_value result = :false_value unless false diff --git a/koans/about_methods.rb b/koans/about_methods.rb index a4df4b8e5..5fd7725af 100644 --- a/koans/about_methods.rb +++ b/koans/about_methods.rb @@ -62,6 +62,7 @@ def method_with_var_args(*args) end def test_calling_with_variable_arguments + assert_equal __, method_with_var_args.class assert_equal __, method_with_var_args assert_equal __, method_with_var_args(:one) assert_equal __, method_with_var_args(:one, :two) From 42847962b4df1f48d85a4ea0c4d8964bc62ba704 Mon Sep 17 00:00:00 2001 From: this guy Date: Thu, 8 Sep 2011 22:04:43 -0700 Subject: [PATCH 185/276] Fixed discrepancy between results for obj.methods in 1.8 v. 1.9 (String v. Symbol) and what looked to be a typo. --- koans/about_classes.rb | 2 +- koans/about_iteration.rb | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/koans/about_classes.rb b/koans/about_classes.rb index fce0be084..3fce64601 100644 --- a/koans/about_classes.rb +++ b/koans/about_classes.rb @@ -126,7 +126,7 @@ def test_args_to_new_must_match_initialize # Why is this so? end - def test_different_objects_have_difference_instance_variables + def test_different_objects_have_different_instance_variables fido = Dog6.new("Fido") rover = Dog6.new("Rover") diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index b48c27813..823128faf 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -1,9 +1,16 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutIteration < EdgeCase::Koan + in_ruby_version("1.8") do + def test_each_is_a_method_on_arrays + assert_equal __, [].methods.include?("each") + end + end - def test_each_is_a_method_on_arrays - assert_equal __, [].methods.include?(:each) + in_ruby_version("1.9") do + def test_each_is_a_method_on_arrays + assert_equal __, [].methods.include?(:each) + end end def test_iterating_with_each From dd36e171b0e51a522539f38dc5e958a3f1c1d470 Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Fri, 7 Oct 2011 22:18:59 +0200 Subject: [PATCH 186/276] testing for win32console --- koans/edgecase.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 82159baa6..8a0c9882a 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -2,7 +2,12 @@ # -*- ruby -*- require 'test/unit/assertions' -require 'win32console' +begin + require 'win32console' + @using_win32console = true +rescue LoadError + @using_win32console = false +end # -------------------------------------------------------------------- # Support code for the Ruby Koans. # -------------------------------------------------------------------- @@ -120,7 +125,7 @@ def using_windows? end def using_win32console begin - !! Win32::Console::ANSI + @using_win32console rescue return false end From 176de995b85765b240b1af91edac1e6702da65af Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Fri, 7 Oct 2011 22:34:53 +0200 Subject: [PATCH 187/276] Edited koans/edgecase.rb via GitHub --- koans/edgecase.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 8a0c9882a..dca38ac5a 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -124,11 +124,7 @@ def using_windows? File::ALT_SEPARATOR end def using_win32console - begin @using_win32console - rescue - return false - end end end From 595f2af341e51fcb4dddb812a51587f43cdefdb0 Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Fri, 7 Oct 2011 23:13:32 +0200 Subject: [PATCH 188/276] finally it worked well --- koans/edgecase.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index dca38ac5a..03c8f298e 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -4,9 +4,9 @@ require 'test/unit/assertions' begin require 'win32console' - @using_win32console = true + USING_WIN32CONSOLE = true rescue LoadError - @using_win32console = false + USING_WIN32CONSOLE = false end # -------------------------------------------------------------------- # Support code for the Ruby Koans. @@ -124,7 +124,7 @@ def using_windows? File::ALT_SEPARATOR end def using_win32console - @using_win32console + USING_WIN32CONSOLE end end From ad3b4f76aadf53ec12b51ee2072123ada2ddedde Mon Sep 17 00:00:00 2001 From: ahmed80dz Date: Fri, 7 Oct 2011 23:55:12 +0200 Subject: [PATCH 189/276] as suggested by sunaku --- koans/edgecase.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 03c8f298e..d727cd7bf 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -4,9 +4,7 @@ require 'test/unit/assertions' begin require 'win32console' - USING_WIN32CONSOLE = true rescue LoadError - USING_WIN32CONSOLE = false end # -------------------------------------------------------------------- # Support code for the Ruby Koans. @@ -124,7 +122,7 @@ def using_windows? File::ALT_SEPARATOR end def using_win32console - USING_WIN32CONSOLE + defined? Win32::Console end end From 95f7fba8ae26c400eb1178ebe796cf1c8ab55dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A1n=20Schmidt?= Date: Fri, 14 Oct 2011 20:56:47 -0300 Subject: [PATCH 190/276] fix typo in message --- koans/about_nil.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_nil.rb b/koans/about_nil.rb index 5e1e28bfa..1a74ed042 100644 --- a/koans/about_nil.rb +++ b/koans/about_nil.rb @@ -8,7 +8,7 @@ def test_nil_is_an_object def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil # What happens when you call a method that doesn't exist. The # following begin/rescue/end code block captures the exception and - # make some assertions about it. + # makes some assertions about it. begin nil.some_method_nil_doesnt_know_about rescue Exception => ex From 271dff23530ef0b2c007865c6286c5b97e9020a6 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 00:57:08 -0500 Subject: [PATCH 191/276] Fixed :each VS "each" conflict in method list inclusion. --- src/about_iteration.rb | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 324a116f8..2e35aa9cf 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -2,8 +2,29 @@ class AboutIteration < EdgeCase::Koan + # -- An Aside ------------------------------------------------------ + # Ruby 1.8 stores names as strings. Ruby 1.9 stores names as + # symbols. So we use a version dependent method "as_name" to convert + # to the right format in the koans. We will use "as_name" whenever + # comparing to lists of methods. + + in_ruby_version("1.8") do + def as_name(name) + name.to_s + end + end + + in_ruby_version("1.9") do + def as_name(name) + name.to_sym + end + end + + # Ok, now back to the Koans. + # ------------------------------------------------------------------- + def test_each_is_a_method_on_arrays - [].methods.include?("each") + assert_equal __(true), [].methods.include?(as_name(:each)) end def test_iterating_with_each From 1a177308622cf25bac82e2745352ecc5de64f74e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 01:17:59 -0500 Subject: [PATCH 192/276] updated koans with latest src --- koans/README.rdoc | 14 ++++++++++++-- koans/about_iteration.rb | 24 +++++++++++++++++++----- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/koans/README.rdoc b/koans/README.rdoc index f1e0f8e4a..fb6abb159 100644 --- a/koans/README.rdoc +++ b/koans/README.rdoc @@ -36,6 +36,8 @@ Windows from the command prompt (cmd.exe) c:\ruby --version c:\rake --version +If you don't have rake installed, just run `gem install rake` + 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. @@ -130,7 +132,15 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: = Other stuff -Author :: Jim Weirich -Author :: Joe O'Brien +Author :: Jim Weirich +Author :: Joe O'Brien Issue Tracker :: http://www.pivotaltracker.com/projects/48111 Requires :: Ruby 1.8.x or later and Rake (any recent version) + += License + +http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png + +RubyKoans is released under a Creative Commons, +Attribution-NonCommercial-ShareAlike, Version 3.0 +(http://creativecommons.org/licenses/by-nc-sa/3.0/) License. diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb index 823128faf..fb62b394b 100644 --- a/koans/about_iteration.rb +++ b/koans/about_iteration.rb @@ -1,18 +1,32 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutIteration < EdgeCase::Koan + + # -- An Aside ------------------------------------------------------ + # Ruby 1.8 stores names as strings. Ruby 1.9 stores names as + # symbols. So we use a version dependent method "as_name" to convert + # to the right format in the koans. We will use "as_name" whenever + # comparing to lists of methods. + in_ruby_version("1.8") do - def test_each_is_a_method_on_arrays - assert_equal __, [].methods.include?("each") + def as_name(name) + name.to_s end end in_ruby_version("1.9") do - def test_each_is_a_method_on_arrays - assert_equal __, [].methods.include?(:each) + def as_name(name) + name.to_sym end end + # Ok, now back to the Koans. + # ------------------------------------------------------------------- + + def test_each_is_a_method_on_arrays + assert_equal __, [].methods.include?(as_name(:each)) + end + def test_iterating_with_each array = [1, 2, 3] sum = 0 @@ -72,7 +86,7 @@ def test_inject_will_blow_your_mind result = [2, 3, 4].inject(0) { |sum, item| sum + item } assert_equal __, result - result2 = [2, 3, 4].inject(1) { |product, item| product * item } + result2 = [2, 3, 4].inject(1) { |sum, item| sum * item } assert_equal __, result2 # Extra Credit: From f9d3bcbb375ee9820bbecf8ccc1d8acfec80cc7a Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 01:18:23 -0500 Subject: [PATCH 193/276] removed deprecated require of rake/rdoctask --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 19b3bc18c..2d2459709 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ # -*- ruby -*- require 'rake/clean' -require 'rake/rdoctask' +require 'rdoc/task' SRC_DIR = 'src' PROB_DIR = 'koans' From 51acb84736a6d91ee7cfb6dc8d92a8a23f4f5694 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 01:58:29 -0500 Subject: [PATCH 194/276] Silence complaint about Rake::DSL --- Rakefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Rakefile b/Rakefile index 2d2459709..5fb5546b1 100644 --- a/Rakefile +++ b/Rakefile @@ -19,6 +19,8 @@ CLEAN.include("**/*.rbc") CLOBBER.include(DIST_DIR) module Koans + extend Rake::DSL if defined?(Rake::DSL) + # Remove solution info from source # __(a,b) => __ # _n_(number) => __ From 6592f3d36eb1928f311a0539110f26417c4765fb Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:00:22 -0500 Subject: [PATCH 195/276] Back ported a lot of changes made to the Koans directory. Evidently, a lot of changes / pull requests were made to the koans directory and not to the src directory. Perhaps we should remove the koans directory entirely from the repo. --- koans/about_control_statements.rb | 2 +- koans/about_proxy_object_project.rb | 49 ++++++++++++++------------- koans/about_strings.rb | 27 ++++----------- koans/about_symbols.rb | 2 +- koans/about_triangle_project_2.rb | 2 +- koans/edgecase.rb | 4 ++- src/about_classes.rb | 2 +- src/about_constants.rb | 6 ++-- src/about_control_statements.rb | 12 +++++-- src/about_hashes.rb | 50 +++++++++++++++++++++++++++ src/about_methods.rb | 1 + src/about_proxy_object_project.rb | 52 +++++++++++++++-------------- src/about_regular_expressions.rb | 2 ++ src/about_triangle_project_2.rb | 1 + src/about_true_and_false.rb | 2 +- src/edgecase.rb | 12 ++++++- 16 files changed, 145 insertions(+), 81 deletions(-) diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb index 71a7af0e4..df503d714 100644 --- a/koans/about_control_statements.rb +++ b/koans/about_control_statements.rb @@ -117,7 +117,7 @@ def test_next_statement while i < 10 i += 1 next if (i % 2) == 0 - result << i + result << i end assert_equal __, result end diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb index 1666e4596..064eb683a 100644 --- a/koans/about_proxy_object_project.rb +++ b/koans/about_proxy_object_project.rb @@ -27,51 +27,52 @@ class AboutProxyObjectProject < EdgeCase::Koan def test_proxy_method_returns_wrapped_object # NOTE: The Television class is defined below tv = Proxy.new(Television.new) - + + # HINT: Proxy class is defined above, may need tweaking... + assert tv.instance_of?(Proxy) end - + def test_tv_methods_still_perform_their_function tv = Proxy.new(Television.new) - # HINT Proxy class is defined above, may need tweaking... tv.channel = 10 tv.power - + assert_equal 10, tv.channel assert tv.on? end def test_proxy_records_messages_sent_to_tv tv = Proxy.new(Television.new) - + tv.power tv.channel = 10 - + assert_equal [:power, :channel=], tv.messages end - + def test_proxy_handles_invalid_messages tv = Proxy.new(Television.new) - + assert_raise(NoMethodError) do tv.no_such_method end end - + def test_proxy_reports_methods_have_been_called tv = Proxy.new(Television.new) - + tv.power tv.power - + assert tv.called?(:power) assert ! tv.called?(:channel) end - + def test_proxy_counts_method_calls tv = Proxy.new(Television.new) - + tv.power tv.channel = 48 tv.power @@ -100,7 +101,7 @@ def test_proxy_can_record_more_than_just_tv_objects # Example class using in the proxy testing above. class Television attr_accessor :channel - + def power if @power == :on @power = :off @@ -108,7 +109,7 @@ def power @power = :on end end - + def on? @power == :on end @@ -118,31 +119,31 @@ def on? class TelevisionTest < EdgeCase::Koan def test_it_turns_on tv = Television.new - + tv.power assert tv.on? end - + def test_it_also_turns_off tv = Television.new - + tv.power tv.power - + assert ! tv.on? end - + def test_edge_case_on_off tv = Television.new - + tv.power tv.power tv.power - + assert tv.on? - + tv.power - + assert ! tv.on? end diff --git a/koans/about_strings.rb b/koans/about_strings.rb index aa427d48f..34d4a5087 100644 --- a/koans/about_strings.rb +++ b/koans/about_strings.rb @@ -141,6 +141,13 @@ def test_you_can_get_a_substring_from_a_string assert_equal __, string[7..9] end + def test_you_can_get_a_single_character_from_a_string + string = "Bacon, lettuce and tomato" + assert_equal __, string[1] + + # Surprised? + end + in_ruby_version("1.8") do def test_in_ruby_1_8_single_characters_are_represented_by_integers assert_equal __, ?a @@ -157,26 +164,6 @@ def test_in_ruby_1_9_single_characters_are_represented_by_strings end end -in_ruby_version("1.8") do - def test_in_ruby_1_8_you_can_get_a_single_character_from_a_string - string = "Bacon, lettuce and tomato" - assert_equal __, string[1] - - # Surprised? - end - end - - in_ruby_version("1.9") do - - def test_in_ruby_1_9_you_can_get_a_single_character_from_a_string - string = "Bacon, lettuce and tomato" - assert_equal "__", string[1] - - # Surprised? - end - end - - def test_strings_can_be_split string = "Sausage Egg Cheese" words = string.split diff --git a/koans/about_symbols.rb b/koans/about_symbols.rb index f4a431968..a88d6fee2 100644 --- a/koans/about_symbols.rb +++ b/koans/about_symbols.rb @@ -84,7 +84,7 @@ def test_symbols_do_not_have_string_methods # interesting string operations are available on symbols. def test_symbols_cannot_be_concatenated - # Exceptions will be pondered further farther down the path + # Exceptions will be pondered further down the path assert_raise(___) do :cats + :dogs end diff --git a/koans/about_triangle_project_2.rb b/koans/about_triangle_project_2.rb index fc90ba181..0a57e2519 100644 --- a/koans/about_triangle_project_2.rb +++ b/koans/about_triangle_project_2.rb @@ -11,7 +11,7 @@ def test_illegal_triangles_throw_exceptions 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 - #HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions + # HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions end end diff --git a/koans/edgecase.rb b/koans/edgecase.rb index d727cd7bf..070768750 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -2,10 +2,11 @@ # -*- ruby -*- require 'test/unit/assertions' -begin +begin require 'win32console' rescue LoadError end + # -------------------------------------------------------------------- # Support code for the Ruby Koans. # -------------------------------------------------------------------- @@ -121,6 +122,7 @@ def use_colors? def using_windows? File::ALT_SEPARATOR end + def using_win32console defined? Win32::Console end diff --git a/src/about_classes.rb b/src/about_classes.rb index b8b67ea12..a8336bf82 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -126,7 +126,7 @@ def test_args_to_new_must_match_initialize # Why is this so? end - def test_different_objects_have_difference_instance_variables + def test_different_objects_have_different_instance_variables fido = Dog6.new("Fido") rover = Dog6.new("Rover") diff --git a/src/about_constants.rb b/src/about_constants.rb index ad780c698..dd0bc390a 100644 --- a/src/about_constants.rb +++ b/src/about_constants.rb @@ -67,7 +67,7 @@ def test_who_wins_with_both_nested_and_inherited_constants end # QUESTION: Which has precedence: The constant in the lexical scope, - # or the constant from the inheritance heirarachy? + # or the constant from the inheritance hierarchy? # ------------------------------------------------------------------ @@ -81,7 +81,7 @@ 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 + # QUESTION: Now which has precedence: The constant in the lexical + # scope, or the constant from the inheritance hierarchy? Why is it # different than the previous answer? end diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index 319bde005..1e799e647 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -59,12 +59,20 @@ def test_if_statement_modifiers def test_unless_statement result = :default_value - unless false + unless false # same as saying 'if !false', which evaluates as 'if true' result = :false_value end assert_equal __(:false_value), result end + def test_unless_statement_evaluate_true + result = :default_value + unless true # same as saying 'if !true', which evaluates as 'if false' + result = :true_value + end + assert_equal __(:default_value), result + end + def test_unless_statement_modifier result = :default_value result = :false_value unless false @@ -109,7 +117,7 @@ def test_next_statement while i < 10 i += 1 next if (i % 2) == 0 - result << i + result << i end assert_equal __([1, 3, 5, 7, 9]), result end diff --git a/src/about_hashes.rb b/src/about_hashes.rb index 49b393915..0915fa604 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -20,6 +20,18 @@ def test_accessing_hashes assert_equal __(nil), hash[:doesnt_exist] end + def test_accessing_hashes_with_fetch + hash = { :one => "uno" } + assert_equal "uno", hash.fetch(:one) + assert_raise(___(IndexError)) do + hash.fetch(:doesnt_exist) + end + + # THINK ABOUT IT: + # + # Why might you want to use #fetch instead of #[] when accessing hash keys? + end + def test_changing_hashes hash = { :one => "uno", :two => "dos" } hash[:one] = "eins" @@ -63,4 +75,42 @@ def test_combining_hashes expected = { "jim" => __(54), "amy" => 20, "dan" => 23, "jenny" => __(26) } assert_equal __(true), expected == new_hash end + + def test_default_value + hash1 = Hash.new + hash1[:one] = 1 + + assert_equal __(1), hash1[:one] + assert_equal __(nil), hash1[:two] + + hash2 = Hash.new("dos") + hash2[:one] = 1 + + assert_equal __(1), hash2[:one] + assert_equal __("dos"), hash2[:two] + end + + def test_default_value_is_the_same_object + hash = Hash.new([]) + + hash[:one] << "uno" + hash[:two] << "dos" + + assert_equal __(["uno", "dos"]), hash[:one] + assert_equal __(["uno", "dos"]), hash[:two] + assert_equal __(["uno", "dos"]), hash[:three] + + assert_equal __(true), hash[:one].object_id == hash[:two].object_id + end + + def test_default_value_with_block + hash = Hash.new {|hash, key| hash[key] = [] } + + hash[:one] << "uno" + hash[:two] << "dos" + + assert_equal __(["uno"]), hash[:one] + assert_equal __(["dos"]), hash[:two] + assert_equal __([]), hash[:three] + end end diff --git a/src/about_methods.rb b/src/about_methods.rb index 9e7af3744..b720010ea 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -72,6 +72,7 @@ def method_with_var_args(*args) end def test_calling_with_variable_arguments + assert_equal __(Array), method_with_var_args.class assert_equal __([]), method_with_var_args assert_equal __([:one]), method_with_var_args(:one) assert_equal __([:one, :two]), method_with_var_args(:one, :two) diff --git a/src/about_proxy_object_project.rb b/src/about_proxy_object_project.rb index 483a7d7c0..7e8be0387 100644 --- a/src/about_proxy_object_project.rb +++ b/src/about_proxy_object_project.rb @@ -29,7 +29,7 @@ def method_missing(sym, *args, &block) @messages << sym @object.send(sym, *args, &block) end - + def called?(method) @messages.include?(method) end @@ -46,50 +46,52 @@ class AboutProxyObjectProject < EdgeCase::Koan def test_proxy_method_returns_wrapped_object # NOTE: The Television class is defined below tv = Proxy.new(Television.new) - + + # HINT: Proxy class is defined above, may need tweaking... + assert tv.instance_of?(Proxy) end - + def test_tv_methods_still_perform_their_function tv = Proxy.new(Television.new) - + tv.channel = 10 tv.power - + assert_equal 10, tv.channel assert tv.on? end def test_proxy_records_messages_sent_to_tv tv = Proxy.new(Television.new) - + tv.power tv.channel = 10 - + assert_equal [:power, :channel=], tv.messages end - + def test_proxy_handles_invalid_messages tv = Proxy.new(Television.new) - + assert_raise(NoMethodError) do tv.no_such_method end end - + def test_proxy_reports_methods_have_been_called tv = Proxy.new(Television.new) - + tv.power tv.power - + assert tv.called?(:power) assert ! tv.called?(:channel) end - + def test_proxy_counts_method_calls tv = Proxy.new(Television.new) - + tv.power tv.channel = 48 tv.power @@ -118,7 +120,7 @@ def test_proxy_can_record_more_than_just_tv_objects # Example class using in the proxy testing above. class Television attr_accessor :channel - + def power if @power == :on @power = :off @@ -126,7 +128,7 @@ def power @power = :on end end - + def on? @power == :on end @@ -136,31 +138,31 @@ def on? class TelevisionTest < EdgeCase::Koan def test_it_turns_on tv = Television.new - + tv.power assert tv.on? end - + def test_it_also_turns_off tv = Television.new - + tv.power tv.power - + assert ! tv.on? end - + def test_edge_case_on_off tv = Television.new - + tv.power tv.power tv.power - + assert tv.on? - + tv.power - + assert ! tv.on? end diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb index 55b85f678..03e8f9a9e 100644 --- a/src/about_regular_expressions.rb +++ b/src/about_regular_expressions.rb @@ -84,6 +84,8 @@ def test_a_character_class_can_be_negated 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+/] + # ... a programmer would most likely do + assert_equal __(" = "), "variable_1 = 42"[/[^a-zA-Z0-9_]+/] assert_equal __(" = "), "variable_1 = 42"[/\W+/] end diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index c48c3cb68..0a57e2519 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -11,6 +11,7 @@ def test_illegal_triangles_throw_exceptions 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 + # HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions end end diff --git a/src/about_true_and_false.rb b/src/about_true_and_false.rb index 4c99d99aa..e9910f63f 100644 --- a/src/about_true_and_false.rb +++ b/src/about_true_and_false.rb @@ -10,7 +10,7 @@ def truth_value(condition) end def test_true_is_treated_as_true - assert_equal __(:true_stuff), truth_value(true) + assert_equal __(:true_stuff), truth_value(true) end def test_false_is_treated_as_false diff --git a/src/edgecase.rb b/src/edgecase.rb index ba49956de..070768750 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -2,6 +2,10 @@ # -*- ruby -*- require 'test/unit/assertions' +begin + require 'win32console' +rescue LoadError +end # -------------------------------------------------------------------- # Support code for the Ruby Koans. @@ -107,7 +111,9 @@ def color(color_value) def use_colors? return false if ENV['NO_COLOR'] if ENV['ANSI_COLOR'].nil? - ! using_windows? + if using_windows? + using_win32console + end else ENV['ANSI_COLOR'] =~ /^(t|y)/i end @@ -116,6 +122,10 @@ def use_colors? def using_windows? File::ALT_SEPARATOR end + + def using_win32console + defined? Win32::Console + end end class Sensei From 5665cb03663dc844bc730212d2ce5d590b63ab41 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:03:10 -0500 Subject: [PATCH 196/276] Handle 1.8 VS 1.9 differences in fetch exception. --- src/about_hashes.rb | 2 +- src/edgecase.rb | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/about_hashes.rb b/src/about_hashes.rb index 0915fa604..27a6fd12a 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -23,7 +23,7 @@ def test_accessing_hashes def test_accessing_hashes_with_fetch hash = { :one => "uno" } assert_equal "uno", hash.fetch(:one) - assert_raise(___(IndexError)) do + assert_raise(___(IndexError, KeyError)) do hash.fetch(:doesnt_exist) end diff --git a/src/edgecase.rb b/src/edgecase.rb index 070768750..1136218b5 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -44,8 +44,12 @@ def _n_(value=999999, value19=:mu) end # Error object replacement value. -def ___(value=FillMeInError) - value +def ___(value=FillMeInError, value19=:mu) + if RUBY_VERSION < "1.9" + value + else + (value19 == :mu) ? value : value19 + end end # Method name replacement. From 4633ba5c799808473a9ec2574578c1699fd9aef8 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:14:42 -0500 Subject: [PATCH 197/276] Add a dummy KeyError to 1.8 so that src koans will run. --- src/edgecase.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/edgecase.rb b/src/edgecase.rb index 1136218b5..1443807c8 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -24,6 +24,11 @@ def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end +in_ruby_version("1.8") do + class KeyError < StandardError + end +end + # Standard, generic replacement value. # If value19 is given, it is used in place of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) From 007eeff1d8f592017aebe2b59c6d3d63b3c94285 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:35:47 -0500 Subject: [PATCH 198/276] Removed support for Ruby 1.8.6. --- Rakefile | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Rakefile b/Rakefile index 5fb5546b1..07da09565 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,11 @@ # -*- ruby -*- require 'rake/clean' -require 'rdoc/task' +begin + require 'rdoc/task' +rescue LoadError => ex + # No rdoc task availble. +end SRC_DIR = 'src' PROB_DIR = 'koans' @@ -63,7 +67,7 @@ end module RubyImpls # Calculate the list of relevant Ruby implementations. def self.find_ruby_impls - rubys = `rvm list`.gsub(/=>/,'').split(/\n/).sort + rubys = `rvm list`.gsub(/=>/,'').split(/\n/).map { |x| x.strip }.reject { |x| x.empty? || x =~ /^rvm/ }.sort expected.map { |impl| last = rubys.grep(Regexp.new(Regexp.quote(impl))).last last ? last.split.first : nil @@ -77,7 +81,7 @@ module RubyImpls # List of expected ruby implementations. def self.expected - %w(ruby-1.8.6 ruby-1.8.7 ruby-1.9.2 jruby ree) + %w(ruby-1.8.7 ruby-1.9.2 jruby ree) end end @@ -88,9 +92,11 @@ task :walk_the_path do ruby 'path_to_enlightenment.rb' end -Rake::RDocTask.new do |rd| - rd.main = "README.rdoc" - rd.rdoc_files.include("README.rdoc", "koans/*.rb") +if defined?(Rake::RDocTask) + Rake::RDocTask.new do |rd| + rd.main = "README.rdoc" + rd.rdoc_files.include("README.rdoc", "koans/*.rb") + end end directory DIST_DIR @@ -150,7 +156,7 @@ task :run_all do RubyImpls.list.each do |impl| puts "=" * 40 puts "On Ruby #{impl}" - sh "rvm #{impl} rake run" + sh ". rvm #{impl}; rake run" results << [impl, "RAN"] puts end From d92f3234c7710dde3ce0b410d7234e18497729cf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:39:29 -0500 Subject: [PATCH 199/276] Added __ to assert with no __ blanks. --- src/about_hashes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_hashes.rb b/src/about_hashes.rb index 27a6fd12a..2382d68cd 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -22,7 +22,7 @@ def test_accessing_hashes def test_accessing_hashes_with_fetch hash = { :one => "uno" } - assert_equal "uno", hash.fetch(:one) + assert_equal __("uno"), hash.fetch(:one) assert_raise(___(IndexError, KeyError)) do hash.fetch(:doesnt_exist) end From a3fcc3904a600962522c30a7e0954a3dd93fb350 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:40:08 -0500 Subject: [PATCH 200/276] Updated koans directory from source. --- koans/edgecase.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/koans/edgecase.rb b/koans/edgecase.rb index 070768750..1443807c8 100644 --- a/koans/edgecase.rb +++ b/koans/edgecase.rb @@ -24,6 +24,11 @@ def in_ruby_version(*versions) yield if versions.any? { |v| ruby_version?(v) } end +in_ruby_version("1.8") do + class KeyError < StandardError + end +end + # Standard, generic replacement value. # If value19 is given, it is used in place of value for Ruby 1.9. def __(value="FILL ME IN", value19=:mu) @@ -44,8 +49,12 @@ def _n_(value=999999, value19=:mu) end # Error object replacement value. -def ___(value=FillMeInError) - value +def ___(value=FillMeInError, value19=:mu) + if RUBY_VERSION < "1.9" + value + else + (value19 == :mu) ? value : value19 + end end # Method name replacement. From a83000b4d395aa3ea8fd9aa0f737aef2687112fe Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:41:54 -0500 Subject: [PATCH 201/276] Restrict assert checks to .rb files. --- rakelib/checks.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rakelib/checks.rake b/rakelib/checks.rake index fa5aaf7e0..c1b20d7de 100644 --- a/rakelib/checks.rake +++ b/rakelib/checks.rake @@ -19,7 +19,7 @@ namespace "check" do task :asserts do puts "Checking for asserts missing the replacement text:" begin - sh "egrep -n 'assert( |_)' src/about_* | egrep -v '__|_n_|project|about_assert' | egrep -v ' *#'" + sh "egrep -n 'assert( |_)' src/about_*.rb | egrep -v '__|_n_|project|about_assert' | egrep -v ' *#'" puts puts "Examine the above lines for missing __ replacements" rescue RuntimeError => ex From 2ddd9294735af7b722969cbcf3e7ca7867c8e1a4 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:47:24 -0500 Subject: [PATCH 202/276] Remove koans directory from source control. Patches were submitted against the koans directory rather than the src directory. This lead to potential problems when we regenerate the koans directory from scratch, leading to the very real possibility that changes could be lost. Please make all changes to the src directory and use "rake gen" (or "rake regen") to generate the koans directory as needed. --- koans/GREED_RULES.txt | 66 ---- koans/README.rdoc | 146 --------- koans/Rakefile | 12 - koans/about_array_assignment.rb | 51 --- koans/about_arrays.rb | 84 ----- koans/about_asserts.rb | 40 --- koans/about_blocks.rb | 96 ------ koans/about_class_methods.rb | 170 ---------- koans/about_classes.rb | 190 ----------- koans/about_constants.rb | 87 ----- koans/about_control_statements.rb | 134 -------- koans/about_dice_project.rb | 63 ---- koans/about_exceptions.rb | 68 ---- koans/about_extra_credit.rb | 8 - koans/about_hashes.rb | 116 ------- koans/about_inheritance.rb | 85 ----- koans/about_iteration.rb | 124 ------- koans/about_java_interop.rb | 137 -------- koans/about_message_passing.rb | 178 ---------- koans/about_methods.rb | 151 --------- koans/about_modules.rb | 63 ---- koans/about_nil.rb | 38 --- koans/about_objects.rb | 56 ---- koans/about_open_classes.rb | 45 --- koans/about_proxy_object_project.rb | 156 --------- koans/about_regular_expressions.rb | 161 --------- koans/about_sandwich_code.rb | 106 ------ koans/about_scope.rb | 79 ----- koans/about_scoring_project.rb | 74 ----- koans/about_strings.rb | 195 ----------- koans/about_symbols.rb | 100 ------ koans/about_to_str.rb | 54 --- koans/about_triangle_project.rb | 25 -- koans/about_triangle_project_2.rb | 17 - koans/about_true_and_false.rb | 33 -- koans/array_test.rb | 47 --- koans/autotest/discover.rb | 3 - koans/autotest/rubykoan.rb | 24 -- koans/code_mash.rb | 1 - koans/edgecase.rb | 490 ---------------------------- koans/example_file.txt | 4 - koans/first_test.rb | 11 - koans/path_to_enlightenment.rb | 38 --- koans/test_helper.rb | 7 - koans/triangle.rb | 22 -- 45 files changed, 3855 deletions(-) delete mode 100644 koans/GREED_RULES.txt delete mode 100644 koans/README.rdoc delete mode 100644 koans/Rakefile delete mode 100644 koans/about_array_assignment.rb delete mode 100644 koans/about_arrays.rb delete mode 100644 koans/about_asserts.rb delete mode 100644 koans/about_blocks.rb delete mode 100644 koans/about_class_methods.rb delete mode 100644 koans/about_classes.rb delete mode 100644 koans/about_constants.rb delete mode 100644 koans/about_control_statements.rb delete mode 100644 koans/about_dice_project.rb delete mode 100644 koans/about_exceptions.rb delete mode 100644 koans/about_extra_credit.rb delete mode 100644 koans/about_hashes.rb delete mode 100644 koans/about_inheritance.rb delete mode 100644 koans/about_iteration.rb delete mode 100644 koans/about_java_interop.rb delete mode 100644 koans/about_message_passing.rb delete mode 100644 koans/about_methods.rb delete mode 100644 koans/about_modules.rb delete mode 100644 koans/about_nil.rb delete mode 100644 koans/about_objects.rb delete mode 100644 koans/about_open_classes.rb delete mode 100644 koans/about_proxy_object_project.rb delete mode 100644 koans/about_regular_expressions.rb delete mode 100644 koans/about_sandwich_code.rb delete mode 100644 koans/about_scope.rb delete mode 100644 koans/about_scoring_project.rb delete mode 100644 koans/about_strings.rb delete mode 100644 koans/about_symbols.rb delete mode 100644 koans/about_to_str.rb delete mode 100644 koans/about_triangle_project.rb delete mode 100644 koans/about_triangle_project_2.rb delete mode 100644 koans/about_true_and_false.rb delete mode 100644 koans/array_test.rb delete mode 100644 koans/autotest/discover.rb delete mode 100644 koans/autotest/rubykoan.rb delete mode 100644 koans/code_mash.rb delete mode 100644 koans/edgecase.rb delete mode 100644 koans/example_file.txt delete mode 100644 koans/first_test.rb delete mode 100644 koans/path_to_enlightenment.rb delete mode 100644 koans/test_helper.rb delete mode 100644 koans/triangle.rb diff --git a/koans/GREED_RULES.txt b/koans/GREED_RULES.txt deleted file mode 100644 index 58b5a9cb6..000000000 --- a/koans/GREED_RULES.txt +++ /dev/null @@ -1,66 +0,0 @@ -= Playing Greed - -Greed is a dice game played among 2 or more players, using 5 -six-sided dice. - -== Playing Greed - -Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all five dice which are -scored according to the following: - - Three 1's => 1000 points - Three 6's => 600 points - Three 5's => 500 points - Three 4's => 400 points - Three 3's => 300 points - Three 2's => 200 points - One 1 => 100 points - One 5 => 50 points - -A single die can only be counted once in each roll. For example, -a "5" can only count as part of a triplet (contributing to the 500 -points) or as a single 50 points, but not both in the same roll. - -Example Scoring - - Throw Score - --------- ------------------ - 5 1 3 4 1 50 + 2 * 100 = 250 - 1 1 1 3 1 1000 + 100 = 1100 - 2 4 4 5 4 400 + 50 = 450 - -The dice not contributing to the score are called the non-scoring -dice. "3" and "4" are non-scoring dice in the first example. "3" is -a non-scoring die in the second, and "2" is a non-score die in the -final example. - -After a player rolls and the score is calculated, the scoring dice are -removed and the player has the option of rolling again using only the -non-scoring dice. If all of the thrown dice are scoring, then the -player may roll all 5 dice in the next roll. - -The player may continue to roll as long as each roll scores points. If -a roll has zero points, then the player loses not only their turn, but -also accumulated score for that turn. If a player decides to stop -rolling before rolling a zero-point roll, then the accumulated points -for the turn is added to his total score. - -== Getting "In The Game" - -Before a player is allowed to accumulate points, they must get at -least 300 points in a single turn. Once they have achieved 300 points -in a single turn, the points earned in that turn and each following -turn will be counted toward their total score. - -== End Game - -Once a player reaches 3000 (or more) points, the game enters the final -round where each of the other players gets one more turn. The winner -is the player with the highest score after the final round. - -== References - -Greed is described on Wikipedia at -http://en.wikipedia.org/wiki/Greed_(dice_game), however the rules are -a bit different from the rules given here. diff --git a/koans/README.rdoc b/koans/README.rdoc deleted file mode 100644 index fb6abb159..000000000 --- a/koans/README.rdoc +++ /dev/null @@ -1,146 +0,0 @@ -= 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 -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. - -== 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. - -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. - -== 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 -installed. To check the installations simply type: - -*nix platforms from any terminal window: - - [~] $ ruby --version - [~] $ rake --version - -Windows from the command prompt (cmd.exe) - - c:\ruby --version - c:\rake --version - -If you don't have rake installed, just run `gem install rake` - -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 - -You can run the tests through rake or by calling the file itself (rake is the -recommended way to run them as we might build more functionality into this task). - -*nix platforms, from the koans directory - - [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 -moment and reflect upon the test to see what it is teaching you and improve the -code to better communicate its intent (refactor). - -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 ... - 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. - def test_assert_truth - assert false # This should be true - end - -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+ -method, it will either ensure it is +true+ and continue on, or fail if in fact -the statement is +false+. - -== Inspiration - -A special thanks to Mike Clark and Ara Howard for inspiring this -project. Mike Clark wrote an excellent blog post about learning Ruby -through unit testing. This sparked an idea that has taken a bit to -solidify, that of bringing new rubyists into the community through -testing. Ara Howard then gave us the idea for the Koans in his ruby -quiz entry on Meta Koans (a must for any rubyist wanting to improve -their skills). Also, "The Little Lisper" taught us all the value of -the short questions/simple answers style of learning. - -Mike Clark's post :: http://www.clarkware.com/cgi/blosxom/2005/03/18 -Meta Koans :: http://rubyquiz.com/quiz67.html -The Little Lisper :: http://www.amazon.com/Little-LISPer-Third-Daniel-Friedman/dp/0023397632 - -== Other Resources - -The Ruby Language :: http://ruby-lang.org -Try Ruby in your browser :: http://tryruby.org - -Dave Thomas' introduction to Ruby Programming Ruby (the Pick Axe) :: http://pragprog.com/titles/ruby/programming-ruby - -Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: http://pragprog.com/titles/bmsft/everyday-scripting-with-ruby - -= Other stuff - -Author :: Jim Weirich -Author :: Joe O'Brien -Issue Tracker :: http://www.pivotaltracker.com/projects/48111 -Requires :: Ruby 1.8.x or later and Rake (any recent version) - -= License - -http://i.creativecommons.org/l/by-nc-sa/3.0/88x31.png - -RubyKoans is released under a Creative Commons, -Attribution-NonCommercial-ShareAlike, Version 3.0 -(http://creativecommons.org/licenses/by-nc-sa/3.0/) License. diff --git a/koans/Rakefile b/koans/Rakefile deleted file mode 100644 index 1a2c7f26d..000000000 --- a/koans/Rakefile +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env ruby -# -*- ruby -*- - -require 'rake/clean' -require 'rake/testtask' - -task :default => :test - -task :test do - ruby 'path_to_enlightenment.rb' -end - diff --git a/koans/about_array_assignment.rb b/koans/about_array_assignment.rb deleted file mode 100644 index 21a64bb81..000000000 --- a/koans/about_array_assignment.rb +++ /dev/null @@ -1,51 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutArrayAssignment < EdgeCase::Koan - def test_non_parallel_assignment - names = ["John", "Smith"] - assert_equal __, names - end - - def test_parallel_assignments - first_name, last_name = ["John", "Smith"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_extra_values - first_name, last_name = ["John", "Smith", "III"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_splat_operator - first_name, *last_name = ["John", "Smith", "III"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_too_few_variables - first_name, last_name = ["Cher"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignments_with_subarrays - first_name, last_name = [["Willie", "Rae"], "Johnson"] - assert_equal __, first_name - assert_equal __, last_name - end - - def test_parallel_assignment_with_one_variable - first_name, = ["John", "Smith"] - 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 diff --git a/koans/about_arrays.rb b/koans/about_arrays.rb deleted file mode 100644 index 9f27b5aaa..000000000 --- a/koans/about_arrays.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutArrays < EdgeCase::Koan - def test_creating_arrays - empty_array = Array.new - assert_equal __, empty_array.class - assert_equal __, empty_array.size - end - - def test_array_literals - array = Array.new - assert_equal [], array - - array[0] = 1 - assert_equal [1], array - - array[1] = 2 - assert_equal [1, __], array - - array << 333 - assert_equal __, array - end - - def test_accessing_array_elements - array = [:peanut, :butter, :and, :jelly] - - assert_equal __, array[0] - assert_equal __, array.first - assert_equal __, array[3] - assert_equal __, array.last - assert_equal __, array[-1] - assert_equal __, array[-3] - end - - def test_slicing_arrays - array = [:peanut, :butter, :and, :jelly] - - assert_equal __, array[0,1] - assert_equal __, array[0,2] - assert_equal __, array[2,2] - assert_equal __, array[2,20] - assert_equal __, array[4,0] - assert_equal __, array[4,100] - assert_equal __, array[5,0] - end - - def test_arrays_and_ranges - assert_equal __, (1..5).class - assert_not_equal [1,2,3,4,5], (1..5) - assert_equal __, (1..5).to_a - assert_equal __, (1...5).to_a - end - - def test_slicing_with_ranges - array = [:peanut, :butter, :and, :jelly] - - assert_equal __, array[0..2] - assert_equal __, array[0...2] - assert_equal __, array[2..-1] - end - - def test_pushing_and_popping_arrays - array = [1,2] - array.push(:last) - - assert_equal __, array - - popped_value = array.pop - assert_equal __, popped_value - assert_equal __, array - end - - def test_shifting_arrays - array = [1,2] - array.unshift(:first) - - assert_equal __, array - - shifted_value = array.shift - assert_equal __, shifted_value - assert_equal __, array - end - -end diff --git a/koans/about_asserts.rb b/koans/about_asserts.rb deleted file mode 100644 index e1c34d44e..000000000 --- a/koans/about_asserts.rb +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env ruby -# -*- ruby -*- - -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutAsserts < EdgeCase::Koan - - # We shall contemplate truth by testing reality, via asserts. - def test_assert_truth - assert false # This should be true - end - - # Enlightenment may be more easily achieved with appropriate - # messages. - def test_assert_with_message - assert false, "This should be true -- Please fix this" - end - - # To understand reality, we must compare our expectations against - # reality. - def test_assert_equality - expected_value = __ - actual_value = 1 + 1 - - assert expected_value == actual_value - end - - # Some ways of asserting equality are better than others. - def test_a_better_way_of_asserting_equality - expected_value = __ - actual_value = 1 + 1 - - assert_equal expected_value, actual_value - end - - # Sometimes we will ask you to fill in the values - def test_fill_in_values - assert_equal __, 1 + 1 - end -end diff --git a/koans/about_blocks.rb b/koans/about_blocks.rb deleted file mode 100644 index 0abee8f9b..000000000 --- a/koans/about_blocks.rb +++ /dev/null @@ -1,96 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutBlocks < EdgeCase::Koan - def method_with_block - result = yield - result - end - - def test_methods_can_take_blocks - yielded_result = method_with_block { 1 + 2 } - assert_equal __, yielded_result - end - - def test_blocks_can_be_defined_with_do_end_too - yielded_result = method_with_block do 1 + 2 end - assert_equal __, yielded_result - end - - # ------------------------------------------------------------------ - - def method_with_block_arguments - yield("Jim") - end - - def test_blocks_can_take_arguments - result = method_with_block_arguments do |argument| - assert_equal __, argument - end - end - - # ------------------------------------------------------------------ - - def many_yields - yield(:peanut) - yield(:butter) - yield(:and) - yield(:jelly) - end - - def test_methods_can_call_yield_many_times - result = [] - many_yields { |item| result << item } - assert_equal __, result - end - - # ------------------------------------------------------------------ - - def yield_tester - if block_given? - yield - else - :no_block - end - end - - def test_methods_can_see_if_they_have_been_called_with_a_block - assert_equal __, yield_tester { :with_block } - assert_equal __, yield_tester - end - - # ------------------------------------------------------------------ - - def test_block_can_affect_variables_in_the_code_where_they_are_created - value = :initial_value - method_with_block { value = :modified_in_a_block } - assert_equal __, value - end - - def test_blocks_can_be_assigned_to_variables_and_called_explicitly - add_one = lambda { |n| n + 1 } - assert_equal __, add_one.call(10) - - # Alternative calling sequence - assert_equal __, add_one[10] - end - - def test_stand_alone_blocks_can_be_passed_to_methods_expecting_blocks - make_upper = lambda { |n| n.upcase } - result = method_with_block_arguments(&make_upper) - assert_equal __, result - end - - # ------------------------------------------------------------------ - - def method_with_explicit_block(&block) - block.call(10) - end - - def test_methods_can_take_an_explicit_block_argument - assert_equal __, method_with_explicit_block { |n| n * 2 } - - add_one = lambda { |n| n + 1 } - assert_equal __, method_with_explicit_block(&add_one) - end - -end diff --git a/koans/about_class_methods.rb b/koans/about_class_methods.rb deleted file mode 100644 index ddd32bd51..000000000 --- a/koans/about_class_methods.rb +++ /dev/null @@ -1,170 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutClassMethods < EdgeCase::Koan - class Dog - end - - def test_objects_are_objects - fido = Dog.new - assert_equal __, fido.is_a?(Object) - end - - def test_classes_are_classes - assert_equal __, Dog.is_a?(Class) - end - - def test_classes_are_objects_too - assert_equal __, Dog.is_a?(Object) - end - - def test_objects_have_methods - fido = Dog.new - assert fido.methods.size > _n_ - end - - def test_classes_have_methods - assert Dog.methods.size > _n_ - end - - def test_you_can_define_methods_on_individual_objects - fido = Dog.new - def fido.wag - :fidos_wag - end - assert_equal __, fido.wag - end - - def test_other_objects_are_not_affected_by_these_singleton_methods - fido = Dog.new - rover = Dog.new - def fido.wag - :fidos_wag - end - - assert_raise(___) do - rover.wag - end - end - - # ------------------------------------------------------------------ - - class Dog2 - def wag - :instance_level_wag - end - end - - def Dog2.wag - :class_level_wag - end - - def test_since_classes_are_objects_you_can_define_singleton_methods_on_them_too - assert_equal __, Dog2.wag - end - - def test_class_methods_are_independent_of_instance_methods - fido = Dog2.new - assert_equal __, fido.wag - assert_equal __, Dog2.wag - end - - # ------------------------------------------------------------------ - - class Dog - attr_accessor :name - end - - def Dog.name - @name - end - - def test_classes_and_instances_do_not_share_instance_variables - fido = Dog.new - fido.name = "Fido" - assert_equal __, fido.name - assert_equal __, Dog.name - end - - # ------------------------------------------------------------------ - - class Dog - def Dog.a_class_method - :dogs_class_method - end - end - - def test_you_can_define_class_methods_inside_the_class - assert_equal __, Dog.a_class_method - end - - - # ------------------------------------------------------------------ - - LastExpressionInClassStatement = class Dog - 21 - end - - def test_class_statements_return_the_value_of_their_last_expression - assert_equal __, LastExpressionInClassStatement - end - - # ------------------------------------------------------------------ - - SelfInsideOfClassStatement = class Dog - self - end - - def test_self_while_inside_class_is_class_object_not_instance - assert_equal __, Dog == SelfInsideOfClassStatement - end - - # ------------------------------------------------------------------ - - class Dog - def self.class_method2 - :another_way_to_write_class_methods - end - end - - def test_you_can_use_self_instead_of_an_explicit_reference_to_dog - assert_equal __, Dog.class_method2 - end - - # ------------------------------------------------------------------ - - class Dog - class << self - def another_class_method - :still_another_way - end - end - end - - def test_heres_still_another_way_to_write_class_methods - assert_equal __, Dog.another_class_method - end - - # THINK ABOUT IT: - # - # The two major ways to write class methods are: - # class Demo - # def self.method - # end - # - # class << self - # def class_methods - # end - # end - # end - # - # Which do you prefer and why? - # Are there times you might prefer one over the other? - - # ------------------------------------------------------------------ - - def test_heres_an_easy_way_to_call_class_methods_from_instance_methods - fido = Dog.new - assert_equal __, fido.class.another_class_method - end - -end diff --git a/koans/about_classes.rb b/koans/about_classes.rb deleted file mode 100644 index 3fce64601..000000000 --- a/koans/about_classes.rb +++ /dev/null @@ -1,190 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutClasses < EdgeCase::Koan - class Dog - end - - def test_instances_of_classes_can_be_created_with_new - fido = Dog.new - assert_equal __, fido.class - end - - # ------------------------------------------------------------------ - - class Dog2 - def set_name(a_name) - @name = a_name - end - end - - def test_instance_variables_can_be_set_by_assigning_to_them - fido = Dog2.new - assert_equal __, fido.instance_variables - - fido.set_name("Fido") - assert_equal __, fido.instance_variables - end - - def test_instance_variables_cannot_be_accessed_outside_the_class - fido = Dog2.new - fido.set_name("Fido") - - assert_raise(___) do - fido.name - end - - assert_raise(___) do - eval "fido.@name" - # NOTE: Using eval because the above line is a syntax error. - end - end - - def test_you_can_politely_ask_for_instance_variable_values - fido = Dog2.new - fido.set_name("Fido") - - assert_equal __, fido.instance_variable_get("@name") - end - - def test_you_can_rip_the_value_out_using_instance_eval - fido = Dog2.new - fido.set_name("Fido") - - assert_equal __, fido.instance_eval("@name") # string version - assert_equal __, fido.instance_eval { @name } # block version - end - - # ------------------------------------------------------------------ - - class Dog3 - def set_name(a_name) - @name = a_name - end - def name - @name - end - end - - def test_you_can_create_accessor_methods_to_return_instance_variables - fido = Dog3.new - fido.set_name("Fido") - - assert_equal __, fido.name - end - - # ------------------------------------------------------------------ - - class Dog4 - attr_reader :name - - def set_name(a_name) - @name = a_name - end - end - - - def test_attr_reader_will_automatically_define_an_accessor - fido = Dog4.new - fido.set_name("Fido") - - assert_equal __, fido.name - end - - # ------------------------------------------------------------------ - - class Dog5 - attr_accessor :name - end - - - def test_attr_accessor_will_automatically_define_both_read_and_write_accessors - fido = Dog5.new - - fido.name = "Fido" - assert_equal __, fido.name - end - - # ------------------------------------------------------------------ - - class Dog6 - attr_reader :name - def initialize(initial_name) - @name = initial_name - end - end - - def test_initialize_provides_initial_values_for_instance_variables - fido = Dog6.new("Fido") - assert_equal __, fido.name - end - - def test_args_to_new_must_match_initialize - assert_raise(___) do - Dog6.new - end - # THINK ABOUT IT: - # Why is this so? - end - - def test_different_objects_have_different_instance_variables - fido = Dog6.new("Fido") - rover = Dog6.new("Rover") - - assert_equal __, rover.name != fido.name - end - - # ------------------------------------------------------------------ - - class Dog7 - attr_reader :name - - def initialize(initial_name) - @name = initial_name - end - - def get_self - self - end - - def to_s - __ - end - - def inspect - "" - end - end - - def test_inside_a_method_self_refers_to_the_containing_object - fido = Dog7.new("Fido") - - fidos_self = fido.get_self - assert_equal __, fidos_self - end - - def test_to_s_provides_a_string_version_of_the_object - fido = Dog7.new("Fido") - assert_equal __, fido.to_s - end - - def test_to_s_is_used_in_string_interpolation - fido = Dog7.new("Fido") - assert_equal __, "My dog is #{fido}" - end - - def test_inspect_provides_a_more_complete_string_version - fido = Dog7.new("Fido") - assert_equal __, fido.inspect - end - - def test_all_objects_support_to_s_and_inspect - array = [1,2,3] - - assert_equal __, array.to_s - assert_equal __, array.inspect - - assert_equal __, "STRING".to_s - assert_equal __, "STRING".inspect - end - -end diff --git a/koans/about_constants.rb b/koans/about_constants.rb deleted file mode 100644 index 41d3f0126..000000000 --- a/koans/about_constants.rb +++ /dev/null @@ -1,87 +0,0 @@ -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 hierarchy? - - # ------------------------------------------------------------------ - - 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 hierarchy? Why is it - # different than the previous answer? -end diff --git a/koans/about_control_statements.rb b/koans/about_control_statements.rb deleted file mode 100644 index df503d714..000000000 --- a/koans/about_control_statements.rb +++ /dev/null @@ -1,134 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutControlStatements < EdgeCase::Koan - - def test_if_then_else_statements - if true - result = :true_value - else - result = :false_value - end - assert_equal __, result - end - - def test_if_then_statements - result = :default_value - if true - result = :true_value - end - assert_equal __, result - end - - def test_if_statements_return_values - value = if true - :true_value - else - :false_value - end - assert_equal __, value - - value = if false - :true_value - else - :false_value - end - assert_equal __, value - - # NOTE: Actually, EVERY statement in Ruby will return a value, not - # just if statements. - end - - def test_if_statements_with_no_else_with_false_condition_return_value - value = if false - :true_value - end - assert_equal __, value - end - - def test_condition_operators - assert_equal __, (true ? :true_value : :false_value) - assert_equal __, (false ? :true_value : :false_value) - end - - def test_if_statement_modifiers - result = :default_value - result = :true_value if true - - assert_equal __, result - end - - def test_unless_statement - result = :default_value - unless false # same as saying 'if !false', which evaluates as 'if true' - result = :false_value - end - assert_equal __, result - end - - def test_unless_statement_evaluate_true - result = :default_value - unless true # same as saying 'if !true', which evaluates as 'if false' - result = :true_value - end - assert_equal __, result - end - - def test_unless_statement_modifier - result = :default_value - result = :false_value unless false - - assert_equal __, result - end - - def test_while_statement - i = 1 - result = 1 - while i <= 10 - result = result * i - i += 1 - end - assert_equal __, result - end - - def test_break_statement - i = 1 - result = 1 - while true - break unless i <= 10 - result = result * i - i += 1 - end - assert_equal __, result - end - - def test_break_statement_returns_values - i = 1 - result = while i <= 10 - break i if i % 2 == 0 - i += 1 - end - - assert_equal __, result - end - - def test_next_statement - i = 0 - result = [] - while i < 10 - i += 1 - next if (i % 2) == 0 - result << i - end - assert_equal __, result - end - - def test_for_statement - array = ["fish", "and", "chips"] - result = [] - for item in array - result << item.upcase - end - assert_equal [__, __, __], result - end - -end diff --git a/koans/about_dice_project.rb b/koans/about_dice_project.rb deleted file mode 100644 index ce817155e..000000000 --- a/koans/about_dice_project.rb +++ /dev/null @@ -1,63 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -# Implement a DiceSet Class here: -# -# class DiceSet -# code ... -# end - -class AboutDiceProject < EdgeCase::Koan - def test_can_create_a_dice_set - dice = DiceSet.new - assert_not_nil dice - end - - def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6 - dice = DiceSet.new - - dice.roll(5) - assert dice.values.is_a?(Array), "should be an array" - assert_equal 5, dice.values.size - dice.values.each do |value| - assert value >= 1 && value <= 6, "value #{value} must be between 1 and 6" - end - end - - def test_dice_values_do_not_change_unless_explicitly_rolled - dice = DiceSet.new - dice.roll(5) - first_time = dice.values - second_time = dice.values - assert_equal first_time, second_time - end - - def test_dice_values_should_change_between_rolls - dice = DiceSet.new - - dice.roll(5) - first_time = dice.values - - dice.roll(5) - second_time = dice.values - - assert_not_equal first_time, second_time, - "Two rolls should not be equal" - - # THINK ABOUT IT: - # - # If the rolls are random, then it is possible (although not - # likely) that two consecutive rolls are equal. What would be a - # better way to test this. - end - - def test_you_can_roll_different_numbers_of_dice - dice = DiceSet.new - - dice.roll(3) - assert_equal 3, dice.values.size - - dice.roll(1) - assert_equal 1, dice.values.size - end - -end diff --git a/koans/about_exceptions.rb b/koans/about_exceptions.rb deleted file mode 100644 index d745f961b..000000000 --- a/koans/about_exceptions.rb +++ /dev/null @@ -1,68 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutExceptions < EdgeCase::Koan - - class MySpecialError < RuntimeError - end - - def test_exceptions_inherit_from_Exception - assert_equal __, MySpecialError.ancestors[1] - assert_equal __, MySpecialError.ancestors[2] - assert_equal __, MySpecialError.ancestors[3] - assert_equal __, MySpecialError.ancestors[4] - end - - def test_rescue_clause - result = nil - begin - fail "Oops" - rescue StandardError => ex - result = :exception_handled - end - - assert_equal __, result - - assert_equal __, ex.is_a?(StandardError), "Should be a Standard Error" - assert_equal __, ex.is_a?(RuntimeError), "Should be a Runtime Error" - - assert RuntimeError.ancestors.include?(StandardError), - "RuntimeError is a subclass of StandardError" - - assert_equal __, ex.message - end - - def test_raising_a_particular_error - result = nil - begin - # 'raise' and 'fail' are synonyms - raise MySpecialError, "My Message" - rescue MySpecialError => ex - result = :exception_handled - end - - assert_equal __, result - assert_equal __, ex.message - end - - def test_ensure_clause - result = nil - begin - fail "Oops" - rescue StandardError => ex - # no code here - ensure - result = :always_run - end - - assert_equal __, result - end - - # Sometimes, we must know about the unknown - def test_asserting_an_error_is_raised - # A do-end is a block, a topic to explore more later - assert_raise(___) do - raise MySpecialError.new("New instances can be raised directly.") - end - end - -end diff --git a/koans/about_extra_credit.rb b/koans/about_extra_credit.rb deleted file mode 100644 index 5012edf8c..000000000 --- a/koans/about_extra_credit.rb +++ /dev/null @@ -1,8 +0,0 @@ -# EXTRA CREDIT: -# -# Create a program that will play the Greed Game. -# Rules for the game are in GREED_RULES.TXT. -# -# You already have a DiceSet class and score function you can use. -# Write a player class and a Game class to complete the project. This -# is a free form assignment, so approach it however you desire. diff --git a/koans/about_hashes.rb b/koans/about_hashes.rb deleted file mode 100644 index 511e3c126..000000000 --- a/koans/about_hashes.rb +++ /dev/null @@ -1,116 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutHashes < EdgeCase::Koan - def test_creating_hashes - empty_hash = Hash.new - assert_equal __, empty_hash.class - assert_equal({}, empty_hash) - assert_equal __, empty_hash.size - end - - def test_hash_literals - hash = { :one => "uno", :two => "dos" } - assert_equal __, hash.size - end - - def test_accessing_hashes - hash = { :one => "uno", :two => "dos" } - assert_equal __, hash[:one] - assert_equal __, hash[:two] - assert_equal __, hash[:doesnt_exist] - end - - def test_accessing_hashes_with_fetch - hash = { :one => "uno" } - assert_equal "uno", hash.fetch(:one) - assert_raise(___) do - hash.fetch(:doesnt_exist) - end - - # THINK ABOUT IT: - # - # Why might you want to use #fetch instead of #[] when accessing hash keys? - end - - def test_changing_hashes - hash = { :one => "uno", :two => "dos" } - hash[:one] = "eins" - - expected = { :one => __, :two => "dos" } - assert_equal __, expected == hash - - # Bonus Question: Why was "expected" broken out into a variable - # rather than used as a literal? - end - - def test_hash_is_unordered - hash1 = { :one => "uno", :two => "dos" } - hash2 = { :two => "dos", :one => "uno" } - - assert_equal __, hash1 == hash2 - end - - def test_hash_keys - hash = { :one => "uno", :two => "dos" } - assert_equal __, hash.keys.size - assert_equal __, hash.keys.include?(:one) - assert_equal __, hash.keys.include?(:two) - assert_equal __, hash.keys.class - end - - def test_hash_values - hash = { :one => "uno", :two => "dos" } - assert_equal __, hash.values.size - assert_equal __, hash.values.include?("uno") - assert_equal __, hash.values.include?("dos") - assert_equal __, hash.values.class - end - - def test_combining_hashes - hash = { "jim" => 53, "amy" => 20, "dan" => 23 } - new_hash = hash.merge({ "jim" => 54, "jenny" => 26 }) - - assert_equal __, hash != new_hash - - expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ } - assert_equal __, expected == new_hash - end - - def test_default_value - hash1 = Hash.new - hash1[:one] = 1 - - assert_equal __, hash1[:one] - assert_equal __, hash1[:two] - - hash2 = Hash.new("dos") - hash2[:one] = 1 - - assert_equal __, hash2[:one] - assert_equal __, hash2[:two] - end - - def test_default_value_is_the_same_object - hash = Hash.new([]) - - hash[:one] << "uno" - hash[:two] << "dos" - - assert_equal __, hash[:one] - assert_equal __, hash[:two] - assert_equal __, hash[:three] - - assert_equal __, hash[:one].object_id == hash[:two].object_id - end - - def test_default_value_with_block - hash = Hash.new {|hash, key| hash[key] = [] } - - hash[:one] << "uno" - hash[:two] << "dos" - - assert_equal __, hash[:one] - assert_equal __, hash[:two] - assert_equal __, hash[:three] - end -end diff --git a/koans/about_inheritance.rb b/koans/about_inheritance.rb deleted file mode 100644 index 712daca55..000000000 --- a/koans/about_inheritance.rb +++ /dev/null @@ -1,85 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutInheritance < EdgeCase::Koan - class Dog - attr_reader :name - - def initialize(name) - @name = name - end - - def bark - "WOOF" - end - end - - class Chihuahua < Dog - def wag - :happy - end - - def bark - "yip" - end - end - - def test_subclasses_have_the_parent_as_an_ancestor - assert_equal __, Chihuahua.ancestors.include?(Dog) - end - - def test_all_classes_ultimately_inherit_from_object - assert_equal __, Chihuahua.ancestors.include?(Object) - end - - def test_subclasses_inherit_behavior_from_parent_class - chico = Chihuahua.new("Chico") - assert_equal __, chico.name - end - - def test_subclasses_add_new_behavior - chico = Chihuahua.new("Chico") - assert_equal __, chico.wag - - assert_raise(___) do - fido = Dog.new("Fido") - fido.wag - end - end - - def test_subclasses_can_modify_existing_behavior - chico = Chihuahua.new("Chico") - assert_equal __, chico.bark - - fido = Dog.new("Fido") - assert_equal __, fido.bark - end - - # ------------------------------------------------------------------ - - class BullDog < Dog - def bark - super + ", GROWL" - end - end - - def test_subclasses_can_invoke_parent_behavior_via_super - ralph = BullDog.new("Ralph") - assert_equal __, ralph.bark - end - - # ------------------------------------------------------------------ - - class GreatDane < Dog - def growl - super.bark + ", GROWL" - end - end - - def test_super_does_not_work_cross_method - george = GreatDane.new("George") - assert_raise(___) do - george.growl - end - end - -end diff --git a/koans/about_iteration.rb b/koans/about_iteration.rb deleted file mode 100644 index fb62b394b..000000000 --- a/koans/about_iteration.rb +++ /dev/null @@ -1,124 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutIteration < EdgeCase::Koan - - # -- An Aside ------------------------------------------------------ - # Ruby 1.8 stores names as strings. Ruby 1.9 stores names as - # symbols. So we use a version dependent method "as_name" to convert - # to the right format in the koans. We will use "as_name" whenever - # comparing to lists of methods. - - in_ruby_version("1.8") do - def as_name(name) - name.to_s - end - end - - in_ruby_version("1.9") do - def as_name(name) - name.to_sym - end - end - - # Ok, now back to the Koans. - # ------------------------------------------------------------------- - - def test_each_is_a_method_on_arrays - assert_equal __, [].methods.include?(as_name(:each)) - end - - def test_iterating_with_each - array = [1, 2, 3] - sum = 0 - array.each do |item| - sum += item - end - assert_equal __, sum - end - - def test_each_can_use_curly_brace_blocks_too - array = [1, 2, 3] - sum = 0 - array.each { |item| - sum += item - } - assert_equal __, sum - end - - def test_break_works_with_each_style_iterations - array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sum = 0 - array.each { |item| - break if item > 3 - sum += item - } - assert_equal __, sum - end - - def test_collect_transforms_elements_of_an_array - array = [1, 2, 3] - new_array = array.collect { |item| item + 10 } - assert_equal __, new_array - - # NOTE: 'map' is another name for the 'collect' operation - another_array = array.map { |item| item + 10 } - assert_equal __, another_array - end - - def test_select_selects_certain_items_from_an_array - array = [1, 2, 3, 4, 5, 6] - - even_numbers = array.select { |item| (item % 2) == 0 } - assert_equal __, even_numbers - - # NOTE: 'find_all' is another name for the 'select' operation - more_even_numbers = array.find_all { |item| (item % 2) == 0 } - assert_equal __, more_even_numbers - end - - def test_find_locates_the_first_element_matching_a_criteria - array = ["Jim", "Bill", "Clarence", "Doug", "Eli"] - - assert_equal __, array.find { |item| item.size > 4 } - end - - def test_inject_will_blow_your_mind - result = [2, 3, 4].inject(0) { |sum, item| sum + item } - assert_equal __, result - - result2 = [2, 3, 4].inject(1) { |sum, item| sum * item } - assert_equal __, result2 - - # Extra Credit: - # Describe in your own words what inject does. - end - - def test_all_iteration_methods_work_on_any_collection_not_just_arrays - # Ranges act like a collection - result = (1..3).map { |item| item + 10 } - assert_equal __, result - - # Files act like a collection of lines - File.open("example_file.txt") do |file| - upcase_lines = file.map { |line| line.strip.upcase } - assert_equal __, upcase_lines - end - - # NOTE: You can create your own collections that work with each, - # map, select, etc. - end - - # Bonus Question: In the previous koan, we saw the construct: - # - # File.open(filename) do |file| - # # code to read 'file' - # end - # - # Why did we do it that way instead of the following? - # - # file = File.open(filename) - # # code to read 'file' - # - # When you get to the "AboutSandwichCode" koan, recheck your answer. - -end diff --git a/koans/about_java_interop.rb b/koans/about_java_interop.rb deleted file mode 100644 index 4d35d5dd4..000000000 --- a/koans/about_java_interop.rb +++ /dev/null @@ -1,137 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -include Java - -# Concepts -# * Pull in a java class -# * calling a method, Camel vs snake -# * Resolving module/class name conflicts -# * Showing what gets returned -# * Ruby Strings VS Java Strings -# * Calling custom java class -# * Calling Ruby from java??? - -class AboutJavaInterop < EdgeCase::Koan - def test_using_a_java_library_class - java_array = java.util.ArrayList.new - assert_equal __, java_array.class - end - - def test_java_class_can_be_referenced_using_both_ruby_and_java_like_syntax - assert_equal __, Java::JavaUtil::ArrayList == java.util.ArrayList - end - - def test_include_class_includes_class_in_module_scope - assert_nil defined?(TreeSet) - include_class "java.util.TreeSet" - assert_equal __, defined?(TreeSet) - end - - # THINK ABOUT IT: - # - # What if we use: - # - # include_class "java.lang.String" - # - # What would be the value of the String constant after this - # include_class is run? Would it be useful to provide a way of - # aliasing java classes to different names? - - JString = java.lang.String - def test_also_java_class_can_be_given_ruby_aliases - java_string = JString.new("A Java String") - assert_equal __, java_string.class - assert_equal __, JString - end - - def test_can_directly_call_java_methods_on_java_objects - java_string = JString.new("A Java String") - assert_equal __, java_string.toLowerCase - end - - def test_jruby_provides_snake_case_versions_of_java_methods - java_string = JString.new("A Java String") - assert_equal __, java_string.to_lower_case - end - - def test_jruby_provides_question_mark_versions_of_boolean_methods - java_string = JString.new("A Java String") - assert_equal __, java_string.endsWith("String") - assert_equal __, java_string.ends_with("String") - assert_equal __, java_string.ends_with?("String") - end - - def test_java_string_are_not_ruby_strings - ruby_string = "A Java String" - java_string = java.lang.String.new(ruby_string) - assert_equal __, java_string.is_a?(java.lang.String) - assert_equal __, java_string.is_a?(String) - end - - def test_java_strings_can_be_compared_to_ruby_strings_maybe - ruby_string = "A Java String" - java_string = java.lang.String.new(ruby_string) - assert_equal __, ruby_string == java_string - assert_equal __, java_string == ruby_string - - # THINK ABOUT IT: - # - # Is there any possible way for this to be more wrong? - # - # SERIOUSLY, THINK ABOUT IT: - # - # Why do you suppose that Ruby and Java strings compare like that? - # - # ADVANCED THINK ABOUT IT: - # - # Is there a way to make Ruby/Java string comparisons commutative? - # How would you do it? - end - - def test_however_most_methods_returning_strings_return_ruby_strings - java_array = java.util.ArrayList.new - assert_equal __, java_array.toString - assert_equal __, java_array.toString.is_a?(String) - assert_equal __, java_array.toString.is_a?(java.lang.String) - end - - def test_some_ruby_objects_can_be_coerced_to_java - assert_equal __, "ruby string".to_java.class - assert_equal __, 1.to_java.class - assert_equal __, 9.32.to_java.class - assert_equal __, false.to_java.class - end - - def test_some_ruby_objects_are_not_coerced_to_what_you_might_expect - assert_equal __, [].to_java.class == Java::JavaUtil::ArrayList - assert_equal __, {}.to_java.class == Java::JavaUtil::HashMap - assert_equal __, Object.new.to_java.class == Java::JavaLang::Object - end - - def test_java_collections_are_enumerable - java_array = java.util.ArrayList.new - java_array << "one" << "two" << "three" - assert_equal __, java_array.map { |item| item.upcase } - end - - # ------------------------------------------------------------------ - - # Open the Java ArrayList class and add a new method. - class Java::JavaUtil::ArrayList - def multiply_all - result = 1 - each do |item| - result *= item - end - result - end - end - - def test_java_class_are_open_from_ruby - java_array = java.util.ArrayList.new - java_array.add_all([1,2,3,4,5]) - - assert_equal __, java_array.multiply_all - end - -end diff --git a/koans/about_message_passing.rb b/koans/about_message_passing.rb deleted file mode 100644 index a978ddec4..000000000 --- a/koans/about_message_passing.rb +++ /dev/null @@ -1,178 +0,0 @@ -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? - 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? - end - - def test_send_with_underscores_will_also_send_messages - mc = MessageCatcher.new - - assert_equal __, mc.__send__(:caught?) - - # THINK ABOUT IT: - # - # Why does Ruby provide both send and __send__ ? - end - - 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) - 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) - - assert_equal __, mc.add_a_payload(3, 4, nil, 6) - assert_equal __, mc.send(:add_a_payload, 3, 4, nil, 6) - end - - # ------------------------------------------------------------------ - - class TypicalObject - end - - def test_sending_undefined_messages_to_a_typical_object_results_in_errors - typical = TypicalObject.new - - exception = assert_raise(___) do - typical.foobar - end - assert_match(/foobar/, exception.message) - end - - def test_calling_method_missing_causes_the_no_method_error - typical = TypicalObject.new - - exception = assert_raise(___) do - typical.method_missing(:foobar) - end - assert_match(/foobar/, exception.message) - - # THINK ABOUT IT: - # - # 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 scheduled Ruby - # Koans. - end - - # ------------------------------------------------------------------ - - class AllMessageCatcher - def method_missing(method_name, *args, &block) - "Someone called #{method_name} with <#{args.join(", ")}>" - end - end - - def test_all_messages_are_caught - catcher = AllMessageCatcher.new - - assert_equal __, catcher.foobar - assert_equal __, catcher.foobaz(1) - assert_equal __, catcher.sum(1,2,3,4,5,6) - end - - def test_catching_messages_makes_respond_to_lie - catcher = AllMessageCatcher.new - - assert_nothing_raised(NoMethodError) do - catcher.any_method - end - assert_equal __, catcher.respond_to?(:any_method) - end - - # ------------------------------------------------------------------ - - class WellBehavedFooCatcher - def method_missing(method_name, *args, &block) - if method_name.to_s[0,3] == "foo" - "Foo to you too" - else - super(method_name, *args, &block) - end - end - end - - def test_foo_method_are_caught - catcher = WellBehavedFooCatcher.new - - assert_equal __, catcher.foo_bar - assert_equal __, catcher.foo_baz - end - - def test_non_foo_messages_are_treated_normally - catcher = WellBehavedFooCatcher.new - - assert_raise(___) do - catcher.normal_undefined_method - end - end - - # ------------------------------------------------------------------ - - # (note: just reopening class from above) - class WellBehavedFooCatcher - def respond_to?(method_name) - if method_name.to_s[0,3] == "foo" - true - else - super(method_name) - end - end - end - - def test_explicitly_implementing_respond_to_lets_objects_tell_the_truth - catcher = WellBehavedFooCatcher.new - - assert_equal __, catcher.respond_to?(:foo_bar) - assert_equal __, catcher.respond_to?(:something_else) - end - -end diff --git a/koans/about_methods.rb b/koans/about_methods.rb deleted file mode 100644 index 5fd7725af..000000000 --- a/koans/about_methods.rb +++ /dev/null @@ -1,151 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -def my_global_method(a,b) - a + b -end - -class AboutMethods < EdgeCase::Koan - - def test_calling_global_methods - assert_equal __, my_global_method(2,3) - end - - 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_parentheses_are_ambiguous - eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK - # - # Ruby doesn't know if you mean: - # - # assert_equal(5, my_global_method(2), 3) - # or - # assert_equal(5, my_global_method(2, 3)) - # - # Rewrite the eval string to continue. - # - end - - # NOTE: wrong number of argument is not a SYNTAX error, but a - # runtime error. - def test_calling_global_methods_with_wrong_number_of_arguments - exception = assert_raise(___) do - my_global_method - end - assert_match(/__/, exception.message) - - exception = assert_raise(___) do - my_global_method(1,2,3) - end - assert_match(/__/, exception.message) - end - - # ------------------------------------------------------------------ - - def method_with_defaults(a, b=:default_value) - [a, b] - end - - def test_calling_with_default_values - assert_equal [1, __], method_with_defaults(1) - assert_equal [1, __], method_with_defaults(1, 2) - end - - # ------------------------------------------------------------------ - - def method_with_var_args(*args) - args - end - - def test_calling_with_variable_arguments - assert_equal __, method_with_var_args.class - assert_equal __, method_with_var_args - assert_equal __, method_with_var_args(:one) - assert_equal __, method_with_var_args(:one, :two) - end - - # ------------------------------------------------------------------ - - def method_with_explicit_return - :a_non_return_value - return :return_value - :another_non_return_value - end - - def test_method_with_explicit_return - assert_equal __, method_with_explicit_return - end - - # ------------------------------------------------------------------ - - def method_without_explicit_return - :a_non_return_value - :return_value - end - - def test_method_without_explicit_return - assert_equal __, method_without_explicit_return - end - - # ------------------------------------------------------------------ - - def my_method_in_the_same_class(a, b) - a * b - end - - def test_calling_methods_in_same_class - assert_equal __, my_method_in_the_same_class(3,4) - end - - def test_calling_methods_in_same_class_with_explicit_receiver - assert_equal __, self.my_method_in_the_same_class(3,4) - end - - # ------------------------------------------------------------------ - - def my_private_method - "a secret" - end - private :my_private_method - - def test_calling_private_methods_without_receiver - assert_equal __, my_private_method - end - - def test_calling_private_methods_with_an_explicit_receiver - exception = assert_raise(___) do - self.my_private_method - end - assert_match /__/, exception.message - end - - # ------------------------------------------------------------------ - - class Dog - def name - "Fido" - end - - private - - def tail - "tail" - end - end - - def test_calling_methods_in_other_objects_require_explicit_receiver - rover = Dog.new - assert_equal __, rover.name - end - - def test_calling_private_methods_in_other_objects - rover = Dog.new - assert_raise(___) do - rover.tail - end - end -end diff --git a/koans/about_modules.rb b/koans/about_modules.rb deleted file mode 100644 index 8b56b65c0..000000000 --- a/koans/about_modules.rb +++ /dev/null @@ -1,63 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutModules < EdgeCase::Koan - module Nameable - def set_name(new_name) - @name = new_name - end - - def here - :in_module - end - end - - def test_cant_instantiate_modules - assert_raise(___) do - Nameable.new - end - end - - # ------------------------------------------------------------------ - - class Dog - include Nameable - - attr_reader :name - - def initialize - @name = "Fido" - end - - def bark - "WOOF" - end - - def here - :in_object - end - end - - def test_normal_methods_are_available_in_the_object - fido = Dog.new - assert_equal __, fido.bark - end - - def test_module_methods_are_also_available_in_the_object - fido = Dog.new - assert_nothing_raised(Exception) do - fido.set_name("Rover") - end - end - - def test_module_methods_can_affect_instance_variables_in_the_object - fido = Dog.new - assert_equal __, fido.name - fido.set_name("Rover") - assert_equal __, fido.name - end - - def test_classes_can_override_module_methods - fido = Dog.new - assert_equal __, fido.here - end -end diff --git a/koans/about_nil.rb b/koans/about_nil.rb deleted file mode 100644 index 1a74ed042..000000000 --- a/koans/about_nil.rb +++ /dev/null @@ -1,38 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutNil < EdgeCase::Koan - def test_nil_is_an_object - assert_equal __, nil.is_a?(Object), "Unlike NULL in other languages" - end - - def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil - # What happens when you call a method that doesn't exist. The - # following begin/rescue/end code block captures the exception and - # makes some assertions about it. - begin - nil.some_method_nil_doesnt_know_about - rescue Exception => ex - # What exception has been caught? - assert_equal __, ex.class - - # What message was attached to the exception? - # (HINT: replace __ with part of the error message.) - assert_match(/__/, ex.message) - end - end - - def test_nil_has_a_few_methods_defined_on_it - assert_equal __, nil.nil? - assert_equal __, nil.to_s - assert_equal __, nil.inspect - - # THINK ABOUT IT: - # - # Is it better to use - # obj.nil? - # or - # obj == nil - # Why? - end - -end diff --git a/koans/about_objects.rb b/koans/about_objects.rb deleted file mode 100644 index 05c44de0c..000000000 --- a/koans/about_objects.rb +++ /dev/null @@ -1,56 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutObjects < EdgeCase::Koan - def test_everything_is_an_object - assert_equal __, 1.is_a?(Object) - assert_equal __, 1.5.is_a?(Object) - assert_equal __, "string".is_a?(Object) - assert_equal __, nil.is_a?(Object) - assert_equal __, Object.is_a?(Object) - end - - def test_objects_can_be_converted_to_strings - assert_equal __, 123.to_s - assert_equal __, nil.to_s - end - - def test_objects_can_be_inspected - assert_equal __, 123.inspect - assert_equal __, nil.inspect - end - - def test_every_object_has_an_id - obj = Object.new - assert_equal __, obj.object_id.class - end - - def test_every_object_has_different_id - obj = Object.new - another_obj = Object.new - assert_equal __, obj.object_id != another_obj.object_id - end - - def test_some_system_objects_always_have_the_same_id - assert_equal __, false.object_id - assert_equal __, true.object_id - assert_equal __, nil.object_id - end - - def test_small_integers_have_fixed_ids - assert_equal __, 0.object_id - assert_equal __, 1.object_id - assert_equal __, 2.object_id - assert_equal __, 100.object_id - - # THINK ABOUT IT: - # What pattern do the object IDs for small integers follow? - end - - def test_clone_creates_a_different_object - obj = Object.new - copy = obj.clone - - assert_equal __, obj != copy - assert_equal __, obj.object_id != copy.object_id - end -end diff --git a/koans/about_open_classes.rb b/koans/about_open_classes.rb deleted file mode 100644 index afef1f956..000000000 --- a/koans/about_open_classes.rb +++ /dev/null @@ -1,45 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutOpenClasses < EdgeCase::Koan - class Dog - def bark - "WOOF" - end - end - - def test_as_defined_dogs_do_bark - fido = Dog.new - assert_equal __, fido.bark - end - - # ------------------------------------------------------------------ - - # Open the existing Dog class and add a new method. - class Dog - def wag - "HAPPY" - end - end - - def test_after_reopening_dogs_can_both_wag_and_bark - fido = Dog.new - assert_equal __, fido.wag - assert_equal __, fido.bark - end - - # ------------------------------------------------------------------ - - class ::Integer - def even? - (self % 2) == 0 - end - end - - def test_even_existing_built_in_classes_can_be_reopened - assert_equal __, 1.even? - assert_equal __, 2.even? - end - - # NOTE: To understand why we need the :: before Integer, you need to - # become enlightened about scope. -end diff --git a/koans/about_proxy_object_project.rb b/koans/about_proxy_object_project.rb deleted file mode 100644 index 064eb683a..000000000 --- a/koans/about_proxy_object_project.rb +++ /dev/null @@ -1,156 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -# Project: Create a Proxy Class -# -# In this assignment, create a proxy class (one is started for you -# below). You should be able to initialize the proxy object with any -# object. Any messages sent to the proxy object should be forwarded -# to the target object. As each message is sent, the proxy should -# record the name of the method sent. -# -# The proxy class is started for you. You will need to add a method -# missing handler and any other supporting methods. The specification -# of the Proxy class is given in the AboutProxyObjectProject koan. - -class Proxy - def initialize(target_object) - @object = target_object - # ADD MORE CODE HERE - end - - # WRITE CODE HERE -end - -# The proxy object should pass the following Koan: -# -class AboutProxyObjectProject < EdgeCase::Koan - def test_proxy_method_returns_wrapped_object - # NOTE: The Television class is defined below - tv = Proxy.new(Television.new) - - # HINT: Proxy class is defined above, may need tweaking... - - assert tv.instance_of?(Proxy) - end - - def test_tv_methods_still_perform_their_function - tv = Proxy.new(Television.new) - - tv.channel = 10 - tv.power - - assert_equal 10, tv.channel - assert tv.on? - end - - def test_proxy_records_messages_sent_to_tv - tv = Proxy.new(Television.new) - - tv.power - tv.channel = 10 - - assert_equal [:power, :channel=], tv.messages - end - - def test_proxy_handles_invalid_messages - tv = Proxy.new(Television.new) - - assert_raise(NoMethodError) do - tv.no_such_method - end - end - - def test_proxy_reports_methods_have_been_called - tv = Proxy.new(Television.new) - - tv.power - tv.power - - assert tv.called?(:power) - assert ! tv.called?(:channel) - end - - def test_proxy_counts_method_calls - tv = Proxy.new(Television.new) - - tv.power - tv.channel = 48 - tv.power - - assert_equal 2, tv.number_of_times_called(:power) - assert_equal 1, tv.number_of_times_called(:channel=) - assert_equal 0, tv.number_of_times_called(:on?) - end - - def test_proxy_can_record_more_than_just_tv_objects - proxy = Proxy.new("Code Mash 2009") - - proxy.upcase! - result = proxy.split - - assert_equal ["CODE", "MASH", "2009"], result - assert_equal [:upcase!, :split], proxy.messages - end -end - - -# ==================================================================== -# The following code is to support the testing of the Proxy class. No -# changes should be necessary to anything below this comment. - -# Example class using in the proxy testing above. -class Television - attr_accessor :channel - - def power - if @power == :on - @power = :off - else - @power = :on - end - end - - def on? - @power == :on - end -end - -# Tests for the Television class. All of theses tests should pass. -class TelevisionTest < EdgeCase::Koan - def test_it_turns_on - tv = Television.new - - tv.power - assert tv.on? - end - - def test_it_also_turns_off - tv = Television.new - - tv.power - tv.power - - assert ! tv.on? - end - - def test_edge_case_on_off - tv = Television.new - - tv.power - tv.power - tv.power - - assert tv.on? - - tv.power - - assert ! tv.on? - end - - def test_can_set_the_channel - tv = Television.new - - tv.channel = 11 - assert_equal 11, tv.channel - end -end diff --git a/koans/about_regular_expressions.rb b/koans/about_regular_expressions.rb deleted file mode 100644 index 790bea324..000000000 --- a/koans/about_regular_expressions.rb +++ /dev/null @@ -1,161 +0,0 @@ -# -*- 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 __, /pattern/.class - end - - def test_a_regexp_can_search_a_string_for_matching_content - assert_equal __, "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+/] - # ... a programmer would most likely do - assert_equal __, "variable_1 = 42"[/[^a-zA-Z0-9_]+/] - 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 diff --git a/koans/about_sandwich_code.rb b/koans/about_sandwich_code.rb deleted file mode 100644 index 614a3740b..000000000 --- a/koans/about_sandwich_code.rb +++ /dev/null @@ -1,106 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutSandwichCode < EdgeCase::Koan - - def count_lines(file_name) - file = open(file_name) - count = 0 - while line = file.gets - count += 1 - end - count - ensure - file.close if file - end - - def test_counting_lines - assert_equal __, count_lines("example_file.txt") - end - - # ------------------------------------------------------------------ - - def find_line(file_name) - file = open(file_name) - while line = file.gets - return line if line.match(/e/) - end - ensure - file.close if file - end - - def test_finding_lines - assert_equal __, find_line("example_file.txt") - end - - # ------------------------------------------------------------------ - # THINK ABOUT IT: - # - # The count_lines and find_line are similar, and yet different. - # They both follow the pattern of "sandwich code". - # - # Sandwich code is code that comes in three parts: (1) the top slice - # of bread, (2) the meat, and (3) the bottom slice of bread. The - # the bread part of the sandwich almost always goes together, but - # the meat part changes all the time. - # - # Because the changing part of the sandwich code is in the middle, - # abstracting the top and bottom bread slices to a library can be - # difficult in many languages. - # - # (Aside for C++ programmers: The idiom of capturing allocated - # pointers in a smart pointer constructor is an attempt to deal with - # the problem of sandwich code for resource allocation.) - # - # Consider the following code: - # - - def file_sandwich(file_name) - file = open(file_name) - yield(file) - ensure - file.close if file - end - - # Now we write: - - def count_lines2(file_name) - file_sandwich(file_name) do |file| - count = 0 - while line = file.gets - count += 1 - end - count - end - end - - def test_counting_lines2 - assert_equal __, count_lines2("example_file.txt") - end - - # ------------------------------------------------------------------ - - def find_line2(file_name) - # Rewrite find_line using the file_sandwich library function. - end - - def test_finding_lines2 - assert_equal __, find_line2("example_file.txt") - end - - # ------------------------------------------------------------------ - - def count_lines3(file_name) - open(file_name) do |file| - count = 0 - while line = file.gets - count += 1 - end - count - end - end - - def test_open_handles_the_file_sandwich_when_given_a_block - assert_equal __, count_lines3("example_file.txt") - end - -end diff --git a/koans/about_scope.rb b/koans/about_scope.rb deleted file mode 100644 index d07d2af18..000000000 --- a/koans/about_scope.rb +++ /dev/null @@ -1,79 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutScope < EdgeCase::Koan - module Jims - class Dog - def identify - :jims_dog - end - end - end - - module Joes - class Dog - def identify - :joes_dog - end - end - end - - def test_dog_is_not_available_in_the_current_scope - assert_raise(___) do - fido = Dog.new - end - end - - def test_you_can_reference_nested_classes_using_the_scope_operator - fido = Jims::Dog.new - rover = Joes::Dog.new - assert_equal __, fido.identify - assert_equal __, rover.identify - - assert_equal __, fido.class != rover.class - assert_equal __, Jims::Dog != Joes::Dog - end - - # ------------------------------------------------------------------ - - class String - end - - 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 - - def test_use_the_prefix_scope_operator_to_force_the_global_scope - assert_equal __, ::String == "HI".class - end - - # ------------------------------------------------------------------ - - PI = 3.1416 - - def test_constants_are_defined_with_an_initial_uppercase_letter - assert_equal __, PI - end - - # ------------------------------------------------------------------ - - MyString = ::String - - def test_class_names_are_just_constants - assert_equal __, MyString == ::String - assert_equal __, MyString == "HI".class - end - - def test_constants_can_be_looked_up_explicitly - assert_equal __, PI == AboutScope.const_get("PI") - assert_equal __, MyString == AboutScope.const_get("MyString") - end - - def test_you_can_get_a_list_of_constants_for_any_class_or_module - assert_equal __, Jims.constants - assert Object.constants.size > _n_ - end -end diff --git a/koans/about_scoring_project.rb b/koans/about_scoring_project.rb deleted file mode 100644 index bc617854e..000000000 --- a/koans/about_scoring_project.rb +++ /dev/null @@ -1,74 +0,0 @@ -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 to calculate the -# score of a single roll of the dice. -# -# A greed roll is scored as follows: -# -# * A set of three ones is 1000 points -# -# * A set of three numbers (other than ones) is worth 100 times the -# number. (e.g. three fives is 500 points). -# -# * A one (that is not part of a set of three) is worth 100 points. -# -# * A five (that is not part of a set of three) is worth 50 points. -# -# * Everything else is worth 0 points. -# -# -# Examples: -# -# score([1,1,1,5,1]) => 1150 points -# score([2,3,4,6,2]) => 0 points -# score([3,4,5,3,3]) => 350 points -# score([1,5,1,2,4]) => 250 points -# -# More scoring examples are given in the tests below: -# -# Your goal is to write the score method. - -def score(dice) - # You need to write this method -end - -class AboutScoringProject < EdgeCase::Koan - def test_score_of_an_empty_list_is_zero - assert_equal 0, score([]) - end - - def test_score_of_a_single_roll_of_5_is_50 - assert_equal 50, score([5]) - end - - def test_score_of_a_single_roll_of_1_is_100 - assert_equal 100, score([1]) - end - - def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores - assert_equal 300, score([1,5,5,1]) - end - - def test_score_of_single_2s_3s_4s_and_6s_are_zero - assert_equal 0, score([2,3,4,6]) - end - - def test_score_of_a_triple_1_is_1000 - assert_equal 1000, score([1,1,1]) - end - - def test_score_of_other_triples_is_100x - assert_equal 200, score([2,2,2]) - assert_equal 300, score([3,3,3]) - assert_equal 400, score([4,4,4]) - assert_equal 500, score([5,5,5]) - assert_equal 600, score([6,6,6]) - end - - def test_score_of_mixed_is_sum - assert_equal 250, score([2,5,2,2,3]) - assert_equal 550, score([5,5,5,5]) - end - -end diff --git a/koans/about_strings.rb b/koans/about_strings.rb deleted file mode 100644 index 34d4a5087..000000000 --- a/koans/about_strings.rb +++ /dev/null @@ -1,195 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') - -class AboutStrings < EdgeCase::Koan - def test_double_quoted_strings_are_strings - string = "Hello, World" - assert_equal __, string.is_a?(String) - end - - def test_single_quoted_strings_are_also_strings - string = 'Goodbye, World' - assert_equal __, string.is_a?(String) - end - - def test_use_single_quotes_to_create_string_with_double_quotes - string = 'He said, "Go Away."' - assert_equal __, string - end - - def test_use_double_quotes_to_create_strings_with_single_quotes - string = "Don't" - assert_equal __, string - end - - def test_use_backslash_for_those_hard_cases - a = "He said, \"Don't\"" - b = 'He said, "Don\'t"' - assert_equal __, a == b - end - - def test_use_flexible_quoting_to_handle_really_hard_cases - a = %(flexible quotes can handle both ' and " characters) - b = %!flexible quotes can handle both ' and " characters! - c = %{flexible quotes can handle both ' and " characters} - assert_equal __, a == b - assert_equal __, a == c - end - - def test_flexible_quotes_can_handle_multiple_lines - long_string = %{ -It was the best of times, -It was the worst of times. -} - assert_equal __, long_string.length - assert_equal __, long_string.lines.count - end - - def test_here_documents_can_also_handle_multiple_lines - long_string = < 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 use_colors? - color(color_value) + string + color(COLORS[:clear]) - else - string - end - end - - def color(color_value) - "\e[#{color_value}m" - end - - def use_colors? - return false if ENV['NO_COLOR'] - if ENV['ANSI_COLOR'].nil? - if using_windows? - using_win32console - end - else - ENV['ANSI_COLOR'] =~ /^(t|y)/i - end - end - - def using_windows? - File::ALT_SEPARATOR - end - - def using_win32console - defined? Win32::Console - end - end - - class Sensei - attr_reader :failure, :failed_test, :pass_count - - 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 - @failure = nil - @failed_test = nil - @observations = [] - end - - PROGRESS_FILE_NAME = '.path_progress' - - def add_progress(prog) - @_contents = nil - exists = File.exists?(PROGRESS_FILE_NAME) - File.open(PROGRESS_FILE_NAME,'a+') do |f| - f.print "#{',' if exists}#{prog}" - end - end - - def progress - if @_contents.nil? - if File.exists?(PROGRESS_FILE_NAME) - File.open(PROGRESS_FILE_NAME,'r') do |f| - @_contents = f.read.to_s.gsub(/\s/,'').split(',') - end - else - @_contents = [] - end - end - @_contents - end - - def observe(step) - if step.passed? - @pass_count += 1 - if @pass_count > progress.last.to_i - @observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.") - end - else - @failed_test = step - @failure = step.failure - add_progress(@pass_count) - @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.") - throw :edgecase_exit - end - end - - def failed? - ! @failure.nil? - end - - def assert_failed? - failure.is_a?(AssertionError) - end - - def instruct - if failed? - @observations.each{|c| puts c } - encourage - guide_through_error - a_zenlike_statement - show_progress - else - end_screen - end - end - - def show_progress - bar_width = 50 - total_tests = EdgeCase::Koan.total_tests - scale = bar_width.to_f/total_tests - print Color.green("your path thus far [") - happy_steps = (pass_count*scale).to_i - happy_steps = 1 if happy_steps == 0 && pass_count > 0 - print Color.green('.'*happy_steps) - if failed? - print Color.red('X') - print Color.cyan('_'*(bar_width-1-happy_steps)) - end - print Color.green(']') - print " #{pass_count}/#{total_tests}" - puts - end - - def end_screen - if EdgeCase.simple_output - boring_end_screen - else - artistic_end_screen - end - end - - def boring_end_screen - puts "Mountains are again merely mountains" - end - - def artistic_end_screen - "JRuby 1.9.x Koans" - ruby_version = "(in #{'J' if defined?(JRUBY_VERSION)}Ruby #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION})" - ruby_version = ruby_version.side_padding(54) - completed = <<-ENDTEXT - ,, , ,, - : ::::, :::, - , ,,: :::::::::::::,, :::: : , - , ,,, ,:::::::::::::::::::, ,: ,: ,, - :, ::, , , :, ,::::::::::::::::::, ::: ,:::: - : : ::, ,:::::::: ::, ,:::: - , ,::::: :,:::::::,::::, - ,: , ,:,,: ::::::::::::: - ::,: ,,:::, ,::::::::::::, - ,:::, :,,::: ::::::::::::, - ,::: :::::::, Mountains are again merely mountains ,:::::::::::: - :::,,,:::::: :::::::::::: - ,:::::::::::, ::::::::::::, - :::::::::::, ,:::::::::::: -::::::::::::: ,:::::::::::: -:::::::::::: Ruby Koans ::::::::::::, -::::::::::::#{ ruby_version },::::::::::::, -:::::::::::, , :::::::::::: -,:::::::::::::, brought to you by ,,::::::::::::, -:::::::::::::: ,:::::::::::: - ::::::::::::::, ,::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: - :,::::::::: :::: ::::::::::::: - ,::::::::::: ,: ,,:::::::::::::, - :::::::::::: ,::::::::::::::, - :::::::::::::::::, :::::::::::::::: - :::::::::::::::::::, :::::::::::::::: - ::::::::::::::::::::::, ,::::,:, , ::::,::: - :::::::::::::::::::::::, ::,: ::,::, ,,: :::: - ,:::::::::::::::::::: ::,, , ,, ,:::: - ,:::::::::::::::: ::,, , ,:::, - ,:::: , ,, - ,,, -ENDTEXT - puts completed - end - - def encourage - puts - puts "The Master says:" - puts Color.cyan(" You have not yet reached enlightenment.") - if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1) - puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.") - elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1 - puts Color.cyan(" Do not lose hope.") - elsif progress.last.to_i > 0 - puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.") - end - end - - def guide_through_error - puts - puts "The answers you seek..." - puts Color.red(indent(failure.message).join) - puts - puts "Please meditate on the following code:" - if assert_failed? - puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace))) - else - puts embolden_first_line_only(indent(failure.backtrace)) - end - puts - end - - def embolden_first_line_only(text) - first_line = true - text.collect { |t| - if first_line - first_line = false - Color.red(t) - else - Color.cyan(t) - end - } - end - - def indent(text) - text = text.split(/\n/) if text.is_a?(String) - text.collect{|t| " #{t}"} - end - - def find_interesting_lines(backtrace) - backtrace.reject { |line| - line =~ /test\/unit\/|edgecase\.rb|minitest/ - } - end - - # Hat's tip to Ara T. Howard for the zen statements from his - # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html) - def a_zenlike_statement - if !failed? - zen_statement = "Mountains are again merely mountains" - else - zen_statement = case (@pass_count % 10) - when 0 - "mountains are merely mountains" - when 1, 2 - "learn the rules so you know how to break them properly" - when 3, 4 - "remember that silence is sometimes the best answer" - when 5, 6 - "sleep is the best meditation" - when 7, 8 - "when you lose, don't lose the lesson" - else - "things are not what they appear to be: nor are they otherwise" - end - end - puts Color.green(zen_statement) - end - end - - class Koan - include Test::Unit::Assertions - - attr_reader :name, :failure, :koan_count, :step_count, :koan_file - - def initialize(name, koan_file=nil, koan_count=0, step_count=0) - @name = name - @failure = nil - @koan_count = koan_count - @step_count = step_count - @koan_file = koan_file - end - - def passed? - @failure.nil? - end - - def failed(failure) - @failure = failure - end - - def setup - end - - def teardown - end - - def meditate - setup - begin - send(name) - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - failed(ex) - ensure - begin - teardown - rescue StandardError, EdgeCase::Sensei::AssertionError => ex - failed(ex) if passed? - end - end - self - end - - # Class methods for the EdgeCase test suite. - class << self - def inherited(subclass) - subclasses << subclass - end - - def method_added(name) - testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s - end - - def end_of_enlightenment - @tests_disabled = true - end - - def command_line(args) - args.each do |arg| - case arg - when /^-n\/(.*)\/$/ - @test_pattern = Regexp.new($1) - when /^-n(.*)$/ - @test_pattern = Regexp.new(Regexp.quote($1)) - else - if File.exist?(arg) - load(arg) - else - fail "Unknown command line argument '#{arg}'" - end - end - end - end - - # Lazy initialize list of subclasses - def subclasses - @subclasses ||= [] - end - - # Lazy initialize list of test methods. - def testmethods - @test_methods ||= [] - end - - def tests_disabled? - @tests_disabled ||= false - end - - def test_pattern - @test_pattern ||= /^test_/ - end - - def total_tests - self.subclasses.inject(0){|total, k| total + k.testmethods.size } - end - end - end - - class ThePath - def walk - sensei = EdgeCase::Sensei.new - each_step do |step| - sensei.observe(step.meditate) - end - sensei.instruct - end - - def each_step - catch(:edgecase_exit) { - step_count = 0 - EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index| - koan.testmethods.each do |method_name| - step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1) - yield step - end - end - } - end - end -end - -END { - EdgeCase::Koan.command_line(ARGV) - EdgeCase::ThePath.new.walk -} diff --git a/koans/example_file.txt b/koans/example_file.txt deleted file mode 100644 index ffe7cbd89..000000000 --- a/koans/example_file.txt +++ /dev/null @@ -1,4 +0,0 @@ -this -is -a -test diff --git a/koans/first_test.rb b/koans/first_test.rb deleted file mode 100644 index 708baf17a..000000000 --- a/koans/first_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'test/unit' - -class TestSomething < Test::Unit::TestCase - def test_assert - assert true - assert_equal 1, 1 - assert_equal 1, 1.0 - end -end - - diff --git a/koans/path_to_enlightenment.rb b/koans/path_to_enlightenment.rb deleted file mode 100644 index 64621bf4f..000000000 --- a/koans/path_to_enlightenment.rb +++ /dev/null @@ -1,38 +0,0 @@ -# The path to Ruby Enlightenment starts with the following: - -$LOAD_PATH << File.dirname(__FILE__) - -require 'about_asserts' -require 'about_nil' -require 'about_objects' -require 'about_arrays' -require 'about_array_assignment' -require 'about_hashes' -require 'about_strings' -require 'about_symbols' -require 'about_regular_expressions' -require 'about_methods' -require 'about_constants' -require 'about_control_statements' -require 'about_true_and_false' -require 'about_triangle_project' -require 'about_exceptions' -require 'about_triangle_project_2' -require 'about_iteration' -require 'about_blocks' -require 'about_sandwich_code' -require 'about_scoring_project' -require 'about_classes' -require 'about_open_classes' -require 'about_dice_project' -require 'about_inheritance' -require 'about_modules' -require 'about_scope' -require 'about_class_methods' -require 'about_message_passing' -require 'about_proxy_object_project' -require 'about_to_str' -in_ruby_version("jruby") do - require 'about_java_interop' -end -require 'about_extra_credit' diff --git a/koans/test_helper.rb b/koans/test_helper.rb deleted file mode 100644 index 9accf96d8..000000000 --- a/koans/test_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test/unit' - -def __ - "FILL ME IN" -end - -EdgeCase = Test::Unit diff --git a/koans/triangle.rb b/koans/triangle.rb deleted file mode 100644 index 8df052a1e..000000000 --- a/koans/triangle.rb +++ /dev/null @@ -1,22 +0,0 @@ -# Triangle Project Code. - -# Triangle analyzes the lengths of the sides of a triangle -# (represented by a, b and c) and returns the type of triangle. -# -# It returns: -# :equilateral if all sides are equal -# :isosceles if exactly 2 sides are equal -# :scalene if no sides are equal -# -# The tests for this method can be found in -# about_triangle_project.rb -# and -# about_triangle_project_2.rb -# -def triangle(a, b, c) - # WRITE THIS CODE -end - -# Error class used in part 2. No need to change this code. -class TriangleError < StandardError -end From e76be64f9dc41e6db6e8d1b0db5d6224e3c7994c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Sun, 4 Dec 2011 02:48:20 -0500 Subject: [PATCH 203/276] Added koans directory to the .git ignore list. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f15e83aba..ffb9a5a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ dist .project_env.rc .path_progress *.rbc +koans/* From 63a7f27313cbf59c8f162ebd76bfd5082085d7d2 Mon Sep 17 00:00:00 2001 From: Rich Lewis Date: Tue, 20 Dec 2011 15:42:07 -0500 Subject: [PATCH 204/276] removed duplicate word "The" in comment. --- src/about_sandwich_code.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb index 07be3fcc9..e641b13db 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -40,7 +40,7 @@ def test_finding_lines # # Sandwich code is code that comes in three parts: (1) the top slice # of bread, (2) the meat, and (3) the bottom slice of bread. The - # the bread part of the sandwich almost always goes together, but + # bread part of the sandwich almost always goes together, but # the meat part changes all the time. # # Because the changing part of the sandwich code is in the middle, From b44b5f8bb230b5fc84d99f9f6ff6b5f541ff0889 Mon Sep 17 00:00:00 2001 From: oflannabhra Date: Mon, 2 Jan 2012 22:33:46 -0500 Subject: [PATCH 205/276] Compare strings instead of symbols for constants, similar to method names. --- src/about_symbols.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 95cdffd03..720ca8c6f 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -36,9 +36,9 @@ def test_method_names_become_symbols in_ruby_version("mri") do RubyConstant = "What is the sound of one hand clapping?" def test_constants_become_symbols - all_symbols = Symbol.all_symbols + all_symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } - assert_equal __(true), all_symbols.include?(__(:RubyConstant)) + assert_equal __(true), all_symbols_as_strings.include?(__("RubyConstant")) end end From 907c1fc0bedce26fb5a27b1a802b26c2e96d2231 Mon Sep 17 00:00:00 2001 From: Henry Liu Date: Sun, 22 Jan 2012 00:17:45 -0800 Subject: [PATCH 206/276] Fixed color support in OS X --- src/edgecase.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/edgecase.rb b/src/edgecase.rb index 1443807c8..40c9607b4 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -122,6 +122,8 @@ def use_colors? if ENV['ANSI_COLOR'].nil? if using_windows? using_win32console + else + return true end else ENV['ANSI_COLOR'] =~ /^(t|y)/i From d1ab51e7cdddd6e28608b9ff1908e2ea507fa47c Mon Sep 17 00:00:00 2001 From: Matthew Boston Date: Fri, 27 Jan 2012 10:22:08 -0500 Subject: [PATCH 207/276] updating README with directions for generating the koans --- README.rdoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.rdoc b/README.rdoc index fb6abb159..c4cb97825 100644 --- a/README.rdoc +++ b/README.rdoc @@ -41,6 +41,19 @@ If you don't have rake installed, just run `gem install rake` 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. +== Generating the Koans + +A fresh checkout will not include the koans, you will need to generate +them. + + [ruby_koans] $ rake gen # generates the + koans directory + +If you need to regenerate the koans, thus wiping your current `koans`, + + [ruby_koans] $ rake regen # regenerates the + koans directory, wiping the original + == The Path To Enlightenment You can run the tests through rake or by calling the file itself (rake is the From 2625f10997852c90ade9970139e4820d69a77841 Mon Sep 17 00:00:00 2001 From: Matthew Boston Date: Fri, 27 Jan 2012 10:34:00 -0500 Subject: [PATCH 208/276] not sure why the extra line was thrown in... --- README.rdoc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.rdoc b/README.rdoc index c4cb97825..f8208bc01 100644 --- a/README.rdoc +++ b/README.rdoc @@ -46,13 +46,11 @@ around 1.8.6 or more). Any version of rake will do. A fresh checkout will not include the koans, you will need to generate them. - [ruby_koans] $ rake gen # generates the - koans directory + [ruby_koans] $ rake gen # generates the koans directory If you need to regenerate the koans, thus wiping your current `koans`, - [ruby_koans] $ rake regen # regenerates the - koans directory, wiping the original + [ruby_koans] $ rake regen # regenerates the koans directory, wiping the original == The Path To Enlightenment From c014f6db04520dd27c707089f3d26444d7b953be Mon Sep 17 00:00:00 2001 From: Matthew Boston Date: Fri, 27 Jan 2012 10:39:22 -0500 Subject: [PATCH 209/276] update Rakefile to use pre-defined directories --- Rakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index 07da09565..d35dfe3bd 100644 --- a/Rakefile +++ b/Rakefile @@ -88,14 +88,14 @@ end task :default => :walk_the_path task :walk_the_path do - cd 'koans' + cd PROB_DIR ruby 'path_to_enlightenment.rb' end if defined?(Rake::RDocTask) Rake::RDocTask.new do |rd| rd.main = "README.rdoc" - rd.rdoc_files.include("README.rdoc", "koans/*.rb") + rd.rdoc_files.include("README.rdoc", "${PROB_DIR}/*.rb") end end @@ -140,7 +140,7 @@ end task :run do puts 'koans' - Dir.chdir("src") do + Dir.chdir("${SRC_DIR}") do puts "in #{Dir.pwd}" sh "ruby path_to_enlightenment.rb" end From 34d1127f986d64f6e3cfba2ea0f2c69d2f42154e Mon Sep 17 00:00:00 2001 From: Matthew Boston Date: Mon, 6 Feb 2012 23:17:48 -0500 Subject: [PATCH 210/276] whitespace cleanup --- src/about_class_methods.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index 930345d6a..2cadbaa8f 100644 --- a/src/about_class_methods.rb +++ b/src/about_class_methods.rb @@ -47,7 +47,7 @@ def fido.wag end # ------------------------------------------------------------------ - + class Dog2 def wag :instance_level_wag @@ -96,14 +96,13 @@ def Dog.a_class_method def test_you_can_define_class_methods_inside_the_class assert_equal __(:dogs_class_method), Dog.a_class_method end - # ------------------------------------------------------------------ LastExpressionInClassStatement = class Dog 21 end - + def test_class_statements_return_the_value_of_their_last_expression assert_equal __(21), LastExpressionInClassStatement end From 711564c4522a603a665b67bf3173bb28c02c1d14 Mon Sep 17 00:00:00 2001 From: Matthew Boston Date: Tue, 7 Feb 2012 22:16:52 -0500 Subject: [PATCH 211/276] remove line-ending whitespace --- src/about_open_classes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_open_classes.rb b/src/about_open_classes.rb index bef7effde..80df88831 100644 --- a/src/about_open_classes.rb +++ b/src/about_open_classes.rb @@ -41,5 +41,5 @@ def test_even_existing_built_in_classes_can_be_reopened end # NOTE: To understand why we need the :: before Integer, you need to - # become enlightened about scope. + # become enlightened about scope. end From a565ac232d6ac6d922a65a8fd0d60c0217f0892a Mon Sep 17 00:00:00 2001 From: Alex Burkhart Date: Thu, 9 Feb 2012 18:57:31 +0000 Subject: [PATCH 212/276] Removed autotest. Added Watchr script. --- Rakefile | 2 -- src/autotest/discover.rb | 3 --- src/autotest/rubykoan.rb | 24 ------------------------ src/koans.watchr | 3 +++ 4 files changed, 3 insertions(+), 29 deletions(-) mode change 100644 => 100755 Rakefile delete mode 100644 src/autotest/discover.rb delete mode 100644 src/autotest/rubykoan.rb create mode 100644 src/koans.watchr diff --git a/Rakefile b/Rakefile old mode 100644 new mode 100755 index d35dfe3bd..ab77d1972 --- a/Rakefile +++ b/Rakefile @@ -42,8 +42,6 @@ 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| diff --git a/src/autotest/discover.rb b/src/autotest/discover.rb deleted file mode 100644 index 31a7804b2..000000000 --- a/src/autotest/discover.rb +++ /dev/null @@ -1,3 +0,0 @@ -Autotest.add_discovery do - "rubykoan" if File.exist? 'path_to_enlightenment.rb' -end diff --git a/src/autotest/rubykoan.rb b/src/autotest/rubykoan.rb deleted file mode 100644 index d43dc9112..000000000 --- a/src/autotest/rubykoan.rb +++ /dev/null @@ -1,24 +0,0 @@ -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 - diff --git a/src/koans.watchr b/src/koans.watchr new file mode 100644 index 000000000..810f0cc9c --- /dev/null +++ b/src/koans.watchr @@ -0,0 +1,3 @@ +watch( '.*\.rb' ) do + system("ruby path_to_enlightenment.rb") +end From 6af4597b8002a4ceafcfbba3107a0fab0c85589d Mon Sep 17 00:00:00 2001 From: Alex Burkhart Date: Fri, 10 Feb 2012 19:36:50 +0000 Subject: [PATCH 213/276] Use rake instead of directly invoking path_to_enlightenment. --- src/koans.watchr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/koans.watchr b/src/koans.watchr index 810f0cc9c..b740cf9c5 100644 --- a/src/koans.watchr +++ b/src/koans.watchr @@ -1,3 +1,3 @@ watch( '.*\.rb' ) do - system("ruby path_to_enlightenment.rb") + system 'rake' end From 03caa9b3493ff5f0cf3688efe4f4136d06e4eb24 Mon Sep 17 00:00:00 2001 From: Erkan Yilmaz Date: Thu, 8 Mar 2012 13:57:01 +0100 Subject: [PATCH 214/276] add missing: ) --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index f8208bc01..75e53a709 100644 --- a/README.rdoc +++ b/README.rdoc @@ -71,7 +71,7 @@ Windows is the same thing 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 +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 moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor). From f3d20b8e14f50a5103d322a08ff7f1648a36b17c Mon Sep 17 00:00:00 2001 From: Erkan Yilmaz Date: Thu, 8 Mar 2012 14:03:45 +0100 Subject: [PATCH 215/276] seems screen output of the 1st example changed --- README.rdoc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.rdoc b/README.rdoc index 75e53a709..121228b99 100644 --- a/README.rdoc +++ b/README.rdoc @@ -80,26 +80,31 @@ The very first time you run it you will see the following output: [ ruby_koans ] $ rake (in /Users/person/dev/ruby_koans) - cd koans + /usr/bin/ruby1.8 path_to_enlightenment.rb - Thinking AboutAsserts - test_assert_truth has damaged your karma. + AboutAsserts#test_assert_truth has damaged your karma. - You have not yet reached enlightenment ... + The Master says: + You have not yet reached enlightenment. + + The answers you seek... is not true. Please meditate on the following code: ./about_asserts.rb:10:in `test_assert_truth' - path_to_enlightenment.rb:27 + path_to_enlightenment.rb:38:in `each_with_index' + path_to_enlightenment.rb:38 mountains are merely mountains + your path thus far [X_________________________________________________] 0/280 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 + path_to_enlightenment.rb:38:in `each_with_index' + path_to_enlightenment.rb:38 We then open up the about_asserts.rb file and look at the first test: From 7f29082e95c894ea94c8eb4d1db15d07dd1ba671 Mon Sep 17 00:00:00 2001 From: Ethan Zimmerman Date: Tue, 5 Jun 2012 14:22:14 -0400 Subject: [PATCH 216/276] Modify test to better illustrate point --- src/about_hashes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_hashes.rb b/src/about_hashes.rb index 2382d68cd..afb17b35a 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -37,7 +37,7 @@ def test_changing_hashes hash[:one] = "eins" expected = { :one => __("eins"), :two => "dos" } - assert_equal __(true), expected == hash + assert_equal __(expected), hash # Bonus Question: Why was "expected" broken out into a variable # rather than used as a literal? From 5f3a6a19f23caa7d0dc097ae8e197be507c03d11 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 14 Feb 2013 12:51:00 +0000 Subject: [PATCH 217/276] Ignore RVM config if the user wants to use it RVM allows the user to select a specific Ruby for a specific project. It is common to put a .rvmrc config file in the root of a project to select the Ruby automatically when the user switches into that project. The Ruby Koans should ignore this file if present and not mistake it for a change to the Koans themselves. There are other ways of choosing a Ruby to use, and use of RVM is not mandated by the Koans so ignoring seems like the right solution. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ffb9a5a5e..81fb2a49d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ dist .project_env.rc .path_progress +.rvmrc *.rbc koans/* From eedfeb1022d3b102335a7846ef993b008fd33c5f Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 14 Feb 2013 13:21:06 +0000 Subject: [PATCH 218/276] Explain how to use watchr in the README Support has been added for watchr, and this is very helpful while walking the path to enlightenment as it keeps the users focus on the koans and not on the repeated need to run rake after each edit. However, only an experienced Rubyist would know how to install and use watchr (or worse, they might just not notice the watchr config file). So let's add an optional section to the README explaining how to use watchr. --- README.rdoc | 56 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/README.rdoc b/README.rdoc index 121228b99..93e4bc831 100644 --- a/README.rdoc +++ b/README.rdoc @@ -8,9 +8,9 @@ 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. @@ -23,8 +23,8 @@ 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 -installed. To check the installations simply type: +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: @@ -36,10 +36,10 @@ Windows from the command prompt (cmd.exe) c:\ruby --version c:\rake --version -If you don't have rake installed, just run `gem install rake` +If you don't have rake installed, just run gem install rake 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. +around 1.8.6 or more). Any version of rake will do. == Generating the Koans @@ -69,12 +69,13 @@ Windows is the same thing === 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 -moment and reflect upon the test to see what it is teaching you and improve the -code to better communicate its intent (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 moment and reflect upon the test to +see what it is teaching you and improve the code to better communicate its intent +(refactor). The very first time you run it you will see the following output: @@ -106,7 +107,7 @@ the first solution: path_to_enlightenment.rb:38:in `each_with_index' path_to_enlightenment.rb:38 -We then open up the about_asserts.rb file and look at the first test: +We then open up the about_asserts.rb file and look at the first test: # We shall contemplate truth by testing reality, via asserts. def test_assert_truth @@ -122,6 +123,33 @@ 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+. +=== Running the Koans automatically + +This section is optional. + +Normally the path to enlightenment looks like this: + + cd ruby_koans + rake + # edit + rake + # edit + rake + # etc + +If you prefer, you can keep the koans running in the background so that after you +make a change in your editor, the koans will immediately run again. This will +hopefully keep your focus on learning Ruby instead of the command line. + +Install the Ruby gem (library) called +watchr+ and then ask it to +"watch" the koans for changes: + + cd ruby_koans + rake + # decide to run rake automatically from now on as you edit + gem install watchr + watchr ./koans/koans.watchr + == Inspiration A special thanks to Mike Clark and Ara Howard for inspiring this From f36a964fdd95b5b516b4869edac96491fc156529 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 14 Feb 2013 14:22:11 +0000 Subject: [PATCH 219/276] Explain how to use Watchr in the README The koans have support for Watchr now, and this is very helpful as you can focus on editing and not on re-running rake over and over. However, a user new to Ruby will not even know what Watchr is (I'd not used it before! I was using Guard) so they might miss this choice. There are some other minor edits for style and consistency. I explain that Koans are tests. We/You tidy up. Removed some excess wordage. Made some "your should do this" statements more imperative. Made mark up more consistent. --- README.rdoc | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/README.rdoc b/README.rdoc index 93e4bc831..5034992e2 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,17 +2,17 @@ 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. +functions and libraries. We also teach you culture by basing the koans on tests. +Testing is not just something we pay lip service to, but something we +live. Testing is essential in your quest to learn and do great things in Ruby. == 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 +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. @@ -23,23 +23,23 @@ 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 installed. To check the installations simply type: +operating specific instructions. In order to run the koans you need +ruby+ and ++rake+ installed. To check your installations simply type: *nix platforms from any terminal window: [~] $ ruby --version [~] $ rake --version -Windows from the command prompt (cmd.exe) +Windows from the command prompt (+cmd.exe+) c:\ruby --version c:\rake --version -If you don't have rake installed, just run gem install rake +If you don't have +rake+ installed, just run +gem install rake+ 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. +around 1.8.6 or more). Any version of +rake+ will do. == Generating the Koans @@ -54,10 +54,10 @@ If you need to regenerate the koans, thus wiping your current `koans`, == The Path To Enlightenment -You can run the tests through rake or by calling the file itself (rake is the +You can run the tests through +rake+ or by calling the file itself (+rake+ is the recommended way to run them as we might build more functionality into this task). -*nix platforms, from the koans directory +*nix platforms, from the +ruby_koans+ directory [ruby_koans] $ rake # runs the default target :walk_the_path [ruby_koans] $ ruby path_to_enlightenment.rb # simply call the file directly @@ -71,13 +71,14 @@ Windows is the same thing 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 moment and reflect upon the test to -see what it is teaching you and improve the code to better communicate its intent -(refactor). +then look at the code and consider if you can make it any better (refactor). -The very first time you run it you will see the following output: +While walking the path to Ruby enlightenment you will need 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). + +The very first time you run the koans you will see the following output: [ ruby_koans ] $ rake (in /Users/person/dev/ruby_koans) @@ -99,7 +100,7 @@ The very first time you run it you will see the following output: mountains are merely mountains your path thus far [X_________________________________________________] 0/280 -You have come to your first stage. If you notice it is telling you where to look for +You have come to your first stage. Notice it is telling you where to look for the first solution: Please meditate on the following code: @@ -107,20 +108,20 @@ the first solution: path_to_enlightenment.rb:38:in `each_with_index' path_to_enlightenment.rb:38 -We then open up the about_asserts.rb file and look at the first test: +Open the +about_asserts.rb+ file and look at the first test: # We shall contemplate truth by testing reality, via asserts. def test_assert_truth assert false # This should be true end -We then change the +false+ to +true+ and run the test again. After you are +Change the +false+ to +true+ and re-run the test. 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+ -method, it will either ensure it is +true+ and continue on, or fail if in fact +method, it will either ensure it is +true+ and continue on, or fail if the statement is +false+. === Running the Koans automatically @@ -139,7 +140,7 @@ Normally the path to enlightenment looks like this: If you prefer, you can keep the koans running in the background so that after you make a change in your editor, the koans will immediately run again. This will -hopefully keep your focus on learning Ruby instead of the command line. +hopefully keep your focus on learning Ruby instead of on the command line. Install the Ruby gem (library) called +watchr+ and then ask it to "watch" the koans for changes: From 676d9ce8ac44b6628006b29f63273b11c83bc23e Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 28 Feb 2013 15:44:28 +0800 Subject: [PATCH 220/276] Fix indentation --- src/about_triangle_project_2.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index 0a57e2519..347c3b1a9 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -12,6 +12,6 @@ def test_illegal_triangles_throw_exceptions assert_raise(TriangleError) do triangle(1, 1, 3) end assert_raise(TriangleError) do triangle(2, 4, 2) end # HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions - end + end end From aa3c83f04493545ae0316d5f8d90e263aa6a4e96 Mon Sep 17 00:00:00 2001 From: Wei Lu Date: Thu, 28 Feb 2013 18:59:58 +0800 Subject: [PATCH 221/276] Remove assigned but unused variables --- src/about_blocks.rb | 2 +- src/about_exceptions.rb | 2 +- src/about_sandwich_code.rb | 6 +++--- src/about_scope.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/about_blocks.rb b/src/about_blocks.rb index 7fefcd907..483fc263e 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -23,7 +23,7 @@ def method_with_block_arguments end def test_blocks_can_take_arguments - result = method_with_block_arguments do |argument| + method_with_block_arguments do |argument| assert_equal __("Jim"), argument end end diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index f24398249..652f932cf 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -48,7 +48,7 @@ def test_ensure_clause result = nil begin fail "Oops" - rescue StandardError => ex + rescue StandardError # no code here ensure result = :always_run diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb index e641b13db..c12525d00 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -5,7 +5,7 @@ class AboutSandwichCode < EdgeCase::Koan def count_lines(file_name) file = open(file_name) count = 0 - while line = file.gets + while file.gets count += 1 end count @@ -66,7 +66,7 @@ def file_sandwich(file_name) def count_lines2(file_name) file_sandwich(file_name) do |file| count = 0 - while line = file.gets + while file.gets count += 1 end count @@ -99,7 +99,7 @@ def test_finding_lines2 def count_lines3(file_name) open(file_name) do |file| count = 0 - while line = file.gets + while file.gets count += 1 end count diff --git a/src/about_scope.rb b/src/about_scope.rb index f6843c870..afd876764 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -19,7 +19,7 @@ def identify def test_dog_is_not_available_in_the_current_scope assert_raise(___(NameError)) do - fido = Dog.new + Dog.new end end From 4d41bab6e68f40517e99e189f9f5ce4784b1e9b5 Mon Sep 17 00:00:00 2001 From: lucasrcosta Date: Sun, 10 Mar 2013 14:31:05 -0300 Subject: [PATCH 222/276] Added Times Statement --- src/about_control_statements.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index 1e799e647..ef5de529c 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -130,5 +130,13 @@ def test_for_statement end assert_equal [__("FISH"), __("AND"), __("CHIPS")], result end + + def test_times_statement + i = 0 + 10.times do + i += 1 + end + assert_equal __(10), result + end end From 213aece7e9f637088ab11d0a37e1dc926c3813eb Mon Sep 17 00:00:00 2001 From: Adam McCrea Date: Mon, 1 Apr 2013 17:11:02 -0300 Subject: [PATCH 223/276] Move to Neo --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 121228b99..7ca4f59fd 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,4 +1,4 @@ -= EdgeCase Ruby Koans += Neo 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 From 2df8e5554d8e822ca4d7102433aa13ac1ba6bcbf Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 1 Apr 2013 19:10:47 -0400 Subject: [PATCH 224/276] Added todo for EdgeCase to Neo conversion. --- src/edgecase.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/src/edgecase.rb b/src/edgecase.rb index 40c9607b4..e2002beb4 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -83,6 +83,7 @@ def side_padding(width) end end +# TODO: Change EdgeCase to Neo module EdgeCase class << self def simple_output From 405c42eb81b1b12f7884fb91a3284c4f0cd63c13 Mon Sep 17 00:00:00 2001 From: mfeckie Date: Sat, 6 Apr 2013 11:31:32 +0800 Subject: [PATCH 225/276] Updated Sensei for 2.0.0 Add support for Ruby 2.0.0 --- src/edgecase.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edgecase.rb b/src/edgecase.rb index e2002beb4..bd65fdfa5 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -147,7 +147,7 @@ class Sensei AssertionError = Test::Unit::AssertionFailedError end - in_ruby_version("1.9") do + in_ruby_version("1.9", "2.0") do if defined?(MiniTest) AssertionError = MiniTest::Assertion else From cb14e48f1dcf3a26c288a6d12b9a23a8cfb30724 Mon Sep 17 00:00:00 2001 From: mfeckie Date: Sat, 6 Apr 2013 12:18:41 +0800 Subject: [PATCH 226/276] Add tests for keyword arguments in Ruby 2.0 --- src/about_methods.rb | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/about_methods.rb b/src/about_methods.rb index b720010ea..eabe7aa51 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -77,6 +77,36 @@ def test_calling_with_variable_arguments assert_equal __([:one]), method_with_var_args(:one) assert_equal __([:one, :two]), method_with_var_args(:one, :two) end + # ------------------------------------------------------------------ + + if ruby_version?('2.0') + def method_with_keyword_arguments(one: 1, two: 'two') + [one, two] + end + + def test_keyword_arguments + assert_equal __, method_with_keyword_arguments.class + assert_equal __, method_with_keyword_arguments + assert_equal __, method_with_keyword_arguments(one: 'one') + assert_equal __, method_with_keyword_arguments(two: 2) + end + + def method_with_keywork_arguments_with_mandatory_argument(one, two: 2, three: 3) + [one, two, three] + end + + def test_keyword_arguments_with_wrong_number_of_arguments + exception = assert_raise (__) do + method_with_keywork_arguments_with_mandatory_argument + end + assert_match(/__/, exception.message) + end + + # THINK ABOUT IT: + # + # Keyword arguments always have a default value, making them optional to the caller + + end # ------------------------------------------------------------------ From 9c5ecb509ad923b0d548731c26a9ec87c0377740 Mon Sep 17 00:00:00 2001 From: mfeckie Date: Sat, 6 Apr 2013 13:23:56 +0800 Subject: [PATCH 227/276] Add support for Ruby 2.0 --- src/about_iteration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 2e35aa9cf..09ccfa2d5 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -14,7 +14,7 @@ def as_name(name) end end - in_ruby_version("1.9") do + in_ruby_version("1.9", "2.0") do def as_name(name) name.to_sym end From 58238ef54a83b01ef2d5b9c41ebad754cb377b9e Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 09:30:33 -0400 Subject: [PATCH 228/276] Removed fixed object_id koan This koan is not as important now that Ruby 2 has changed all the object ids. --- src/about_objects.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/about_objects.rb b/src/about_objects.rb index 1faf0a0eb..3d068a9a2 100644 --- a/src/about_objects.rb +++ b/src/about_objects.rb @@ -30,12 +30,6 @@ def test_every_object_has_different_id assert_equal __(true), obj.object_id != another_obj.object_id end - def test_some_system_objects_always_have_the_same_id - assert_equal __(0), false.object_id - assert_equal __(2), true.object_id - assert_equal __(4), nil.object_id - end - def test_small_integers_have_fixed_ids assert_equal __(1), 0.object_id assert_equal __(3), 1.object_id From f03e0d21eef530299bff95a358c7c26017dce726 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 09:45:23 -0400 Subject: [PATCH 229/276] Add keyword arguments (with correct answers). --- src/about_keyword_arguments.rb | 31 +++++++++++++++++++++++++++++++ src/about_message_passing.rb | 10 +++++----- src/about_methods.rb | 30 ------------------------------ src/edgecase.rb | 2 +- src/path_to_enlightenment.rb | 3 +++ 5 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 src/about_keyword_arguments.rb diff --git a/src/about_keyword_arguments.rb b/src/about_keyword_arguments.rb new file mode 100644 index 000000000..7b37e1b29 --- /dev/null +++ b/src/about_keyword_arguments.rb @@ -0,0 +1,31 @@ +require File.expand_path(File.dirname(__FILE__) + '/edgecase') + +class AboutMethods < EdgeCase::Koan + + def method_with_keyword_arguments(one: 1, two: 'two') + [one, two] + end + + def test_keyword_arguments + assert_equal __(Array), method_with_keyword_arguments.class + assert_equal __([1, 'two']), method_with_keyword_arguments + assert_equal __(['one', 'two']), method_with_keyword_arguments(one: 'one') + assert_equal __([1, 2]), method_with_keyword_arguments(two: 2) + end + + def method_with_keywork_arguments_with_mandatory_argument(one, two: 2, three: 3) + [one, two, three] + end + + def test_keyword_arguments_with_wrong_number_of_arguments + exception = assert_raise (___(ArgumentError)) do + method_with_keywork_arguments_with_mandatory_argument + end + assert_match(/#{__("wrong number of arguments")}/, exception.message) + end + + # THINK ABOUT IT: + # + # Keyword arguments always have a default value, making them optional to the caller + +end diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 882716ecc..11a0a7904 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -93,11 +93,11 @@ def test_calling_method_missing_causes_the_no_method_error # 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. + # called as shown above. However, in Ruby 1.9 (and later versions) + # 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 after Ruby 1.9 normally. # # Thanks. We now return you to your regularly scheduled Ruby # Koans. diff --git a/src/about_methods.rb b/src/about_methods.rb index eabe7aa51..b720010ea 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -77,36 +77,6 @@ def test_calling_with_variable_arguments assert_equal __([:one]), method_with_var_args(:one) assert_equal __([:one, :two]), method_with_var_args(:one, :two) end - # ------------------------------------------------------------------ - - if ruby_version?('2.0') - def method_with_keyword_arguments(one: 1, two: 'two') - [one, two] - end - - def test_keyword_arguments - assert_equal __, method_with_keyword_arguments.class - assert_equal __, method_with_keyword_arguments - assert_equal __, method_with_keyword_arguments(one: 'one') - assert_equal __, method_with_keyword_arguments(two: 2) - end - - def method_with_keywork_arguments_with_mandatory_argument(one, two: 2, three: 3) - [one, two, three] - end - - def test_keyword_arguments_with_wrong_number_of_arguments - exception = assert_raise (__) do - method_with_keywork_arguments_with_mandatory_argument - end - assert_match(/__/, exception.message) - end - - # THINK ABOUT IT: - # - # Keyword arguments always have a default value, making them optional to the caller - - end # ------------------------------------------------------------------ diff --git a/src/edgecase.rb b/src/edgecase.rb index bd65fdfa5..713f55da2 100644 --- a/src/edgecase.rb +++ b/src/edgecase.rb @@ -65,7 +65,7 @@ def ____(method=nil) end end - in_ruby_version("1.9") do + in_ruby_version("1.9", "2") do public :method_missing end end diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index 64621bf4f..9e8ccbe2b 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -12,6 +12,9 @@ require 'about_symbols' require 'about_regular_expressions' require 'about_methods' +in_ruby_version("2") do + require 'about_keyword_arguments' +end require 'about_constants' require 'about_control_statements' require 'about_true_and_false' From e150dd6d9e5f1fc871bc67e98f538d09fb0849e2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:10:24 -0400 Subject: [PATCH 230/276] Fix private message error for JRuby. --- src/about_methods.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_methods.rb b/src/about_methods.rb index b720010ea..dee1387e9 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -130,7 +130,7 @@ def test_calling_private_methods_with_an_explicit_receiver exception = assert_raise(___(NoMethodError)) do self.my_private_method end - assert_match /#{__("private method `my_private_method' called ")}/, exception.message + assert_match /#{__("method `my_private_method'")}/, exception.message end # ------------------------------------------------------------------ From f2e4a1f357483222bf9eaf670a1a4262e4d89b52 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:22:12 -0400 Subject: [PATCH 231/276] Make each do/end usage more consistent. --- src/about_iteration.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 09ccfa2d5..331c18ca3 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -39,19 +39,19 @@ def test_iterating_with_each def test_each_can_use_curly_brace_blocks_too array = [1, 2, 3] sum = 0 - array.each { |item| + array.each do |item| sum += item - } + end assert_equal __(6), sum end def test_break_works_with_each_style_iterations array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] sum = 0 - array.each { |item| + array.each do |item| break if item > 3 sum += item - } + end assert_equal __(6), sum end From 7eb51a9a304676ef8620b504608968d06e98a588 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:25:41 -0400 Subject: [PATCH 232/276] Remove unused files. --- src/array_test.rb | 47 ----------------------------------------------- src/code_mash.rb | 1 - src/first_test.rb | 11 ----------- 3 files changed, 59 deletions(-) delete mode 100644 src/array_test.rb delete mode 100644 src/code_mash.rb delete mode 100644 src/first_test.rb diff --git a/src/array_test.rb b/src/array_test.rb deleted file mode 100644 index 83ec07b46..000000000 --- a/src/array_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'test_helper' - -class ArrayTest < EdgeCase::TestCase - - def test_basic_arrays - food = [:peanut, :button, :and, :jelly] - assert_equal __, food[0] - assert_equal __, food.size - end - - def test_array_access - food = [:peanut, :button, :and, :jelly] - assert_equal __, food.first - assert_equal __, food.last - assert_equal __, food[0] - assert_equal __, food[2] - assert_equal __, food[(food.size() - 1)] - end - - def test_arrays_with_other_objects - food = [:peanut, :button, :and, :jelly, 1, nil] - assert_equal __, food.size - assert_equal __, food.last - assert_equal __, food[5] - end - - def test_adding_to_an_array_with_shovel_shovel - food = [:peanut, :button, :and, :jelly] - food << 'sandwich' - assert_equal __, food.size - assert_equal __, food.first - end - - def test_adding_to_an_array_with_push - food = [:peanut, :button, :and, :jelly] - food.push('sandwich') - assert_equal __, food.last - end - - def test_adding_to_an_array_with_unshift - food = [:peanut, :button, :and, :jelly] - food.unshift('a') - assert_equal __, food.first - end - -end - diff --git a/src/code_mash.rb b/src/code_mash.rb deleted file mode 100644 index 8fbf61788..000000000 --- a/src/code_mash.rb +++ /dev/null @@ -1 +0,0 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') diff --git a/src/first_test.rb b/src/first_test.rb deleted file mode 100644 index 708baf17a..000000000 --- a/src/first_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'test/unit' - -class TestSomething < Test::Unit::TestCase - def test_assert - assert true - assert_equal 1, 1 - assert_equal 1, 1.0 - end -end - - From 67750bf9bfe67101c40a4fd48d1756496060debd Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:31:08 -0400 Subject: [PATCH 233/276] Fix missing blanks in about hashes. --- src/about_hashes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_hashes.rb b/src/about_hashes.rb index afb17b35a..b9a4f2486 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -4,7 +4,7 @@ class AboutHashes < EdgeCase::Koan def test_creating_hashes empty_hash = Hash.new assert_equal __(Hash), empty_hash.class - assert_equal({}, empty_hash) # __ + assert_equal(__({}), empty_hash) assert_equal __(0), empty_hash.size end From 09b03e9b1c45343cf5399c40a2210f5d741f2ae2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:40:27 -0400 Subject: [PATCH 234/276] Change EdgeCase to Neo --- src/about_array_assignment.rb | 4 ++-- src/about_arrays.rb | 4 ++-- src/about_asserts.rb | 4 ++-- src/about_blocks.rb | 4 ++-- src/about_class_methods.rb | 4 ++-- src/about_classes.rb | 4 ++-- src/about_constants.rb | 4 ++-- src/about_control_statements.rb | 4 ++-- src/about_dice_project.rb | 4 ++-- src/about_exceptions.rb | 4 ++-- src/about_hashes.rb | 4 ++-- src/about_inheritance.rb | 4 ++-- src/about_iteration.rb | 4 ++-- src/about_java_interop.rb | 4 ++-- src/about_keyword_arguments.rb | 4 ++-- src/about_message_passing.rb | 4 ++-- src/about_methods.rb | 4 ++-- src/about_modules.rb | 4 ++-- src/about_nil.rb | 4 ++-- src/about_objects.rb | 4 ++-- src/about_open_classes.rb | 4 ++-- src/about_proxy_object_project.rb | 6 +++--- src/about_regular_expressions.rb | 4 ++-- src/about_sandwich_code.rb | 4 ++-- src/about_scope.rb | 4 ++-- src/about_scoring_project.rb | 4 ++-- src/about_strings.rb | 4 ++-- src/about_symbols.rb | 4 ++-- src/about_to_str.rb | 4 ++-- src/about_triangle_project.rb | 4 ++-- src/about_triangle_project_2.rb | 4 ++-- src/about_true_and_false.rb | 4 ++-- src/{edgecase.rb => neo.rb} | 29 ++++++++++++++--------------- 33 files changed, 79 insertions(+), 80 deletions(-) rename src/{edgecase.rb => neo.rb} (94%) diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 35af856a2..a08f512fd 100644 --- a/src/about_array_assignment.rb +++ b/src/about_array_assignment.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutArrayAssignment < EdgeCase::Koan +class AboutArrayAssignment < Neo::Koan def test_non_parallel_assignment names = ["John", "Smith"] assert_equal __(["John", "Smith"]), names diff --git a/src/about_arrays.rb b/src/about_arrays.rb index 35c951d64..a415538ae 100644 --- a/src/about_arrays.rb +++ b/src/about_arrays.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutArrays < EdgeCase::Koan +class AboutArrays < Neo::Koan def test_creating_arrays empty_array = Array.new assert_equal __(Array), empty_array.class diff --git a/src/about_asserts.rb b/src/about_asserts.rb index 5ac6b551f..88c310005 100644 --- a/src/about_asserts.rb +++ b/src/about_asserts.rb @@ -1,9 +1,9 @@ #!/usr/bin/env ruby # -*- ruby -*- -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutAsserts < EdgeCase::Koan +class AboutAsserts < Neo::Koan # We shall contemplate truth by testing reality, via asserts. def test_assert_truth diff --git a/src/about_blocks.rb b/src/about_blocks.rb index 483fc263e..af6f2074f 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutBlocks < EdgeCase::Koan +class AboutBlocks < Neo::Koan def method_with_block result = yield result diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index 2cadbaa8f..a352d2df9 100644 --- a/src/about_class_methods.rb +++ b/src/about_class_methods.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutClassMethods < EdgeCase::Koan +class AboutClassMethods < Neo::Koan class Dog end diff --git a/src/about_classes.rb b/src/about_classes.rb index a8336bf82..e1de7d782 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutClasses < EdgeCase::Koan +class AboutClasses < Neo::Koan class Dog end diff --git a/src/about_constants.rb b/src/about_constants.rb index dd0bc390a..49d2b5af5 100644 --- a/src/about_constants.rb +++ b/src/about_constants.rb @@ -1,8 +1,8 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') C = "top level" -class AboutConstants < EdgeCase::Koan +class AboutConstants < Neo::Koan C = "nested" diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index 1e799e647..99953ecbe 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutControlStatements < EdgeCase::Koan +class AboutControlStatements < Neo::Koan def test_if_then_else_statements if true diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index 65c21dfe7..98717ba3c 100644 --- a/src/about_dice_project.rb +++ b/src/about_dice_project.rb @@ -1,4 +1,4 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') # Implement a DiceSet Class here: # @@ -15,7 +15,7 @@ def roll(n) end #++ -class AboutDiceProject < EdgeCase::Koan +class AboutDiceProject < Neo::Koan def test_can_create_a_dice_set dice = DiceSet.new assert_not_nil dice diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index 652f932cf..b4ad63da2 100644 --- a/src/about_exceptions.rb +++ b/src/about_exceptions.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutExceptions < EdgeCase::Koan +class AboutExceptions < Neo::Koan class MySpecialError < RuntimeError end diff --git a/src/about_hashes.rb b/src/about_hashes.rb index b9a4f2486..ef5862170 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutHashes < EdgeCase::Koan +class AboutHashes < Neo::Koan def test_creating_hashes empty_hash = Hash.new assert_equal __(Hash), empty_hash.class diff --git a/src/about_inheritance.rb b/src/about_inheritance.rb index 73030c6ef..3a119c078 100644 --- a/src/about_inheritance.rb +++ b/src/about_inheritance.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutInheritance < EdgeCase::Koan +class AboutInheritance < Neo::Koan class Dog attr_reader :name diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 331c18ca3..8e16bf654 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutIteration < EdgeCase::Koan +class AboutIteration < Neo::Koan # -- An Aside ------------------------------------------------------ # Ruby 1.8 stores names as strings. Ruby 1.9 stores names as diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index c2d2142ce..83c2a21eb 100644 --- a/src/about_java_interop.rb +++ b/src/about_java_interop.rb @@ -1,4 +1,4 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') include Java @@ -11,7 +11,7 @@ # * Calling custom java class # * Calling Ruby from java??? -class AboutJavaInterop < EdgeCase::Koan +class AboutJavaInterop < Neo::Koan def test_using_a_java_library_class java_array = java.util.ArrayList.new assert_equal __(Java::JavaUtil::ArrayList), java_array.class diff --git a/src/about_keyword_arguments.rb b/src/about_keyword_arguments.rb index 7b37e1b29..15960340d 100644 --- a/src/about_keyword_arguments.rb +++ b/src/about_keyword_arguments.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutMethods < EdgeCase::Koan +class AboutMethods < Neo::Koan def method_with_keyword_arguments(one: 1, two: 'two') [one, two] diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 11a0a7904..4301a956e 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutMessagePassing < EdgeCase::Koan +class AboutMessagePassing < Neo::Koan class MessageCatcher def caught? diff --git a/src/about_methods.rb b/src/about_methods.rb index dee1387e9..2a1c3fa10 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -1,10 +1,10 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') def my_global_method(a,b) a + b end -class AboutMethods < EdgeCase::Koan +class AboutMethods < Neo::Koan def test_calling_global_methods assert_equal __(5), my_global_method(2,3) diff --git a/src/about_modules.rb b/src/about_modules.rb index 334b175d6..a96c66276 100644 --- a/src/about_modules.rb +++ b/src/about_modules.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutModules < EdgeCase::Koan +class AboutModules < Neo::Koan module Nameable def set_name(new_name) @name = new_name diff --git a/src/about_nil.rb b/src/about_nil.rb index 9df4f9bf8..0c084d727 100644 --- a/src/about_nil.rb +++ b/src/about_nil.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutNil < EdgeCase::Koan +class AboutNil < Neo::Koan def test_nil_is_an_object assert_equal __(true), nil.is_a?(Object), "Unlike NULL in other languages" end diff --git a/src/about_objects.rb b/src/about_objects.rb index 3d068a9a2..0d752583b 100644 --- a/src/about_objects.rb +++ b/src/about_objects.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutObjects < EdgeCase::Koan +class AboutObjects < Neo::Koan def test_everything_is_an_object assert_equal __(true), 1.is_a?(Object) assert_equal __(true), 1.5.is_a?(Object) diff --git a/src/about_open_classes.rb b/src/about_open_classes.rb index 80df88831..0372f50a5 100644 --- a/src/about_open_classes.rb +++ b/src/about_open_classes.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutOpenClasses < EdgeCase::Koan +class AboutOpenClasses < Neo::Koan class Dog def bark "WOOF" diff --git a/src/about_proxy_object_project.rb b/src/about_proxy_object_project.rb index 7e8be0387..3f969f61f 100644 --- a/src/about_proxy_object_project.rb +++ b/src/about_proxy_object_project.rb @@ -1,4 +1,4 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') # Project: Create a Proxy Class # @@ -42,7 +42,7 @@ def number_of_times_called(method) # The proxy object should pass the following Koan: # -class AboutProxyObjectProject < EdgeCase::Koan +class AboutProxyObjectProject < Neo::Koan def test_proxy_method_returns_wrapped_object # NOTE: The Television class is defined below tv = Proxy.new(Television.new) @@ -135,7 +135,7 @@ def on? end # Tests for the Television class. All of theses tests should pass. -class TelevisionTest < EdgeCase::Koan +class TelevisionTest < Neo::Koan def test_it_turns_on tv = Television.new diff --git a/src/about_regular_expressions.rb b/src/about_regular_expressions.rb index 03e8f9a9e..76bd56640 100644 --- a/src/about_regular_expressions.rb +++ b/src/about_regular_expressions.rb @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutRegularExpressions < EdgeCase::Koan +class AboutRegularExpressions < Neo::Koan def test_a_pattern_is_a_regular_expression assert_equal __(Regexp), /pattern/.class end diff --git a/src/about_sandwich_code.rb b/src/about_sandwich_code.rb index c12525d00..1314ec834 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutSandwichCode < EdgeCase::Koan +class AboutSandwichCode < Neo::Koan def count_lines(file_name) file = open(file_name) diff --git a/src/about_scope.rb b/src/about_scope.rb index afd876764..4760a9aee 100644 --- a/src/about_scope.rb +++ b/src/about_scope.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutScope < EdgeCase::Koan +class AboutScope < Neo::Koan module Jims class Dog def identify diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 60b468226..831552081 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -1,4 +1,4 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') # Greed is a dice game where you roll up to five dice to accumulate # points. The following "score" function will be used to calculate the @@ -54,7 +54,7 @@ def score(dice) #++ end -class AboutScoringProject < EdgeCase::Koan +class AboutScoringProject < Neo::Koan def test_score_of_an_empty_list_is_zero assert_equal 0, score([]) end diff --git a/src/about_strings.rb b/src/about_strings.rb index dd13fecfd..8a96a529b 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutStrings < EdgeCase::Koan +class AboutStrings < Neo::Koan def test_double_quoted_strings_are_strings string = "Hello, World" assert_equal __(true), string.is_a?(String) diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 720ca8c6f..c2c9321c6 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutSymbols < EdgeCase::Koan +class AboutSymbols < Neo::Koan def test_symbols_are_symbols symbol = :ruby assert_equal __(true), symbol.is_a?(Symbol) diff --git a/src/about_to_str.rb b/src/about_to_str.rb index 68c40b258..669a4df01 100644 --- a/src/about_to_str.rb +++ b/src/about_to_str.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutToStr < EdgeCase::Koan +class AboutToStr < Neo::Koan class CanNotBeTreatedAsString def to_s diff --git a/src/about_triangle_project.rb b/src/about_triangle_project.rb index da23bbd78..ec2447c51 100644 --- a/src/about_triangle_project.rb +++ b/src/about_triangle_project.rb @@ -1,9 +1,9 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleProject < EdgeCase::Koan +class AboutTriangleProject < Neo::Koan def test_equilateral_triangles_have_equal_sides assert_equal :equilateral, triangle(2, 2, 2) assert_equal :equilateral, triangle(10, 10, 10) diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index 347c3b1a9..55dd742fe 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -1,9 +1,9 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') # You need to write the triangle method in the file 'triangle.rb' require 'triangle.rb' -class AboutTriangleProject2 < EdgeCase::Koan +class AboutTriangleProject2 < Neo::Koan # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions diff --git a/src/about_true_and_false.rb b/src/about_true_and_false.rb index e9910f63f..470489eb0 100644 --- a/src/about_true_and_false.rb +++ b/src/about_true_and_false.rb @@ -1,6 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/edgecase') +require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutTrueAndFalse < EdgeCase::Koan +class AboutTrueAndFalse < Neo::Koan def truth_value(condition) if condition :true_stuff diff --git a/src/edgecase.rb b/src/neo.rb similarity index 94% rename from src/edgecase.rb rename to src/neo.rb index 713f55da2..06c60ca3f 100644 --- a/src/edgecase.rb +++ b/src/neo.rb @@ -83,8 +83,7 @@ def side_padding(width) end end -# TODO: Change EdgeCase to Neo -module EdgeCase +module Neo class << self def simple_output ENV['SIMPLE_KOAN_OUTPUT'] == 'true' @@ -196,7 +195,7 @@ def observe(step) @failure = step.failure add_progress(@pass_count) @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.") - throw :edgecase_exit + throw :neo_exit end end @@ -222,7 +221,7 @@ def instruct def show_progress bar_width = 50 - total_tests = EdgeCase::Koan.total_tests + total_tests = Neo::Koan.total_tests scale = bar_width.to_f/total_tests print Color.green("your path thus far [") happy_steps = (pass_count*scale).to_i @@ -238,7 +237,7 @@ def show_progress end def end_screen - if EdgeCase.simple_output + if Neo.simple_output boring_end_screen else artistic_end_screen @@ -275,7 +274,7 @@ def artistic_end_screen ,:::::::::::::, brought to you by ,,::::::::::::, :::::::::::::: ,:::::::::::: ::::::::::::::, ,::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: + ::::::::::::, Neo Software Artisans , :::::::::::: :,::::::::: :::: ::::::::::::: ,::::::::::: ,: ,,:::::::::::::, :::::::::::: ,::::::::::::::, @@ -337,7 +336,7 @@ def indent(text) def find_interesting_lines(backtrace) backtrace.reject { |line| - line =~ /test\/unit\/|edgecase\.rb|minitest/ + line =~ /test\/unit\/|neo\.rb|minitest/ } end @@ -397,19 +396,19 @@ def meditate setup begin send(name) - rescue StandardError, EdgeCase::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::AssertionError => ex failed(ex) ensure begin teardown - rescue StandardError, EdgeCase::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::AssertionError => ex failed(ex) if passed? end end self end - # Class methods for the EdgeCase test suite. + # Class methods for the Neo test suite. class << self def inherited(subclass) subclasses << subclass @@ -466,7 +465,7 @@ def total_tests class ThePath def walk - sensei = EdgeCase::Sensei.new + sensei = Neo::Sensei.new each_step do |step| sensei.observe(step.meditate) end @@ -474,9 +473,9 @@ def walk end def each_step - catch(:edgecase_exit) { + catch(:neo_exit) { step_count = 0 - EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index| + Neo::Koan.subclasses.each_with_index do |koan,koan_index| koan.testmethods.each do |method_name| step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1) yield step @@ -488,6 +487,6 @@ def each_step end END { - EdgeCase::Koan.command_line(ARGV) - EdgeCase::ThePath.new.walk + Neo::Koan.command_line(ARGV) + Neo::ThePath.new.walk } From dc8f73f1070924f334a714ce86994eeb11b6bde7 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:40:49 -0400 Subject: [PATCH 235/276] Remove test_helper.rb --- src/test_helper.rb | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/test_helper.rb diff --git a/src/test_helper.rb b/src/test_helper.rb deleted file mode 100644 index 9accf96d8..000000000 --- a/src/test_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test/unit' - -def __ - "FILL ME IN" -end - -EdgeCase = Test::Unit From 86cb9c5a27c53d38bec8fe8bf894a8e931e64e7f Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:46:13 -0400 Subject: [PATCH 236/276] Fixed times example. --- src/about_control_statements.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/about_control_statements.rb b/src/about_control_statements.rb index b9d104589..6fedd700e 100644 --- a/src/about_control_statements.rb +++ b/src/about_control_statements.rb @@ -130,13 +130,13 @@ def test_for_statement end assert_equal [__("FISH"), __("AND"), __("CHIPS")], result end - + def test_times_statement - i = 0 + sum = 0 10.times do - i += 1 + sum += 1 end - assert_equal __(10), result + assert_equal __(10), sum end end From f3560581ce185e94cb8baaab1d5c69c1ffd965b6 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 10:58:49 -0400 Subject: [PATCH 237/276] Removed RDoc --- Rakefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Rakefile b/Rakefile index ab77d1972..11c4353dd 100755 --- a/Rakefile +++ b/Rakefile @@ -2,11 +2,6 @@ # -*- ruby -*- require 'rake/clean' -begin - require 'rdoc/task' -rescue LoadError => ex - # No rdoc task availble. -end SRC_DIR = 'src' PROB_DIR = 'koans' @@ -90,13 +85,6 @@ task :walk_the_path do ruby 'path_to_enlightenment.rb' end -if defined?(Rake::RDocTask) - Rake::RDocTask.new do |rd| - rd.main = "README.rdoc" - rd.rdoc_files.include("README.rdoc", "${PROB_DIR}/*.rb") - end -end - directory DIST_DIR directory PROB_DIR From 63753656afc0214853bdb2196d2f076c27ce794d Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 11:06:31 -0400 Subject: [PATCH 238/276] Fix prematurely correct answer. --- src/about_classes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_classes.rb b/src/about_classes.rb index e1de7d782..48c805430 100644 --- a/src/about_classes.rb +++ b/src/about_classes.rb @@ -147,7 +147,7 @@ def get_self end def to_s - __(@name) + @name end def inspect From 197dd8eff88f70a1d3a31a5fe0952dbfb598c536 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 11:13:51 -0400 Subject: [PATCH 239/276] Clarify the difference between here docs and multi-line strings. --- src/about_strings.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/about_strings.rb b/src/about_strings.rb index 8a96a529b..24969826a 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -42,6 +42,7 @@ def test_flexible_quotes_can_handle_multiple_lines } assert_equal __(54), long_string.length assert_equal __(3), long_string.lines.count + assert_equal __("\n"), long_string[0,1] end def test_here_documents_can_also_handle_multiple_lines @@ -51,6 +52,7 @@ def test_here_documents_can_also_handle_multiple_lines EOS assert_equal __(53), long_string.length assert_equal __(2), long_string.lines.count + assert_equal __("I"), long_string[0,1] end def test_plus_will_concatenate_two_strings From 12639186cb48d61c1d097f36cd39805f9b022338 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 11:26:58 -0400 Subject: [PATCH 240/276] Fix order of comparison in about symbols to follow standard. --- src/about_symbols.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_symbols.rb b/src/about_symbols.rb index c2c9321c6..5963c65fd 100644 --- a/src/about_symbols.rb +++ b/src/about_symbols.rb @@ -50,14 +50,14 @@ def test_symbols_can_be_made_from_strings def test_symbols_with_spaces_can_be_built symbol = :"cats and dogs" - assert_equal symbol, __("cats and dogs").to_sym + assert_equal __("cats and dogs").to_sym, symbol end def test_symbols_with_interpolation_can_be_built value = "and" symbol = :"cats #{value} dogs" - assert_equal symbol, __("cats and dogs").to_sym + assert_equal __("cats and dogs").to_sym, symbol end def test_to_s_is_called_on_interpolated_symbols From e947652bcf5953001dd4134d37ee38c301201c20 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 9 Apr 2013 15:19:32 -0400 Subject: [PATCH 241/276] Zip file goes in download directory. Moving the zip file to the source tree so it can be downloaded. --- Rakefile | 20 ++++++-------------- download/rubykoans.zip | Bin 0 -> 38100 bytes 2 files changed, 6 insertions(+), 14 deletions(-) create mode 100644 download/rubykoans.zip diff --git a/Rakefile b/Rakefile index 11c4353dd..ab0a2ec93 100755 --- a/Rakefile +++ b/Rakefile @@ -5,17 +5,14 @@ require 'rake/clean' SRC_DIR = 'src' PROB_DIR = 'koans' -DIST_DIR = 'dist' +DOWNLOAD_DIR = 'download' SRC_FILES = FileList["#{SRC_DIR}/*"] KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f") -today = Time.now.strftime("%Y-%m-%d") -TAR_FILE = "#{DIST_DIR}/rubykoans-#{today}.tgz" -ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip" +ZIP_FILE = "#{DOWNLOAD_DIR}/rubykoans.zip" CLEAN.include("**/*.rbc") -CLOBBER.include(DIST_DIR) module Koans extend Rake::DSL if defined?(Rake::DSL) @@ -85,23 +82,18 @@ task :walk_the_path do ruby 'path_to_enlightenment.rb' end -directory DIST_DIR +directory DOWNLOAD_DIR directory PROB_DIR -file ZIP_FILE => KOAN_FILES + [DIST_DIR] do +file ZIP_FILE => KOAN_FILES + [DOWNLOAD_DIR] do sh "zip #{ZIP_FILE} #{PROB_DIR}/*" end -file TAR_FILE => KOAN_FILES + [DIST_DIR] do - sh "tar zcvf #{TAR_FILE} #{PROB_DIR}" -end - desc "Create packaged files for distribution" -task :package => [TAR_FILE, ZIP_FILE] +task :package => [ZIP_FILE] desc "Upload the package files to the web server" -task :upload => [TAR_FILE, ZIP_FILE] do - sh "scp #{TAR_FILE} linode:sites/onestepback.org/download" +task :upload => [ZIP_FILE] do sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download" end diff --git a/download/rubykoans.zip b/download/rubykoans.zip new file mode 100644 index 0000000000000000000000000000000000000000..91662455cbcee4dc9b8f0705a6d49fcea7270587 GIT binary patch literal 38100 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 Date: Tue, 9 Apr 2013 16:04:07 -0400 Subject: [PATCH 242/276] Added deploy instructions. --- DEPLOYING | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 DEPLOYING diff --git a/DEPLOYING b/DEPLOYING new file mode 100644 index 000000000..3b91dc39f --- /dev/null +++ b/DEPLOYING @@ -0,0 +1,12 @@ += Deploying a new Ruby Koans ZIP file + +The "Download" button on the rubykoans.com web-site points to the +download/rubykoans.zip file in the github repository. So to update the +download target on the web-site, just rebuild the .zip file, commit +and push the changes. + + rake package + git add download + git push + +That's it. \ No newline at end of file From 610e219fa5e340592db262a925935d3b161c601c Mon Sep 17 00:00:00 2001 From: Mike Mazur Date: Fri, 12 Apr 2013 09:23:21 -0400 Subject: [PATCH 243/276] One more EdgeCase -> Neo change in the Rakefile Fixes #92. --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index ab0a2ec93..0c3b2c0e5 100755 --- a/Rakefile +++ b/Rakefile @@ -32,7 +32,7 @@ module Koans end def Koans.make_koan_file(infile, outfile) - if infile =~ /edgecase/ + if infile =~ /neo/ cp infile, outfile else open(infile) do |ins| From 24a0069c20bbfc4273286f00318441499860188c Mon Sep 17 00:00:00 2001 From: Jason Noble Date: Sun, 14 Apr 2013 11:53:37 -0600 Subject: [PATCH 244/276] Update .gitignore with .ruby-version .ruby-version is the new .rvmrc, although .rvmrc is used still. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 81fb2a49d..26bb3fce5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ dist .project_env.rc .path_progress .rvmrc +.ruby-version *.rbc koans/* From f4d9dc0db70766f2eff673024aeffa924d97fff2 Mon Sep 17 00:00:00 2001 From: Artur Moczulski Date: Wed, 24 Apr 2013 00:24:09 -0700 Subject: [PATCH 245/276] Fixes a silly typo in the method name in method_with_keyword_arguments_with_mandatory_argument --- src/about_keyword_arguments.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_keyword_arguments.rb b/src/about_keyword_arguments.rb index 15960340d..e92dc1426 100644 --- a/src/about_keyword_arguments.rb +++ b/src/about_keyword_arguments.rb @@ -13,13 +13,13 @@ def test_keyword_arguments assert_equal __([1, 2]), method_with_keyword_arguments(two: 2) end - def method_with_keywork_arguments_with_mandatory_argument(one, two: 2, three: 3) + def method_with_keyword_arguments_with_mandatory_argument(one, two: 2, three: 3) [one, two, three] end def test_keyword_arguments_with_wrong_number_of_arguments exception = assert_raise (___(ArgumentError)) do - method_with_keywork_arguments_with_mandatory_argument + method_with_keyword_arguments_with_mandatory_argument end assert_match(/#{__("wrong number of arguments")}/, exception.message) end From 6b66d4615636b5bcb35d1b8d4f12d8972b1b9ab4 Mon Sep 17 00:00:00 2001 From: Steven Ndaye Date: Mon, 13 May 2013 11:22:02 +0200 Subject: [PATCH 246/276] Wrong class name from AboutMethods to AboutKeywordArguments --- src/about_keyword_arguments.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_keyword_arguments.rb b/src/about_keyword_arguments.rb index 15960340d..22acdc3a5 100644 --- a/src/about_keyword_arguments.rb +++ b/src/about_keyword_arguments.rb @@ -1,6 +1,6 @@ require File.expand_path(File.dirname(__FILE__) + '/neo') -class AboutMethods < Neo::Koan +class AboutKeywordArguments < Neo::Koan def method_with_keyword_arguments(one: 1, two: 'two') [one, two] From 1ce6d52963221eb6df2c3c8bca3e2147feeef2e2 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 13 May 2013 16:48:57 -0300 Subject: [PATCH 247/276] test_inject_will_blow_your_mind uses an incorrect memo argument name No big NBD, but the second memo argument is better called 'product' than 'sum'. --- src/about_iteration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 8e16bf654..8a4c16b22 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -86,7 +86,7 @@ def test_inject_will_blow_your_mind result = [2, 3, 4].inject(0) { |sum, item| sum + item } assert_equal __(9), result - result2 = [2, 3, 4].inject(1) { |sum, item| sum * item } + result2 = [2, 3, 4].inject(1) { |product, item| sum * item } assert_equal __(24), result2 # Extra Credit: From dfaeb570e505f557ce35806b381ec93f21d675e2 Mon Sep 17 00:00:00 2001 From: Adler Santos Date: Mon, 3 Jun 2013 02:18:29 +0800 Subject: [PATCH 248/276] corrected example code in test_each_can_use_curly_brace_blocks_too test_each_can_use_curly_brace_blocks_too was using the do-end block instead of the curly brace syntax for the each method. --- src/about_iteration.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 8e16bf654..d1132d1f2 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -39,9 +39,7 @@ def test_iterating_with_each def test_each_can_use_curly_brace_blocks_too array = [1, 2, 3] sum = 0 - array.each do |item| - sum += item - end + array.each { |item| sum += item } assert_equal __(6), sum end From 718538b72936c47691ecd0fdbe4f326aa8bd20f2 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 6 Jun 2013 23:03:33 +0800 Subject: [PATCH 249/276] Add ~ files to ignore list. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 81fb2a49d..d7338af49 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist .rvmrc *.rbc koans/* +*~ \ No newline at end of file From 4ba9f3c1422b4c650e2a50ffc22a3a952b2436c4 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 6 Jun 2013 23:03:44 +0800 Subject: [PATCH 250/276] Add zip task for building zip file. --- Rakefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Rakefile b/Rakefile index 0c3b2c0e5..cb79c190f 100755 --- a/Rakefile +++ b/Rakefile @@ -85,6 +85,13 @@ end directory DOWNLOAD_DIR directory PROB_DIR +desc "Build zip file" +task :zip => [:clobber_zip, ZIP_FILE] + +task :clobber_zip do + rm ZIP_FILE +end + file ZIP_FILE => KOAN_FILES + [DOWNLOAD_DIR] do sh "zip #{ZIP_FILE} #{PROB_DIR}/*" end From 623e21fc18eef6be5b21ac2fe2d49d66589872ed Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Thu, 6 Jun 2013 23:04:18 +0800 Subject: [PATCH 251/276] Updated zip file to latest changes. --- download/rubykoans.zip | Bin 38100 -> 38421 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 91662455cbcee4dc9b8f0705a6d49fcea7270587..95299d5e6f73ad3cc5201cb200bcc1b2c2517d98 100644 GIT binary patch delta 9512 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 A9RL6T delta 9079 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 From ad5f6f5fe86090fdfc901179689a635935df0913 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 7 Jun 2013 05:38:44 +0800 Subject: [PATCH 252/276] Fixed missed sum => product change --- src/about_iteration.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index 938b175de..c14e5fb92 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -84,7 +84,7 @@ def test_inject_will_blow_your_mind result = [2, 3, 4].inject(0) { |sum, item| sum + item } assert_equal __(9), result - result2 = [2, 3, 4].inject(1) { |product, item| sum * item } + result2 = [2, 3, 4].inject(1) { |product, item| product * item } assert_equal __(24), result2 # Extra Credit: From d5b787cd2b85db4cfafb05a5b58571a969c52170 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 7 Jun 2013 06:01:01 +0800 Subject: [PATCH 253/276] Beefed up the greed scoring tests just a bit. --- src/about_scoring_project.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 831552081..4031eb44c 100644 --- a/src/about_scoring_project.rb +++ b/src/about_scoring_project.rb @@ -90,6 +90,9 @@ def test_score_of_other_triples_is_100x def test_score_of_mixed_is_sum assert_equal 250, score([2,5,2,2,3]) assert_equal 550, score([5,5,5,5]) + assert_equal 1100, score([1,1,1,1]) + assert_equal 1200, score([1,1,1,1,1]) + assert_equal 1150, score([1,1,1,5,1]) end end From 8dd3acae415fe7323213ef334180b4e5bc358d84 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Fri, 7 Jun 2013 06:02:26 +0800 Subject: [PATCH 254/276] Update the zip file with the latest changes. --- download/rubykoans.zip | Bin 38421 -> 38449 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 95299d5e6f73ad3cc5201cb200bcc1b2c2517d98..ec2da90aa65f4644f99e01252a98344f2b66ede8 100644 GIT binary patch delta 4419 zcmZ{nc|4R|8^`Y%hG)o{hRh`UI=09bM)oX)$WlZigqg;YrA%ThlO=AHhh)nZA{0eL z*^@0vLYB%?Av<~XPBWRF>GQsS+<%X3FZkhBY#zaj3cZRc$`yoM+k;-CQuj$*TEfDWy<9Y zp}=x(n#ZaM?g=Vv;XzZBKV7c!j8fq%#BU`tZz+^w{$TF`n$P*YHy9`|b|2N8Jj$y2 zeN$AJDAc$V21do&b zJexkWH+A{U-&19j8 zeWYzk6Au<)_3@0*f4n)F@NPBe3xdz?-aRc(31r-$1+s1@1+^L<18a~{;KNrz2>Z!ujJTb z^eVhGmJ}2pqzI(2yZSBOTzIdgTSgMTX*V^fG-#{<5mTDcJ#fBNCS{4eTXZB)s;i*7 zVmcva7qjDH{h`RwUKHmzTz?uuAh5MaGA16!MzYRNTNQ4Mu?3BoXNP7A%!NNj&x@>0 zeAR^bc=2_4k4Z0U6mc<3UF5(J^htyy%m5O1{)7qs^qMr|U?s{IU@MaW_?cPQ; z>XS02Cq8Rew<2av4YqO<_`M1X$`)0y(tl{X*!`Cp4ZZ#%r#}$B3}AO2##tMaC(v#f-wHx~y=mC@f+O{X~zHy((ButkhG9 zK3wzRy}sdNu^EBZfHP;zH)`>BgKB+I1u4bE@=nD&WqYQWE}4gL+7Sp0ZF*{XSAt_U z#fSE(OOQ&k&?F;epSZEq>U7My0 zza2fUBlhss+;*->&$fJ##kZy0>xh7;t?ze=3%2Uf)~Z>}|B@7=z6pP($iRVHTxyuLK+a_@B?w_*6E0RhCURbl)onu%J z;$5`Vak2w#)3JS1GMBz{pivK#{Dbw

pUCor#mfrvCXq`05OtPd^>xmpt|%VKcl} zT>;+d!Dlk#*dQ4)w4sDJ#JlJ%865IPTq>&|d(VEEu^Ktz;K3tWgcsYqqrR^DR~ON{FzwXIZ^UA~aQ`DtMt zb){<`&fY}$FRnZiHvtcGL*4etJkR08=cvA3mfIqh$<<^tpdp72I}ue-8*NsL3AoR$ zG#Hxf$`gmOY5?v_?LW`OUnAQW(u?cZRWmx6m?WY8u@?IM!h>QW+t~Lv-1yWg8>ppr zh*7L=lFyjQxwcc{`B#di$~4C(nv47;4@o|UarDQuDxPAynX8CB+2*@$^etgKW>7lA zv3Jgwr}d1A-am>hITrTieO3>QPOl25xp1^^HQ zP+(5H2muZ-{Ga3SmX-OjW*yFkHCwaE95L>gkn_t|V)d^+WzC9vv+HZG$`@wehdkR2 z1F{CsA|dxM2AqIOl_L?CTBGaZ%oSN z;PH?*;Npy{eqe8$Z)$a+|K9u}mr>;_zHkUq{MZ1S?yr2U2c>{KjM!xpIp^!a^mXEy|!Xa z0332w*3W3%5+7*Mc~zt8fsRv#BOQ38c@i(LoIpNYMNOPFjqE#=p9_z}-Tzxu7*i$K z5lEWqI0{O-=uh{Eqy$!Qwcgnd4P3PzsJ@7Pf6B?QWz}8|+c)~S26NCGtu1^TfQJN2 zjF?AwHoGk3oi>=mpykWk7Ur~gV4*0&JVQbExed+J({9gD&@B~_UNqF50d-hJeknLI zV%M(T@P}pBfPk|QtB@{8d%0`Y}0kpezy<$ zel))72?{3hY)QRu(AaaMdoh^DiO|dORUjjjWv$XueRqb52!EF4c)*2jzo6UP_spv= zMpw^N&(|#9Sl9@EF=?R5_#!l0eMNIWv{Im*Ba1B@q1Ag;AWCH5{LH?gCweALIuWJg zf=jaO-_Lo!9I2?w9mYiabAPX0g7l8tlXcQ=uVVi3YFW`KU0%j}{2*@spw) zE}MR|BLkH3*P}43zc9`CrazQ}0&hhq)8KGKD%B&7`1?VUMKq$qPf_YWYYO->8bz_x zi$2Ie-uSfk-_Zx?`sbqc=-S6)=8SwM>4ou0APrP_@8k-ok%P5`pRXe! z;UII8C>=FVLP8-E_1AO}`*=PBd8n072)*-4g)LV_kgx1^b-Adi%-Y&)8W1k=%6GV&2>2 z6<3Ah#jLWyo4Id2U>Eb0ZJ|@CuP< Q=jWME6=Yh8`niq%3u~28rvLx| delta 4519 zcmZ`-c|4Tc8-JOxr;C_q7&{r;P-M#xMMD@&g^YcTXpF65BxTL^QjtiOvTtQ6vX=GQ zN|A_0anqHAl&*eb<{C|(`}^bl<9yHeIp6a<=bYy`=dCJbPA_HVwlIM}`2hf62hP_& zP2rYjdzD{_rF>OrRw(2`{Zr5wD$6!b!6;u%5cCxngu(-@c%-(7U^q`A75jr%Z40Y0 z;dNx9g5`Yl5o@OSrf6V0zXFxHIpiw;YZ^EL+h(%uE@h^g*9xi9$NVI89YO_TMQG-f zS=Ka)kZIr@aV0wQrT7_|xv|s%I(S8@fCehbs?b4q*?*ZY<&^0lH`0X0v{RrnK~Q0p zDxRRYJHZX(>V1lkN0RT1Z zPfqyyjjQu)EI6F4R2juvD=JUC*aN2Q<0nZLAt$SUKGwEeGPwioRd?KQw7C$v&=B4E zsOHHVq#G~3gxRVQfAm&-`f@y0uq%C}x+8_BLYdUa4yXY=kBwkqe783Y9EZ2>(^j%k>{Yf2NQOV z3A2v8ZI4X|GQk)o%y;xYoTbeXWR)zEWy@=$ zu-)_5vi2R8wtzi>WFE<@lU6MH7-N>IIFsi!dGVu#W`q@U^0G_}g8QTyOhu0+{hm*2 zsA*i^61O$M;qQ$e5$J=cj2$Vn^_^5k+=)RAunqYmh)08S=!>&miMF&=#G;V*PW9R zhnHP{bSYGpEQl?qd>wr&bJt>zWW}JvFv}f0w8E_csp0R{<*+`O(!$+b8{1^-mKuj2 zH8X7QxgwJ^0i8-a--_GwQk|&H{>j<5xD~&1ZNyqH5T=ThMbvfHt~|j?+-@fa07?NZ z@Ai7>#R%e3lO^{)Tl1Mc#kNQqp6h8f7Z6dJHU*Sie%4p7*$8F6J)$}-Gt#ZqX92+^ z;%wN9^ntPTqzCL1ud+QMF{e}w!Vajp%^dA-C~I-r2S4rDv0i!7pqx;P5$icHiH)>y zy;(OrrgB|K&e0nqs~l91LW*G63fxw5>Sv=LX-RiM>#-9Xbu6`QR2pht%f4EfE=N=UF zRDBsIaK-Ut+Vi{>J{c(F^O{u-4 zK<{aUOg=fJ6wAV-hY3i2EcK!7owNQ;+nd(6yOBqG#*F3TrVF{sU#LVi2DnVEw6Y|H zFUb}WU;ddAIP0r(Ia-_yU2o-!n%gLU{pFd1USq`Y!yTb-9P-9OzOVuGp&Xx#tX^s)7vIFsE@-8a#Dfj!& zXXkgVE=9Oqg>z|^vsZFJONLuHd*cki`n}dqt5TqUkF4QuodJw16}qANdEY1np6izi z4;rHP(@PZzjbhokS*mQl4qb|ZP;LP`!4%_N;Gp47I_I5XHm$~8G2X7a4aUW^qV0~^ zOJ}BI#A#)-!E~GX(X^7r%rV>ECNIr0XkdVaCf&To;wqF{VGVE^bTAUf!9oQSZMQE1 zowkOwDec4~=}a`3QyCg3c*x^k3nPSe0!q@ zVFY8$Uu>6GEipVj3!}%!(oY?QYkyl23F{c^Ffm1qo;>$u^5zh@V`DyFzdn^4RzJ>; z`*PKP9((d$0rt)l-q{m5&3Jk{?78gi_mMginE?`)~0ry z;n6ZlHMEQ^b`lAb;sOGwHfNla z1iD77do_;iTyZoFB|(_w#b}SRlP!N9)E=;YcK@rw^eMbidv?vK$vX`Jr%B$UCodT4 zGVv`FWM3V-c+wZnHPFB_Yj1~3(as~OHYM}Y~j+J&>jMyAkYqPDdAG)r2 z0_Z~EhX6V1Nrn;WDFZxAG@!mQ;)xRUH^zM;^B+{O;nIFOxO^#{i3%oM-hPcdylh01 zfktaWC^ZIjN)V=!9HP}Al(z-7z4=eyeG28Z={XH>S4E-{(jQtm5 z^%(lev5b6loDM_(t+>MsZD>52q3srbkfGi2TfcMyqkcq!?iT;Im&S(#Mo)FG!XfG! z0BEm)U}XWej6^qcKD|U!^1c`#NJ;(xK&jY3{zZTA(bc^STo#!ZMlj08%H;(B1OrzI z6i<}d;!@YwD-kY{We89iqnX6s1`X zfN~&zjdF-B0A|~Y{<18z@TI^ZYxV$$!0-O0i#i*6Wn=q&6_UX>DfCs)qv|rGf?st@ zTo^+YKqPpb@%YbBU7!6P5JH)}4(IP{g8_3=8Q11bDx8TATu&9*a-Zsr76@ks{J=&K z!S&nX(_#j~nMmLxP;SeJ>Srfv@Y@DuC%&OnaS?`?X@U}I(*JT{pko>IPN{b|SiX5`Gzk zmSRNG;eyV@EzL7-ep~Ks<( Date: Sat, 8 Jun 2013 02:44:41 +0800 Subject: [PATCH 255/276] :zip task now depends on :package. Rather than directly depending on ZIP_FILE. --- Rakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index cb79c190f..ba8bacf32 100755 --- a/Rakefile +++ b/Rakefile @@ -85,8 +85,8 @@ end directory DOWNLOAD_DIR directory PROB_DIR -desc "Build zip file" -task :zip => [:clobber_zip, ZIP_FILE] +desc "(re)Build zip file" +task :zip => [:clobber_zip, :package] task :clobber_zip do rm ZIP_FILE From 98a72a5a4cca21cce343e44f27330ed31ff8c608 Mon Sep 17 00:00:00 2001 From: Mike Henry Date: Mon, 10 Jun 2013 15:34:58 -0600 Subject: [PATCH 256/276] Update about_strings.rb Update single character representation test for Ruby 2. --- src/about_strings.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_strings.rb b/src/about_strings.rb index 24969826a..bb2859378 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -159,8 +159,8 @@ def test_in_ruby_1_8_single_characters_are_represented_by_integers end end - in_ruby_version("1.9") do - def test_in_ruby_1_9_single_characters_are_represented_by_strings + in_ruby_version("1.9", "2") do + def test_in_ruby_1_9_and_2_single_characters_are_represented_by_strings assert_equal __('a'), ?a assert_equal __(false), ?a == 97 end From 8ce0fb65065c15257d5c56fd08c6fecfd32e2bff Mon Sep 17 00:00:00 2001 From: michael-gebis Date: Tue, 11 Jun 2013 23:11:48 -0700 Subject: [PATCH 257/276] Trimmed artistic end message to 79 columns. On Windows, the standard terminal will insert a blank line after any 80-column line. Yes, this is a silly way for a terminal to work, but on Windows, this is likely to happen. Trimming to 79 columns makes things much less ugly. --- src/neo.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo.rb b/src/neo.rb index 06c60ca3f..1948b199f 100644 --- a/src/neo.rb +++ b/src/neo.rb @@ -268,10 +268,10 @@ def artistic_end_screen ,:::::::::::, ::::::::::::, :::::::::::, ,:::::::::::: ::::::::::::: ,:::::::::::: -:::::::::::: Ruby Koans ::::::::::::, -::::::::::::#{ ruby_version },::::::::::::, -:::::::::::, , :::::::::::: -,:::::::::::::, brought to you by ,,::::::::::::, +:::::::::::: Ruby Koans :::::::::::: +::::::::::::#{ ruby_version },:::::::::::: +:::::::::::, , ::::::::::: +,:::::::::::::, brought to you by ,,:::::::::::: :::::::::::::: ,:::::::::::: ::::::::::::::, ,::::::::::::: ::::::::::::, Neo Software Artisans , :::::::::::: From a380b44165435d9998c160e11c890fbf9d07cc4c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 2 Jul 2013 15:55:31 -0400 Subject: [PATCH 258/276] Updated email addresses. --- README.rdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rdoc b/README.rdoc index dc7c1739b..c18b083bc 100644 --- a/README.rdoc +++ b/README.rdoc @@ -177,8 +177,8 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby :: = Other stuff -Author :: Jim Weirich -Author :: Joe O'Brien +Author :: Jim Weirich +Author :: Joe O'Brien Issue Tracker :: http://www.pivotaltracker.com/projects/48111 Requires :: Ruby 1.8.x or later and Rake (any recent version) From ea66a6d175414f7166ec4026339a4ef55675ba59 Mon Sep 17 00:00:00 2001 From: smlance Date: Tue, 9 Jul 2013 09:40:01 -0400 Subject: [PATCH 259/276] Initial minor changes (grammatical in methods; require -> require_relative in tri...). --- src/about_methods.rb | 2 +- src/about_triangle_project.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_methods.rb b/src/about_methods.rb index 2a1c3fa10..bd6d8b3cb 100644 --- a/src/about_methods.rb +++ b/src/about_methods.rb @@ -37,7 +37,7 @@ def test_sometimes_missing_parentheses_are_ambiguous # end - # NOTE: wrong number of argument is not a SYNTAX error, but a + # NOTE: wrong number of arguments is not a SYNTAX error, but a # runtime error. def test_calling_global_methods_with_wrong_number_of_arguments exception = assert_raise(___(ArgumentError)) do diff --git a/src/about_triangle_project.rb b/src/about_triangle_project.rb index ec2447c51..0bf2aa9f0 100644 --- a/src/about_triangle_project.rb +++ b/src/about_triangle_project.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/neo') # You need to write the triangle method in the file 'triangle.rb' -require 'triangle.rb' +require_relative 'triangle.rb' class AboutTriangleProject < Neo::Koan def test_equilateral_triangles_have_equal_sides From 4e5b9ca9698989dd7c51e9d24e4e97a0602ad274 Mon Sep 17 00:00:00 2001 From: smlance Date: Tue, 9 Jul 2013 09:44:01 -0400 Subject: [PATCH 260/276] Fixed another small grammatical mistake (. to ? in dice file) --- src/about_dice_project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index 98717ba3c..b4581476d 100644 --- a/src/about_dice_project.rb +++ b/src/about_dice_project.rb @@ -56,7 +56,7 @@ def test_dice_values_should_change_between_rolls # # If the rolls are random, then it is possible (although not # likely) that two consecutive rolls are equal. What would be a - # better way to test this. + # better way to test this? end def test_you_can_roll_different_numbers_of_dice From cf615027345e1a73c2258d14acbe55dc363889a5 Mon Sep 17 00:00:00 2001 From: smlance Date: Tue, 9 Jul 2013 09:57:17 -0400 Subject: [PATCH 261/276] Made a minor readability change to a comment in about_blocks.rb --- src/about_blocks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/about_blocks.rb b/src/about_blocks.rb index af6f2074f..fa06eab65 100644 --- a/src/about_blocks.rb +++ b/src/about_blocks.rb @@ -70,7 +70,7 @@ def test_blocks_can_be_assigned_to_variables_and_called_explicitly add_one = lambda { |n| n + 1 } assert_equal __(11), add_one.call(10) - # Alternative calling sequence + # Alternative calling syntax assert_equal __(11), add_one[10] end From 0e6d826af44fda04ff6134d1a8d2e9ac9b4c1717 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 10 Jul 2013 17:25:39 -0400 Subject: [PATCH 262/276] Internalized assertions. This makes us independent of test/unit and minitest. --- src/about_message_passing.rb | 2 +- src/about_modules.rb | 2 +- src/neo.rb | 75 +++++++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/about_message_passing.rb b/src/about_message_passing.rb index 4301a956e..f6af2bf1c 100644 --- a/src/about_message_passing.rb +++ b/src/about_message_passing.rb @@ -122,7 +122,7 @@ def test_all_messages_are_caught def test_catching_messages_makes_respond_to_lie catcher = AllMessageCatcher.new - assert_nothing_raised(NoMethodError) do # __ + assert_nothing_raised do # __ catcher.any_method end assert_equal __(false), catcher.respond_to?(:any_method) diff --git a/src/about_modules.rb b/src/about_modules.rb index a96c66276..246831c41 100644 --- a/src/about_modules.rb +++ b/src/about_modules.rb @@ -44,7 +44,7 @@ def test_normal_methods_are_available_in_the_object def test_module_methods_are_also_available_in_the_object fido = Dog.new - assert_nothing_raised(Exception) do # __ + assert_nothing_raised do # __ fido.set_name("Rover") end end diff --git a/src/neo.rb b/src/neo.rb index 1948b199f..0e5a86743 100644 --- a/src/neo.rb +++ b/src/neo.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby # -*- ruby -*- -require 'test/unit/assertions' begin require 'win32console' rescue LoadError @@ -139,20 +138,68 @@ def using_win32console end end - class Sensei - attr_reader :failure, :failed_test, :pass_count + module Assertions + FailedAssertionError = Class.new(StandardError) - in_ruby_version("1.8") do - AssertionError = Test::Unit::AssertionFailedError + def flunk(msg) + raise FailedAssertionError, msg end - in_ruby_version("1.9", "2.0") do - if defined?(MiniTest) - AssertionError = MiniTest::Assertion - else - AssertionError = Test::Unit::AssertionFailedError + def assert(condition, msg=nil) + msg ||= "Failed assertion." + flunk(msg) unless condition + true + end + + def assert_equal(expected, actual, msg=nil) + msg ||= "Expected #{expected.inspect} to equal #{actual.inspect}" + assert(expected == actual, msg) + end + + def assert_not_equal(expected, actual, msg=nil) + msg ||= "Expected #{expected.inspect} to not equal #{actual.inspect}" + assert(expected != actual, msg) + end + + def assert_nil(actual, msg=nil) + msg ||= "Expected #{actual.inspect} to be nil" + assert(nil == actual, msg) + end + + def assert_not_nil(actual, msg=nil) + msg ||= "Expected #{actual.inspect} to not be nil" + assert(nil != actual, msg) + end + + def assert_match(pattern, actual, msg=nil) + msg ||= "Expected #{actual.inspect} to match #{pattern.inspect}" + assert pattern =~ actual, msg + end + + def assert_raise(exception) + begin + yield + rescue Exception => ex + expected = ex.is_a?(exception) + assert(expected, "Exception #{exception.inspect} expected, but #{ex.inspect} was raised") + return ex + end + flunk "Exception #{exception.inspect} expected, but nothing raised" + end + + def assert_nothing_raised + begin + yield + rescue Exception => ex + flunk "Expected nothing to be raised, but exception #{exception.inspect} was raised" end end + end + + class Sensei + attr_reader :failure, :failed_test, :pass_count + + FailedAssertionError = Assertions::FailedAssertionError def initialize @pass_count = 0 @@ -204,7 +251,7 @@ def failed? end def assert_failed? - failure.is_a?(AssertionError) + failure.is_a?(FailedAssertionError) end def instruct @@ -366,7 +413,7 @@ def a_zenlike_statement end class Koan - include Test::Unit::Assertions + include Assertions attr_reader :name, :failure, :koan_count, :step_count, :koan_file @@ -396,12 +443,12 @@ def meditate setup begin send(name) - rescue StandardError, Neo::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::FailedAssertionError => ex failed(ex) ensure begin teardown - rescue StandardError, Neo::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::FailedAssertionError => ex failed(ex) if passed? end end From 3a8f125dd7f8dd889ac3b6ba62ffbfb8d2068b56 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 10 Jul 2013 17:30:34 -0400 Subject: [PATCH 263/276] Shorter stack traces, even on exceptions. --- src/neo.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/neo.rb b/src/neo.rb index 0e5a86743..18e7ef734 100644 --- a/src/neo.rb +++ b/src/neo.rb @@ -356,11 +356,7 @@ def guide_through_error puts Color.red(indent(failure.message).join) puts puts "Please meditate on the following code:" - if assert_failed? - puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace))) - else - puts embolden_first_line_only(indent(failure.backtrace)) - end + puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace))) puts end @@ -383,7 +379,7 @@ def indent(text) def find_interesting_lines(backtrace) backtrace.reject { |line| - line =~ /test\/unit\/|neo\.rb|minitest/ + line =~ /neo\.rb/ } end From d85e9f09dc85b293383dec069f8d7d6d650822f1 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 10 Jul 2013 17:31:07 -0400 Subject: [PATCH 264/276] Update zip file. --- download/rubykoans.zip | Bin 38449 -> 38654 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index ec2da90aa65f4644f99e01252a98344f2b66ede8..44640d189707b67fd772142597fbd9793c9df6bc 100644 GIT binary patch delta 10563 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 R4`w69KZETGyjL3V{{YD>Cq@7O delta 10319 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 U;Ko?|2SeXt$zacd?p*==AAlBVQ2+n{ From 482ae6f86f7963035683c88ff2ba9b0e32f64af5 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 10 Jul 2013 17:40:36 -0400 Subject: [PATCH 265/276] Using the term 'modern ruby' --- src/about_strings.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/about_strings.rb b/src/about_strings.rb index bb2859378..c74bef2ad 100644 --- a/src/about_strings.rb +++ b/src/about_strings.rb @@ -151,7 +151,7 @@ def test_you_can_get_a_single_character_from_a_string end in_ruby_version("1.8") do - def test_in_ruby_1_8_single_characters_are_represented_by_integers + def test_in_older_ruby_single_characters_are_represented_by_integers assert_equal __(97, 'a'), ?a assert_equal __(true, false), ?a == 97 @@ -160,7 +160,7 @@ def test_in_ruby_1_8_single_characters_are_represented_by_integers end in_ruby_version("1.9", "2") do - def test_in_ruby_1_9_and_2_single_characters_are_represented_by_strings + def test_in_modern_ruby_single_characters_are_represented_by_strings assert_equal __('a'), ?a assert_equal __(false), ?a == 97 end From fa699e6eeb14378049bd1a9ac5165aac46c55677 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 10 Jul 2013 17:41:21 -0400 Subject: [PATCH 266/276] Update zip file. --- download/rubykoans.zip | Bin 38654 -> 38676 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 44640d189707b67fd772142597fbd9793c9df6bc..bd88cbbd9601bc9ab3da179f2d6a539751b9c665 100644 GIT binary patch delta 5053 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 I{b14m0fbpjssI20 delta 4969 zcmZ`-cQjn<*Pbymh#q}(qW3nUccP2lTlC&rh>-}<+hH(Kqq`x|ONdSoJ$eZdqPOHC zqI|gP{?__^>-+xN>zwnRv-f%Tv-f_UH?0cesuCkv5-3O@sn%wO0&)o?wNcOmT#Tpf zKp@c&#?pAL;(Y*oYv+hbF>dVv=>i!49psyQ29cdWDh3F|1I&;!VsaQw=q!x`SLBS~ zY=D7+42jsj3VBszry9du#G^~k?IJuBQd^yWP|T@f&ZX)2%Qiu|i|W#a2Bu4f=}QGM zM_wF*t(h!iCm%-bZrKSB3X8Kqk)%g?T=P_v<2)xQvjbR zq`_Fx4xMJx8+$D!e9&g`3t4ad@VIxN*zKF-yoa3|um*OFHz?zaA90&wb zYJlGXJ(N$7&b)x!=rgvihxVwhYIs&Wrqq(gsAou~7`<1aLjo4}OsC#=<3_g0Z(ZI! zCrW9rl#Hup7Ci`m=cMo8(Hf8vS`iHA(&P#6vtA=d7CvoLu|}@}XDXTBs>?r<@Op#= zT*^7l$S?&{e)zu)5H1J|{TmDdK}kU%P`bXEC$Su9*bk#@ z*@>Ezw~U&9WMeV;5{gRD(MR5byL7YTbMS02GsPX`>E~VfMp%XP`|pb%f95QRURZLx z@+uZCIkRQabg?Z(#Z(t<_Y6BjLFDDW&5*x z_bgqvq)0ctzHC)%ldty;3d%b8z7*Cpkp%+9>-+6IxNtn^b1q}yoh*y_vz*<(>ZeLZafteaG5co4x0m&9I%f(}UbFGUGz= zqCxnmDy7wIn2|WK2`c1xbOH8oizq6jR2vd-E$Lic{&%CU(WYLns^tmW$bhC` zcom;pv2W%B6^NkIhduEiOWp3@E8v$#GDp%@g^F2Z$!1M)#};)5*ow5Rl-)#HT2xy; zcoZ7>39ly$Wd97!5EF4132n1!^Tx52mp+Tl?X4-B-GgrSjb67VNPvF0L!P#svvJ z(DUscp=C^#^5-J<-P{>#q8!#lg+Gfa2fB{YeO}h|tg<=Y?*0MSa4a-km@Qe%!JsA@ zNQzz?e!tG(gwKw#Zex#ZGxALs%Rq~c)?f!yfhs>1EHm%&-HZOsuU=xB(&FB&tjy7o zvC^LN;QKqk|t^cWq4tCO~>SPJmMwf#sg5J z$ONpw|4($c87+8B$`U<0HHz<2aOba@?}~#F!gQa9GkM=Q!OV&A#3I3kZMBr-k5QRw5fY=aAtcS1zP zQDup57}&iqrcyPL>gh+R22PF@*umLKU=Uk3x2y?N&eF$rMN+T+*^WD&=W|nU zcycwa-MBI8XAP-O3-v@Y3?__OZ{LH;=rCSXl1><-=B=lOgqC2G%XKwEg*0>Ye{{@ zYelJ?aV_4Y4;ANcA1OMA24C$CQ|7kQ$RPJF4-iH{R*vfIq*TFntEEM|Jy29d6i%~7 zphjRZZU}OvYcl%q&9vo~gs6DCQwE&3?tSGTubFK<7gSXZ!;H~YW13)R0+DX!q=c%e z68w_Ss^8~qk%HD|OdixlBF~=wKDxlopH}Nnp7I<0vt!yKC`_0Nkw^)aoL&(?*l@Kr z7|w`|R6b5UuQ8DKwOMQ};xJ+NgwpCzS(&&6x+8ntrE!zs5{VCONL;A9ODSPU42s;I zJ(^aoZPW$f^;s?Y62Dy8@_f`emdZ4jAq3rkgd>y^@K-(e2TrAS`UA52svT|41BfSM z52g08WMcMr?{{w@lYhjz&Umx79#rwDQ!TM#{l1r*9#m-Y!PTG8@Y`u*_a0#*o*ql} zBjk45i9k_6!Bxa`T|bJ6Lb!Nr+Vm-!!%=tOL~GJ~&*8g=?0j&tkLgQ?I{jZwOK)f0 zS3(fm;umJYi>OeFNDsAIw%-L~e~u4Me^U^18|g>d>6jUczlLMsA73UCh*?gzC{nfwJemPAvMs|0QU!A&6wIW&{>y38C ztXe9XP8Z_pl#Qc{>FeN7*N`El=9<8@aYI9_x`5h`6}wm))5#522xnQhN+(5m5~d}^ zZ%+sF^+(KR5i-(NG&+49q zHOqwyF&mC^{p=X@=;_rS$v0Bo)oI6Ddbt)W+SoM=IOmAW9xWwDsi6Qa3VbZmcj99+oJ!`|EpX zM}c2i!Xt04BH}EjG^)#3{&$u3K7Mk3-&YRpq)Ztt4rARpHK?O%)r6OFu7X%!o5Kvu8lpb{GoZivImp9G*1cmuK!R3q2oPT?WwUYMqjdg#(TXi znpm(#d#u-1FbO-T^YfHLi=RQfj?O8FPDKaD++S0s%7&wDI$P+uXQX}y(eL|9g>$!U%R14-6Ow+(;V`UvBnMjtqY)`o#V zoxm4crhoH&VM~j=KdX%AZ=zEtKtsBR5|L~4a}xZeKtq(KXtv9)%UIrIIez`IkiA`5 zch?O@-V>v-e3Tm!)GDD?yYRvl^PtI^@ef)rD>-|<&WM27Tpe9a$9OP;lwc_$d^Prr zHEa7sBFFf#?TTg*PKYxiLl5$x$=XHqBEM`G#O#KFf~zBm4HRFbEXbRnh}I(SO}QP# zcY&_pS`4DL@@3#qLsMosu~(?f256@)_$40aYVw-kyO8BjdX_8=@f{R?;*42ISJ~5_ zOQ&iqiN*SC%q1l?@|Pct5)<1hy;mxg zUURQ3Qa%^<3g^m^{St1+G;8$Hx-%t7xQOzn=nFe+fp^{hV`gQ~f54t_cK#(- z!AB$;KQG*%@%oDRtP{Ab&r6%Hp1f*kKRLyUc1Fh`T~!ts@VYT8`LKs@Y=RRBUkt_a z6eLgBchH3HWSeE`Ktz<@H_@=0qZ~iuO*=ZMz0-`$!Mt#dd-Y#HzwPOrAyB$g@I0@_KMEZ>#4E!bX;~N#L}zW9PY)Tv?^kDOQ@D{ zgo^rScH}0@c0oyNSZIOnjvR+!e>UecS=u+OFH>0vCDsDGwCQ>lFe~sj0(2Y2me3!u z>Uuu1{0bu6=d0UGjBwNS?}zG$O@4Wj#UaJ{3|SbwkFC6%;=dz`WF9XZN5U!n^SMx( zORN_}8w(cmmSt&Aaf}>)P|&XoFC-x?JAY4&B^mnW#X1o*8|rD+;>F!Rk6j<&%p8*_ z9^(Fy6BRi*MxAgTuCVS_ACLR^5ZuBV6g2V5WRO`AMiKL~{nKB7t9%h6V2Bo9= z*Y>qaP6syrrT`PF-OC_4DBB>lm&}&n#G$BrBqQ^6K8-8>fy@xT*w@CUFJB2n zPRbOg5{u2^?7tG^42q2h1z=lt2@CZZv>@Y0RC}gVm=VI1<}^tSh81qKmO-TLYb?CN zjq@j#zfM^ls$y$Kv!3KzS8>1L3}rL5e?8y}Tj%M8#%V%p8=_6-(oEA=o81v%mp+FV zB^C^LNjs(~Jn>;%8LJl$@}E4?w=W&SAiV#O+eH1L`T1qH*84WrW8NX%SX0N10j;X0K(N(-K?ReGpCNR;_CaQ7og1V-FN zgZ@&7_g?tf=y1o*E_Pwd*3SVbF0TlZNv!@;@?zCPW9Tcik64ctu%;l?vRu1b8^+ax zpK0*RGPG5kwu?U9-)jJJunt%6prtzNDT&Od(#nYWG&NmQRT`vSFvUqpYP>lWzop9P zk|ukoq9+yT5BC(AO<3(^>r>O;65==$?%fCN>7Eh~7+mAU>k5Wuj`87m3JvIB3e0py zqG7Yx-fLIiT-IgYhR7*IaUc{L_4&f{PcFyjsSD+g7cf55Y~sf4&70wxx({qy^v*w? z^bh%a(uaevji(FHb@{tqep~t)bT^(Y07@X-nen#$7CQId@o^XTmVZQkxwlt7>y2t; z00cb$e>JHirQOX>v~Hh9vtv-QGrSQmM6NU0|TRu}2xIFv5M7)@ljO3DUZU>8^5vF?@e*oCC0UE*n zoSP<_3Cbxi#)AC(L3x&u%rYodrVK&urp)anMK9gjz zOK6@uq^^q}6l2EltA~r82Rmo1_2+Rbk(F^h#%8)AJt?S@iWb3d2eFyQN}}M<=MyvI zZ`Ud)SBp@tu@PUd9IaOKL+`QsOnl8IXi%Ni$f8^@!;^^O)oZ%v$+=D{<&|+=XcX(a zwFD#A!#Zppb2{{UW_x{>WB71B7?JLxQ6)62pn3H@v%O;Y5B@e!7zoJqQn}sbO|QB; zvXkqh0lqzY0WN)2?yRw&`7KFm@S`KT8-_1??$%{Txj+Ex1n5oe{(Iy?63YjCN_kLg zAA2)9Zyv$^k^FmcVt{qZ13)#N3ev>^0#-O^fZh~Vpe&vWtPFI=Ti+aKFejLTYXD?| z6_^S5nqUDI1*8(K!9GB4qCJF91_WrzFam5zOt)X9{*T-u0D;IslsCEy1iC>3sOUKw za7v=P34tCcPNIW&sDOZE6*%xUN%qDML$VPhO9KRa(1720Z%(FyAhke1ffgNb8OsV# zrBH$O07Qxt_yLfc;t26Dy?NV|9$-to^Gf?4u7?Ezk^Yz0eG3pkWJ&SwN}x2A3KC@v z0^V9P0v0K()F%J329p0BZymr2+{XI=a0I9zdd?u=xicKd0c63{z%n3t`?oaz0sD=> zr2j9!_dJ2TG&;aIg$syCqXI_*xoHkyc>tFF1e^glrJG@#_yWD@hG18K2BiZI20T!< QU=3gbC5hSf>UPim2gqp&TL1t6 From 35e93072f6381ba9c24437c56615b8c346a155d0 Mon Sep 17 00:00:00 2001 From: Harshad Sabne Date: Wed, 11 Sep 2013 14:28:31 +0530 Subject: [PATCH 267/276] Code fix (Update README.rdoc) Applied correct tags to display "gem install rake" as code in rdoc. --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index c18b083bc..590854799 100644 --- a/README.rdoc +++ b/README.rdoc @@ -36,7 +36,7 @@ Windows from the command prompt (+cmd.exe+) c:\ruby --version c:\rake --version -If you don't have +rake+ installed, just run +gem install rake+ +If you don't have +rake+ installed, just run gem install rake 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. From 9485ec734f91fbe01c0b67c48cf069238fcaa467 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 1 Oct 2013 21:41:42 -0400 Subject: [PATCH 268/276] Don't answer the first few questions (#120) https://github.com/neo/ruby_koans/pull/120 --- download/rubykoans.zip | Bin 38676 -> 38674 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index bd88cbbd9601bc9ab3da179f2d6a539751b9c665..20a9a9af9f29a3513f8b133114901f1843ca1bfb 100644 GIT binary patch delta 3536 zcmZ`*c|4Ts9)B2*j5SQg(kN?aLLb?Wb4s1G7>R4LHZuyROekcH2RCIctw^2W zR-}cFOxkN2PN{GRXc`~5A?Go@$bOU}rv2Ky5f zv;Y8efpL?ESFtK>ZbORyFT(HK3ZjC75QM%877~=dQ=wN`3B|vB{XJ4cF@^dBn97>ppY7EXwV< zGDlzUr@nXduY4Ga>4h!pT!NpBo_c8&QN4V3iv0-LDDmPH#kM)`2)mSIc$41aJwuK8{;@XcBcV>Gn=cAn zq6#al?>kTVM)#O^3;0(#F>q>rX2Z`TX^ph0NtMabs%I^omm?OBMpu@!)vjjx^%c~f zZoM>2c5SG=|IzNlJz8q{&Pr0;C+k5o`t)9>TK|oeCSBY1@e+bumy)OD@8#!3{P)$K zYY!=KG=8RV+ld}8l0oc4cqH4z^W%-O1CO3-Mtk*91rAfEIoI31?Kon z+m4^-XFsOi@gOE~17+G(yZ=fF<;iEmW!;6{d+&}v=+*v|nJ(}bm{O9ohBWF!CYlAe zE150%^9o$nd}eq?jnJs?hZ*ztKdAc2>hb!HvC_0HDg?7p@5zDG*3O=r+}N$l9QqD- z3Fc+k-E!}LnvlvP;D-tRM+fWq@45~0;z?-Mvy*h1KdM(w5W^V;Rv6rB@B)Poo7iCR zU6VMJ#KX)HgL!84C`_f&F*uAGkHYsXZ82Dp=7+)|)>t$wu$~kP$+E#z^Do#CQ6bmp zi!qK*bO)5fZmE>MsHM-)m09JCQS*7uGbo(y?tqb8cHf0A$8yF}3{GKK6VaVnDOHlE zE9+1t={{0$i%%U&vfhu1k>vOpqXHWPq@o7`n$hTzASr=2gASr_RIoEfay&R6)$JJK zguzK6b5Vimp;E1E3-uz1mfC~R{mD-r07s~_*_bzbog^hI1386BWZ6acO;gB|!d|-i z?um6O!{Hlj6q;7Jt<;(~Z*6JJv2S~dVL+(vL)Cxr+lR;WTv^bT)u6q>GBDPtrh*go z;@2;m{QVPcw9UC;^ENTfziuN@l~}Eh?kc=Xoq4VKLd$mWMVST1&Y*y8UYW^Lt2p&7 zFrJpN^KE9pp)?22BH(!Zr1mx4i`(7gqn{hyUQ!5@XdXKC9oFYxYprODa@P4x{eN5T zKkMQZJ-&PNpk7*`%lL<(U03V4Cks|>x2h*qn3j^i<>MMS|v)BCJDu?@>3+rAQykFf>*Grse;U;(-ax7*#x*GDE&gPA^n|kMI zk36EZrSva}?#;;R+ELeC^Xg^CW3{daXEc7 z-}jPr>hVoi_$|y`F|VM}YUs`$=)qiSX|?_9sBe~AcFp5M?13ippc#{7wUg%pX&ZTR zGRt4Zl$z;B%n5WHZ$(Ir<4i;%I!SDn6nu7oRwH)dbsUTKee zOHt;;EUEXhI?Ee{N3)$3gxdh`9EK0D8C+e^>(e z+>#=FLR6B=*#?5AND17LI^c8o!mj*<616LYg6fu-6UGsG3uOSbarCJ+0K_DO$8#2k zZ%IhvhDC>SqW`8otH+#nQxK8}L?anT(h7M6rjm>zd3n~a#;+>?(5)g{OmjF;fE82h z1-x$?MuP3sWxcpU_d?8zC^)6(YEA@VdI!>CW1Ng6SY5bCB16=P0r`uAnn)K)GypKf z1utO$7|1Y@uB*7QfkkAwDi~d4h-cD!Bk;~a(uN^A@l%!L1Knahhnbx|k*j7L$w>lL<+oh`UfDX?G$`lD8At7A+jp zsH|zf8gns1-3N+lwtM z0Ml8x3W|JJM4ZyCK`LmE%mRJ^Xs{m|$oMuaCCe{JfHkFtDnGm_NW^B%Fof+0;>HB$ zy%JWJTFS8fSxS~$3yEdsv$!^_DVu{1TNzod0Y;Ze42php7w#-$hry5~vf#oGKR!y_ z*_{<_uId<;ux=JV|hTWWo>K7*ZCF|Ax3(j?9HjUtoN>#jI+5H=(MF nUKKM|NU$|xT?1#GnKi45%Vveg|06aMmu;flXii@?;syL4BEasU delta 3548 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 Date: Tue, 1 Oct 2013 21:51:07 -0400 Subject: [PATCH 269/276] Remove require_relative (#117) Require relative is only available in modern rubies. Let's keep this working on some of the older versions as well. https://github.com/neo/ruby_koans/pull/117 --- src/about_triangle_project.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/about_triangle_project.rb b/src/about_triangle_project.rb index 0bf2aa9f0..2ac9d9ad0 100644 --- a/src/about_triangle_project.rb +++ b/src/about_triangle_project.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/neo') # You need to write the triangle method in the file 'triangle.rb' -require_relative 'triangle.rb' +require './triangle' class AboutTriangleProject < Neo::Koan def test_equilateral_triangles_have_equal_sides @@ -22,4 +22,3 @@ def test_scalene_triangles_have_no_equal_sides assert_equal :scalene, triangle(5, 4, 2) end end - From 832e5e4ab5163ab5b16db8923b7ee52595d5e9c1 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Tue, 1 Oct 2013 22:54:48 -0400 Subject: [PATCH 270/276] Updated the zip file. --- download/rubykoans.zip | Bin 38674 -> 39686 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 20a9a9af9f29a3513f8b133114901f1843ca1bfb..4a4ef3f7643b7026f35d5a523099bb3ad14c72d2 100644 GIT binary patch delta 4963 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 K)9Gmj{Of;<@FLv+ From 6622cf0d9933fea92f6db856881468df182b2997 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 13 Nov 2013 23:11:26 -0500 Subject: [PATCH 271/276] Fix typo in Rakefile --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index ba8bacf32..45f5df42c 100755 --- a/Rakefile +++ b/Rakefile @@ -125,7 +125,7 @@ end task :run do puts 'koans' - Dir.chdir("${SRC_DIR}") do + Dir.chdir("#{SRC_DIR}") do puts "in #{Dir.pwd}" sh "ruby path_to_enlightenment.rb" end From 174defbd1a202b71b2c56a89e98bd6fa5e28dc22 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Wed, 13 Nov 2013 23:13:26 -0500 Subject: [PATCH 272/276] Added clarification note about sending messages. --- download/rubykoans.zip | Bin 39686 -> 39819 bytes src/about_message_passing.rb | 7 +++++++ 2 files changed, 7 insertions(+) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 4a4ef3f7643b7026f35d5a523099bb3ad14c72d2..f5d286e942fc6fdbcb802133016f08d6bb6068ce 100644 GIT binary patch delta 2790 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 delta 2661 zcmZvec{r4N8^@oSi3pRmm}Yp9u?@#E(llX+vNJfAp|Ta(Mj=YfkuyLH z$C9#>8l*W{M(S`(mga4Djy2`H%>477_j><$uIKZ7@9+J)?&rDg>wfO62k@&c@Z7@) zdZxpD3;Yg5dZt6;`5hvX+X6_I9^Ae+I>_X~1TZ5z1CuIgu{<)U>D18+gP?IREU!k} z^0;kZaS0L-Y{&AJzC#{@pt?Lu>T3hZw9lIg)Zw2$vhe(7@7-oi-3~k8>FHzpZ58?|x}+)mCr1jxIk@wH&_U`}k*cmWbzPul1O(TAA!F(S1rT z+(oIbrMd7?(BwsMea)|)rRfHhnkQYrFQ8PSAFiPF>$A$w<;yA$8nBPpqcwQyo#$HH zHqh+7A`RWUkA@8pJbEPJJJbVg(UobkVw(4pQ`vKOvmGMzQWhwtHT4e%2&b7haAOBo z>_XWZPX-#hW5U6TRBA1GA^EP(%Ch7#|K?OvZ)eaC{LqrTM`iB*G?5+6hzU?mSG8JwT9Es4MlSRSS98E*r6%U_qrWe)&b)>D73&c++USOjS@!t%(jDXB z(Z1*nqQZ1n9{RQ4y7HkX%qLfV`!GJLu$G!K;4q+uj+390sr>PC{lIXEe^a(NgW$1l zae6^V^Urw;sf_WPF1nLG9q;p#10@mr`A3)kxY*pw9*m6$K4iiz?i&!lY&c{#{X6v{ z4FLxC2)d(DeD6G5&;*N0g9rh1Vib1>U{dw2FqFQ3N(iBvRYH)~NfiPMrzPy69z8Q* zI?OO!7@`{Q5fPk|e(t}MKb>W&cO`1 zBHP8G>2^*dCtEN1PJvCr&-Tw21NGxn7e-tXd1bDiL%R~K+7GVJdZ(LT+PO;m6pmm0 zdh>Z}{_~y}?6FOgLzu~p_#!1Fd{M zMio`7+a}>&XfuSrV9%O3@SwKue81It^_{pBE~6U9L=L*KM{cYgZtnl+OH;S}QmCO( zdX}$-lG%6s-Q!mJ4=&CpdtNk}Qt8n~=*OeZU^Gvbw39Yoq4BJa;3d+_Uej(MlPWPFn6APAiboS4+07z2~~&TVAQasd8Iv zc@Vsj`09h%vl+4|r9kO$XS)sYaBxH2MNI}u|E;49_2}n}`1(7uHH$055W@HHXnF|51!G$tt2iRRG9z#C6~RS{Y2 zcWnYM!b{<|C!XzTb9GqB+in~`WQmFt?p;-V9kTS&OEnzk=6F?8ezQ7LFYF${*J)3J zPwe_}LoV6pgwgSqDA%upzEsfwZt$1kJNQ{2Mu{uym%*bR}_om;$B)~myO6D_1|n5 z0q(g*&(6jR>&T%$m7M1Zdw$4X58F{wfRvc`@L1*0c2D-vc>i|iyBW9HF&peZjfhk} z7)RhR_k#V*jl}N& z)-~Q~0b3f{+6<3`Ezz#Nf-Uh&XP{|go-ZEn)8~kkF7bBnAK?BW$0{xiMqo^L^4^(# zkLxylz5C4jMQ!;U%jr1;AtG9G#2&)_dCmII$4| zt9cwoS^y`~`h?c~^diy!Sv!Up2A~M217#)(#s&l?1yQX80k)C~CbgbNM=Q8;C=noC0bqz8dp zdWwR~Ap_)Y#jRZig0{9As4}I^00OTJFo2tb1w`Y2#&nG#U~jw+NavAYmVlh+k4Q9w zK#`gHc1`>K`78VHGYg%pG`6$0H Date: Thu, 19 Dec 2013 15:17:00 -0500 Subject: [PATCH 273/276] Fix 'accidental' solving of first 3 koans --- download/rubykoans.zip | Bin 39819 -> 39817 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index f5d286e942fc6fdbcb802133016f08d6bb6068ce..73aff89792b023021f15fc1144c62b0378bed8df 100644 GIT binary patch delta 2731 zcmZvdX;4#F6vuA}izpO`pukI_VT(Y5VUw+hh+3ARfFQPFAqchXVF@mXpeUjS5V?S5 zu_DEBP%PNMs342zV1jj8N5P5}v9e9Up;`eIi+#Lj-pj*&$cOj4_kYg+o^$Vs|TWgqvNH?Ru%O2{gbQD2vRjz_bcd7O-!CQ6K+o5vjosor%;X=x>W2b zdMwb&ot!fe-97uF%weqgD;@Wy&c;Z?MisZkP5!sLqUCU`c5dd!VV>W8;dvv0FgSB) z#+yHIDNq05xvBW+uv=%D61C9Dt#8xbtvW92P)Cdc`d(^xydH|b51Y2S1U??Cd!B6_ z^~2izdmToMS0rDXX4*7JYEnxW>>h#4%a>{X%(OlAYU?ahwp^{TQ)g40+$H43lHF~l zk>1SOT*e~q<*Y-pq56Ek1pdL1ZB7>&uE||?7MAlKI8Xb;$jrOt($2JaIIVr?V$eud zz18%T*3{VPCrw@LQLD#ds)}2xgN50?eFfDQny(KVyIrh)Fk}1ro>fNK?kYy&8{RWB z!R%qDYQODOoSSjEqA%U-jb~Nvc4*Pf#x_ko&1mkD^@tOqT^;)>Z^|`uZ11=a{2|K7rc-X0S6zMj(_$3>tTh2J z089`sicCs_FP0e)_eOJhy$W`3t{T}9@TJiyItC>y9s%1~&v97Gu_53iP7*HnHFF~1 zQL}S66mV?`7{e9eu-|eu0d=kXa2U=bcEU2=G?x4XpS;O8`09A_9)W;R(`?t^YFB&G zk;r}ke@21ML`dmT=MOkM?!JbQ-*(@RKbbE)90-`>(Wr)Hcic!GJ!WGKo?Y9AgzJ22 zaQU$BDnhRB$H6T*`;$B4{TuO}>;TeIXh1m*Uj@1la=V}c+-KJoX9ChfHE~PYVPuOo zg>Aqs6@*(6JKMvf@$BZ2@cfgy)vx5vPxkbJ8sD0baOSi3=T_Z_pDmF=c4JBjx*2z8&S8R^UbX-dRBC7fjAO z1p>-WRv|)@L6<_7f^z03?b4g$TKnk$gntIm_hyLBc>vG>3u+J6838CWTA{866avg( ze<4E8WC2*oGE!PvKOd{4ImagieZ7Mk0F9&^tCR!qx4b%XhbUbf5hY4W6GtYA(`-_A zYzZMVte6k;&rnl^1P$|KF#sG&7&q8>!jj@<_5?!bZ~9sNdd!!pJgRQ_8MHkPYV&_$%FjTWNG+3C6ppnxRVQB;!z6R|C^?8`4%nMjBB1J<w%?SW4$|2REph90!Qfx1qX*#hFb-Whs w8Jn_KALdk03*A$Juttw4$|O#WjZFG3;oAizg6v8*?HlM`>8<{kWPW1(2M`ISod5s; delta 2911 zcmZvddt8%c6vvjV@h<<^Ki~J9-#Olw zCMQx{I{?5eaIibJ#?sHcbYJ4?*w}5IF=ku}AsEN?GA|>nE06n)1%_*EJg{N$7u#Tw zO%-O=wjr2pirdqbX!|?|!xMa>sE0TCH#wGXz8@L0H9oQmtS{{B8@ZSLw=jC2+r+0i?!yC-=Wo?l z?UF@mf6C@v4K2uiSUjkEtGd})bGrYDO(&vCKOSv8B79>{>5}yPxbnjuyZYu^?by+5 z@~{;M{=5=r8ByxH^H#UggIB&`f%nTV@<)5hR$NKwy>Ny9!rSV@lZ|20s)j9@cG<$x zwidqhfoS~Op*EQ~FJ!RO@n~6LRA5xW)*elV;%keIBc*MjcWiXpVs+G!Y|+?z{ona| zsh{ILcQPS*Fm+XV_b$PUHahW#2bJX&LC>#0KK^Bvw7>uSlflD3*gc4F`KwXNzwt?P z?7g~hug^NW9ewgI*`A3yvFCzW^OLFXMh~nXJ``zw?7H)(PYtz$uQH!rHSp_iMH9*8 zo{q2f6qw5^*6dK;c;q+G-lQmQ$++8|G^^>=f}ttJ9Nsetf?G$ROSOw;W3i?DP43~0 z6+=2{UGdJqpL#!8u`YAs_GZiSFE!Tm*Qw|3)D|7GcHpa8CKcy4N-76c+3DdS*P4b0 zcpvC)a}*1q3kOQvspGJ3Ppcku2ytvPP@Ii6mOBu9EO60?VR88TX4(g&b;W zw+t?i2{xCaeL%mi-7y`eIC{`>L+P2zTS;__cms@%ZzUTyoZ!u9@)KQ2N}($amRT!1 zh@~)zsj_QrQUihG$q|fuK#GRs*|#p7fm7>dlawq{4J}%hx{Rb$k>-o9g?``9rlphU z?vh{zrb)&LOi33pa8LSnqWNc*0s3WYiDsY7kFlJPo&N8zC_)%Gq7V}pusw`{^6mKq zj^qY0&_iiYV2p|cLhXRLDj)pDudBSVp`Kkk&o=tn}h~gh5 z&Bx@Lxs(G4BY1W@RP z!kd*s9D%N)IfF2)%F&?ViVnGW?nk4%LJEL1D}Xl79^HHZ(6I$=FCTRPu;0O%YYHeP z*=W5>XG)&)0CGvT20*}aDRKn*<&`TJOSUM~s?E|IiBg%NT$HCmSn}^^G|IxU#IH;E8G`~iH;-=3w2lUp+yRwzWtNzDLQz)J2M ztf_G`#KG1TqMz?x-~!OkGcMd8{#IjL_<1mK<~Fhpv;lx-X^UZ!*4;=u|59I>6!k9; z^~Z%}T?jk0-Ue%YR3^1FClU&vCxy-mGb(A2=6J&b=rqGx|DS&b(iDgXkdAj?Jwc?t zo1-yBz2@i%rchu$EAUVPdnn{tIsY37+!uK*&GCc#YK`L#*3y)15`dzl$MnUoj;3xW z18s^YD<}NWS!w(3kD;gYRe#7S~YO189hySRw4;)dQXeYpf!yr>UpX0hFZU7i2abuT}lelggdw^_HRuXRp=0 zEcOd3^JQBUIm}uyGB~3KY5V+UGy%b;`ajc|Yjp~a*EMsk1YXzKf104H-@^z9&0#~a9zOKYI1U=@H#su|T!e>~Gb z3!!SdPJBcb?U1OXFXZCW!6X%|A2x5R?Yv9q`k00Rz+=@oOFb%XFg8+QNz From ad08a8de35084430178c295197ede668bb9d3c01 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 13 Jan 2014 15:07:30 -0500 Subject: [PATCH 274/276] Handle version 2.1 --- src/about_iteration.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/about_iteration.rb b/src/about_iteration.rb index c14e5fb92..2a595dd84 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -3,10 +3,10 @@ class AboutIteration < Neo::Koan # -- An Aside ------------------------------------------------------ - # Ruby 1.8 stores names as strings. Ruby 1.9 stores names as - # symbols. So we use a version dependent method "as_name" to convert - # to the right format in the koans. We will use "as_name" whenever - # comparing to lists of methods. + # Ruby 1.8 stores names as strings. Ruby 1.9 and later stores names + # as symbols. So we use a version dependent method "as_name" to + # convert to the right format in the koans. We will use "as_name" + # whenever comparing to lists of methods. in_ruby_version("1.8") do def as_name(name) @@ -14,7 +14,7 @@ def as_name(name) end end - in_ruby_version("1.9", "2.0") do + in_ruby_version("1.9", "2") do def as_name(name) name.to_sym end From 0fb9b21a4e745bd1e6e467d80f5ba05f7d42988c Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 13 Jan 2014 15:16:46 -0500 Subject: [PATCH 275/276] Fix require to include ./ --- src/about_triangle_project_2.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/about_triangle_project_2.rb b/src/about_triangle_project_2.rb index 55dd742fe..fdeb8dbb2 100644 --- a/src/about_triangle_project_2.rb +++ b/src/about_triangle_project_2.rb @@ -1,7 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/neo') # You need to write the triangle method in the file 'triangle.rb' -require 'triangle.rb' +require './triangle.rb' class AboutTriangleProject2 < Neo::Koan # The first assignment did not talk about how to handle errors. @@ -14,4 +14,3 @@ def test_illegal_triangles_throw_exceptions # HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions end end - From 8068f1f106c8f535bded1b7b6b01047f76a6bf43 Mon Sep 17 00:00:00 2001 From: Jim Weirich Date: Mon, 13 Jan 2014 15:16:57 -0500 Subject: [PATCH 276/276] Latest zip file --- download/rubykoans.zip | Bin 39817 -> 40269 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/download/rubykoans.zip b/download/rubykoans.zip index 73aff89792b023021f15fc1144c62b0378bed8df..60b497b0fd2978f379f5e3400ed2b7ef97dfeccd 100644 GIT binary patch delta 4136 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 F{{x#AeDMGP delta 3610 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 QXmWnfbAtSNVdby?0KUS40{{R3