mirror of
https://github.com/edgecase/ruby_koans.git
synced 2026-04-15 07:23:19 -04:00
Compare commits
273 Commits
output_ref
...
e072392099
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e072392099 | ||
|
|
fb05c506f0 | ||
|
|
411e86e5c3 | ||
|
|
f2699f0ae7 | ||
|
|
8e70162472 | ||
|
|
9082c4378a | ||
|
|
0bcbe408e7 | ||
|
|
9687825fe0 | ||
|
|
ec0ae9dc99 | ||
|
|
8a56b2bd16 | ||
|
|
104b7f67b4 | ||
|
|
6f919cdb01 | ||
|
|
59b29e7b86 | ||
|
|
c2538ad118 | ||
|
|
3334d7df48 | ||
|
|
6fc6906274 | ||
|
|
3bb8d5da68 | ||
|
|
51f25cf68d | ||
|
|
49a18944ed | ||
|
|
71196f474b | ||
|
|
c7a56e50fa | ||
|
|
0659d2a672 | ||
|
|
18c3504596 | ||
|
|
aa614489b4 | ||
|
|
93e33b001c | ||
|
|
e79e874a18 | ||
|
|
561965bb6a | ||
|
|
250aaa44ab | ||
|
|
cd9bbe3df8 | ||
|
|
79fadeff4d | ||
|
|
453777ead0 | ||
|
|
353e281470 | ||
|
|
b77b8d90d8 | ||
|
|
08945a10a1 | ||
|
|
580c1fcf7d | ||
|
|
7163953851 | ||
|
|
e647408062 | ||
|
|
7d152b8afc | ||
|
|
45c0ff2a20 | ||
|
|
dc5bbb58f8 | ||
|
|
e3b4ac36b0 | ||
|
|
33ed452081 | ||
|
|
3efe58ac1e | ||
|
|
4d2a32cbd1 | ||
|
|
943f4dc543 | ||
|
|
ff3795a815 | ||
|
|
c486b81dd4 | ||
|
|
f9929c21d6 | ||
|
|
a1d3902b01 | ||
|
|
8068f1f106 | ||
|
|
0fb9b21a4e | ||
|
|
ad08a8de35 | ||
|
|
c57b275de8 | ||
|
|
174defbd1a | ||
|
|
6622cf0d99 | ||
|
|
832e5e4ab5 | ||
|
|
8d7dd30c0b | ||
|
|
e746cd33f4 | ||
|
|
9485ec734f | ||
|
|
35e93072f6 | ||
|
|
fa699e6eeb | ||
|
|
482ae6f86f | ||
|
|
068c9357c9 | ||
|
|
d3b06902d8 | ||
|
|
d85e9f09dc | ||
|
|
3a8f125dd7 | ||
|
|
0e6d826af4 | ||
|
|
2202e07785 | ||
|
|
cf61502734 | ||
|
|
4e5b9ca969 | ||
|
|
ea66a6d175 | ||
|
|
a380b44165 | ||
|
|
8ce0fb6506 | ||
|
|
98a72a5a4c | ||
|
|
7c2b5fe273 | ||
|
|
8dd3acae41 | ||
|
|
d5b787cd2b | ||
|
|
8122d347f0 | ||
|
|
b8fa86ed1e | ||
|
|
3f49c8f000 | ||
|
|
ad5f6f5fe8 | ||
|
|
4509e0c8fe | ||
|
|
799f583ff3 | ||
|
|
623e21fc18 | ||
|
|
4ba9f3c142 | ||
|
|
718538b729 | ||
|
|
dfaeb570e5 | ||
|
|
1ce6d52963 | ||
|
|
6b66d46156 | ||
|
|
f4d9dc0db7 | ||
|
|
24a0069c20 | ||
|
|
610e219fa5 | ||
|
|
d7b5a6120d | ||
|
|
e947652bcf | ||
|
|
12639186cb | ||
|
|
197dd8eff8 | ||
|
|
63753656af | ||
|
|
f3560581ce | ||
|
|
5119038f9c | ||
|
|
86cb9c5a27 | ||
|
|
a079acbacd | ||
|
|
dc8f73f107 | ||
|
|
09b03e9b1c | ||
|
|
67750bf9bf | ||
|
|
7eb51a9a30 | ||
|
|
f2e4a1f357 | ||
|
|
ceca9875cf | ||
|
|
957b672d7a | ||
|
|
e150dd6d9e | ||
|
|
f03e0d21ee | ||
|
|
58238ef54a | ||
|
|
9c5ecb509a | ||
|
|
cb14e48f1d | ||
|
|
405c42eb81 | ||
|
|
2df8e5554d | ||
|
|
213aece7e9 | ||
|
|
5c5ffc645d | ||
|
|
4d41bab6e6 | ||
|
|
aa3c83f044 | ||
|
|
676d9ce8ac | ||
|
|
f36a964fdd | ||
|
|
eedfeb1022 | ||
|
|
4ca68510b0 | ||
|
|
5f3a6a19f2 | ||
|
|
1a073e5db5 | ||
|
|
9cb57ef35f | ||
|
|
7f29082e95 | ||
|
|
75ba956176 | ||
|
|
f3d20b8e14 | ||
|
|
03caa9b349 | ||
|
|
7bef32522e | ||
|
|
48fd6fdb1e | ||
|
|
7d0550259b | ||
|
|
bd94b445de | ||
|
|
6af4597b80 | ||
|
|
a565ac232d | ||
|
|
711564c452 | ||
|
|
34d1127f98 | ||
|
|
8926a0d96b | ||
|
|
c014f6db04 | ||
|
|
2625f10997 | ||
|
|
d1ab51e7cd | ||
|
|
907c1fc0be | ||
|
|
212e29b659 | ||
|
|
b44b5f8bb2 | ||
|
|
63a7f27313 | ||
|
|
e76be64f9d | ||
|
|
2ddd929473 | ||
|
|
a83000b4d3 | ||
|
|
a3fcc3904a | ||
|
|
d92f3234c7 | ||
|
|
007eeff1d8 | ||
|
|
4633ba5c79 | ||
|
|
5665cb0366 | ||
|
|
6592f3d36e | ||
|
|
51acb84736 | ||
|
|
f9d3bcbb37 | ||
|
|
1a17730862 | ||
|
|
271dff2353 | ||
|
|
6001bec44b | ||
|
|
95f7fba8ae | ||
|
|
a53c815da0 | ||
|
|
ad3b4f76aa | ||
|
|
595f2af341 | ||
|
|
176de995b8 | ||
|
|
dd36e171b0 | ||
|
|
e2c4cb6c07 | ||
|
|
2871422507 | ||
|
|
e5197a9417 | ||
|
|
63089bc5fe | ||
|
|
42847962b4 | ||
|
|
c160ee8b03 | ||
|
|
6acc65ac92 | ||
|
|
7c34268f84 | ||
|
|
db594e16fd | ||
|
|
58565c8686 | ||
|
|
3371a31885 | ||
|
|
75d1505a44 | ||
|
|
f2f122dab1 | ||
|
|
8807fcbe44 | ||
|
|
0a4f89cae3 | ||
|
|
0032cee9a6 | ||
|
|
4be1620759 | ||
|
|
6fd8668b70 | ||
|
|
dfb272e626 | ||
|
|
0ae75e0dbd | ||
|
|
3d8391174b | ||
|
|
007afa4017 | ||
|
|
3e6d01a15b | ||
|
|
ac3b3d6957 | ||
|
|
c96925e0fe | ||
|
|
6777853f39 | ||
|
|
ed90af6a86 | ||
|
|
0ba8091882 | ||
|
|
8ad07e027f | ||
|
|
0fae65d634 | ||
|
|
a1f3d96e8e | ||
|
|
88ef49e500 | ||
|
|
561a74d809 | ||
|
|
6c8fe05507 | ||
|
|
b27f1a7bd9 | ||
|
|
bb805940c2 | ||
|
|
dde32db1c4 | ||
|
|
52ae1c0627 | ||
|
|
3d18d339e4 | ||
|
|
d78e284e55 | ||
|
|
bb8d835ad4 | ||
|
|
6dc43a1ab0 | ||
|
|
39d556d66e | ||
|
|
d6f69b5b26 | ||
|
|
434016150e | ||
|
|
eb3403b0ff | ||
|
|
a46642e192 | ||
|
|
3fd8d9da79 | ||
|
|
e207f7fe64 | ||
|
|
d8b4865d84 | ||
|
|
ea5841d1f7 | ||
|
|
e338fff35a | ||
|
|
34cc5c4069 | ||
|
|
ef1536eda0 | ||
|
|
caceba4d23 | ||
|
|
0447d69a6d | ||
|
|
a05d7b8980 | ||
|
|
c350469e93 | ||
|
|
70eae5b306 | ||
|
|
670101783b | ||
|
|
b7c27f5b01 | ||
|
|
ac3de6debd | ||
|
|
14792b8ce0 | ||
|
|
71ce393683 | ||
|
|
3ce23a8ee0 | ||
|
|
db3bbdcf45 | ||
|
|
1a0d82a402 | ||
|
|
c8b4c3e6c5 | ||
|
|
204cd44ea9 | ||
|
|
325ad5bce3 | ||
|
|
b733076165 | ||
|
|
5e9083e754 | ||
|
|
ab59dc4791 | ||
|
|
ccfa664b48 | ||
|
|
9b9eb640f8 | ||
|
|
297cfde6a3 | ||
|
|
3dab146b8d | ||
|
|
0b9727f299 | ||
|
|
d3ce64a768 | ||
|
|
9291f534c6 | ||
|
|
71f670ac1d | ||
|
|
1864c9c346 | ||
|
|
cfd5b6bbe1 | ||
|
|
e26666280c | ||
|
|
e5843f64fd | ||
|
|
fdb8774c95 | ||
|
|
5b483df29b | ||
|
|
7dee146a8c | ||
|
|
e24d94eeff | ||
|
|
4789e831df | ||
|
|
b41d6167b4 | ||
|
|
c0bbe773d9 | ||
|
|
6fb8e3c3af | ||
|
|
1dcd9babd4 | ||
|
|
45523c03c0 | ||
|
|
8436b46c1a | ||
|
|
322ca38767 | ||
|
|
91f15dc690 | ||
|
|
beb7fe591e | ||
|
|
17fb071814 | ||
|
|
012cb20bb3 | ||
|
|
ece35b2539 | ||
|
|
fe2ee86172 | ||
|
|
9caf7a950a | ||
|
|
a13f184ef1 | ||
|
|
1bc1b8e50c | ||
|
|
9b5dfb4e42 |
16
.github/workflows/ci.yml
vendored
Normal file
16
.github/workflows/ci.yml
vendored
Normal 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
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,8 @@
|
|||||||
dist
|
dist
|
||||||
.project_env.rc
|
.project_env.rc
|
||||||
.path_progress
|
.path_progress
|
||||||
|
.rvmrc
|
||||||
|
.ruby-version
|
||||||
|
*.rbc
|
||||||
|
koans/*
|
||||||
|
*~
|
||||||
|
|||||||
12
DEPLOYING
Normal file
12
DEPLOYING
Normal 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.
|
||||||
20
MIT-LICENSE
20
MIT-LICENSE
@@ -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.
|
|
||||||
121
README.rdoc
121
README.rdoc
@@ -1,16 +1,16 @@
|
|||||||
= EdgeCase Ruby Koans
|
= Ruby Koans
|
||||||
|
|
||||||
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
|
The Ruby Koans walk you along the path to enlightenment in order to learn Ruby.
|
||||||
The goal is to learn the Ruby language, syntax, structure, and some common
|
The 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
|
functions and libraries. We also teach you culture by basing the koans on tests.
|
||||||
pay lip service to, but something we live. It is essential in your quest to learn
|
Testing is not just something we pay lip service to, but something we
|
||||||
and do great things in the language.
|
live. Testing is essential in your quest to learn and do great things in Ruby.
|
||||||
|
|
||||||
== The Structure
|
== The Structure
|
||||||
|
|
||||||
The koans are broken out into areas by file, hashes are covered in about_hashes.rb,
|
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
|
modules are introduced in +about_modules.rb+, <em>etc</em>. They are presented in
|
||||||
path_to_enlightenment.rb file.
|
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.
|
the first place you need to correct.
|
||||||
@@ -23,28 +23,41 @@ make it work correctly.
|
|||||||
== Installing Ruby
|
== Installing Ruby
|
||||||
|
|
||||||
If you do not have Ruby setup, please visit http://ruby-lang.org/en/downloads/ for
|
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
|
operating specific instructions. In order to run the koans you need +ruby+ and
|
||||||
installed. To check the installations simply type:
|
+rake+ installed. To check your installations simply type:
|
||||||
|
|
||||||
*nix platforms from any terminal window:
|
*nix platforms from any terminal window:
|
||||||
|
|
||||||
[~] $ ruby --version
|
[~] $ ruby --version
|
||||||
[~] $ rake --version
|
[~] $ rake --version
|
||||||
|
|
||||||
Windows from the command prompt (cmd.exe)
|
Windows from the command prompt (+cmd.exe+)
|
||||||
|
|
||||||
c:\ruby --version
|
c:\ruby --version
|
||||||
c:\rake --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
|
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
|
== 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).
|
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] $ rake # runs the default target :walk_the_path
|
||||||
[ruby_koans] $ ruby path_to_enlightenment.rb # simply call the file directly
|
[ruby_koans] $ ruby path_to_enlightenment.rb # simply call the file directly
|
||||||
@@ -56,54 +69,88 @@ Windows is the same thing
|
|||||||
|
|
||||||
=== Red, Green, Refactor
|
=== Red, Green, Refactor
|
||||||
|
|
||||||
In test-driven development the mantra has always been, red, green, refactor. Write a
|
In test-driven development the mantra has always been <em>red, green, refactor</em>.
|
||||||
failing test and run it (red), make the test pass (green), then refactor it (that is
|
Write a failing test and run it (<em>red</em>), make the test pass (<em>green</em>),
|
||||||
look at the code and see if you can make it any better. In this case you will need
|
then look at the code and consider if you can make it any better (<em>refactor</em>).
|
||||||
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:
|
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
|
[ ruby_koans ] $ rake
|
||||||
(in /Users/person/dev/ruby_koans)
|
(in /Users/person/dev/ruby_koans)
|
||||||
cd koans
|
/usr/bin/ruby1.8 path_to_enlightenment.rb
|
||||||
|
|
||||||
Thinking AboutAsserts
|
AboutAsserts#test_assert_truth has damaged your karma.
|
||||||
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.
|
<false> is not true.
|
||||||
|
|
||||||
Please meditate on the following code:
|
Please meditate on the following code:
|
||||||
./about_asserts.rb:10:in `test_assert_truth'
|
./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
|
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:
|
the first solution:
|
||||||
|
|
||||||
Please meditate on the following code:
|
Please meditate on the following code:
|
||||||
./about_asserts.rb:10:in `test_assert_truth'
|
./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.
|
# We shall contemplate truth by testing reality, via asserts.
|
||||||
def test_assert_truth
|
def test_assert_truth
|
||||||
assert false # This should be true
|
assert false # This should be true
|
||||||
end
|
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
|
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
|
the method name (+test_assert_truth+) and the parts inside the method (everything
|
||||||
before the +end+).
|
before the +end+).
|
||||||
|
|
||||||
In this case the goal is for you to see that if you pass a value to the +assert+
|
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+.
|
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
|
== Inspiration
|
||||||
|
|
||||||
A special thanks to Mike Clark and Ara Howard for inspiring this
|
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
|
= Other stuff
|
||||||
|
|
||||||
Author :: Jim Weirich <jim@weirichhouse.org>
|
Author :: Jim Weirich <jim@neo.org>
|
||||||
Author :: Joe O'Brien <joe@edgecase.com>
|
Author :: Joe O'Brien <joe@objo.com>
|
||||||
Issue Tracker :: http://www.pivotaltracker.com/projects/48111
|
Issue Tracker :: https://github.com/edgecase/ruby_koans/issues
|
||||||
Requires :: Ruby 1.8.x or later and Rake (any recent version)
|
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
110
Rakefile
Normal file → Executable file
@@ -2,35 +2,38 @@
|
|||||||
# -*- ruby -*-
|
# -*- ruby -*-
|
||||||
|
|
||||||
require 'rake/clean'
|
require 'rake/clean'
|
||||||
require 'rake/rdoctask'
|
|
||||||
|
|
||||||
SRC_DIR = 'src'
|
SRC_DIR = 'src'
|
||||||
PROB_DIR = 'koans'
|
PROB_DIR = 'koans'
|
||||||
DIST_DIR = 'dist'
|
DOWNLOAD_DIR = 'download'
|
||||||
|
|
||||||
SRC_FILES = FileList["#{SRC_DIR}/*"]
|
SRC_FILES = FileList["#{SRC_DIR}/*"]
|
||||||
KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f")
|
KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f")
|
||||||
|
|
||||||
TAR_FILE = "#{DIST_DIR}/rubykoans.tgz"
|
ZIP_FILE = "#{DOWNLOAD_DIR}/rubykoans.zip"
|
||||||
ZIP_FILE = "#{DIST_DIR}/rubykoans.zip"
|
|
||||||
|
|
||||||
CLOBBER.include(DIST_DIR)
|
CLEAN.include("**/*.rbc")
|
||||||
|
|
||||||
module Koans
|
module Koans
|
||||||
|
extend Rake::DSL if defined?(Rake::DSL)
|
||||||
|
|
||||||
|
# Remove solution info from source
|
||||||
|
# __(a,b) => __
|
||||||
|
# _n_(number) => __
|
||||||
|
# # __ =>
|
||||||
def Koans.remove_solution(line)
|
def Koans.remove_solution(line)
|
||||||
line = line.gsub(/\b____\([^\)]+\)/, "____")
|
line = line.gsub(/\b____\([^\)]+\)/, "____")
|
||||||
line = line.gsub(/\b___\([^\)]+\)/, "___")
|
line = line.gsub(/\b___\([^\)]+\)/, "___")
|
||||||
line = line.gsub(/\b__\([^\)]+\)/, "__")
|
line = line.gsub(/\b__\([^\)]+\)/, "__")
|
||||||
line = line.gsub(/\b_n_\([^\)]+\)/, "_n_")
|
line = line.gsub(/\b_n_\([^\)]+\)/, "_n_")
|
||||||
line = line.gsub(%r(/\#\{__\}/), "/__/")
|
line = line.gsub(%r(/\#\{__\}/), "/__/")
|
||||||
|
line = line.gsub(/\s*#\s*__\s*$/, '')
|
||||||
line
|
line
|
||||||
end
|
end
|
||||||
|
|
||||||
def Koans.make_koan_file(infile, outfile)
|
def Koans.make_koan_file(infile, outfile)
|
||||||
if infile =~ /edgecase/
|
if infile =~ /neo/
|
||||||
cp infile, outfile
|
cp infile, outfile
|
||||||
elsif infile =~ /autotest/
|
|
||||||
cp_r infile, outfile
|
|
||||||
else
|
else
|
||||||
open(infile) do |ins|
|
open(infile) do |ins|
|
||||||
open(outfile, "w") do |outs|
|
open(outfile, "w") do |outs|
|
||||||
@@ -51,46 +54,56 @@ module Koans
|
|||||||
end
|
end
|
||||||
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 :default => :walk_the_path
|
||||||
|
|
||||||
task :walk_the_path do
|
task :walk_the_path do
|
||||||
cd 'koans'
|
cd PROB_DIR
|
||||||
ruby 'path_to_enlightenment.rb'
|
ruby 'path_to_enlightenment.rb'
|
||||||
end
|
end
|
||||||
|
|
||||||
Rake::RDocTask.new do |rd|
|
directory DOWNLOAD_DIR
|
||||||
rd.main = "README.rdoc"
|
|
||||||
rd.rdoc_files.include("README.rdoc", "koans/*.rb")
|
|
||||||
end
|
|
||||||
|
|
||||||
directory DIST_DIR
|
|
||||||
directory PROB_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}/*"
|
sh "zip #{ZIP_FILE} #{PROB_DIR}/*"
|
||||||
end
|
end
|
||||||
|
|
||||||
file TAR_FILE => KOAN_FILES + [DIST_DIR] do
|
|
||||||
sh "tar zcvf #{TAR_FILE} #{PROB_DIR}"
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Create packaged files for distribution"
|
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"
|
desc "Upload the package files to the web server"
|
||||||
task :upload => [TAR_FILE, ZIP_FILE] do
|
task :upload => [ZIP_FILE] do
|
||||||
sh "scp #{TAR_FILE} linode:sites/onestepback.org/download"
|
|
||||||
sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download"
|
sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download"
|
||||||
end
|
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."
|
desc "Generate the Koans from the source files from scratch."
|
||||||
task :regen => [:clobber_koans, :gen]
|
task :regen => [:clobber_koans, :gen]
|
||||||
|
|
||||||
@@ -109,3 +122,38 @@ SRC_FILES.each do |koan_src|
|
|||||||
Koans.make_koan_file koan_src, t.name
|
Koans.make_koan_file koan_src, t.name
|
||||||
end
|
end
|
||||||
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
BIN
download/rubykoans.zip
Normal file
Binary file not shown.
BIN
keynote/RubyKoans.key
Normal file
BIN
keynote/RubyKoans.key
Normal file
Binary file not shown.
@@ -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.
|
|
||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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.
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Autotest.add_discovery do
|
|
||||||
"rubykoan" if File.exist? 'path_to_enlightenment.rb'
|
|
||||||
end
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|
||||||
@@ -1,409 +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, :pass_count
|
|
||||||
|
|
||||||
in_ruby_version("1.8") do
|
|
||||||
AssertionError = Test::Unit::AssertionFailedError
|
|
||||||
end
|
|
||||||
|
|
||||||
in_ruby_version("1.9") do
|
|
||||||
if defined?(MiniTest)
|
|
||||||
AssertionError = MiniTest::Assertion
|
|
||||||
else
|
|
||||||
AssertionError = Test::Unit::AssertionFailedError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@pass_count = 0
|
|
||||||
@failure = nil
|
|
||||||
@failed_test = nil
|
|
||||||
@observations = []
|
|
||||||
end
|
|
||||||
|
|
||||||
PROGRESS_FILE_NAME = '.path_progress'
|
|
||||||
|
|
||||||
def add_progress(prog)
|
|
||||||
@_contents = nil
|
|
||||||
exists = File.exists?(PROGRESS_FILE_NAME)
|
|
||||||
File.open(PROGRESS_FILE_NAME,'a+') do |f|
|
|
||||||
f.print "#{',' if exists}#{prog}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def progress
|
|
||||||
if @_contents.nil?
|
|
||||||
if File.exists?(PROGRESS_FILE_NAME)
|
|
||||||
File.open(PROGRESS_FILE_NAME,'r') do |f|
|
|
||||||
@_contents = f.read.to_s.gsub(/\s/,'').split(',')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@_contents = []
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@_contents
|
|
||||||
end
|
|
||||||
|
|
||||||
def observe(step)
|
|
||||||
if step.passed?
|
|
||||||
@pass_count += 1
|
|
||||||
if @pass_count > progress.last.to_i
|
|
||||||
@observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
@failed_test = step
|
|
||||||
@failure = step.failure
|
|
||||||
add_progress(@pass_count)
|
|
||||||
@observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.")
|
|
||||||
throw :edgecase_exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def failed?
|
|
||||||
! @failure.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_failed?
|
|
||||||
failure.is_a?(AssertionError)
|
|
||||||
end
|
|
||||||
|
|
||||||
def instruct
|
|
||||||
if failed?
|
|
||||||
@observations.each{|c| puts c }
|
|
||||||
encourage
|
|
||||||
guide_through_error
|
|
||||||
a_zenlike_statement
|
|
||||||
show_progress
|
|
||||||
else
|
|
||||||
end_screen
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_progress
|
|
||||||
bar_width = 50
|
|
||||||
total_tests = EdgeCase::Koan.total_tests
|
|
||||||
scale = bar_width.to_f/total_tests
|
|
||||||
print Color.green("your path thus far [")
|
|
||||||
happy_steps = (pass_count*scale).to_i
|
|
||||||
happy_steps = 1 if happy_steps == 0 && pass_count > 0
|
|
||||||
print Color.green('.'*happy_steps)
|
|
||||||
if failed?
|
|
||||||
print Color.red('X')
|
|
||||||
print Color.cyan('_'*(bar_width-1-happy_steps))
|
|
||||||
end
|
|
||||||
print Color.green(']')
|
|
||||||
print " #{pass_count}/#{total_tests}"
|
|
||||||
puts
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_screen
|
|
||||||
completed = <<-ENDTEXT
|
|
||||||
,, , ,,
|
|
||||||
: ::::, :::,
|
|
||||||
, ,,: :::::::::::::,, :::: : ,
|
|
||||||
, ,,, ,:::::::::::::::::::, ,: ,: ,,
|
|
||||||
:, ::, , , :, ,::::::::::::::::::, ::: ,::::
|
|
||||||
: : ::, ,:::::::: ::, ,::::
|
|
||||||
, ,::::: :,:::::::,::::,
|
|
||||||
,: , ,:,,: :::::::::::::
|
|
||||||
::,: ,,:::, ,::::::::::::,
|
|
||||||
,:::, :,,::: ::::::::::::,
|
|
||||||
,::: :::::::, Mountains are again merely mountains ,::::::::::::
|
|
||||||
:::,,,:::::: ::::::::::::
|
|
||||||
,:::::::::::, ::::::::::::,
|
|
||||||
:::::::::::, ,::::::::::::
|
|
||||||
::::::::::::: ,::::::::::::
|
|
||||||
:::::::::::: Ruby Koans ::::::::::::,
|
|
||||||
:::::::::::: ,::::::::::::,
|
|
||||||
:::::::::::, , ::::::::::::
|
|
||||||
,:::::::::::::, brought to you by ,,::::::::::::,
|
|
||||||
:::::::::::::: ,::::::::::::
|
|
||||||
::::::::::::::, ,:::::::::::::
|
|
||||||
::::::::::::, EdgeCase Software Artisans , ::::::::::::
|
|
||||||
:,::::::::: :::: :::::::::::::
|
|
||||||
,::::::::::: ,: ,,:::::::::::::,
|
|
||||||
:::::::::::: ,::::::::::::::,
|
|
||||||
:::::::::::::::::, ::::::::::::::::
|
|
||||||
:::::::::::::::::::, ::::::::::::::::
|
|
||||||
::::::::::::::::::::::, ,::::,:, , ::::,:::
|
|
||||||
:::::::::::::::::::::::, ::,: ::,::, ,,: ::::
|
|
||||||
,:::::::::::::::::::: ::,, , ,, ,::::
|
|
||||||
,:::::::::::::::: ::,, , ,:::,
|
|
||||||
,:::: , ,,
|
|
||||||
,,,
|
|
||||||
ENDTEXT
|
|
||||||
puts completed
|
|
||||||
end
|
|
||||||
|
|
||||||
def encourage
|
|
||||||
puts
|
|
||||||
puts "The Master says:"
|
|
||||||
puts Color.cyan(" You have not yet reached enlightenment.")
|
|
||||||
if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1)
|
|
||||||
puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.")
|
|
||||||
elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1
|
|
||||||
puts Color.cyan(" Do not lose hope.")
|
|
||||||
elsif progress.last.to_i > 0
|
|
||||||
puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def guide_through_error
|
|
||||||
puts
|
|
||||||
puts "The answers you seek..."
|
|
||||||
puts Color.red(indent(failure.message).join)
|
|
||||||
puts
|
|
||||||
puts "Please meditate on the following code:"
|
|
||||||
if assert_failed?
|
|
||||||
puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
|
|
||||||
else
|
|
||||||
puts embolden_first_line_only(indent(failure.backtrace))
|
|
||||||
end
|
|
||||||
puts
|
|
||||||
end
|
|
||||||
|
|
||||||
def embolden_first_line_only(text)
|
|
||||||
first_line = true
|
|
||||||
text.collect { |t|
|
|
||||||
if first_line
|
|
||||||
first_line = false
|
|
||||||
Color.red(t)
|
|
||||||
else
|
|
||||||
Color.cyan(t)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def indent(text)
|
|
||||||
text.collect{|t| " #{t}"}
|
|
||||||
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
|
|
||||||
if !failed?
|
|
||||||
zen_statement = "Mountains are again merely mountains"
|
|
||||||
else
|
|
||||||
zen_statement = case (@pass_count % 10)
|
|
||||||
when 0
|
|
||||||
"mountains are merely mountains"
|
|
||||||
when 1, 2
|
|
||||||
"learn the rules so you know how to break them properly"
|
|
||||||
when 3, 4
|
|
||||||
"remember that silence is sometimes the best answer"
|
|
||||||
when 5, 6
|
|
||||||
"sleep is the best meditation"
|
|
||||||
when 7, 8
|
|
||||||
"when you lose, don't lose the lesson"
|
|
||||||
else
|
|
||||||
"things are not what they appear to be: nor are they otherwise"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
puts Color.green(zen_statement)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Koan
|
|
||||||
include Test::Unit::Assertions
|
|
||||||
|
|
||||||
attr_reader :name, :failure, :koan_count, :step_count, :koan_file
|
|
||||||
|
|
||||||
def initialize(name, koan_file=nil, koan_count=0, step_count=0)
|
|
||||||
@name = name
|
|
||||||
@failure = nil
|
|
||||||
@koan_count = koan_count
|
|
||||||
@step_count = step_count
|
|
||||||
@koan_file = koan_file
|
|
||||||
end
|
|
||||||
|
|
||||||
def passed?
|
|
||||||
@failure.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def failed(failure)
|
|
||||||
@failure = failure
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup
|
|
||||||
end
|
|
||||||
|
|
||||||
def teardown
|
|
||||||
end
|
|
||||||
|
|
||||||
def meditate
|
|
||||||
setup
|
|
||||||
begin
|
|
||||||
send(name)
|
|
||||||
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
|
|
||||||
failed(ex)
|
|
||||||
ensure
|
|
||||||
begin
|
|
||||||
teardown
|
|
||||||
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
|
|
||||||
failed(ex) if passed?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
# Class methods for the EdgeCase test suite.
|
|
||||||
class << self
|
|
||||||
def inherited(subclass)
|
|
||||||
subclasses << subclass
|
|
||||||
end
|
|
||||||
|
|
||||||
def method_added(name)
|
|
||||||
testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def end_of_enlightenment
|
|
||||||
@tests_disabled = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def command_line(args)
|
|
||||||
args.each do |arg|
|
|
||||||
case arg
|
|
||||||
when /^-n\/(.*)\/$/
|
|
||||||
@test_pattern = Regexp.new($1)
|
|
||||||
when /^-n(.*)$/
|
|
||||||
@test_pattern = Regexp.new(Regexp.quote($1))
|
|
||||||
else
|
|
||||||
if File.exist?(arg)
|
|
||||||
load(arg)
|
|
||||||
else
|
|
||||||
fail "Unknown command line argument '#{arg}'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Lazy initialize list of subclasses
|
|
||||||
def subclasses
|
|
||||||
@subclasses ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
# Lazy initialize list of test methods.
|
|
||||||
def testmethods
|
|
||||||
@test_methods ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
def tests_disabled?
|
|
||||||
@tests_disabled ||= false
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_pattern
|
|
||||||
@test_pattern ||= /^test_/
|
|
||||||
end
|
|
||||||
|
|
||||||
def total_tests
|
|
||||||
self.subclasses.inject(0){|total, k| total + k.testmethods.size }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class ThePath
|
|
||||||
def walk
|
|
||||||
sensei = EdgeCase::Sensei.new
|
|
||||||
each_step do |step|
|
|
||||||
sensei.observe(step.meditate)
|
|
||||||
end
|
|
||||||
sensei.instruct
|
|
||||||
end
|
|
||||||
|
|
||||||
def each_step
|
|
||||||
catch(:edgecase_exit) {
|
|
||||||
step_count = 0
|
|
||||||
EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index|
|
|
||||||
koan.testmethods.each do |method_name|
|
|
||||||
step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1)
|
|
||||||
yield step
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
END {
|
|
||||||
EdgeCase::Koan.command_line(ARGV)
|
|
||||||
EdgeCase::ThePath.new.walk
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
this
|
|
||||||
is
|
|
||||||
a
|
|
||||||
test
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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'
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
require 'test/unit'
|
|
||||||
|
|
||||||
def __
|
|
||||||
"FILL ME IN"
|
|
||||||
end
|
|
||||||
|
|
||||||
EdgeCase = Test::Unit
|
|
||||||
@@ -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
33
rakelib/checks.rake
Normal 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
8
rakelib/run.rake
Normal 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
9
rakelib/test.rake
Normal 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'
|
||||||
|
|
||||||
@@ -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
|
def test_non_parallel_assignment
|
||||||
names = ["John", "Smith"]
|
names = ["John", "Smith"]
|
||||||
assert_equal __(["John", "Smith"]), names
|
assert_equal __(["John", "Smith"]), names
|
||||||
@@ -18,13 +18,19 @@ class AboutArrayAssignment < EdgeCase::Koan
|
|||||||
assert_equal __("Smith"), last_name
|
assert_equal __("Smith"), last_name
|
||||||
end
|
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"]
|
first_name, last_name = ["Cher"]
|
||||||
assert_equal __("Cher"), first_name
|
assert_equal __("Cher"), first_name
|
||||||
assert_equal __(nil), last_name
|
assert_equal __(nil), last_name
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_parallel_assignements_with_subarrays
|
def test_parallel_assignments_with_subarrays
|
||||||
first_name, last_name = [["Willie", "Rae"], "Johnson"]
|
first_name, last_name = [["Willie", "Rae"], "Johnson"]
|
||||||
assert_equal __(["Willie", "Rae"]), first_name
|
assert_equal __(["Willie", "Rae"]), first_name
|
||||||
assert_equal __("Johnson"), last_name
|
assert_equal __("Johnson"), last_name
|
||||||
|
|||||||
@@ -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
|
def test_creating_arrays
|
||||||
empty_array = Array.new
|
empty_array = Array.new
|
||||||
assert_equal Array, empty_array.class
|
assert_equal __(Array), empty_array.class
|
||||||
assert_equal __(0), empty_array.size
|
assert_equal __(0), empty_array.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_array_literals
|
def test_array_literals
|
||||||
array = Array.new
|
array = Array.new
|
||||||
assert_equal [], array
|
assert_equal [], array # __
|
||||||
|
|
||||||
array[0] = 1
|
array[0] = 1
|
||||||
assert_equal [1], array
|
assert_equal [1], array # __
|
||||||
|
|
||||||
array[1] = 2
|
array[1] = 2
|
||||||
assert_equal [1, __(2)], array
|
assert_equal [1, __(2)], array
|
||||||
@@ -45,9 +45,9 @@ class AboutArrays < EdgeCase::Koan
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_arrays_and_ranges
|
def test_arrays_and_ranges
|
||||||
assert_equal Range, (1..5).class
|
assert_equal __(Range), (1..5).class
|
||||||
assert_not_equal [1,2,3,4,5], (1..5)
|
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,5]), (1..5).to_a
|
||||||
assert_equal __([1,2,3,4]), (1...5).to_a
|
assert_equal __([1,2,3,4]), (1...5).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
# -*- 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.
|
# We shall contemplate truth by testing reality, via asserts.
|
||||||
def test_assert_truth
|
def test_assert_truth
|
||||||
|
|||||||
@@ -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
|
def method_with_block
|
||||||
result = yield
|
result = yield
|
||||||
result
|
result
|
||||||
@@ -23,7 +23,7 @@ class AboutBlocks < EdgeCase::Koan
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_blocks_can_take_arguments
|
def test_blocks_can_take_arguments
|
||||||
result = method_with_block_arguments do |argument|
|
method_with_block_arguments do |argument|
|
||||||
assert_equal __("Jim"), argument
|
assert_equal __("Jim"), argument
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -70,7 +70,7 @@ class AboutBlocks < EdgeCase::Koan
|
|||||||
add_one = lambda { |n| n + 1 }
|
add_one = lambda { |n| n + 1 }
|
||||||
assert_equal __(11), add_one.call(10)
|
assert_equal __(11), add_one.call(10)
|
||||||
|
|
||||||
# Alternative calling sequence
|
# Alternative calling syntax
|
||||||
assert_equal __(11), add_one[10]
|
assert_equal __(11), add_one[10]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
class Dog
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -97,7 +97,6 @@ class AboutClassMethods < EdgeCase::Koan
|
|||||||
assert_equal __(:dogs_class_method), Dog.a_class_method
|
assert_equal __(:dogs_class_method), Dog.a_class_method
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
LastExpressionInClassStatement = class Dog
|
LastExpressionInClassStatement = class Dog
|
||||||
|
|||||||
@@ -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
|
class Dog
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -126,11 +126,11 @@ class AboutClasses < EdgeCase::Koan
|
|||||||
# Why is this so?
|
# Why is this so?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_different_objects_have_difference_instance_variables
|
def test_different_objects_have_different_instance_variables
|
||||||
fido = Dog6.new("Fido")
|
fido = Dog6.new("Fido")
|
||||||
rover = Dog6.new("Rover")
|
rover = Dog6.new("Rover")
|
||||||
|
|
||||||
assert_not_equal rover.name, fido.name
|
assert_equal __(true), rover.name != fido.name
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -147,7 +147,7 @@ class AboutClasses < EdgeCase::Koan
|
|||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
__(@name)
|
@name
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def inspect
|
||||||
@@ -164,12 +164,12 @@ class AboutClasses < EdgeCase::Koan
|
|||||||
|
|
||||||
def test_to_s_provides_a_string_version_of_the_object
|
def test_to_s_provides_a_string_version_of_the_object
|
||||||
fido = Dog7.new("Fido")
|
fido = Dog7.new("Fido")
|
||||||
assert_equal "Fido", fido.to_s
|
assert_equal __("Fido"), fido.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_to_s_is_used_in_string_interpolation
|
def test_to_s_is_used_in_string_interpolation
|
||||||
fido = Dog7.new("Fido")
|
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
|
end
|
||||||
|
|
||||||
def test_inspect_provides_a_more_complete_string_version
|
def test_inspect_provides_a_more_complete_string_version
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
require File.expand_path(File.dirname(__FILE__) + '/neo')
|
||||||
|
|
||||||
C = "top level"
|
C = "top level"
|
||||||
|
|
||||||
class AboutConstants < EdgeCase::Koan
|
class AboutConstants < Neo::Koan
|
||||||
|
|
||||||
C = "nested"
|
C = "nested"
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class AboutConstants < EdgeCase::Koan
|
|||||||
end
|
end
|
||||||
|
|
||||||
# QUESTION: Which has precedence: The constant in the lexical scope,
|
# 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
|
assert_equal __(4), MyAnimals::Oyster.new.legs_in_oyster
|
||||||
end
|
end
|
||||||
|
|
||||||
# QUESTION: Now Which has precedence: The constant in the lexical
|
# QUESTION: Now which has precedence: The constant in the lexical
|
||||||
# scope, or the constant from the inheritance heirarachy? Why is it
|
# scope, or the constant from the inheritance hierarchy? Why is it
|
||||||
# different than the previous answer?
|
# different than the previous answer?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
def test_if_then_else_statements
|
||||||
if true
|
if true
|
||||||
@@ -59,12 +59,20 @@ class AboutControlStatements < EdgeCase::Koan
|
|||||||
|
|
||||||
def test_unless_statement
|
def test_unless_statement
|
||||||
result = :default_value
|
result = :default_value
|
||||||
unless false
|
unless false # same as saying 'if !false', which evaluates as 'if true'
|
||||||
result = :false_value
|
result = :false_value
|
||||||
end
|
end
|
||||||
assert_equal __(:false_value), result
|
assert_equal __(:false_value), result
|
||||||
end
|
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
|
def test_unless_statement_modifier
|
||||||
result = :default_value
|
result = :default_value
|
||||||
result = :false_value unless false
|
result = :false_value unless false
|
||||||
@@ -93,6 +101,16 @@ class AboutControlStatements < EdgeCase::Koan
|
|||||||
assert_equal __(3628800), result
|
assert_equal __(3628800), result
|
||||||
end
|
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
|
def test_next_statement
|
||||||
i = 0
|
i = 0
|
||||||
result = []
|
result = []
|
||||||
@@ -113,4 +131,12 @@ class AboutControlStatements < EdgeCase::Koan
|
|||||||
assert_equal [__("FISH"), __("AND"), __("CHIPS")], result
|
assert_equal [__("FISH"), __("AND"), __("CHIPS")], result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_times_statement
|
||||||
|
sum = 0
|
||||||
|
10.times do
|
||||||
|
sum += 1
|
||||||
|
end
|
||||||
|
assert_equal __(10), sum
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
class DiceSet
|
||||||
attr_reader :values
|
attr_reader :values
|
||||||
def roll(n)
|
def roll(n)
|
||||||
@@ -7,7 +14,8 @@ class DiceSet
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class AboutDiceProject < EdgeCase::Koan
|
#++
|
||||||
|
class AboutDiceProject < Neo::Koan
|
||||||
def test_can_create_a_dice_set
|
def test_can_create_a_dice_set
|
||||||
dice = DiceSet.new
|
dice = DiceSet.new
|
||||||
assert_not_nil dice
|
assert_not_nil dice
|
||||||
@@ -48,7 +56,7 @@ class AboutDiceProject < EdgeCase::Koan
|
|||||||
#
|
#
|
||||||
# If the rolls are random, then it is possible (although not
|
# If the rolls are random, then it is possible (although not
|
||||||
# likely) that two consecutive rolls are equal. What would be a
|
# likely) that two consecutive rolls are equal. What would be a
|
||||||
# better way to test this.
|
# better way to test this?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_you_can_roll_different_numbers_of_dice
|
def test_you_can_roll_different_numbers_of_dice
|
||||||
|
|||||||
@@ -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
|
class MySpecialError < RuntimeError
|
||||||
end
|
end
|
||||||
@@ -22,10 +22,10 @@ class AboutExceptions < EdgeCase::Koan
|
|||||||
|
|
||||||
assert_equal __(:exception_handled), result
|
assert_equal __(:exception_handled), result
|
||||||
|
|
||||||
assert ex.is_a?(StandardError), "Failure message."
|
assert_equal __(true), ex.is_a?(StandardError), "Should be a Standard Error"
|
||||||
assert ex.is_a?(RuntimeError), "Failure message."
|
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"
|
"RuntimeError is a subclass of StandardError"
|
||||||
|
|
||||||
assert_equal __("Oops"), ex.message
|
assert_equal __("Oops"), ex.message
|
||||||
@@ -48,7 +48,7 @@ class AboutExceptions < EdgeCase::Koan
|
|||||||
result = nil
|
result = nil
|
||||||
begin
|
begin
|
||||||
fail "Oops"
|
fail "Oops"
|
||||||
rescue StandardError => ex
|
rescue StandardError
|
||||||
# no code here
|
# no code here
|
||||||
ensure
|
ensure
|
||||||
result = :always_run
|
result = :always_run
|
||||||
@@ -57,4 +57,12 @@ class AboutExceptions < EdgeCase::Koan
|
|||||||
assert_equal __(:always_run), result
|
assert_equal __(:always_run), result
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -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
|
def test_creating_hashes
|
||||||
empty_hash = Hash.new
|
empty_hash = Hash.new
|
||||||
assert_equal Hash, empty_hash.class
|
assert_equal __(Hash), empty_hash.class
|
||||||
assert_equal({}, empty_hash)
|
assert_equal(__({}), empty_hash)
|
||||||
assert_equal __(0), empty_hash.size
|
assert_equal __(0), empty_hash.size
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -20,12 +20,24 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
assert_equal __(nil), hash[:doesnt_exist]
|
assert_equal __(nil), hash[:doesnt_exist]
|
||||||
end
|
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
|
def test_changing_hashes
|
||||||
hash = { :one => "uno", :two => "dos" }
|
hash = { :one => "uno", :two => "dos" }
|
||||||
hash[:one] = "eins"
|
hash[:one] = "eins"
|
||||||
|
|
||||||
expected = { :one => __("eins"), :two => "dos" }
|
expected = { :one => __("eins"), :two => "dos" }
|
||||||
assert_equal expected, hash
|
assert_equal __(expected), hash
|
||||||
|
|
||||||
# Bonus Question: Why was "expected" broken out into a variable
|
# Bonus Question: Why was "expected" broken out into a variable
|
||||||
# rather than used as a literal?
|
# rather than used as a literal?
|
||||||
@@ -35,7 +47,7 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
hash1 = { :one => "uno", :two => "dos" }
|
hash1 = { :one => "uno", :two => "dos" }
|
||||||
hash2 = { :two => "dos", :one => "uno" }
|
hash2 = { :two => "dos", :one => "uno" }
|
||||||
|
|
||||||
assert_equal hash1, hash2
|
assert_equal __(true), hash1 == hash2
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hash_keys
|
def test_hash_keys
|
||||||
@@ -43,7 +55,7 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
assert_equal __(2), hash.keys.size
|
assert_equal __(2), hash.keys.size
|
||||||
assert_equal __(true), hash.keys.include?(:one)
|
assert_equal __(true), hash.keys.include?(:one)
|
||||||
assert_equal __(true), hash.keys.include?(:two)
|
assert_equal __(true), hash.keys.include?(:two)
|
||||||
assert_equal Array, hash.keys.class
|
assert_equal __(Array), hash.keys.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hash_values
|
def test_hash_values
|
||||||
@@ -51,16 +63,64 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
assert_equal __(2), hash.values.size
|
assert_equal __(2), hash.values.size
|
||||||
assert_equal __(true), hash.values.include?("uno")
|
assert_equal __(true), hash.values.include?("uno")
|
||||||
assert_equal __(true), hash.values.include?("dos")
|
assert_equal __(true), hash.values.include?("dos")
|
||||||
assert_equal Array, hash.values.class
|
assert_equal __(Array), hash.values.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_combining_hashes
|
def test_combining_hashes
|
||||||
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
|
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
|
||||||
new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })
|
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) }
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
class Dog
|
||||||
attr_reader :name
|
attr_reader :name
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class AboutInheritance < EdgeCase::Koan
|
|||||||
assert_equal __(true), Chihuahua.ancestors.include?(Object)
|
assert_equal __(true), Chihuahua.ancestors.include?(Object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_subcases_inherit_behavior_from_parent_class
|
def test_subclasses_inherit_behavior_from_parent_class
|
||||||
chico = Chihuahua.new("Chico")
|
chico = Chihuahua.new("Chico")
|
||||||
assert_equal __("Chico"), chico.name
|
assert_equal __("Chico"), chico.name
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
def test_each_is_a_method_on_arrays
|
||||||
[].methods.include?("each")
|
assert_equal __(true), [].methods.include?(as_name(:each))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_iterating_with_each
|
def test_iterating_with_each
|
||||||
@@ -12,25 +33,23 @@ class AboutIteration < EdgeCase::Koan
|
|||||||
array.each do |item|
|
array.each do |item|
|
||||||
sum += item
|
sum += item
|
||||||
end
|
end
|
||||||
assert_equal 6, sum
|
assert_equal __(6), sum
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_each_can_use_curly_brace_blocks_too
|
def test_each_can_use_curly_brace_blocks_too
|
||||||
array = [1, 2, 3]
|
array = [1, 2, 3]
|
||||||
sum = 0
|
sum = 0
|
||||||
array.each { |item|
|
array.each { |item| sum += item }
|
||||||
sum += item
|
|
||||||
}
|
|
||||||
assert_equal __(6), sum
|
assert_equal __(6), sum
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_break_works_with_each_style_iterations
|
def test_break_works_with_each_style_iterations
|
||||||
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
sum = 0
|
sum = 0
|
||||||
array.each { |item|
|
array.each do |item|
|
||||||
break if item > 3
|
break if item > 3
|
||||||
sum += item
|
sum += item
|
||||||
}
|
end
|
||||||
assert_equal __(6), sum
|
assert_equal __(6), sum
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -65,7 +84,7 @@ class AboutIteration < EdgeCase::Koan
|
|||||||
result = [2, 3, 4].inject(0) { |sum, item| sum + item }
|
result = [2, 3, 4].inject(0) { |sum, item| sum + item }
|
||||||
assert_equal __(9), result
|
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
|
assert_equal __(24), result2
|
||||||
|
|
||||||
# Extra Credit:
|
# Extra Credit:
|
||||||
|
|||||||
137
src/about_java_interop.rb
Normal file
137
src/about_java_interop.rb
Normal 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
|
||||||
43
src/about_keyword_arguments.rb
Normal file
43
src/about_keyword_arguments.rb
Normal 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
|
||||||
@@ -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
|
class MessageCatcher
|
||||||
def caught?
|
def caught?
|
||||||
@@ -11,19 +11,19 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
def test_methods_can_be_called_directly
|
def test_methods_can_be_called_directly
|
||||||
mc = MessageCatcher.new
|
mc = MessageCatcher.new
|
||||||
|
|
||||||
assert mc.caught?
|
assert mc.caught? # __
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_methods_can_be_invoked_by_sending_the_message
|
def test_methods_can_be_invoked_by_sending_the_message
|
||||||
mc = MessageCatcher.new
|
mc = MessageCatcher.new
|
||||||
|
|
||||||
assert mc.send(:caught?)
|
assert mc.send(:caught?) # __
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_methods_can_be_invoked_more_dynamically
|
def test_methods_can_be_invoked_more_dynamically
|
||||||
mc = MessageCatcher.new
|
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" + __("?") ) # What do you need to add to the first string?
|
||||||
assert mc.send("CAUGHT?".____(:downcase) ) # What would you need to do to the string?
|
assert mc.send("CAUGHT?".____(:downcase) ) # What would you need to do to the string?
|
||||||
end
|
end
|
||||||
@@ -63,6 +63,13 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
assert_equal __([3, 4, nil, 6]), mc.send(:add_a_payload, 3, 4, nil, 6)
|
assert_equal __([3, 4, nil, 6]), mc.send(:add_a_payload, 3, 4, nil, 6)
|
||||||
end
|
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
|
class TypicalObject
|
||||||
@@ -74,7 +81,7 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
exception = assert_raise(___(NoMethodError)) do
|
exception = assert_raise(___(NoMethodError)) do
|
||||||
typical.foobar
|
typical.foobar
|
||||||
end
|
end
|
||||||
assert_match(/foobar/, exception.message)
|
assert_match(/foobar/, exception.message) # __
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_calling_method_missing_causes_the_no_method_error
|
def test_calling_method_missing_causes_the_no_method_error
|
||||||
@@ -83,7 +90,7 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
exception = assert_raise(___(NoMethodError)) do
|
exception = assert_raise(___(NoMethodError)) do
|
||||||
typical.method_missing(:foobar)
|
typical.method_missing(:foobar)
|
||||||
end
|
end
|
||||||
assert_match(/foobar/, exception.message)
|
assert_match(/foobar/, exception.message) # __
|
||||||
|
|
||||||
# THINK ABOUT IT:
|
# THINK ABOUT IT:
|
||||||
#
|
#
|
||||||
@@ -93,13 +100,13 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
# NOTE:
|
# NOTE:
|
||||||
#
|
#
|
||||||
# In Ruby 1.8 the method_missing method is public and can be
|
# 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
|
# called as shown above. However, in Ruby 1.9 (and later versions)
|
||||||
# method is private. We explicitly made it public in the testing
|
# the method_missing method is private. We explicitly made it
|
||||||
# framework so this example works in both versions of Ruby. Just
|
# public in the testing framework so this example works in both
|
||||||
# keep in mind you can't call method_missing like that in Ruby
|
# versions of Ruby. Just keep in mind you can't call
|
||||||
# 1.9. normally.
|
# 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.
|
# Koans.
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -122,7 +129,7 @@ class AboutMessagePassing < EdgeCase::Koan
|
|||||||
def test_catching_messages_makes_respond_to_lie
|
def test_catching_messages_makes_respond_to_lie
|
||||||
catcher = AllMessageCatcher.new
|
catcher = AllMessageCatcher.new
|
||||||
|
|
||||||
assert_nothing_raised(NoMethodError) do
|
assert_nothing_raised do # __
|
||||||
catcher.any_method
|
catcher.any_method
|
||||||
end
|
end
|
||||||
assert_equal __(false), catcher.respond_to?(:any_method)
|
assert_equal __(false), catcher.respond_to?(:any_method)
|
||||||
|
|||||||
@@ -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)
|
def my_global_method(a,b)
|
||||||
a + b
|
a + b
|
||||||
end
|
end
|
||||||
|
|
||||||
class AboutMethods < EdgeCase::Koan
|
class AboutMethods < Neo::Koan
|
||||||
|
|
||||||
def test_calling_global_methods
|
def test_calling_global_methods
|
||||||
assert_equal __(5), my_global_method(2,3)
|
assert_equal __(5), my_global_method(2,3)
|
||||||
@@ -19,10 +19,10 @@ class AboutMethods < EdgeCase::Koan
|
|||||||
# considered to be syntactically invalid).
|
# considered to be syntactically invalid).
|
||||||
def test_sometimes_missing_parentheses_are_ambiguous
|
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
|
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
|
end
|
||||||
#++
|
#++
|
||||||
@@ -37,18 +37,22 @@ class AboutMethods < EdgeCase::Koan
|
|||||||
#
|
#
|
||||||
end
|
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.
|
# runtime error.
|
||||||
|
# tip: When regex contains parentheses, you must escape them with backslash.
|
||||||
def test_calling_global_methods_with_wrong_number_of_arguments
|
def test_calling_global_methods_with_wrong_number_of_arguments
|
||||||
exception = assert_raise(___(ArgumentError)) do
|
exception = assert_raise(___(ArgumentError)) do
|
||||||
my_global_method
|
my_global_method
|
||||||
end
|
end
|
||||||
assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message)
|
#--
|
||||||
|
pattern = "wrong (number|#) of arguments"
|
||||||
|
#++
|
||||||
|
assert_match(/#{__(pattern)}/, exception.message)
|
||||||
|
|
||||||
exception = assert_raise(___(ArgumentError)) do
|
exception = assert_raise(___(ArgumentError)) do
|
||||||
my_global_method(1,2,3)
|
my_global_method(1,2,3)
|
||||||
end
|
end
|
||||||
assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message)
|
assert_match(/#{__(pattern)}/, exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -69,6 +73,7 @@ class AboutMethods < EdgeCase::Koan
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_calling_with_variable_arguments
|
def test_calling_with_variable_arguments
|
||||||
|
assert_equal __(Array), method_with_var_args.class
|
||||||
assert_equal __([]), method_with_var_args
|
assert_equal __([]), method_with_var_args
|
||||||
assert_equal __([:one]), method_with_var_args(:one)
|
assert_equal __([:one]), method_with_var_args(:one)
|
||||||
assert_equal __([:one, :two]), method_with_var_args(:one, :two)
|
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
|
a * b
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_calling_methods_in_same_class
|
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
|
end
|
||||||
|
|
||||||
def test_calling_methods_in_same_class_with_explicit_receiver
|
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
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -122,11 +127,13 @@ class AboutMethods < EdgeCase::Koan
|
|||||||
assert_equal __("a secret"), my_private_method
|
assert_equal __("a secret"), my_private_method
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if before_ruby_version("2.7") # https://github.com/edgecase/ruby_koans/issues/12
|
||||||
def test_calling_private_methods_with_an_explicit_receiver
|
def test_calling_private_methods_with_an_explicit_receiver
|
||||||
exception = assert_raise(___(NoMethodError)) do
|
exception = assert_raise(___(NoMethodError)) do
|
||||||
self.my_private_method
|
self.my_private_method
|
||||||
end
|
end
|
||||||
assert_match /#{__("private method `my_private_method' called ")}/, exception.message
|
assert_match /#{__("method `my_private_method'")}/, exception.message
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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
|
module Nameable
|
||||||
def set_name(new_name)
|
def set_name(new_name)
|
||||||
@name = new_name
|
@name = new_name
|
||||||
@@ -42,9 +42,9 @@ class AboutModules < EdgeCase::Koan
|
|||||||
assert_equal __("WOOF"), fido.bark
|
assert_equal __("WOOF"), fido.bark
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_module_methods_are_also_availble_in_the_object
|
def test_module_methods_are_also_available_in_the_object
|
||||||
fido = Dog.new
|
fido = Dog.new
|
||||||
assert_nothing_raised(Exception) do
|
assert_nothing_raised do # __
|
||||||
fido.set_name("Rover")
|
fido.set_name("Rover")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
def test_nil_is_an_object
|
||||||
assert_equal __(true), nil.is_a?(Object), "Unlike NULL in other languages"
|
assert_equal __(true), nil.is_a?(Object), "Unlike NULL in other languages"
|
||||||
end
|
end
|
||||||
@@ -8,7 +8,7 @@ class AboutNil < EdgeCase::Koan
|
|||||||
def test_you_dont_get_null_pointer_errors_when_calling_methods_on_nil
|
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
|
# What happens when you call a method that doesn't exist. The
|
||||||
# following begin/rescue/end code block captures the exception and
|
# following begin/rescue/end code block captures the exception and
|
||||||
# make some assertions about it.
|
# makes some assertions about it.
|
||||||
begin
|
begin
|
||||||
nil.some_method_nil_doesnt_know_about
|
nil.some_method_nil_doesnt_know_about
|
||||||
rescue Exception => ex
|
rescue Exception => ex
|
||||||
|
|||||||
50
src/about_objects.rb
Normal file
50
src/about_objects.rb
Normal 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
|
||||||
@@ -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
|
class Dog
|
||||||
def bark
|
def bark
|
||||||
"WOOF"
|
"WOOF"
|
||||||
@@ -30,14 +30,14 @@ class AboutOpenClasses < EdgeCase::Koan
|
|||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
class ::Integer
|
class ::Integer
|
||||||
def even?
|
def answer_to_life_universe_and_everything?
|
||||||
(self % 2) == 0
|
self == 42
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_even_existing_built_in_classes_can_be_reopened
|
def test_even_existing_built_in_classes_can_be_reopened
|
||||||
assert_equal __(false), 1.even?
|
assert_equal __(false), 1.answer_to_life_universe_and_everything?
|
||||||
assert_equal __(true), 2.even?
|
assert_equal __(true), 42.answer_to_life_universe_and_everything?
|
||||||
end
|
end
|
||||||
|
|
||||||
# NOTE: To understand why we need the :: before Integer, you need to
|
# NOTE: To understand why we need the :: before Integer, you need to
|
||||||
|
|||||||
215
src/about_pattern_matching.rb
Normal file
215
src/about_pattern_matching.rb
Normal 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
|
||||||
@@ -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
|
# 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
|
# below). You should be able to initialize the proxy object with any
|
||||||
# object. Any messages sent to the proxy object should be forwarded
|
# object. Any messages sent to the proxy object should be forwarded
|
||||||
# to the target object. As each message is sent, the proxy should
|
# 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
|
# The proxy class is started for you. You will need to add a method
|
||||||
# missing handler and any other supporting methods. The specification
|
# missing handler and any other supporting methods. The specification
|
||||||
@@ -42,11 +42,13 @@ end
|
|||||||
|
|
||||||
# The proxy object should pass the following Koan:
|
# The proxy object should pass the following Koan:
|
||||||
#
|
#
|
||||||
class AboutProxyObjectProject < EdgeCase::Koan
|
class AboutProxyObjectProject < Neo::Koan
|
||||||
def test_proxy_method_returns_wrapped_object
|
def test_proxy_method_returns_wrapped_object
|
||||||
# NOTE: The Television class is defined below
|
# NOTE: The Television class is defined below
|
||||||
tv = Proxy.new(Television.new)
|
tv = Proxy.new(Television.new)
|
||||||
|
|
||||||
|
# HINT: Proxy class is defined above, may need tweaking...
|
||||||
|
|
||||||
assert tv.instance_of?(Proxy)
|
assert tv.instance_of?(Proxy)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -133,7 +135,7 @@ class Television
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Tests for the Television class. All of theses tests should pass.
|
# Tests for the Television class. All of theses tests should pass.
|
||||||
class TelevisionTest < EdgeCase::Koan
|
class TelevisionTest < Neo::Koan
|
||||||
def test_it_turns_on
|
def test_it_turns_on
|
||||||
tv = Television.new
|
tv = Television.new
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- 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
|
def test_a_pattern_is_a_regular_expression
|
||||||
assert_equal Regexp, /pattern/.class
|
assert_equal __(Regexp), /pattern/.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_a_regexp_can_search_a_string_for_matching_content
|
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
|
end
|
||||||
|
|
||||||
def test_a_failed_match_returns_nil
|
def test_a_failed_match_returns_nil
|
||||||
@@ -84,6 +84,8 @@ class AboutRegularExpressions < EdgeCase::Koan
|
|||||||
def test_shortcut_character_classes_are_negated_with_capitals
|
def test_shortcut_character_classes_are_negated_with_capitals
|
||||||
assert_equal __("the number is "), "the number is 42"[/\D+/]
|
assert_equal __("the number is "), "the number is 42"[/\D+/]
|
||||||
assert_equal __("space:"), "space: \t\n"[/\S+/]
|
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+/]
|
assert_equal __(" = "), "variable_1 = 42"[/\W+/]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
def count_lines(file_name)
|
||||||
file = open(file_name)
|
file = open(file_name)
|
||||||
count = 0
|
count = 0
|
||||||
while line = file.gets
|
while file.gets
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
count
|
count
|
||||||
@@ -40,7 +40,7 @@ class AboutSandwichCode < EdgeCase::Koan
|
|||||||
#
|
#
|
||||||
# Sandwich code is code that comes in three parts: (1) the top slice
|
# 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
|
# 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.
|
# the meat part changes all the time.
|
||||||
#
|
#
|
||||||
# Because the changing part of the sandwich code is in the middle,
|
# 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)
|
def count_lines2(file_name)
|
||||||
file_sandwich(file_name) do |file|
|
file_sandwich(file_name) do |file|
|
||||||
count = 0
|
count = 0
|
||||||
while line = file.gets
|
while file.gets
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
count
|
count
|
||||||
@@ -99,7 +99,7 @@ class AboutSandwichCode < EdgeCase::Koan
|
|||||||
def count_lines3(file_name)
|
def count_lines3(file_name)
|
||||||
open(file_name) do |file|
|
open(file_name) do |file|
|
||||||
count = 0
|
count = 0
|
||||||
while line = file.gets
|
while file.gets
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
count
|
count
|
||||||
|
|||||||
@@ -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
|
module Jims
|
||||||
class Dog
|
class Dog
|
||||||
def identify
|
def identify
|
||||||
@@ -19,7 +19,7 @@ class AboutScope < EdgeCase::Koan
|
|||||||
|
|
||||||
def test_dog_is_not_available_in_the_current_scope
|
def test_dog_is_not_available_in_the_current_scope
|
||||||
assert_raise(___(NameError)) do
|
assert_raise(___(NameError)) do
|
||||||
fido = Dog.new
|
Dog.new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -29,8 +29,8 @@ class AboutScope < EdgeCase::Koan
|
|||||||
assert_equal __(:jims_dog), fido.identify
|
assert_equal __(:jims_dog), fido.identify
|
||||||
assert_equal __(:joes_dog), rover.identify
|
assert_equal __(:joes_dog), rover.identify
|
||||||
|
|
||||||
assert_not_equal fido.class, rover.class
|
assert_equal __(true), fido.class != rover.class
|
||||||
assert_not_equal Jims::Dog, Joes::Dog
|
assert_equal __(true), Jims::Dog != Joes::Dog
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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
|
# 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.
|
# score of a single roll of the dice.
|
||||||
#
|
#
|
||||||
# A greed roll is scored as follows:
|
# A greed roll is scored as follows:
|
||||||
@@ -54,7 +54,7 @@ def score(dice)
|
|||||||
#++
|
#++
|
||||||
end
|
end
|
||||||
|
|
||||||
class AboutScoringProject < EdgeCase::Koan
|
class AboutScoringProject < Neo::Koan
|
||||||
def test_score_of_an_empty_list_is_zero
|
def test_score_of_an_empty_list_is_zero
|
||||||
assert_equal 0, score([])
|
assert_equal 0, score([])
|
||||||
end
|
end
|
||||||
@@ -90,6 +90,9 @@ class AboutScoringProject < EdgeCase::Koan
|
|||||||
def test_score_of_mixed_is_sum
|
def test_score_of_mixed_is_sum
|
||||||
assert_equal 250, score([2,5,2,2,3])
|
assert_equal 250, score([2,5,2,2,3])
|
||||||
assert_equal 550, score([5,5,5,5])
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
def test_double_quoted_strings_are_strings
|
||||||
string = "Hello, World"
|
string = "Hello, World"
|
||||||
assert_equal __(true), string.is_a?(String)
|
assert_equal __(true), string.is_a?(String)
|
||||||
@@ -40,7 +40,9 @@ class AboutStrings < EdgeCase::Koan
|
|||||||
It was the best of times,
|
It was the best of times,
|
||||||
It was the worst 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
|
end
|
||||||
|
|
||||||
def test_here_documents_can_also_handle_multiple_lines
|
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 best of times,
|
||||||
It was the worst of times.
|
It was the worst of times.
|
||||||
EOS
|
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
|
end
|
||||||
|
|
||||||
def test_plus_will_concatenate_two_strings
|
def test_plus_will_concatenate_two_strings
|
||||||
@@ -147,7 +151,7 @@ EOS
|
|||||||
end
|
end
|
||||||
|
|
||||||
in_ruby_version("1.8") do
|
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 __(97, 'a'), ?a
|
||||||
assert_equal __(true, false), ?a == 97
|
assert_equal __(true, false), ?a == 97
|
||||||
|
|
||||||
@@ -155,8 +159,8 @@ EOS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
in_ruby_version("1.9") do
|
in_ruby_version("1.9", "2", "3") do
|
||||||
def test_in_ruby_1_9_single_characters_are_represented_by_strings
|
def test_in_modern_ruby_single_characters_are_represented_by_strings
|
||||||
assert_equal __('a'), ?a
|
assert_equal __('a'), ?a
|
||||||
assert_equal __(false), ?a == 97
|
assert_equal __(false), ?a == 97
|
||||||
end
|
end
|
||||||
@@ -182,4 +186,12 @@ EOS
|
|||||||
words = ["Now", "is", "the", "time"]
|
words = ["Now", "is", "the", "time"]
|
||||||
assert_equal __("Now is the time"), words.join(" ")
|
assert_equal __("Now is the time"), words.join(" ")
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -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
|
def test_symbols_are_symbols
|
||||||
symbol = :ruby
|
symbol = :ruby
|
||||||
assert_equal __(true), symbol.is_a?(Symbol)
|
assert_equal __(true), symbol.is_a?(Symbol)
|
||||||
@@ -11,34 +11,34 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
symbol2 = :a_symbol
|
symbol2 = :a_symbol
|
||||||
symbol3 = :something_else
|
symbol3 = :something_else
|
||||||
|
|
||||||
assert symbol1 == __(symbol2)
|
assert_equal __(true), symbol1 == symbol2
|
||||||
assert symbol1 != __(symbol3)
|
assert_equal __(false), symbol1 == symbol3
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_identical_symbols_are_a_single_internal_object
|
def test_identical_symbols_are_a_single_internal_object
|
||||||
symbol1 = :a_symbol
|
symbol1 = :a_symbol
|
||||||
symbol2 = :a_symbol
|
symbol2 = :a_symbol
|
||||||
|
|
||||||
assert symbol1.equal?(__(symbol2))
|
assert_equal __(true), symbol1 == symbol2
|
||||||
assert_equal __(symbol1.object_id), symbol2.object_id
|
assert_equal __(true), symbol1.object_id == symbol2.object_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_method_names_become_symbols
|
def test_method_names_become_symbols
|
||||||
all_symbols = Symbol.all_symbols
|
symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }
|
||||||
assert_equal __(true), all_symbols.include?(:test_method_names_become_symbols)
|
assert_equal __(true), symbols_as_strings.include?("test_method_names_become_symbols")
|
||||||
end
|
end
|
||||||
|
|
||||||
# THINK ABOUT IT:
|
# THINK ABOUT IT:
|
||||||
#
|
#
|
||||||
# Why do we capture the list of symbols before we check for the
|
# Why do we convert the list of symbols to strings and then compare
|
||||||
# method name?
|
# against the string value rather than against symbols?
|
||||||
|
|
||||||
in_ruby_version("mri") do
|
in_ruby_version("mri") do
|
||||||
RubyConstant = "What is the sound of one hand clapping?"
|
RubyConstant = "What is the sound of one hand clapping?"
|
||||||
def test_constants_become_symbols
|
def test_constants_become_symbols
|
||||||
all_symbols = Symbol.all_symbols
|
all_symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }
|
||||||
|
|
||||||
assert_equal __(true), all_symbols.include?(__(:RubyConstant))
|
assert_equal __(true), all_symbols_as_strings.include?(__("RubyConstant"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,14 +50,14 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
def test_symbols_with_spaces_can_be_built
|
def test_symbols_with_spaces_can_be_built
|
||||||
symbol = :"cats and dogs"
|
symbol = :"cats and dogs"
|
||||||
|
|
||||||
assert_equal symbol, __("cats and dogs").to_sym
|
assert_equal __("cats and dogs").to_sym, symbol
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_symbols_with_spaces_can_be_built
|
def test_symbols_with_interpolation_can_be_built
|
||||||
value = "and"
|
value = "and"
|
||||||
symbol = :"cats #{value} dogs"
|
symbol = :"cats #{value} dogs"
|
||||||
|
|
||||||
assert_equal symbol, __("cats and dogs").to_sym
|
assert_equal __("cats and dogs").to_sym, symbol
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_to_s_is_called_on_interpolated_symbols
|
def test_to_s_is_called_on_interpolated_symbols
|
||||||
@@ -84,7 +84,7 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
# interesting string operations are available on symbols.
|
# interesting string operations are available on symbols.
|
||||||
|
|
||||||
def test_symbols_cannot_be_concatenated
|
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
|
assert_raise(___(NoMethodError)) do
|
||||||
:cats + :dogs
|
:cats + :dogs
|
||||||
end
|
end
|
||||||
|
|||||||
54
src/about_to_str.rb
Normal file
54
src/about_to_str.rb
Normal 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
|
||||||
@@ -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'
|
# 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
|
def test_equilateral_triangles_have_equal_sides
|
||||||
assert_equal :equilateral, triangle(2, 2, 2)
|
assert_equal :equilateral, triangle(2, 2, 2)
|
||||||
assert_equal :equilateral, triangle(10, 10, 10)
|
assert_equal :equilateral, triangle(10, 10, 10)
|
||||||
@@ -22,4 +22,3 @@ class AboutTriangleProject < EdgeCase::Koan
|
|||||||
assert_equal :scalene, triangle(5, 4, 2)
|
assert_equal :scalene, triangle(5, 4, 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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'
|
# 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.
|
# The first assignment did not talk about how to handle errors.
|
||||||
# Let's handle that part now.
|
# Let's handle that part now.
|
||||||
def test_illegal_triangles_throw_exceptions
|
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(3, 4, -5) end
|
||||||
assert_raise(TriangleError) do triangle(1, 1, 3) end
|
assert_raise(TriangleError) do triangle(1, 1, 3) end
|
||||||
assert_raise(TriangleError) do triangle(2, 4, 2) end
|
assert_raise(TriangleError) do triangle(2, 4, 2) end
|
||||||
|
# HINT: for tips, see http://stackoverflow.com/questions/3834203/ruby-koan-151-raising-exceptions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
def truth_value(condition)
|
||||||
if condition
|
if condition
|
||||||
:true_stuff
|
:true_stuff
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Autotest.add_discovery do
|
|
||||||
"rubykoan" if File.exist? 'path_to_enlightenment.rb'
|
|
||||||
end
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|
||||||
@@ -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
3
src/koans.watchr
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
watch( '.*\.rb' ) do
|
||||||
|
system 'rake'
|
||||||
|
end
|
||||||
@@ -1,7 +1,16 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
# -*- ruby -*-
|
# -*- ruby -*-
|
||||||
|
|
||||||
require 'test/unit/assertions'
|
$VERBOSE = nil
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'win32console'
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# Support code for the Ruby Koans.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
class FillMeInError < StandardError
|
class FillMeInError < StandardError
|
||||||
end
|
end
|
||||||
@@ -16,6 +25,17 @@ def in_ruby_version(*versions)
|
|||||||
yield if versions.any? { |v| ruby_version?(v) }
|
yield if versions.any? { |v| ruby_version?(v) }
|
||||||
end
|
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)
|
def __(value="FILL ME IN", value19=:mu)
|
||||||
if RUBY_VERSION < "1.9"
|
if RUBY_VERSION < "1.9"
|
||||||
value
|
value
|
||||||
@@ -24,6 +44,7 @@ def __(value="FILL ME IN", value19=:mu)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Numeric replacement value.
|
||||||
def _n_(value=999999, value19=:mu)
|
def _n_(value=999999, value19=:mu)
|
||||||
if RUBY_VERSION < "1.9"
|
if RUBY_VERSION < "1.9"
|
||||||
value
|
value
|
||||||
@@ -32,10 +53,16 @@ def _n_(value=999999, value19=:mu)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ___(value=FillMeInError)
|
# Error object replacement value.
|
||||||
|
def ___(value=FillMeInError, value19=:mu)
|
||||||
|
if RUBY_VERSION < "1.9"
|
||||||
value
|
value
|
||||||
|
else
|
||||||
|
(value19 == :mu) ? value : value19
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Method name replacement.
|
||||||
class Object
|
class Object
|
||||||
def ____(method=nil)
|
def ____(method=nil)
|
||||||
if method
|
if method
|
||||||
@@ -43,12 +70,30 @@ class Object
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
in_ruby_version("1.9") do
|
in_ruby_version("1.9", "2", "3") do
|
||||||
public :method_missing
|
public :method_missing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module EdgeCase
|
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
|
module Color
|
||||||
#shamelessly stolen (and modified) from redgreen
|
#shamelessly stolen (and modified) from redgreen
|
||||||
@@ -66,32 +111,101 @@ module EdgeCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def colorize(string, color_value)
|
def colorize(string, color_value)
|
||||||
if ENV['NO_COLOR']
|
if use_colors?
|
||||||
string
|
|
||||||
else
|
|
||||||
color(color_value) + string + color(COLORS[:clear])
|
color(color_value) + string + color(COLORS[:clear])
|
||||||
|
else
|
||||||
|
string
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def color(color_value)
|
def color(color_value)
|
||||||
"\e[#{color_value}m"
|
"\e[#{color_value}m"
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
class Sensei
|
class Sensei
|
||||||
attr_reader :failure, :failed_test, :pass_count
|
attr_reader :failure, :failed_test, :pass_count
|
||||||
|
|
||||||
in_ruby_version("1.8") do
|
FailedAssertionError = Assertions::FailedAssertionError
|
||||||
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
|
def initialize
|
||||||
@pass_count = 0
|
@pass_count = 0
|
||||||
@@ -104,7 +218,7 @@ module EdgeCase
|
|||||||
|
|
||||||
def add_progress(prog)
|
def add_progress(prog)
|
||||||
@_contents = nil
|
@_contents = nil
|
||||||
exists = File.exists?(PROGRESS_FILE_NAME)
|
exists = File.exist?(PROGRESS_FILE_NAME)
|
||||||
File.open(PROGRESS_FILE_NAME,'a+') do |f|
|
File.open(PROGRESS_FILE_NAME,'a+') do |f|
|
||||||
f.print "#{',' if exists}#{prog}"
|
f.print "#{',' if exists}#{prog}"
|
||||||
end
|
end
|
||||||
@@ -112,7 +226,7 @@ module EdgeCase
|
|||||||
|
|
||||||
def progress
|
def progress
|
||||||
if @_contents.nil?
|
if @_contents.nil?
|
||||||
if File.exists?(PROGRESS_FILE_NAME)
|
if File.exist?(PROGRESS_FILE_NAME)
|
||||||
File.open(PROGRESS_FILE_NAME,'r') do |f|
|
File.open(PROGRESS_FILE_NAME,'r') do |f|
|
||||||
@_contents = f.read.to_s.gsub(/\s/,'').split(',')
|
@_contents = f.read.to_s.gsub(/\s/,'').split(',')
|
||||||
end
|
end
|
||||||
@@ -134,7 +248,7 @@ module EdgeCase
|
|||||||
@failure = step.failure
|
@failure = step.failure
|
||||||
add_progress(@pass_count)
|
add_progress(@pass_count)
|
||||||
@observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.")
|
@observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.")
|
||||||
throw :edgecase_exit
|
throw :neo_exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -143,7 +257,7 @@ module EdgeCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def assert_failed?
|
def assert_failed?
|
||||||
failure.is_a?(AssertionError)
|
failure.is_a?(FailedAssertionError)
|
||||||
end
|
end
|
||||||
|
|
||||||
def instruct
|
def instruct
|
||||||
@@ -160,7 +274,7 @@ module EdgeCase
|
|||||||
|
|
||||||
def show_progress
|
def show_progress
|
||||||
bar_width = 50
|
bar_width = 50
|
||||||
total_tests = EdgeCase::Koan.total_tests
|
total_tests = Neo::Koan.total_tests
|
||||||
scale = bar_width.to_f/total_tests
|
scale = bar_width.to_f/total_tests
|
||||||
print Color.green("your path thus far [")
|
print Color.green("your path thus far [")
|
||||||
happy_steps = (pass_count*scale).to_i
|
happy_steps = (pass_count*scale).to_i
|
||||||
@@ -171,11 +285,26 @@ module EdgeCase
|
|||||||
print Color.cyan('_'*(bar_width-1-happy_steps))
|
print Color.cyan('_'*(bar_width-1-happy_steps))
|
||||||
end
|
end
|
||||||
print Color.green(']')
|
print Color.green(']')
|
||||||
print " #{pass_count}/#{total_tests}"
|
print " #{pass_count}/#{total_tests} (#{pass_count*100/total_tests}%)"
|
||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
|
|
||||||
def end_screen
|
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
|
completed = <<-ENDTEXT
|
||||||
,, , ,,
|
,, , ,,
|
||||||
: ::::, :::,
|
: ::::, :::,
|
||||||
@@ -192,13 +321,13 @@ module EdgeCase
|
|||||||
,:::::::::::, ::::::::::::,
|
,:::::::::::, ::::::::::::,
|
||||||
:::::::::::, ,::::::::::::
|
:::::::::::, ,::::::::::::
|
||||||
::::::::::::: ,::::::::::::
|
::::::::::::: ,::::::::::::
|
||||||
:::::::::::: Ruby Koans ::::::::::::,
|
:::::::::::: Ruby Koans ::::::::::::
|
||||||
:::::::::::: ,::::::::::::,
|
::::::::::::#{ ruby_version },::::::::::::
|
||||||
:::::::::::, , ::::::::::::
|
:::::::::::, , :::::::::::
|
||||||
,:::::::::::::, brought to you by ,,::::::::::::,
|
,:::::::::::::, brought to you by ,,::::::::::::
|
||||||
:::::::::::::: ,::::::::::::
|
:::::::::::::: ,::::::::::::
|
||||||
::::::::::::::, ,:::::::::::::
|
::::::::::::::, ,:::::::::::::
|
||||||
::::::::::::, EdgeCase Software Artisans , ::::::::::::
|
::::::::::::, Neo Software Artisans , ::::::::::::
|
||||||
:,::::::::: :::: :::::::::::::
|
:,::::::::: :::: :::::::::::::
|
||||||
,::::::::::: ,: ,,:::::::::::::,
|
,::::::::::: ,: ,,:::::::::::::,
|
||||||
:::::::::::: ,::::::::::::::,
|
:::::::::::: ,::::::::::::::,
|
||||||
@@ -233,11 +362,7 @@ ENDTEXT
|
|||||||
puts Color.red(indent(failure.message).join)
|
puts Color.red(indent(failure.message).join)
|
||||||
puts
|
puts
|
||||||
puts "Please meditate on the following code:"
|
puts "Please meditate on the following code:"
|
||||||
if assert_failed?
|
|
||||||
puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
|
puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
|
||||||
else
|
|
||||||
puts embolden_first_line_only(indent(failure.backtrace))
|
|
||||||
end
|
|
||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -260,7 +385,7 @@ ENDTEXT
|
|||||||
|
|
||||||
def find_interesting_lines(backtrace)
|
def find_interesting_lines(backtrace)
|
||||||
backtrace.reject { |line|
|
backtrace.reject { |line|
|
||||||
line =~ /test\/unit\/|edgecase\.rb/
|
line =~ /neo\.rb/
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -290,7 +415,7 @@ ENDTEXT
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Koan
|
class Koan
|
||||||
include Test::Unit::Assertions
|
include Assertions
|
||||||
|
|
||||||
attr_reader :name, :failure, :koan_count, :step_count, :koan_file
|
attr_reader :name, :failure, :koan_count, :step_count, :koan_file
|
||||||
|
|
||||||
@@ -320,19 +445,19 @@ ENDTEXT
|
|||||||
setup
|
setup
|
||||||
begin
|
begin
|
||||||
send(name)
|
send(name)
|
||||||
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
|
rescue StandardError, Neo::Sensei::FailedAssertionError => ex
|
||||||
failed(ex)
|
failed(ex)
|
||||||
ensure
|
ensure
|
||||||
begin
|
begin
|
||||||
teardown
|
teardown
|
||||||
rescue StandardError, EdgeCase::Sensei::AssertionError => ex
|
rescue StandardError, Neo::Sensei::FailedAssertionError => ex
|
||||||
failed(ex) if passed?
|
failed(ex) if passed?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Class methods for the EdgeCase test suite.
|
# Class methods for the Neo test suite.
|
||||||
class << self
|
class << self
|
||||||
def inherited(subclass)
|
def inherited(subclass)
|
||||||
subclasses << subclass
|
subclasses << subclass
|
||||||
@@ -389,7 +514,7 @@ ENDTEXT
|
|||||||
|
|
||||||
class ThePath
|
class ThePath
|
||||||
def walk
|
def walk
|
||||||
sensei = EdgeCase::Sensei.new
|
sensei = Neo::Sensei.new
|
||||||
each_step do |step|
|
each_step do |step|
|
||||||
sensei.observe(step.meditate)
|
sensei.observe(step.meditate)
|
||||||
end
|
end
|
||||||
@@ -397,9 +522,9 @@ ENDTEXT
|
|||||||
end
|
end
|
||||||
|
|
||||||
def each_step
|
def each_step
|
||||||
catch(:edgecase_exit) {
|
catch(:neo_exit) {
|
||||||
step_count = 0
|
step_count = 0
|
||||||
EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index|
|
Neo::Koan.subclasses.each_with_index do |koan,koan_index|
|
||||||
koan.testmethods.each do |method_name|
|
koan.testmethods.each do |method_name|
|
||||||
step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1)
|
step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1)
|
||||||
yield step
|
yield step
|
||||||
@@ -411,6 +536,6 @@ ENDTEXT
|
|||||||
end
|
end
|
||||||
|
|
||||||
END {
|
END {
|
||||||
EdgeCase::Koan.command_line(ARGV)
|
Neo::Koan.command_line(ARGV)
|
||||||
EdgeCase::ThePath.new.walk
|
Neo::ThePath.new.walk
|
||||||
}
|
}
|
||||||
@@ -3,17 +3,21 @@
|
|||||||
$LOAD_PATH << File.dirname(__FILE__)
|
$LOAD_PATH << File.dirname(__FILE__)
|
||||||
|
|
||||||
require 'about_asserts'
|
require 'about_asserts'
|
||||||
require 'about_nil'
|
require 'about_true_and_false'
|
||||||
require 'about_arrays'
|
|
||||||
require 'about_array_assignment'
|
|
||||||
require 'about_hashes'
|
|
||||||
require 'about_strings'
|
require 'about_strings'
|
||||||
require 'about_symbols'
|
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'
|
require 'about_methods'
|
||||||
|
in_ruby_version("2", "3") do
|
||||||
|
require 'about_keyword_arguments'
|
||||||
|
end
|
||||||
require 'about_constants'
|
require 'about_constants'
|
||||||
|
require 'about_regular_expressions'
|
||||||
require 'about_control_statements'
|
require 'about_control_statements'
|
||||||
require 'about_true_and_false'
|
|
||||||
require 'about_triangle_project'
|
require 'about_triangle_project'
|
||||||
require 'about_exceptions'
|
require 'about_exceptions'
|
||||||
require 'about_triangle_project_2'
|
require 'about_triangle_project_2'
|
||||||
@@ -30,4 +34,11 @@ require 'about_scope'
|
|||||||
require 'about_class_methods'
|
require 'about_class_methods'
|
||||||
require 'about_message_passing'
|
require 'about_message_passing'
|
||||||
require 'about_proxy_object_project'
|
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'
|
require 'about_extra_credit'
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
require 'test/unit'
|
|
||||||
|
|
||||||
def __
|
|
||||||
"FILL ME IN"
|
|
||||||
end
|
|
||||||
|
|
||||||
EdgeCase = Test::Unit
|
|
||||||
26
tests/check_test.rb
Normal file
26
tests/check_test.rb
Normal 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
4
tests/test_helper.rb
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
require "minitest/autorun"
|
||||||
|
require "rake"
|
||||||
|
|
||||||
|
Rake.application.load_rakefile
|
||||||
Reference in New Issue
Block a user