diff --git a/.gitignore b/.gitignore index ffb9a5a..f30bc80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ dist .project_env.rc .path_progress +.rvmrc +.ruby-version *.rbc koans/* +*~ diff --git a/DEPLOYING b/DEPLOYING new file mode 100644 index 0000000..3b91dc3 --- /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 diff --git a/README.rdoc b/README.rdoc index 7ca4f59..5908547 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 @@ -69,14 +69,16 @@ 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 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) @@ -98,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: @@ -106,22 +108,49 @@ 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 + +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 on 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 @@ -148,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) diff --git a/Rakefile b/Rakefile index ab77d19..45f5df4 100755 --- a/Rakefile +++ b/Rakefile @@ -2,25 +2,17 @@ # -*- ruby -*- require 'rake/clean' -begin - require 'rdoc/task' -rescue LoadError => ex - # No rdoc task availble. -end 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) @@ -40,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| @@ -90,30 +82,25 @@ 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 DOWNLOAD_DIR directory PROB_DIR -file ZIP_FILE => KOAN_FILES + [DIST_DIR] do +desc "(re)Build zip file" +task :zip => [:clobber_zip, :package] + +task :clobber_zip do + rm ZIP_FILE +end + +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 @@ -138,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 diff --git a/download/rubykoans.zip b/download/rubykoans.zip new file mode 100644 index 0000000..60b497b Binary files /dev/null and b/download/rubykoans.zip differ diff --git a/src/about_array_assignment.rb b/src/about_array_assignment.rb index 35af856..a08f512 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 35c951d..a415538 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 5ac6b55..88c3100 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 7fefcd9..fa06eab 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 @@ -23,7 +23,7 @@ class AboutBlocks < EdgeCase::Koan 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 @@ -70,7 +70,7 @@ class AboutBlocks < EdgeCase::Koan 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 diff --git a/src/about_class_methods.rb b/src/about_class_methods.rb index 2cadbaa..a352d2d 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 a8336bf..48c8054 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 @@ -147,7 +147,7 @@ class AboutClasses < EdgeCase::Koan end def to_s - __(@name) + @name end def inspect diff --git a/src/about_constants.rb b/src/about_constants.rb index dd0bc39..49d2b5a 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 1e799e6..6fedd70 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 @@ -131,4 +131,12 @@ class AboutControlStatements < EdgeCase::Koan assert_equal [__("FISH"), __("AND"), __("CHIPS")], result end + def test_times_statement + sum = 0 + 10.times do + sum += 1 + end + assert_equal __(10), sum + end + end diff --git a/src/about_dice_project.rb b/src/about_dice_project.rb index 65c21df..b458147 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 @@ class DiceSet end #++ -class AboutDiceProject < EdgeCase::Koan +class AboutDiceProject < Neo::Koan def test_can_create_a_dice_set dice = DiceSet.new assert_not_nil dice @@ -56,7 +56,7 @@ class AboutDiceProject < EdgeCase::Koan # # 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 diff --git a/src/about_exceptions.rb b/src/about_exceptions.rb index f243982..b4ad63d 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 @@ -48,7 +48,7 @@ class AboutExceptions < EdgeCase::Koan result = nil begin fail "Oops" - rescue StandardError => ex + rescue StandardError # no code here ensure result = :always_run diff --git a/src/about_hashes.rb b/src/about_hashes.rb index afb17b3..ef58621 100644 --- a/src/about_hashes.rb +++ b/src/about_hashes.rb @@ -1,10 +1,10 @@ -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 - assert_equal({}, empty_hash) # __ + assert_equal(__({}), empty_hash) assert_equal __(0), empty_hash.size end diff --git a/src/about_inheritance.rb b/src/about_inheritance.rb index 73030c6..3a119c0 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 2e35aa9..2a595dd 100644 --- a/src/about_iteration.rb +++ b/src/about_iteration.rb @@ -1,12 +1,12 @@ -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 - # 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 @@ class AboutIteration < EdgeCase::Koan end end - in_ruby_version("1.9") do + in_ruby_version("1.9", "2") do def as_name(name) name.to_sym end @@ -39,19 +39,17 @@ class AboutIteration < EdgeCase::Koan def test_each_can_use_curly_brace_blocks_too array = [1, 2, 3] sum = 0 - array.each { |item| - sum += item - } + 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| + array.each do |item| break if item > 3 sum += item - } + end assert_equal __(6), sum end @@ -86,7 +84,7 @@ class AboutIteration < EdgeCase::Koan 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| product * item } assert_equal __(24), result2 # Extra Credit: diff --git a/src/about_java_interop.rb b/src/about_java_interop.rb index c2d2142..83c2a21 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 @@ include Java # * 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 new file mode 100644 index 0000000..1addb39 --- /dev/null +++ b/src/about_keyword_arguments.rb @@ -0,0 +1,31 @@ +require File.expand_path(File.dirname(__FILE__) + '/neo') + +class AboutKeywordArguments < Neo::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_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_keyword_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 882716e..84f4787 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? @@ -63,6 +63,13 @@ class AboutMessagePassing < EdgeCase::Koan assert_equal __([3, 4, nil, 6]), mc.send(:add_a_payload, 3, 4, nil, 6) end + # NOTE: + # + # Both obj.msg and obj.send(:msg) sends the message named :msg to + # the object. We use "send" when the name of the message can vary + # dynamically (e.g. calculated at run time), but by far the most + # common way of sending a message is just to say: obj.msg. + # ------------------------------------------------------------------ class TypicalObject @@ -93,11 +100,11 @@ class AboutMessagePassing < EdgeCase::Koan # 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. @@ -122,7 +129,7 @@ class AboutMessagePassing < EdgeCase::Koan 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_methods.rb b/src/about_methods.rb index b720010..bd6d8b3 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) @@ -37,7 +37,7 @@ class AboutMethods < EdgeCase::Koan # 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 @@ -130,7 +130,7 @@ class AboutMethods < EdgeCase::Koan 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 # ------------------------------------------------------------------ diff --git a/src/about_modules.rb b/src/about_modules.rb index 334b175..246831c 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 @@ -44,7 +44,7 @@ class AboutModules < EdgeCase::Koan 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/about_nil.rb b/src/about_nil.rb index 9df4f9b..0c084d7 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 1faf0a0..0d75258 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) @@ -30,12 +30,6 @@ class AboutObjects < EdgeCase::Koan 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 diff --git a/src/about_open_classes.rb b/src/about_open_classes.rb index 80df888..0372f50 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 7e8be03..3f969f6 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 @@ end # 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 @@ class Television 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 03e8f9a..76bd566 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 e641b13..1314ec8 100644 --- a/src/about_sandwich_code.rb +++ b/src/about_sandwich_code.rb @@ -1,11 +1,11 @@ -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) count = 0 - while line = file.gets + while file.gets count += 1 end count @@ -66,7 +66,7 @@ class AboutSandwichCode < EdgeCase::Koan 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 @@ class AboutSandwichCode < EdgeCase::Koan 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 f6843c8..4760a9a 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 @@ -19,7 +19,7 @@ class AboutScope < EdgeCase::Koan def test_dog_is_not_available_in_the_current_scope assert_raise(___(NameError)) do - fido = Dog.new + Dog.new end end diff --git a/src/about_scoring_project.rb b/src/about_scoring_project.rb index 60b4682..4031eb4 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 @@ -90,6 +90,9 @@ class AboutScoringProject < EdgeCase::Koan 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 diff --git a/src/about_strings.rb b/src/about_strings.rb index dd13fec..c74bef2 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) @@ -42,6 +42,7 @@ It was the worst of times. } 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 @@ It was the worst of times. 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 @@ -149,7 +151,7 @@ EOS 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 @@ -157,8 +159,8 @@ EOS 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_modern_ruby_single_characters_are_represented_by_strings assert_equal __('a'), ?a assert_equal __(false), ?a == 97 end diff --git a/src/about_symbols.rb b/src/about_symbols.rb index 720ca8c..5963c65 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) @@ -50,14 +50,14 @@ class AboutSymbols < EdgeCase::Koan 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 diff --git a/src/about_to_str.rb b/src/about_to_str.rb index 68c40b2..669a4df 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 da23bbd..2ac9d9a 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' +require './triangle' -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) @@ -22,4 +22,3 @@ class AboutTriangleProject < EdgeCase::Koan 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 0a57e25..fdeb8db 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' +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 @@ -12,6 +12,5 @@ class AboutTriangleProject2 < EdgeCase::Koan 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 - diff --git a/src/about_true_and_false.rb b/src/about_true_and_false.rb index e9910f6..470489e 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/array_test.rb b/src/array_test.rb deleted file mode 100644 index 83ec07b..0000000 --- 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 8fbf617..0000000 --- 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 708baf1..0000000 --- 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 - - diff --git a/src/edgecase.rb b/src/neo.rb similarity index 82% rename from src/edgecase.rb rename to src/neo.rb index 40c9607..18e7ef7 100644 --- a/src/edgecase.rb +++ b/src/neo.rb @@ -1,7 +1,6 @@ #!/usr/bin/env ruby # -*- ruby -*- -require 'test/unit/assertions' begin require 'win32console' rescue LoadError @@ -65,7 +64,7 @@ class Object end end - in_ruby_version("1.9") do + in_ruby_version("1.9", "2") do public :method_missing end end @@ -83,7 +82,7 @@ class String end end -module EdgeCase +module Neo class << self def simple_output ENV['SIMPLE_KOAN_OUTPUT'] == 'true' @@ -139,20 +138,68 @@ module EdgeCase end end + module Assertions + FailedAssertionError = Class.new(StandardError) + + def flunk(msg) + raise FailedAssertionError, msg + end + + 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 - 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 + FailedAssertionError = Assertions::FailedAssertionError def initialize @pass_count = 0 @@ -195,7 +242,7 @@ module EdgeCase @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 @@ -204,7 +251,7 @@ module EdgeCase end def assert_failed? - failure.is_a?(AssertionError) + failure.is_a?(FailedAssertionError) end def instruct @@ -221,7 +268,7 @@ module EdgeCase 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 @@ -237,7 +284,7 @@ module EdgeCase end def end_screen - if EdgeCase.simple_output + if Neo.simple_output boring_end_screen else artistic_end_screen @@ -268,13 +315,13 @@ module EdgeCase ,:::::::::::, ::::::::::::, :::::::::::, ,:::::::::::: ::::::::::::: ,:::::::::::: -:::::::::::: Ruby Koans ::::::::::::, -::::::::::::#{ ruby_version },::::::::::::, -:::::::::::, , :::::::::::: -,:::::::::::::, brought to you by ,,::::::::::::, +:::::::::::: Ruby Koans :::::::::::: +::::::::::::#{ ruby_version },:::::::::::: +:::::::::::, , ::::::::::: +,:::::::::::::, brought to you by ,,:::::::::::: :::::::::::::: ,:::::::::::: ::::::::::::::, ,::::::::::::: - ::::::::::::, EdgeCase Software Artisans , :::::::::::: + ::::::::::::, Neo Software Artisans , :::::::::::: :,::::::::: :::: ::::::::::::: ,::::::::::: ,: ,,:::::::::::::, :::::::::::: ,::::::::::::::, @@ -309,11 +356,7 @@ ENDTEXT 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 @@ -336,7 +379,7 @@ ENDTEXT def find_interesting_lines(backtrace) backtrace.reject { |line| - line =~ /test\/unit\/|edgecase\.rb|minitest/ + line =~ /neo\.rb/ } end @@ -366,7 +409,7 @@ ENDTEXT end class Koan - include Test::Unit::Assertions + include Assertions attr_reader :name, :failure, :koan_count, :step_count, :koan_file @@ -396,19 +439,19 @@ ENDTEXT setup begin send(name) - rescue StandardError, EdgeCase::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::FailedAssertionError => ex failed(ex) ensure begin teardown - rescue StandardError, EdgeCase::Sensei::AssertionError => ex + rescue StandardError, Neo::Sensei::FailedAssertionError => 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 @@ -465,7 +508,7 @@ ENDTEXT class ThePath def walk - sensei = EdgeCase::Sensei.new + sensei = Neo::Sensei.new each_step do |step| sensei.observe(step.meditate) end @@ -473,9 +516,9 @@ ENDTEXT 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 @@ -487,6 +530,6 @@ ENDTEXT end END { - EdgeCase::Koan.command_line(ARGV) - EdgeCase::ThePath.new.walk + Neo::Koan.command_line(ARGV) + Neo::ThePath.new.walk } diff --git a/src/path_to_enlightenment.rb b/src/path_to_enlightenment.rb index 64621bf..9e8ccbe 100644 --- a/src/path_to_enlightenment.rb +++ b/src/path_to_enlightenment.rb @@ -12,6 +12,9 @@ require 'about_strings' 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' diff --git a/src/test_helper.rb b/src/test_helper.rb deleted file mode 100644 index 9accf96..0000000 --- a/src/test_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test/unit' - -def __ - "FILL ME IN" -end - -EdgeCase = Test::Unit