281 Commits

Author SHA1 Message Date
Tony Schneider
e072392099 Merge pull request #55 from Hikelio/master
add tip about parentheses in regex in AboutMethods
2026-01-10 08:31:33 -05:00
Tony Schneider
fb05c506f0 Merge pull request #56 from werebus/integer-object-id
Fix assertion about the class of `Object#object_id`
2026-01-10 08:30:36 -05:00
Matt Moretti
411e86e5c3 Fix assertion about the class of #object_id
In Ruby 2.4, `Fixnum` and `Bignum` were unified into `Integer` and the
"bigness" of that integer became an internal implementation detail.
Because the koans support some pretty old rubies, we can't make a
universal assertion about the class of `Object.new.object_id`, but it
always `is_a? Integer`.
2025-12-23 10:26:27 -05:00
Ikelio
f2699f0ae7 add needed tip in AboutMethods 2025-02-23 21:41:04 +01:00
Tony Schneider
8e70162472 Merge pull request #54 from kaya3/patch-1
Enable 'about_pattern_matching' for Ruby 3
2025-02-01 13:23:04 -05:00
Andrew Kay
9082c4378a Enable 'about_pattern_matching' for Ruby 3
This set of koans seems to work perfectly fine in Ruby 3, so AFAICT there's no need to gate them to 2.7.
2024-11-21 17:40:07 +00:00
Tony Schneider
0bcbe408e7 Merge pull request #48 from edgecase/ts/ci
Add initial GHA workflows
2023-08-15 08:52:59 -04:00
Tony Schneider
9687825fe0 Add initial tests that run Jim's "checks" 2023-08-15 08:51:54 -04:00
Tony Schneider
ec0ae9dc99 Merge pull request #51 from bo-tato/bo-tato-observr-patch-1
fix path for observr
2023-08-12 07:40:58 -04:00
bo-tato
8a56b2bd16 Merge branch 'edgecase:master' into bo-tato-observr-patch-1 2023-08-09 12:40:48 -05:00
Tony Schneider
104b7f67b4 initial gha workflow 2023-08-09 07:34:49 -04:00
Tony Schneider
6f919cdb01 Update rubykoans.zip 2023-08-09 00:39:23 -04:00
Tony Schneider
59b29e7b86 Merge pull request #17 from Wolwer1nE/pattern_matching
Added pattern matching koans
2023-08-09 00:34:43 -04:00
Tony Schneider
c2538ad118 Merge pull request #35 from varun-iyer/master
Add a koan for mandatory keyword arguments
2023-08-09 00:33:31 -04:00
Tony Schneider
3334d7df48 Merge pull request #15 from Interdictor/master
Add test_default_value_attribute to about_hashes.rb
2023-08-09 00:32:38 -04:00
bo-tato
6fc6906274 fix path for observr 2023-08-04 22:16:55 -05:00
Mike Doel
3bb8d5da68 Upgrading to heroku-22 2023-04-03 10:18:06 -04:00
Tony Schneider
51f25cf68d Merge pull request #38 from wolfsblu/master
Replace deprecated exists call
2023-01-24 17:31:01 -05:00
wolfsblu
49a18944ed Replace deprecated exists call 2023-01-06 11:25:50 +01:00
Wolwer1ne
71196f474b Fix typo 2022-10-17 11:43:38 +03:00
Varun Iyer
c7a56e50fa Add a koan for mandatory keyword arguments
Previously, `about_keyword_arguments.rb` asked the reader
to reflect on the fact that keyword arguments must have default
values. However, this does not seem to be true anymore in Ruby.

This commit replaces that comment with two koans that guide the
reader through validating and using a method with mandatory
keyword arguments.
2022-08-15 14:12:39 -07:00
Tony Schneider
0659d2a672 Release rubykoans zip 2022-03-03 00:17:21 +00:00
Tony Schneider
18c3504596 Merge pull request #32 from merryfaceTech/reorder_koans
re-order
2022-03-03 00:14:44 +00:00
Tarik Merrlees
aa614489b4 re-order first few tests to better match beginner's ability and progression 2022-02-25 15:39:10 +00:00
Mike Doel
93e33b001c deployment package updated 2022-02-13 22:13:58 -05:00
Tony Schneider
e79e874a18 Update ruby koans download 2022-02-13 15:01:04 +00:00
Tony Schneider
561965bb6a Use alt example in about_open_classes
Integer#even? ended up in a more modern version of ruby (yay progress!). This updates the koan to use a different, more outlandish example, that I don’t think will end up in Ruby — and that I know Jim would appreciate <3
2022-02-13 14:54:14 +00:00
Tony Schneider
250aaa44ab Update README.rdoc
Update issue tracker to GitHub issues
2022-02-13 11:22:56 +00:00
Tony Schneider
cd9bbe3df8 Merge pull request #30 from rnestler/patch-1
Fix name of parallel array assignement test
2022-02-13 11:02:53 +00:00
Tony Schneider
79fadeff4d Merge pull request #18 from tongkiat/doc
Update README.rdoc to show new progress indicator
2022-02-13 11:02:24 +00:00
Tony Schneider
453777ead0 Merge pull request #28 from mattschouten/master
Add support for Ruby 3
2022-02-13 10:58:31 +00:00
Raphael Nestler
353e281470 Fix name of parallel array assignement test
There are two variables and just one value, so I think
`test_parallel_assignments_with_too_few_values` is a better name.
2022-02-10 14:44:52 +01:00
Mike Doel
b77b8d90d8 Remove Neo from README 2021-10-02 17:39:06 -04:00
Matt Schouten
08945a10a1 Add support for Ruby 3 2021-09-09 16:30:31 -05:00
Tong-Kiat Tan
580c1fcf7d Update README.rdoc to show new progress indicator 2020-06-16 14:04:18 +08:00
wolwer1ne
7163953851 Added pattern matching koans 2020-06-10 18:46:03 +03:00
interdictor
e647408062 Add test_default_value_attribute to about_hashes.rb 2020-05-21 22:45:22 +02:00
Mike Doel
7d152b8afc new package with progress indicator 2020-05-21 08:29:52 -04:00
Mike Doel
45c0ff2a20 Merge pull request #14 from japf/user/japf/progress-percentage
Display progress as percentage
2020-05-20 10:54:39 -04:00
Jeremy Alles
dc5bbb58f8 display progress as percentage 2020-05-11 14:17:27 +02:00
Mike Doel
e3b4ac36b0 Regenerate download for ruby 2.7 fix 2020-02-28 09:16:29 -05:00
Mike Doel
33ed452081 Merge pull request #13 from edgecase/fix_27
Fix Ruby 2.7 behavior change
2020-02-28 09:09:58 -05:00
Mike Doel
3efe58ac1e Resolve #12 - behavior change in ruby 2.7 2020-02-24 10:03:00 -05:00
Mike Doel
4d2a32cbd1 remove inadvertent gzip files 2020-02-18 15:33:16 -05:00
Mike Doel
943f4dc543 new package file 2020-02-18 15:26:05 -05:00
Mike Doel
ff3795a815 Eliminate warning about method_missing being redefined 2020-02-18 15:06:35 -05:00
Mike Doel
c486b81dd4 Merge pull request #3 from derekgottlieb/replace-watchr-with-observr
Replace unmaintained watchr gem with observr fork
2020-02-18 14:30:22 -05:00
Derek Gottlieb
f9929c21d6 Replace abandoned watchr gem with maintained observr fork 2016-11-19 15:35:23 -06:00
Mike Doel
a1d3902b01 Merge pull request #2 from neo/master
Pull back from neo organization
2015-03-12 13:43:48 -04:00
Jim Weirich
8068f1f106 Latest zip file 2014-01-13 15:16:57 -05:00
Jim Weirich
0fb9b21a4e Fix require to include ./ 2014-01-13 15:16:46 -05:00
Jim Weirich
ad08a8de35 Handle version 2.1 2014-01-13 15:07:30 -05:00
Jim Weirich
c57b275de8 Fix 'accidental' solving of first 3 koans 2013-12-19 15:17:00 -05:00
Jim Weirich
174defbd1a Added clarification note about sending messages. 2013-11-13 23:13:26 -05:00
Jim Weirich
6622cf0d99 Fix typo in Rakefile 2013-11-13 23:11:26 -05:00
Jim Weirich
832e5e4ab5 Updated the zip file. 2013-10-01 22:54:48 -04:00
Jim Weirich
8d7dd30c0b 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
2013-10-01 21:52:10 -04:00
Jim Weirich
e746cd33f4 Merge pull request #119 from harshadsabne/master
Code fix (Update README.rdoc)
2013-10-01 18:44:59 -07:00
Jim Weirich
9485ec734f Don't answer the first few questions (#120)
https://github.com/neo/ruby_koans/pull/120
2013-10-01 21:42:47 -04:00
Harshad Sabne
35e93072f6 Code fix (Update README.rdoc)
Applied correct tags to display "gem install rake" as code in rdoc.
2013-09-11 14:28:31 +05:30
Jim Weirich
fa699e6eeb Update zip file. 2013-07-10 17:41:21 -04:00
Jim Weirich
482ae6f86f Using the term 'modern ruby' 2013-07-10 17:40:36 -04:00
Jim Weirich
068c9357c9 Merge branch 'master' of https://github.com/mhenry07/ruby_koans into mhenry07
* 'master' of https://github.com/mhenry07/ruby_koans:
  Update about_strings.rb
2013-07-10 17:37:45 -04:00
Jim Weirich
d3b06902d8 Merge pull request #111 from smlance/changes-1
Minor changes to existing koan files
2013-07-10 14:36:28 -07:00
Jim Weirich
d85e9f09dc Update zip file. 2013-07-10 17:31:07 -04:00
Jim Weirich
3a8f125dd7 Shorter stack traces, even on exceptions. 2013-07-10 17:30:43 -04:00
Jim Weirich
0e6d826af4 Internalized assertions.
This makes us independent of test/unit and minitest.
2013-07-10 17:30:43 -04:00
Jim Weirich
2202e07785 Merge pull request #104 from michael-gebis/master
Cosmetic change for the benefit of Windows users.
2013-07-10 13:45:10 -07:00
smlance
cf61502734 Made a minor readability change to a comment in about_blocks.rb 2013-07-09 09:57:17 -04:00
smlance
4e5b9ca969 Fixed another small grammatical mistake (. to ? in dice file) 2013-07-09 09:44:01 -04:00
smlance
ea66a6d175 Initial minor changes (grammatical in methods; require -> require_relative in tri...). 2013-07-09 09:40:01 -04:00
Jim Weirich
a380b44165 Updated email addresses. 2013-07-02 15:55:31 -04:00
michael-gebis
8ce0fb6506 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.
2013-06-11 23:11:48 -07:00
Mike Henry
98a72a5a4c Update about_strings.rb
Update single character representation test for Ruby 2.
2013-06-10 15:34:58 -06:00
Jim Weirich
7c2b5fe273 :zip task now depends on :package.
Rather than directly depending on ZIP_FILE.
2013-06-08 02:44:41 +08:00
Jim Weirich
8dd3acae41 Update the zip file with the latest changes. 2013-06-07 06:02:26 +08:00
Jim Weirich
d5b787cd2b Beefed up the greed scoring tests just a bit. 2013-06-07 06:01:01 +08:00
Jim Weirich
8122d347f0 Merge pull request #94 from jasonnoble/patch-1
Update .gitignore with .ruby-version
2013-06-06 14:43:54 -07:00
Jim Weirich
b8fa86ed1e Merge pull request #95 from ArturMoczulski/patch-1
Fixes a silly typo in the method name
2013-06-06 14:43:06 -07:00
Jim Weirich
3f49c8f000 Merge pull request #99 from StevenNdaye/about_keyword_arguments
Wrong class name from AboutMethods to AboutKeywordArguments
2013-06-06 14:39:47 -07:00
Jim Weirich
ad5f6f5fe8 Fixed missed sum => product change 2013-06-07 05:38:44 +08:00
Jim Weirich
4509e0c8fe Merge branch 'patch-1' of https://github.com/backspace/ruby_koans into product
* 'patch-1' of https://github.com/backspace/ruby_koans:
  test_inject_will_blow_your_mind uses an incorrect memo argument name
2013-06-07 05:36:33 +08:00
Jim Weirich
799f583ff3 Merge branch 'patch-1' of https://github.com/adlersantos/ruby_koans into curly
* 'patch-1' of https://github.com/adlersantos/ruby_koans:
  corrected example code in test_each_can_use_curly_brace_blocks_too
2013-06-07 05:32:53 +08:00
Jim Weirich
623e21fc18 Updated zip file to latest changes. 2013-06-06 23:04:18 +08:00
Jim Weirich
4ba9f3c142 Add zip task for building zip file. 2013-06-06 23:03:44 +08:00
Jim Weirich
718538b729 Add ~ files to ignore list. 2013-06-06 23:03:33 +08:00
Adler Santos
dfaeb570e5 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.
2013-06-03 02:18:29 +08:00
Buck Doyle
1ce6d52963 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'.
2013-05-13 16:48:57 -03:00
Steven Ndaye
6b66d46156 Wrong class name from AboutMethods to AboutKeywordArguments 2013-05-13 11:22:02 +02:00
Artur Moczulski
f4d9dc0db7 Fixes a silly typo in the method name
in method_with_keyword_arguments_with_mandatory_argument
2013-04-24 00:24:09 -07:00
Jason Noble
24a0069c20 Update .gitignore with .ruby-version
.ruby-version is the new .rvmrc, although .rvmrc is used still.
2013-04-14 11:53:37 -06:00
Mike Mazur
610e219fa5 One more EdgeCase -> Neo change in the Rakefile
Fixes #92.
2013-04-12 09:23:21 -04:00
Jim Weirich
d7b5a6120d Added deploy instructions. 2013-04-09 16:04:07 -04:00
Jim Weirich
e947652bcf Zip file goes in download directory.
Moving the zip file to the source tree so it can be downloaded.
2013-04-09 15:19:32 -04:00
Jim Weirich
12639186cb Fix order of comparison in about symbols to follow standard. 2013-04-09 11:27:30 -04:00
Jim Weirich
197dd8eff8 Clarify the difference between here docs and multi-line strings. 2013-04-09 11:27:30 -04:00
Jim Weirich
63753656af Fix prematurely correct answer. 2013-04-09 11:27:30 -04:00
Jim Weirich
f3560581ce Removed RDoc 2013-04-09 11:27:30 -04:00
Jim Weirich
5119038f9c Merge pull request #83 from TheTeaNerd/dk-explain-watchr-in-README
Explain Watchr use in README
2013-04-09 07:52:32 -07:00
Jim Weirich
86cb9c5a27 Fixed times example. 2013-04-09 10:46:13 -04:00
Jim Weirich
a079acbacd Merge pull request #89 from lucasrcosta/master
Added Times Statement in Control Statements
2013-04-09 07:45:19 -07:00
Jim Weirich
dc8f73f107 Remove test_helper.rb 2013-04-09 10:40:49 -04:00
Jim Weirich
09b03e9b1c Change EdgeCase to Neo 2013-04-09 10:40:27 -04:00
Jim Weirich
67750bf9bf Fix missing blanks in about hashes. 2013-04-09 10:33:43 -04:00
Jim Weirich
7eb51a9a30 Remove unused files. 2013-04-09 10:33:43 -04:00
Jim Weirich
f2e4a1f357 Make each do/end usage more consistent. 2013-04-09 10:33:43 -04:00
Jim Weirich
ceca9875cf Merge pull request #87 from weilu/remove_unused_variables
Remove assigned but unused variables
2013-04-09 07:13:04 -07:00
Jim Weirich
957b672d7a Merge pull request #86 from weilu/fix_indentation
Fix indentation
2013-04-09 07:12:05 -07:00
Jim Weirich
e150dd6d9e Fix private message error for JRuby. 2013-04-09 10:10:24 -04:00
Jim Weirich
f03e0d21ee Add keyword arguments (with correct answers). 2013-04-09 09:45:23 -04:00
Jim Weirich
58238ef54a Removed fixed object_id koan
This koan is not as important now that Ruby 2 has changed all the
object ids.
2013-04-09 09:30:33 -04:00
mfeckie
9c5ecb509a Add support for Ruby 2.0 2013-04-06 13:23:56 +08:00
mfeckie
cb14e48f1d Add tests for keyword arguments in Ruby 2.0 2013-04-06 12:18:41 +08:00
mfeckie
405c42eb81 Updated Sensei for 2.0.0
Add support for Ruby 2.0.0
2013-04-06 11:31:32 +08:00
Jim Weirich
2df8e5554d Added todo for EdgeCase to Neo conversion. 2013-04-01 19:10:47 -04:00
Adam McCrea
213aece7e9 Move to Neo 2013-04-01 17:11:02 -03:00
Adam McCrea
5c5ffc645d Move to Neo 2013-04-01 17:09:01 -03:00
lucasrcosta
4d41bab6e6 Added Times Statement 2013-03-10 14:31:05 -03:00
Wei Lu
aa3c83f044 Remove assigned but unused variables 2013-02-28 18:59:58 +08:00
Wei Lu
676d9ce8ac Fix indentation 2013-02-28 15:44:28 +08:00
David Kennedy
f36a964fdd 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.
2013-02-14 14:22:11 +00:00
David Kennedy
eedfeb1022 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.
2013-02-14 13:21:06 +00:00
TheTeaNerd
4ca68510b0 Merge pull request #1 from TheTeaNerd/dk-ignore-rvm
Ignore RVM config if the user wants to use it
2013-02-14 04:57:48 -08:00
David Kennedy
5f3a6a19f2 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.
2013-02-14 12:51:00 +00:00
Adam McCrea
1a073e5db5 Merge pull request #66 from oflannabhra/patch-1
Test that constants are symbols by comparing strings
2012-11-26 06:17:39 -08:00
Marc Peabody
9cb57ef35f Merge pull request #77 from thebinarypenguin/about-hashes-bonus-question
Modify test to better illustrate point
2012-06-05 12:19:07 -07:00
Ethan Zimmerman
7f29082e95 Modify test to better illustrate point 2012-06-05 14:22:14 -04:00
Marc Peabody
75ba956176 Merge pull request #72 from Erkan-Yilmaz/master
missing: ) + first example output adapted
2012-03-08 06:35:36 -08:00
Erkan Yilmaz
f3d20b8e14 seems screen output of the 1st example changed 2012-03-08 14:03:45 +01:00
Erkan Yilmaz
03caa9b349 add missing: ) 2012-03-08 13:57:01 +01:00
Matthew Boston
7bef32522e Merge branch 'master' of github.com:edgecase/ruby_koans 2012-02-23 11:19:54 -05:00
Matthew Boston
48fd6fdb1e Merge branch 'master' of github.com:edgecase/ruby_koans 2012-02-10 16:32:45 -05:00
Matthew Boston
7d0550259b Merge branch 'master' of github.com:edgecase/ruby_koans 2012-02-10 16:32:34 -05:00
Matthew Boston
bd94b445de Merge pull request #70 from saterus/master
Switch from Autotest to Watchr
2012-02-10 13:32:14 -08:00
Alex Burkhart
6af4597b80 Use rake instead of directly invoking path_to_enlightenment. 2012-02-10 19:36:50 +00:00
Alex Burkhart
a565ac232d Removed autotest. Added Watchr script. 2012-02-09 18:57:31 +00:00
Matthew Boston
711564c452 remove line-ending whitespace 2012-02-07 22:16:52 -05:00
Matthew Boston
34d1127f98 whitespace cleanup 2012-02-06 23:17:48 -05:00
Matthew Boston
8926a0d96b Merge pull request #68 from liuhenry/master
Fixed color support in OS X
2012-01-27 10:51:25 -08:00
Matthew Boston
c014f6db04 update Rakefile to use pre-defined directories 2012-01-27 10:39:22 -05:00
Matthew Boston
2625f10997 not sure why the extra line was thrown in... 2012-01-27 10:34:00 -05:00
Matthew Boston
d1ab51e7cd updating README with directions for generating the koans 2012-01-27 10:26:46 -05:00
Henry Liu
907c1fc0be Fixed color support in OS X 2012-01-22 00:20:40 -08:00
Matthew Boston
212e29b659 Merge pull request #64 from RichLewis007/master
Fix typo in comments in about_sandwich_code.rb
2012-01-03 12:05:21 -08:00
oflannabhra
b44b5f8bb2 Compare strings instead of symbols for constants, similar to method names. 2012-01-02 22:33:46 -05:00
Rich Lewis
63a7f27313 removed duplicate word "The" in comment. 2011-12-20 15:42:07 -05:00
Jim Weirich
e76be64f9d Added koans directory to the .git ignore list. 2011-12-04 02:48:20 -05:00
Jim Weirich
2ddd929473 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.
2011-12-04 02:47:24 -05:00
Jim Weirich
a83000b4d3 Restrict assert checks to .rb files. 2011-12-04 02:41:54 -05:00
Jim Weirich
a3fcc3904a Updated koans directory from source. 2011-12-04 02:40:08 -05:00
Jim Weirich
d92f3234c7 Added __ to assert with no __ blanks. 2011-12-04 02:39:29 -05:00
Jim Weirich
007eeff1d8 Removed support for Ruby 1.8.6. 2011-12-04 02:35:47 -05:00
Jim Weirich
4633ba5c79 Add a dummy KeyError to 1.8 so that src koans will run. 2011-12-04 02:14:42 -05:00
Jim Weirich
5665cb0366 Handle 1.8 VS 1.9 differences in fetch exception. 2011-12-04 02:03:10 -05:00
Jim Weirich
6592f3d36e 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.
2011-12-04 02:00:22 -05:00
Jim Weirich
51acb84736 Silence complaint about Rake::DSL 2011-12-04 01:58:29 -05:00
Jim Weirich
f9d3bcbb37 removed deprecated require of rake/rdoctask 2011-12-04 01:18:23 -05:00
Jim Weirich
1a17730862 updated koans with latest src 2011-12-04 01:17:59 -05:00
Jim Weirich
271dff2353 Fixed :each VS "each" conflict in method list inclusion. 2011-12-04 00:57:08 -05:00
Matt Darby
6001bec44b Merge pull request #60 from lagartoflojo/master
Fix a small typo in the comment.
2011-10-14 18:10:32 -07:00
Hernán Schmidt
95f7fba8ae fix typo in message 2011-10-14 20:56:47 -03:00
Matt Darby
a53c815da0 Merge pull request #47 from ahmed80dz/master
colors in windows using win32console gem
2011-10-07 16:24:23 -07:00
ahmed80dz
ad3b4f76aa as suggested by sunaku 2011-10-07 23:55:12 +02:00
ahmed80dz
595f2af341 finally it worked well 2011-10-07 23:13:32 +02:00
ahmed80dz
176de995b8 Edited koans/edgecase.rb via GitHub 2011-10-07 22:34:53 +02:00
ahmed80dz
dd36e171b0 testing for win32console 2011-10-07 22:18:59 +02:00
Matt Darby
e2c4cb6c07 Merge pull request #52 from dandorman/hash_fetch_koan
Add koan addressing Hash#fetch.
2011-10-07 12:58:45 -07:00
Matt Darby
2871422507 Merge pull request #53 from dandorman/hash_default_block_koans
Add koans addressing passing a block to Hash#initialize.
2011-10-07 12:56:59 -07:00
Matt Darby
e5197a9417 Merge pull request #54 from bsodmike/master
Others may find these tweaks useful...
2011-10-07 12:56:07 -07:00
Matt Darby
63089bc5fe Merge pull request #55 from deanh/master
Minor 1.8 v. 1.9 fix and typo
2011-10-07 12:53:21 -07:00
this guy
42847962b4 Fixed discrepancy between results for obj.methods in 1.8 v. 1.9
(String v. Symbol) and what looked to be a typo.
2011-09-08 22:04:43 -07:00
Michael de Silva
c160ee8b03 few more enlightening tweaks 2011-09-09 00:16:21 +03:00
Dan Dorman
6acc65ac92 Add koans addressing passing a block to Hash#initialize. 2011-09-08 09:48:41 -06:00
Dan Dorman
7c34268f84 Add koan addressing Hash#fetch. 2011-09-08 09:46:02 -06:00
Michael de Silva
db594e16fd tweak for a more enlightened Regexp koan 2011-09-08 16:23:01 +03:00
Matt Yoho
58565c8686 Merge pull request #50 from daemianmack/master
Fixed a typo.
2011-08-31 14:06:49 -07:00
Daemian Mack
3371a31885 Fix typo. 2011-08-31 18:02:16 -03:00
Daemian Mack
75d1505a44 Edited src/about_symbols.rb via GitHub 2011-08-29 21:44:30 -03:00
Matt Yoho
f2f122dab1 Merge pull request #49 from daemianmack/master
Fixed a typo.
2011-08-29 12:48:08 -07:00
Matt Yoho
8807fcbe44 Merge pull request #48 from daemianmack/patch-1
Edited src/about_nil.rb via GitHub
2011-08-29 08:41:29 -07:00
Daemian Mack
0a4f89cae3 Edited src/about_nil.rb via GitHub 2011-08-29 17:34:35 -03:00
ahmed80dz
0032cee9a6 Edited koans/edgecase.rb via GitHub 2011-08-23 14:28:00 +02:00
ahmed80dz
4be1620759 forgot requires 2011-08-23 02:34:01 +02:00
ahmed80dz
6fd8668b70 using windows32console gem for colors 2011-08-23 02:24:10 +02:00
Isaac Sanders
dfb272e626 Merge pull request #46 from connormontgomery/patch-1
Fixed a typo.
2011-08-18 04:23:27 -07:00
Connor Montgomery
0ae75e0dbd Fixed a typo. 2011-08-18 02:21:03 -05:00
Matt Darby
3d8391174b Added a note on how to (optionally) install rake. 2011-06-03 11:21:25 -07:00
Matt Darby
007afa4017 Merge pull request #33 from tjkirch/string-fixes
Small fixes to about_strings
2011-06-02 19:39:40 -07:00
tjkirch
3e6d01a15b Clarify string length versus line count 2011-06-02 22:35:00 -04:00
Matt Darby
ac3b3d6957 Merge pull request #25 from kimptoc/master
Some minor tweaks
2011-06-02 15:28:50 -07:00
Matt Darby
c96925e0fe Merge pull request #28 from alindeman/master
Remove Trailing Whitespace
2011-06-02 15:27:39 -07:00
Matt Darby
6777853f39 Merge pull request #28 from alindeman/master
Remove Trailing Whitespace
2011-06-02 15:27:28 -07:00
Matt Darby
ed90af6a86 Merge pull request #30 from greyblake/master
Hash default value
2011-06-02 15:27:09 -07:00
Matt Darby
0ba8091882 Merge pull request #31 from erickt/master
Just a small typo
2011-06-02 15:25:43 -07:00
Matt Darby
8ad07e027f Merge pull request #35 from TheSeparateFirst/master
Fixed about_strings for multiple rubies
2011-06-02 15:20:34 -07:00
Matt Darby
0fae65d634 Merge pull request #36 from dcoder2099/master
Fixed a typo in about_inheritance.rb
2011-06-02 15:13:44 -07:00
Matt Darby
a1f3d96e8e Merge pull request #42 from kowen/master
Adding missing assert in iteration test.
2011-06-02 15:06:58 -07:00
Matt Darby
88ef49e500 Merge pull request #43 from rtlechow/master
Just some typos.
2011-06-02 14:49:23 -07:00
R.T. Lechow
561a74d809 Typos. 2011-06-02 17:46:41 -04:00
Katrina Owen
6c8fe05507 Adding missing assert in iteration test.
Also checking against symbol rather than string.
2011-05-16 23:48:53 +02:00
Joe O'Brien
b27f1a7bd9 Merge pull request #32 from skilldrick/spellings.
Spellings
2011-04-30 11:57:21 -07:00
Joe O'Brien
bb805940c2 Merge pull request #37 from abyx/fix_typo_in_proxy_project.
Fix typo in proxy project
2011-04-30 10:47:02 -07:00
Joe O'Brien
dde32db1c4 Merge pull request #38 from bowsersenior/master.
Just some typo fixes
2011-04-30 10:46:31 -07:00
Joe O'Brien
52ae1c0627 Merge pull request #40 from nazgob/master.
typo fixed -> issue #39
2011-04-30 10:45:49 -07:00
nazgob
3d18d339e4 fixed typo -> Issue #39 2011-04-13 06:50:17 -07:00
nazgob
d78e284e55 fixed typo -> Issue #39 2011-04-13 06:49:58 -07:00
Mani Tadayon
bb8d835ad4 Fix typo in about_modules.rb 2011-03-29 17:11:33 -07:00
Mani Tadayon
6dc43a1ab0 Correct spelling: "heirarachy" => "hierarchy" 2011-03-29 15:14:06 -07:00
Mani Tadayon
39d556d66e Fix one letter typo in comments 2011-03-29 11:11:09 -07:00
Aviv Ben-Yosef
d6f69b5b26 fixing typo 2011-03-26 19:14:30 +02:00
Daniel Hedrick
434016150e Fix typo of subclasses (from subcases) 2011-03-21 19:24:38 -05:00
Jeffrey Murray
eb3403b0ff Fixed missed test case. 2011-03-11 17:50:39 -08:00
Jeffrey Murray
a46642e192 Fixed test_you_can_get_a_single_character_from_a_string for multiple rubies (1.8, 1.9) 2011-03-11 17:34:59 -08:00
Jim Weirich
3fd8d9da79 Now that the links are ok, fix the wording. 2011-03-09 11:01:03 -05:00
Jim Weirich
e207f7fe64 Final attempt on license link. 2011-03-09 11:00:07 -05:00
Jim Weirich
d8b4865d84 Another link fix 2011-03-09 10:59:23 -05:00
Jim Weirich
ea5841d1f7 Fixed links in license. 2011-03-09 10:58:25 -05:00
Jim Weirich
e338fff35a Switched from MIT to CC by-nc-sa license. 2011-03-09 10:56:58 -05:00
Skilldrick
34cc5c4069 Fix some typos. 2011-02-20 11:26:27 +00:00
Erick Tryzelaar
ef1536eda0 Fix a typo in a method name. 2011-02-12 10:43:27 -08:00
Potapov Sergey
caceba4d23 Added test for Hash default value. Developers often forget about using it. 2011-02-08 00:50:39 +02:00
Jim Weirich
0447d69a6d my_same_class_method => my_method_in_the_same_class for clarity 2011-02-03 15:30:59 -08:00
David Calavera
a05d7b8980 Add koan on break statements 2011-01-23 19:44:58 +01:00
Andy Lindeman
c350469e93 Remove trailing whitespace 2011-01-22 19:37:45 -06:00
Jeff Casimir
70eae5b306 Fix minor typo in method name: strings ARE unique objects 2011-01-12 15:44:56 -05:00
Marc Peabody
670101783b Revert "Updated with Rubinius Support"
This reverts commit 3ce23a8ee0.
2011-01-12 15:37:38 -05:00
Jim Weirich
b7c27f5b01 Added keynote slides 2011-01-12 08:29:57 -05:00
Chris Kimpton
ac3de6debd fix typo 2011-01-09 11:37:38 +00:00
Chris Kimpton
14792b8ce0 add hint/link to related stack overflow problem 2011-01-09 11:31:10 +00:00
Chris Kimpton
71ce393683 add a hint 2011-01-09 09:40:29 +00:00
Jim Weirich
3ce23a8ee0 Updated with Rubinius Support 2010-12-25 08:11:31 -05:00
Jim Weirich
db3bbdcf45 Better test name in the java interop koan 2010-12-23 15:04:16 -05:00
Jim Weirich
1a0d82a402 Added .rbc to clean list. 2010-12-23 12:28:39 -05:00
Jim Weirich
c8b4c3e6c5 [5458710] Added koans about to_str 2010-12-23 12:28:24 -05:00
Jim Weirich
204cd44ea9 [5462710] Fixed equality koan on symbols. 2010-12-23 12:08:03 -05:00
Jim Weirich
325ad5bce3 Result summary now in order of running. 2010-12-23 11:54:41 -05:00
Jim Weirich
b733076165 Added .rbc to ignore list 2010-12-23 11:48:40 -05:00
Jim Weirich
5e9083e754 Remove dbgs from Rakefile 2010-12-23 11:48:15 -05:00
Jim Weirich
ab59dc4791 Merge branch 'more_jruby' into m
* more_jruby:
  [5553333] Updated java interop on to_java method.
  Added cruise task
  java coercion
2010-12-23 11:46:29 -05:00
Jim Weirich
ccfa664b48 [5553333] Updated java interop on to_java method. 2010-12-23 11:45:46 -05:00
Jim Weirich
9b9eb640f8 Added cruise task 2010-12-23 11:29:39 -05:00
Jim Weirich
297cfde6a3 [7439987] Changed symbol inclusion test to use strings. 2010-12-23 10:16:34 -05:00
Jim Weirich
3dab146b8d Added --/++ markers around the dice class. 2010-12-23 09:26:55 -05:00
Marc Peabody
0b9727f299 fix mistake in about_symbols.rb 2010-12-14 09:12:49 -05:00
Jim Weirich
d3ce64a768 Updatd exception koan to be clearer about StandardError VS RuntimeError 2010-11-29 09:02:22 -05:00
Luke Pearce
9291f534c6 Fixed exceptions typo 2010-11-29 13:24:40 +00:00
Jim Weirich
71f670ac1d Disabled colored output on windows. 2010-10-21 07:05:06 -04:00
Jim Weirich
1864c9c346 Updated koans for about_symbols fix 2010-10-21 07:04:54 -04:00
Jim Weirich
cfd5b6bbe1 Fixed test_symbols_with_spaces_can_be_built method name collision. 2010-10-21 07:02:10 -04:00
Marc Peabody
e26666280c java coercion 2010-10-02 10:11:18 -04:00
Jim Weirich
e5843f64fd Fixed bug where some koans were not generated properly. 2010-10-01 11:05:25 -04:00
Jim Weirich
fdb8774c95 Added Java Interop koans if running jruby. 2010-09-28 14:49:43 -04:00
Jim Weirich
5b483df29b Added descriptions to rake tasks. 2010-09-28 14:49:20 -04:00
Jim Weirich
7dee146a8c Added missing __ replacements 2010-09-28 14:49:06 -04:00
Jim Weirich
e24d94eeff Updated koans from source. 2010-09-28 14:43:34 -04:00
Jim Weirich
4789e831df Added enumerable collections and open java classes to jruby koan. 2010-09-28 14:43:03 -04:00
Jim Weirich
b41d6167b4 Updated koans from src. 2010-09-28 14:17:46 -04:00
Jim Weirich
c0bbe773d9 Moved splat example to later + several typo corrections. 2010-09-28 14:15:08 -04:00
Srdjan Pejic
6fb8e3c3af Cool test; Still can't believe there is no standard implementation of first/rest 2010-09-28 14:11:08 -04:00
Marc Peabody + Jim Weirich
1dcd9babd4 Added more think about its to the ruby/java string comparisons. 2010-09-27 18:24:25 -04:00
Marc Peabody + Jim Weirich
45523c03c0 More class conflict examples. 2010-09-27 16:54:10 -04:00
Jim Weirich
8436b46c1a Added Ruby version information to the output. 2010-09-27 14:36:38 -04:00
Jim Weirich
322ca38767 Minitest lines in backtrace are no longer interesting. 2010-09-27 14:15:59 -04:00
Jim Weirich
91f15dc690 Simplified output for running against multiple rubies. 2010-09-27 14:09:38 -04:00
Jim Weirich
beb7fe591e Added rake task for running koans against several rubies. 2010-09-27 13:46:21 -04:00
Jim Weirich
17fb071814 Evaluated each assert line without a replacement test specified. 2010-09-27 13:38:50 -04:00
Jim Weirich
012cb20bb3 Moved checks into a separate rake file. 2010-09-27 13:38:22 -04:00
Jim Weirich
ece35b2539 Added symbol & string identity tests. 2010-09-27 11:36:38 -04:00
Jim Weirich
fe2ee86172 Added Koan on basic objects 2010-09-27 11:36:00 -04:00
Jim Weirich
9caf7a950a Updated koans from source directory. 2010-09-27 10:50:29 -04:00
Jim Weirich
a13f184ef1 Merge branch 'output_refactoring'
* output_refactoring:
  Updated for JRuby
  Switch blue color to cyan for better contrast on dark terminals.
  80 char limit to end screen
  Updated Koans directory
  Added else clause if progress file is not there.
  regen for updated koans/edgecase.rb
  end screen with koans logo ascii art
2010-09-27 10:49:17 -04:00
Jim Weirich
584b26e532 Updated for JRuby 2010-09-27 10:44:58 -04:00
Jim Weirich
b2c47e0c0f Switch blue color to cyan for better contrast on dark terminals. 2010-09-27 10:37:35 -04:00
Marc Peabody
f56117c0ca merge and 80 char limit on src 2010-09-22 15:14:11 -04:00
Marc Peabody
15551eaf53 80 char limit to end screen 2010-09-22 15:09:08 -04:00
Jim Weirich
b4e907e30e Updated Koans directory 2010-09-22 14:54:42 -04:00
Jim Weirich
754a7694ad Added else clause if progress file is not there. 2010-09-22 14:50:25 -04:00
Marc Peabody
1492d7003a regen for updated koans/edgecase.rb 2010-09-22 14:10:34 -04:00
Marc Peabody
493300b24d end screen with koans logo ascii art 2010-09-22 14:08:38 -04:00
Matt Yoho
1bc1b8e50c Add timestamps to package output 2010-09-21 17:48:30 -04:00
Matt Yoho
9b5dfb4e42 Add koan on asserting exceptions 2010-09-21 17:12:50 -04:00
98 changed files with 1724 additions and 3901 deletions

16
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Ruby!
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2.2"
- name: run tests
run: rake test

6
.gitignore vendored
View File

@@ -1,2 +1,8 @@
dist
.project_env.rc
.path_progress
.rvmrc
.ruby-version
*.rbc
koans/*
*~

12
DEPLOYING Normal file
View File

@@ -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.

View File

@@ -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.

View File

@@ -1,18 +1,18 @@
= EdgeCase Ruby Koans
= 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.
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+, <em>etc</em>. 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,28 +23,41 @@ 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 <code>gem install rake</code>
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
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
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
@@ -56,54 +69,88 @@ 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 <em>red, green, refactor</em>.
Write a failing test and run it (<em>red</em>), make the test pass (<em>green</em>),
then look at the code and consider if you can make it any better (<em>refactor</em>).
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 (<em>red</em>), make the test pass (<em>green</em>), 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 (<em>refactor</em>).
The very first time you run the koans 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...
<false> 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 (0%)
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:
./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:
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
<em>This section is optional.</em>
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 +observr+ 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 observr
observr ./koans.watchr
== Inspiration
A special thanks to Mike Clark and Ara Howard for inspiring this
@@ -130,7 +177,15 @@ Brian Marick's fantastic guide for beginners Everyday Scripting with Ruby ::
= Other stuff
Author :: Jim Weirich <jim@weirichhouse.org>
Author :: Joe O'Brien <joe@edgecase.com>
Issue Tracker :: http://www.pivotaltracker.com/projects/48111
Author :: Jim Weirich <jim@neo.org>
Author :: Joe O'Brien <joe@objo.com>
Issue Tracker :: https://github.com/edgecase/ruby_koans/issues
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.

110
Rakefile Normal file → Executable file
View File

@@ -2,35 +2,38 @@
# -*- ruby -*-
require 'rake/clean'
require 'rake/rdoctask'
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")
TAR_FILE = "#{DIST_DIR}/rubykoans.tgz"
ZIP_FILE = "#{DIST_DIR}/rubykoans.zip"
ZIP_FILE = "#{DOWNLOAD_DIR}/rubykoans.zip"
CLOBBER.include(DIST_DIR)
CLEAN.include("**/*.rbc")
module Koans
extend Rake::DSL if defined?(Rake::DSL)
# 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
def Koans.make_koan_file(infile, outfile)
if infile =~ /edgecase/
if infile =~ /neo/
cp infile, outfile
elsif infile =~ /autotest/
cp_r infile, outfile
else
open(infile) do |ins|
open(outfile, "w") do |outs|
@@ -51,46 +54,56 @@ module Koans
end
end
module RubyImpls
# Calculate the list of relevant Ruby implementations.
def self.find_ruby_impls
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
}.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.7 ruby-1.9.2 jruby ree)
end
end
task :default => :walk_the_path
task :walk_the_path do
cd 'koans'
cd PROB_DIR
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 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
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]
@@ -109,3 +122,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_DIR}") 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}"
sh ". rvm #{impl}; rake run"
results << [impl, "RAN"]
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}" unless results.detect { |x| x.first =~ impl_pattern }
end
end

BIN
download/rubykoans.zip Normal file

Binary file not shown.

BIN
keynote/RubyKoans.key Normal file

Binary file not shown.

View File

@@ -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.

View File

@@ -1,136 +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
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 ...
<false> is not true.
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
mountains are merely mountains
You have come to your first stage. If you notice it is telling you where to look for
the first solution:
Please meditate on the following code:
./about_asserts.rb:10:in `test_assert_truth'
path_to_enlightenment.rb:27
We then open up the about_asserts.rb file and look at the first test:
# We shall contemplate truth by testing reality, via asserts.
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 <jim@weirichhouse.org>
Author :: Joe O'Brien <joe@edgecase.com>
Issue Tracker :: http://www.pivotaltracker.com/projects/48111
Requires :: Ruby 1.8.x or later and Rake (any recent version)

View File

@@ -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

View File

@@ -1,45 +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_extra_variables
first_name, last_name = ["Cher"]
assert_equal __, first_name
assert_equal __, last_name
end
def test_parallel_assignements_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

View File

@@ -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 Array, 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 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...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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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_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
__
end
def inspect
"<Dog named '#{name}'>"
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", 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 __, array.to_s
assert_equal __, array.inspect
assert_equal __, "STRING".to_s
assert_equal __, "STRING".inspect
end
end

View File

@@ -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 heirarachy?
# ------------------------------------------------------------------
class MyAnimals::Oyster < Animal
def legs_in_oyster
LEGS
end
end
def test_who_wins_with_explicit_scoping_on_class_definition
assert_equal __, MyAnimals::Oyster.new.legs_in_oyster
end
# QUESTION: Now Which has precedence: The constant in the lexical
# scope, or the constant from the inheritance heirarachy? Why is it
# different than the previous answer?
end

View File

@@ -1,116 +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
result = :false_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_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

View File

@@ -1,64 +0,0 @@
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
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

View File

@@ -1,60 +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 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 __, 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
end

View File

@@ -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.

View File

@@ -1,66 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/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 __, 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_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 Array, 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 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" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
assert_equal expected, new_hash
end
end

View File

@@ -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_subcases_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

View File

@@ -1,103 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/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 __, 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

View File

@@ -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 schedule 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

View File

@@ -1,150 +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
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_same_class_method(a, b)
a * b
end
def test_calling_methods_in_same_class
assert_equal __, my_same_class_method(3,4)
end
def test_calling_methods_in_same_class_with_explicit_receiver
assert_equal __, 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 __, 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

View File

@@ -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_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.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

View File

@@ -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
# 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
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

View File

@@ -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

View File

@@ -1,154 +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 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
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)
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

View File

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

View File

@@ -1,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

View File

@@ -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_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 __, 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

View File

@@ -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 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

View File

@@ -1,185 +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.size
end
def test_here_documents_can_also_handle_multiple_lines
long_string = <<EOS
It was the best of times,
It was the worst of times.
EOS
assert_equal __, long_string.size
end
def test_plus_will_concatenate_two_strings
string = "Hello, " + "World"
assert_equal __, string
end
def test_plus_concatenation_will_leave_the_original_strings_unmodified
hi = "Hello, "
there = "World"
string = hi + there
assert_equal __, hi
assert_equal __, there
end
def test_plus_equals_will_concatenate_to_the_end_of_a_string
hi = "Hello, "
there = "World"
hi += there
assert_equal __, hi
end
def test_plus_equals_also_will_leave_the_original_string_unmodified
original_string = "Hello, "
hi = original_string
there = "World"
hi += there
assert_equal __, original_string
end
def test_the_shovel_operator_will_also_append_content_to_a_string
hi = "Hello, "
there = "World"
hi << there
assert_equal __, hi
assert_equal __, there
end
def test_the_shovel_operator_modifies_the_original_string
original_string = "Hello, "
hi = original_string
there = "World"
hi << there
assert_equal __, original_string
# THINK ABOUT IT:
#
# Ruby programmers tend to favor the shovel operator (<<) over the
# plus equals operator (+=) when building up strings. Why?
end
def test_double_quoted_string_interpret_escape_characters
string = "\n"
assert_equal __, string.size
end
def test_single_quoted_string_do_not_interpret_escape_characters
string = '\n'
assert_equal __, string.size
end
def test_single_quotes_sometimes_interpret_escape_characters
string = '\\\''
assert_equal __, string.size
assert_equal __, string
end
def test_double_quoted_strings_interpolate_variables
value = 123
string = "The value is #{value}"
assert_equal __, string
end
def test_single_quoted_strings_do_not_interpolate
value = 123
string = 'The value is #{value}'
assert_equal __, string
end
def test_any_ruby_expression_may_be_interpolated
string = "The square root of 5 is #{Math.sqrt(5)}"
assert_equal __, string
end
def test_you_can_get_a_substring_from_a_string
string = "Bacon, lettuce and tomato"
assert_equal __, string[7,3]
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
assert_equal __, ?a == 97
assert_equal __, ?b == (?a + 1)
end
end
in_ruby_version("1.9") do
def test_in_ruby_1_9_single_characters_are_represented_by_strings
assert_equal __, ?a
assert_equal __, ?a == 97
end
end
def test_strings_can_be_split
string = "Sausage Egg Cheese"
words = string.split
assert_equal [__, __, __], words
end
def test_strings_can_be_split_with_different_patterns
string = "the:rain:in:spain"
words = string.split(/:/)
assert_equal [__, __, __, __], words
# NOTE: Patterns are formed from Regular Expressions. Ruby has a
# very powerful Regular Expression library. We will become
# enlightened about them soon.
end
def test_strings_can_be_joined
words = ["Now", "is", "the", "time"]
assert_equal __, words.join(" ")
end
end

View File

@@ -1,77 +0,0 @@
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_can_be_compared
symbol1 = :a_symbol
symbol2 = :a_symbol
symbol3 = :something_else
assert symbol1 == __
assert symbol1 != __
end
def test_identical_symbols_are_a_single_internal_object
symbol1 = :a_symbol
symbol2 = :a_symbol
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 = "What is the sound of one hand clapping?"
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_be_built
symbol = :"cats and 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."
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
end
end

View File

@@ -1,25 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'
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)
end
def test_isosceles_triangles_have_exactly_two_sides_equal
assert_equal :isosceles, triangle(3, 4, 4)
assert_equal :isosceles, triangle(4, 3, 4)
assert_equal :isosceles, triangle(4, 4, 3)
assert_equal :isosceles, triangle(10, 10, 2)
end
def test_scalene_triangles_have_no_equal_sides
assert_equal :scalene, triangle(3, 4, 5)
assert_equal :scalene, triangle(10, 11, 12)
assert_equal :scalene, triangle(5, 4, 2)
end
end

View File

@@ -1,16 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'
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
end
end

View File

@@ -1,33 +0,0 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutTrueAndFalse < EdgeCase::Koan
def truth_value(condition)
if condition
:true_stuff
else
:false_stuff
end
end
def test_true_is_treated_as_true
assert_equal __, truth_value(true)
end
def test_false_is_treated_as_false
assert_equal __, truth_value(false)
end
def test_nil_is_treated_as_false_too
assert_equal __, truth_value(nil)
end
def test_everything_else_is_treated_as_true
assert_equal __, truth_value(1)
assert_equal __, truth_value(0)
assert_equal __, truth_value([])
assert_equal __, truth_value({})
assert_equal __, truth_value("Strings")
assert_equal __, truth_value("")
end
end

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -1,277 +0,0 @@
#!/usr/bin/env ruby
# -*- ruby -*-
require 'test/unit/assertions'
class FillMeInError < StandardError
end
def in_ruby_version(version)
yield if RUBY_VERSION =~ /^#{version}/
end
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def ___(value=FillMeInError)
value
end
class Object
def ____(method=nil)
if method
self.send(method)
end
end
in_ruby_version("1.9") do
public :method_missing
end
end
module EdgeCase
module Color
#shamelessly stolen (and modified) from redgreen
COLORS = {
:clear => 0, :black => 30, :red => 31,
:green => 32, :yellow => 33, :blue => 34,
:magenta => 35, :cyan => 36,
}
module_function
COLORS.each do |color, value|
module_eval "def #{color}(string); colorize(string, #{value}); end"
module_function color
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
color(color_value) + string + color(COLORS[:clear])
end
end
def color(color_value)
"\e[#{color_value}m"
end
end
class Sensei
attr_reader :failure, :failed_test
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
end
def accumulate(test)
if test.passed?
@pass_count += 1
puts Color.green(" #{test.name} has expanded your awareness.")
else
puts Color.red(" #{test.name} has damaged your karma.")
@failed_test = test
@failure = test.failure
throw :edgecase_exit
end
end
def failed?
! @failure.nil?
end
def assert_failed?
failure.is_a?(AssertionError)
end
def report
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) }
else
puts Color.red(failure.backtrace)
end
puts
end
puts Color.green(a_zenlike_statement)
end
def find_interesting_lines(backtrace)
backtrace.reject { |line|
line =~ /test\/unit\/|edgecase\.rb/
}
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
puts
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
zen_statement
end
end
class Koan
include Test::Unit::Assertions
attr_reader :name, :failure
def initialize(name)
@name = name
@failure = nil
end
def passed?
@failure.nil?
end
def failed(failure)
@failure = failure
end
def setup
end
def teardown
end
# Class methods for the EdgeCase test suite.
class << self
def inherited(subclass)
subclasses << 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)
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
}

View File

@@ -1,4 +0,0 @@
this
is
a
test

View File

@@ -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

View File

@@ -1,33 +0,0 @@
# The path to Ruby Enlightenment starts with the following:
$LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
require 'about_strings'
require 'about_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_extra_credit'

View File

@@ -1,7 +0,0 @@
require 'test/unit'
def __
"FILL ME IN"
end
EdgeCase = Test::Unit

View File

@@ -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

33
rakelib/checks.rake Normal file
View File

@@ -0,0 +1,33 @@
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
desc "Check that asserts have __ replacements"
task :asserts do
puts "Checking for asserts missing the replacement text:"
begin
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
puts "OK"
end
puts
end
end
desc "Run some simple consistency checks"
task :check => ["check:abouts", "check:asserts"]

8
rakelib/run.rake Normal file
View File

@@ -0,0 +1,8 @@
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
ENV['SIMPLE_KOAN_OUTPUT'] = 'true'
sh "rvm #{RUBIES} path_to_enlightenment.rb"
end
end

9
rakelib/test.rake Normal file
View File

@@ -0,0 +1,9 @@
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs << "tests"
t.test_files = FileList["tests/**/*_test.rb"]
t.verbose = true
end
desc 'Run tests'

View File

@@ -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
@@ -18,13 +18,19 @@ class AboutArrayAssignment < EdgeCase::Koan
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_values
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

View File

@@ -1,18 +1,18 @@
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
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 @@ class AboutArrays < EdgeCase::Koan
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

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -97,7 +97,6 @@ class AboutClassMethods < EdgeCase::Koan
assert_equal __(:dogs_class_method), Dog.a_class_method
end
# ------------------------------------------------------------------
LastExpressionInClassStatement = class Dog

View File

@@ -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
@@ -126,11 +126,11 @@ class AboutClasses < EdgeCase::Koan
# 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")
assert_not_equal rover.name, fido.name
assert_equal __(true), rover.name != fido.name
end
# ------------------------------------------------------------------
@@ -147,7 +147,7 @@ class AboutClasses < EdgeCase::Koan
end
def to_s
__(@name)
@name
end
def inspect
@@ -164,12 +164,12 @@ class AboutClasses < EdgeCase::Koan
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

View File

@@ -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"
@@ -67,7 +67,7 @@ class AboutConstants < EdgeCase::Koan
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 @@ class AboutConstants < EdgeCase::Koan
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

View File

@@ -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
@@ -59,12 +59,20 @@ class AboutControlStatements < EdgeCase::Koan
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
@@ -93,6 +101,16 @@ class AboutControlStatements < EdgeCase::Koan
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 = []
@@ -113,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

View File

@@ -1,5 +1,12 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
require File.expand_path(File.dirname(__FILE__) + '/neo')
# Implement a DiceSet Class here:
#
# class DiceSet
# code ...
# end
#--
class DiceSet
attr_reader :values
def roll(n)
@@ -7,7 +14,8 @@ class DiceSet
end
end
class AboutDiceProject < EdgeCase::Koan
#++
class AboutDiceProject < Neo::Koan
def test_can_create_a_dice_set
dice = DiceSet.new
assert_not_nil dice
@@ -48,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

View File

@@ -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
@@ -22,10 +22,10 @@ class AboutExceptions < EdgeCase::Koan
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),
assert RuntimeError.ancestors.include?(StandardError), # __
"RuntimeError is a subclass of StandardError"
assert_equal __("Oops"), ex.message
@@ -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
@@ -57,4 +57,12 @@ class AboutExceptions < EdgeCase::Koan
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

View File

@@ -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 __(Hash), empty_hash.class
assert_equal(__({}), empty_hash)
assert_equal __(0), empty_hash.size
end
@@ -20,12 +20,24 @@ class AboutHashes < EdgeCase::Koan
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, KeyError)) 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 => __("eins"), :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 +47,7 @@ class AboutHashes < EdgeCase::Koan
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 +55,7 @@ class AboutHashes < EdgeCase::Koan
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 +63,64 @@ class AboutHashes < EdgeCase::Koan
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
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
def test_default_value_attribute
hash = Hash.new
assert_equal __(nil), hash[:some_key]
hash.default = 'peanut'
assert_equal __('peanut'), hash[:some_key]
end
end

View File

@@ -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
@@ -31,7 +31,7 @@ class AboutInheritance < EdgeCase::Koan
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

View File

@@ -1,9 +1,30 @@
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 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)
name.to_s
end
end
in_ruby_version("1.9", "2", "3") 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
@@ -12,25 +33,23 @@ class AboutIteration < EdgeCase::Koan
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
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
@@ -65,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:

137
src/about_java_interop.rb Normal file
View File

@@ -0,0 +1,137 @@
require File.expand_path(File.dirname(__FILE__) + '/neo')
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 < Neo::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?
#
# 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 __(true), java_array.toString.is_a?(String)
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_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
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

View File

@@ -0,0 +1,43 @@
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
def method_with_mandatory_keyword_arguments(one:, two: 'two')
[one, two]
end
def test_mandatory_keyword_arguments
assert_equal __(['one', 'two']), method_with_mandatory_keyword_arguments(one: 'one')
assert_equal __([1, 2]), method_with_mandatory_keyword_arguments(two: 2, one: 1)
end
def test_mandatory_keyword_arguments_without_mandatory_argument
exception = assert_raise(___(ArgumentError)) do
method_with_mandatory_keyword_arguments
end
assert_match(/#{__("missing keyword: :one")}/, exception.message)
end
end

View File

@@ -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?
@@ -11,19 +11,19 @@ class AboutMessagePassing < EdgeCase::Koan
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
@@ -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
@@ -74,7 +81,7 @@ class AboutMessagePassing < EdgeCase::Koan
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 +90,7 @@ class AboutMessagePassing < EdgeCase::Koan
exception = assert_raise(___(NoMethodError)) do
typical.method_missing(:foobar)
end
assert_match(/foobar/, exception.message)
assert_match(/foobar/, exception.message) # __
# THINK ABOUT IT:
#
@@ -93,13 +100,13 @@ 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 schedule Ruby
# Thanks. We now return you to your regularly scheduled Ruby
# Koans.
end
@@ -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)

View File

@@ -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)
@@ -19,10 +19,10 @@ class AboutMethods < EdgeCase::Koan
# 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
#++
@@ -37,18 +37,22 @@ 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.
# tip: When regex contains parentheses, you must escape them with backslash.
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
# ------------------------------------------------------------------
@@ -69,6 +73,7 @@ class AboutMethods < EdgeCase::Koan
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)
@@ -99,16 +104,16 @@ class AboutMethods < EdgeCase::Koan
# ------------------------------------------------------------------
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
# ------------------------------------------------------------------
@@ -122,11 +127,13 @@ class AboutMethods < EdgeCase::Koan
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
if before_ruby_version("2.7") # https://github.com/edgecase/ruby_koans/issues/12
def test_calling_private_methods_with_an_explicit_receiver
exception = assert_raise(___(NoMethodError)) do
self.my_private_method
end
assert_match /#{__("method `my_private_method'")}/, exception.message
end
assert_match /#{__("private method `my_private_method' called ")}/, exception.message
end
# ------------------------------------------------------------------

View File

@@ -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
@@ -42,9 +42,9 @@ class AboutModules < EdgeCase::Koan
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
assert_nothing_raised do # __
fido.set_name("Rover")
end
end

View File

@@ -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
@@ -8,7 +8,7 @@ class AboutNil < EdgeCase::Koan
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

50
src/about_objects.rb Normal file
View File

@@ -0,0 +1,50 @@
require File.expand_path(File.dirname(__FILE__) + '/neo')
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)
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 obj.object_id.is_a?(__(Integer))
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_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

View File

@@ -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"
@@ -30,14 +30,14 @@ class AboutOpenClasses < EdgeCase::Koan
# ------------------------------------------------------------------
class ::Integer
def even?
(self % 2) == 0
def answer_to_life_universe_and_everything?
self == 42
end
end
def test_even_existing_built_in_classes_can_be_reopened
assert_equal __(false), 1.even?
assert_equal __(true), 2.even?
assert_equal __(false), 1.answer_to_life_universe_and_everything?
assert_equal __(true), 42.answer_to_life_universe_and_everything?
end
# NOTE: To understand why we need the :: before Integer, you need to

View File

@@ -0,0 +1,215 @@
require File.expand_path(File.dirname(__FILE__) + '/neo')
class AboutPatternMatching < Neo::Koan
def test_pattern_may_not_match
begin
case [true, false]
in [a, b] if a == b # The condition after pattern is called guard.
:match
end
rescue Exception => ex
# What exception has been caught?
assert_equal __, ex.class
end
end
def test_we_can_use_else
result = case [true, false]
in [a, b] if a == b
:match
else
:no_match
end
assert_equal __, result
end
# ------------------------------------------------------------------
def value_pattern(variable)
case variable
in 0
:match_exact_value
in 1..10
:match_in_range
in Integer
:match_with_class
else
:no_match
end
end
def test_value_pattern
assert_equal __, value_pattern(0)
assert_equal __, value_pattern(5)
assert_equal __, value_pattern(100)
assert_equal __, value_pattern('Not a Number!')
end
# ------------------------------------------------------------------
# This pattern will bind variable to the value
def variable_pattern_with_binding(variable)
case 0
in variable
variable
else
:no_match
end
end
def test_variable_pattern_with_binding
assert_equal __, variable_pattern_with_binding(1)
end
# ------------------------------------------------------------------
# We can pin the value of the variable with ^
def variable_pattern_with_pin(variable)
case 0
in ^variable
variable
else
:no_match
end
end
def test_variable_pattern_with_pin
assert_equal __, variable_pattern_with_pin(1)
end
# ------------------------------------------------------------------
# We can drop values from pattern
def pattern_with_dropping(variable)
case variable
in [_, 2]
:match
else
:no_match
end
end
def test_pattern_with_dropping
assert_equal __, pattern_with_dropping(['I will not be checked', 2])
assert_equal __, pattern_with_dropping(['I will not be checked', 'But I will!'])
end
# ------------------------------------------------------------------
# We can use logical *or* in patterns
def alternative_pattern(variable)
case variable
in 0 | false | nil
:match
else
:no_match
end
end
def test_alternative_pattern
assert_equal __, alternative_pattern(0)
assert_equal __, alternative_pattern(false)
assert_equal __, alternative_pattern(nil)
assert_equal __, alternative_pattern(4)
end
# ------------------------------------------------------------------
# As pattern binds the variable to the value if pattern matches
# pat: pat => var
def as_pattern
a = 'First I was afraid'
case 'I was petrified'
in String => a
a
else
:no_match
end
end
def test_as_pattern
assert_equal __, as_pattern
end
# ------------------------------------------------------------------
# Array pattern works with all objects that have #deconstruct method that returns Array
# It is useful to cut needed parts from Array-ish objects
class Deconstructible
def initialize(str)
@data = str
end
def deconstruct
@data&.split('')
end
end
def array_pattern(deconstructible)
case deconstructible
in 'a', *res, 'd'
res
else
:no_match
end
end
def test_array_pattern
assert_equal __, array_pattern(Deconstructible.new('abcd'))
assert_equal __, array_pattern(Deconstructible.new('123'))
end
# ------------------------------------------------------------------
# Hash pattern is quite the same as Array pattern, but it expects #deconsturct_keys(keys) method
# It works with symbol keys for now
class LetterAccountant
def initialize(str)
@data = str
end
def deconstruct_keys(keys)
# we will count number of occurrences of each key in our data
keys.map { |key| [key, @data.count(key.to_s)] }.to_h
end
end
def hash_pattern(deconstructible_as_hash)
case deconstructible_as_hash
in {a: a, b: b}
[a, b]
else
:no_match
end
end
def test_hash_pattern
assert_equal __, hash_pattern(LetterAccountant.new('aaabbc'))
assert_equal __, hash_pattern(LetterAccountant.new('xyz'))
end
# we can write it even shorter
def hash_pattern_with_sugar(deconstructible_as_hash)
case deconstructible_as_hash
in a:, b:
[a, b]
else
:no_match
end
end
def test_hash_pattern_with_sugar
assert_equal __, hash_pattern_with_sugar(LetterAccountant.new('aaabbc'))
assert_equal __, hash_pattern_with_sugar(LetterAccountant.new('xyz'))
end
end

View File

@@ -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
#
@@ -6,7 +6,7 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
# 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
@@ -42,11 +42,13 @@ 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)
# HINT: Proxy class is defined above, may need tweaking...
assert tv.instance_of?(Proxy)
end
@@ -133,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

View File

@@ -1,13 +1,13 @@
# -*- 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
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
@@ -84,6 +84,8 @@ class AboutRegularExpressions < EdgeCase::Koan
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

View File

@@ -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
@@ -40,7 +40,7 @@ class AboutSandwichCode < EdgeCase::Koan
#
# 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,
@@ -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

View File

@@ -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
@@ -29,8 +29,8 @@ class AboutScope < EdgeCase::Koan
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
# ------------------------------------------------------------------

View File

@@ -1,7 +1,7 @@
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 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:
@@ -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

View File

@@ -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)
@@ -40,7 +40,9 @@ class AboutStrings < EdgeCase::Koan
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
assert_equal __("\n"), long_string[0,1]
end
def test_here_documents_can_also_handle_multiple_lines
@@ -48,7 +50,9 @@ It was the worst of times.
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
assert_equal __("I"), long_string[0,1]
end
def test_plus_will_concatenate_two_strings
@@ -147,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
@@ -155,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", "3") do
def test_in_modern_ruby_single_characters_are_represented_by_strings
assert_equal __('a'), ?a
assert_equal __(false), ?a == 97
end
@@ -182,4 +186,12 @@ EOS
words = ["Now", "is", "the", "time"]
assert_equal __("Now is the time"), words.join(" ")
end
def test_strings_are_unique_objects
a = "a string"
b = "a string"
assert_equal __(true), a == b
assert_equal __(false), a.object_id == b.object_id
end
end

View File

@@ -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)
@@ -11,29 +11,35 @@ class AboutSymbols < EdgeCase::Koan
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
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
all_symbols = Symbol.all_symbols
assert_equal __(true), all_symbols.include?(:test_method_names_are_symbols)
symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }
assert_equal __(true), symbols_as_strings.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 convert the list of symbols to strings and then compare
# against the string value rather than against symbols?
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_as_strings = Symbol.all_symbols.map { |x| x.to_s }
assert_equal __(true), all_symbols_as_strings.include?(__("RubyConstant"))
end
end
def test_symbols_can_be_made_from_strings
@@ -44,7 +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 __("cats and dogs").to_sym, symbol
end
def test_to_s_is_called_on_interpolated_symbols
@@ -65,13 +78,23 @@ class AboutSymbols < EdgeCase::Koan
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
# Exceptions will be pondered further 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

54
src/about_to_str.rb Normal file
View File

@@ -0,0 +1,54 @@
require File.expand_path(File.dirname(__FILE__) + '/neo')
class AboutToStr < Neo::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

View File

@@ -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

View File

@@ -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
@@ -11,6 +11,6 @@ class AboutTriangleProject2 < EdgeCase::Koan
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
# HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions
end
end

View File

@@ -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

View File

@@ -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

View File

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

View File

@@ -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

View File

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

View File

@@ -1,277 +0,0 @@
#!/usr/bin/env ruby
# -*- ruby -*-
require 'test/unit/assertions'
class FillMeInError < StandardError
end
def in_ruby_version(version)
yield if RUBY_VERSION =~ /^#{version}/
end
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
def ___(value=FillMeInError)
value
end
class Object
def ____(method=nil)
if method
self.send(method)
end
end
in_ruby_version("1.9") do
public :method_missing
end
end
module EdgeCase
module Color
#shamelessly stolen (and modified) from redgreen
COLORS = {
:clear => 0, :black => 30, :red => 31,
:green => 32, :yellow => 33, :blue => 34,
:magenta => 35, :cyan => 36,
}
module_function
COLORS.each do |color, value|
module_eval "def #{color}(string); colorize(string, #{value}); end"
module_function color
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
color(color_value) + string + color(COLORS[:clear])
end
end
def color(color_value)
"\e[#{color_value}m"
end
end
class Sensei
attr_reader :failure, :failed_test
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
end
def accumulate(test)
if test.passed?
@pass_count += 1
puts Color.green(" #{test.name} has expanded your awareness.")
else
puts Color.red(" #{test.name} has damaged your karma.")
@failed_test = test
@failure = test.failure
throw :edgecase_exit
end
end
def failed?
! @failure.nil?
end
def assert_failed?
failure.is_a?(AssertionError)
end
def report
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) }
else
puts Color.red(failure.backtrace)
end
puts
end
puts Color.green(a_zenlike_statement)
end
def find_interesting_lines(backtrace)
backtrace.reject { |line|
line =~ /test\/unit\/|edgecase\.rb/
}
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
puts
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
zen_statement
end
end
class Koan
include Test::Unit::Assertions
attr_reader :name, :failure
def initialize(name)
@name = name
@failure = nil
end
def passed?
@failure.nil?
end
def failed(failure)
@failure = failure
end
def setup
end
def teardown
end
# Class methods for the EdgeCase test suite.
class << self
def inherited(subclass)
subclasses << 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)
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
}

View File

@@ -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

3
src/koans.watchr Normal file
View File

@@ -0,0 +1,3 @@
watch( '.*\.rb' ) do
system 'rake'
end

541
src/neo.rb Normal file
View File

@@ -0,0 +1,541 @@
#!/usr/bin/env ruby
# -*- ruby -*-
$VERBOSE = nil
begin
require 'win32console'
rescue LoadError
end
# --------------------------------------------------------------------
# Support code for the Ruby Koans.
# --------------------------------------------------------------------
class FillMeInError < StandardError
end
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 before_ruby_version(version)
Gem::Version.new(RUBY_VERSION) < Gem::Version.new(version)
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)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
# Numeric replacement value.
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
# Error object replacement value.
def ___(value=FillMeInError, value19=:mu)
if RUBY_VERSION < "1.9"
value
else
(value19 == :mu) ? value : value19
end
end
# Method name replacement.
class Object
def ____(method=nil)
if method
self.send(method)
end
end
in_ruby_version("1.9", "2", "3") do
public :method_missing
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 Neo
class << self
def simple_output
ENV['SIMPLE_KOAN_OUTPUT'] == 'true'
end
end
module Color
#shamelessly stolen (and modified) from redgreen
COLORS = {
:clear => 0, :black => 30, :red => 31,
:green => 32, :yellow => 33, :blue => 34,
:magenta => 35, :cyan => 36,
}
module_function
COLORS.each do |color, value|
module_eval "def #{color}(string); colorize(string, #{value}); end"
module_function color
end
def colorize(string, color_value)
if 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
else
return true
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
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
FailedAssertionError = Assertions::FailedAssertionError
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.exist?(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.exist?(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 :neo_exit
end
end
def failed?
! @failure.nil?
end
def assert_failed?
failure.is_a?(FailedAssertionError)
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 = 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
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} (#{pass_count*100/total_tests}%)"
puts
end
def end_screen
if Neo.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 ,,::::::::::::
:::::::::::::: ,::::::::::::
::::::::::::::, ,:::::::::::::
::::::::::::, Neo 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:"
puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
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 =~ /neo\.rb/
}
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 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, Neo::Sensei::FailedAssertionError => ex
failed(ex)
ensure
begin
teardown
rescue StandardError, Neo::Sensei::FailedAssertionError => ex
failed(ex) if passed?
end
end
self
end
# Class methods for the Neo 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 = Neo::Sensei.new
each_step do |step|
sensei.observe(step.meditate)
end
sensei.instruct
end
def each_step
catch(:neo_exit) {
step_count = 0
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
end
end
}
end
end
end
END {
Neo::Koan.command_line(ARGV)
Neo::ThePath.new.walk
}

View File

@@ -3,17 +3,21 @@
$LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
require 'about_true_and_false'
require 'about_strings'
require 'about_symbols'
require 'about_regular_expressions'
require 'about_arrays'
require 'about_array_assignment'
require 'about_objects'
require 'about_nil'
require 'about_hashes'
require 'about_methods'
in_ruby_version("2", "3") do
require 'about_keyword_arguments'
end
require 'about_constants'
require 'about_regular_expressions'
require 'about_control_statements'
require 'about_true_and_false'
require 'about_triangle_project'
require 'about_exceptions'
require 'about_triangle_project_2'
@@ -30,4 +34,11 @@ 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
in_ruby_version("2.7", "3") do
require 'about_pattern_matching'
end
require 'about_extra_credit'

View File

@@ -1,7 +0,0 @@
require 'test/unit'
def __
"FILL ME IN"
end
EdgeCase = Test::Unit

26
tests/check_test.rb Normal file
View File

@@ -0,0 +1,26 @@
require_relative "test_helper"
class CheckTest < Minitest::Test
def with_captured_stdout
original_stdout = $stdout
$stdout = StringIO.new
yield
$stdout.string
ensure
$stdout = original_stdout
end
def test_check_asserts
output = with_captured_stdout do
Rake::Task['check:asserts'].invoke
end
assert_match(/OK/, output)
end
def test_check_abouts
output = with_captured_stdout do
Rake::Task['check:abouts'].invoke
end
assert_match(/OK/, output)
end
end

4
tests/test_helper.rb Normal file
View File

@@ -0,0 +1,4 @@
require "minitest/autorun"
require "rake"
Rake.application.load_rakefile