28 Commits

Author SHA1 Message Date
Jim Weirich
d3ce64a768 Updatd exception koan to be clearer about StandardError VS RuntimeError 2010-11-29 09:02:22 -05:00
Luke Pearce
9291f534c6 Fixed exceptions typo 2010-11-29 13:24:40 +00:00
Jim Weirich
71f670ac1d Disabled colored output on windows. 2010-10-21 07:05:06 -04:00
Jim Weirich
1864c9c346 Updated koans for about_symbols fix 2010-10-21 07:04:54 -04:00
Jim Weirich
cfd5b6bbe1 Fixed test_symbols_with_spaces_can_be_built method name collision. 2010-10-21 07:02:10 -04:00
Jim Weirich
e5843f64fd Fixed bug where some koans were not generated properly. 2010-10-01 11:05:25 -04:00
Jim Weirich
fdb8774c95 Added Java Interop koans if running jruby. 2010-09-28 14:49:43 -04:00
Jim Weirich
5b483df29b Added descriptions to rake tasks. 2010-09-28 14:49:20 -04:00
Jim Weirich
7dee146a8c Added missing __ replacements 2010-09-28 14:49:06 -04:00
Jim Weirich
e24d94eeff Updated koans from source. 2010-09-28 14:43:34 -04:00
Jim Weirich
4789e831df Added enumerable collections and open java classes to jruby koan. 2010-09-28 14:43:03 -04:00
Jim Weirich
b41d6167b4 Updated koans from src. 2010-09-28 14:17:46 -04:00
Jim Weirich
c0bbe773d9 Moved splat example to later + several typo corrections. 2010-09-28 14:15:08 -04:00
Srdjan Pejic
6fb8e3c3af Cool test; Still can't believe there is no standard implementation of first/rest 2010-09-28 14:11:08 -04:00
Marc Peabody + Jim Weirich
1dcd9babd4 Added more think about its to the ruby/java string comparisons. 2010-09-27 18:24:25 -04:00
Marc Peabody + Jim Weirich
45523c03c0 More class conflict examples. 2010-09-27 16:54:10 -04:00
Jim Weirich
8436b46c1a Added Ruby version information to the output. 2010-09-27 14:36:38 -04:00
Jim Weirich
322ca38767 Minitest lines in backtrace are no longer interesting. 2010-09-27 14:15:59 -04:00
Jim Weirich
91f15dc690 Simplified output for running against multiple rubies. 2010-09-27 14:09:38 -04:00
Jim Weirich
beb7fe591e Added rake task for running koans against several rubies. 2010-09-27 13:46:21 -04:00
Jim Weirich
17fb071814 Evaluated each assert line without a replacement test specified. 2010-09-27 13:38:50 -04:00
Jim Weirich
012cb20bb3 Moved checks into a separate rake file. 2010-09-27 13:38:22 -04:00
Jim Weirich
ece35b2539 Added symbol & string identity tests. 2010-09-27 11:36:38 -04:00
Jim Weirich
fe2ee86172 Added Koan on basic objects 2010-09-27 11:36:00 -04:00
Jim Weirich
9caf7a950a Updated koans from source directory. 2010-09-27 10:50:29 -04:00
Jim Weirich
a13f184ef1 Merge branch 'output_refactoring'
* output_refactoring:
  Updated for JRuby
  Switch blue color to cyan for better contrast on dark terminals.
  80 char limit to end screen
  Updated Koans directory
  Added else clause if progress file is not there.
  regen for updated koans/edgecase.rb
  end screen with koans logo ascii art
2010-09-27 10:49:17 -04:00
Matt Yoho
1bc1b8e50c Add timestamps to package output 2010-09-21 17:48:30 -04:00
Matt Yoho
9b5dfb4e42 Add koan on asserting exceptions 2010-09-21 17:12:50 -04:00
36 changed files with 700 additions and 106 deletions

View File

@@ -11,18 +11,24 @@ DIST_DIR = 'dist'
SRC_FILES = FileList["#{SRC_DIR}/*"]
KOAN_FILES = SRC_FILES.pathmap("#{PROB_DIR}/%f")
TAR_FILE = "#{DIST_DIR}/rubykoans.tgz"
ZIP_FILE = "#{DIST_DIR}/rubykoans.zip"
today = Time.now.strftime("%Y-%m-%d")
TAR_FILE = "#{DIST_DIR}/rubykoans-#{today}.tgz"
ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip"
CLOBBER.include(DIST_DIR)
module Koans
# Remove solution info from source
# __(a,b) => __
# _n_(number) => __
# # __ =>
def Koans.remove_solution(line)
line = line.gsub(/\b____\([^\)]+\)/, "____")
line = line.gsub(/\b___\([^\)]+\)/, "___")
line = line.gsub(/\b__\([^\)]+\)/, "__")
line = line.gsub(/\b_n_\([^\)]+\)/, "_n_")
line = line.gsub(%r(/\#\{__\}/), "/__/")
line = line.gsub(/\s*#\s*__\s*$/, '')
line
end
@@ -83,14 +89,6 @@ task :upload => [TAR_FILE, ZIP_FILE] do
sh "scp #{ZIP_FILE} linode:sites/onestepback.org/download"
end
desc "Check that the require files match the about_* files"
task :check do
about_files = Dir['src/about_*.rb'].size
about_requires = `grep require src/path_to_enlightenment.rb | wc -l`.to_i
puts "# of about files: #{about_files}"
puts "# of about requires: #{about_requires}"
end
desc "Generate the Koans from the source files from scratch."
task :regen => [:clobber_koans, :gen]

View File

@@ -18,13 +18,19 @@ class AboutArrayAssignment < EdgeCase::Koan
assert_equal __, last_name
end
def test_parallel_assignments_with_extra_variables
def test_parallel_assignments_with_splat_operator
first_name, *last_name = ["John", "Smith", "III"]
assert_equal __, first_name
assert_equal __, last_name
end
def test_parallel_assignments_with_too_few_variables
first_name, last_name = ["Cher"]
assert_equal __, first_name
assert_equal __, last_name
end
def test_parallel_assignements_with_subarrays
def test_parallel_assignments_with_subarrays
first_name, last_name = [["Willie", "Rae"], "Johnson"]
assert_equal __, first_name
assert_equal __, last_name

View File

@@ -3,7 +3,7 @@ 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.class
assert_equal __, empty_array.size
end
@@ -45,9 +45,9 @@ class AboutArrays < EdgeCase::Koan
end
def test_arrays_and_ranges
assert_equal Range, (1..5).class
assert_equal __, (1..5).class
assert_not_equal [1,2,3,4,5], (1..5)
assert_equal [1,2,3,4,5], (1..5).to_a
assert_equal __, (1..5).to_a
assert_equal __, (1...5).to_a
end

View File

@@ -130,7 +130,7 @@ class AboutClasses < EdgeCase::Koan
fido = Dog6.new("Fido")
rover = Dog6.new("Rover")
assert_not_equal rover.name, fido.name
assert_equal __, rover.name != fido.name
end
# ------------------------------------------------------------------
@@ -164,12 +164,12 @@ class AboutClasses < EdgeCase::Koan
def test_to_s_provides_a_string_version_of_the_object
fido = Dog7.new("Fido")
assert_equal "Fido", fido.to_s
assert_equal __, fido.to_s
end
def test_to_s_is_used_in_string_interpolation
fido = Dog7.new("Fido")
assert_equal "My dog is Fido", "My dog is #{fido}"
assert_equal __, "My dog is #{fido}"
end
def test_inspect_provides_a_more_complete_string_version

View File

@@ -22,8 +22,8 @@ class AboutExceptions < EdgeCase::Koan
assert_equal __, result
assert ex.is_a?(StandardError), "Failure message."
assert ex.is_a?(RuntimeError), "Failure message."
assert_equal __, ex.is_a?(StandardError), "Should be a Standard Error"
assert_equal __, ex.is_a?(RuntimeError), "Should be a Runtime Error"
assert RuntimeError.ancestors.include?(StandardError),
"RuntimeError is a subclass of StandardError"
@@ -57,4 +57,12 @@ class AboutExceptions < EdgeCase::Koan
assert_equal __, result
end
# Sometimes, we must know about the unknown
def test_asserting_an_error_is_raised
# A do-end is a block, a topic to explore more later
assert_raise(___) do
raise MySpecialError.new("New instances can be raised directly.")
end
end
end

View File

@@ -3,7 +3,7 @@ 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.class
assert_equal({}, empty_hash)
assert_equal __, empty_hash.size
end
@@ -25,7 +25,7 @@ class AboutHashes < EdgeCase::Koan
hash[:one] = "eins"
expected = { :one => __, :two => "dos" }
assert_equal expected, hash
assert_equal __, expected == hash
# Bonus Question: Why was "expected" broken out into a variable
# rather than used as a literal?
@@ -35,7 +35,7 @@ class AboutHashes < EdgeCase::Koan
hash1 = { :one => "uno", :two => "dos" }
hash2 = { :two => "dos", :one => "uno" }
assert_equal hash1, hash2
assert_equal __, hash1 == hash2
end
def test_hash_keys
@@ -43,7 +43,7 @@ class AboutHashes < EdgeCase::Koan
assert_equal __, hash.keys.size
assert_equal __, hash.keys.include?(:one)
assert_equal __, hash.keys.include?(:two)
assert_equal Array, hash.keys.class
assert_equal __, hash.keys.class
end
def test_hash_values
@@ -51,16 +51,16 @@ class AboutHashes < EdgeCase::Koan
assert_equal __, hash.values.size
assert_equal __, hash.values.include?("uno")
assert_equal __, hash.values.include?("dos")
assert_equal Array, hash.values.class
assert_equal __, hash.values.class
end
def test_combining_hashes
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })
assert_not_equal hash, new_hash
assert_equal __, hash != new_hash
expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
assert_equal expected, new_hash
assert_equal __, expected == new_hash
end
end

View File

@@ -12,7 +12,7 @@ class AboutIteration < EdgeCase::Koan
array.each do |item|
sum += item
end
assert_equal 6, sum
assert_equal __, sum
end
def test_each_can_use_curly_brace_blocks_too

124
koans/about_java_interop.rb Normal file
View File

@@ -0,0 +1,124 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
include Java
# Concepts
# * Pull in a java class
# * calling a method, Camel vs snake
# * Resovling module/class name conflicts
# * Showing what gets returned
# * Ruby Strings VS Java Strings
# * Calling custom java class
# * Calling Ruby from java???
class AboutJavaInterop < EdgeCase::Koan
def test_using_a_java_library_class
java_array = java.util.ArrayList.new
assert_equal __, java_array.class
end
def test_java_class_can_be_referenced_using_both_ruby_and_java_like_syntax
assert_equal __, Java::JavaUtil::ArrayList == java.util.ArrayList
end
def test_include_class_includes_class_in_module_scope
assert_nil defined?(TreeSet)
include_class "java.util.TreeSet"
assert_equal __, defined?(TreeSet)
end
# THINK ABOUT IT:
#
# What if we use:
#
# include_class "java.lang.String"
#
# What would be the value of the String constant after this
# include_class is run? Would it be useful to provide a way of
# aliasing java classes to different names?
JString = java.lang.String
def test_also_java_class_can_be_given_ruby_aliases
java_string = JString.new("A Java String")
assert_equal __, java_string.class
assert_equal __, JString
end
def test_can_directly_call_java_methods_on_java_objects
java_string = JString.new("A Java String")
assert_equal __, java_string.toLowerCase
end
def test_jruby_provides_snake_case_versions_of_java_methods
java_string = JString.new("A Java String")
assert_equal __, java_string.to_lower_case
end
def test_jruby_provides_question_mark_versions_of_boolean_methods
java_string = JString.new("A Java String")
assert_equal __, java_string.endsWith("String")
assert_equal __, java_string.ends_with("String")
assert_equal __, java_string.ends_with?("String")
end
def test_java_string_are_not_ruby_strings
ruby_string = "A Java String"
java_string = java.lang.String.new(ruby_string)
assert_equal __, java_string.is_a?(java.lang.String)
assert_equal __, java_string.is_a?(String)
end
def test_java_strings_can_be_compared_to_ruby_strings_maybe
ruby_string = "A Java String"
java_string = java.lang.String.new(ruby_string)
assert_equal __, ruby_string == java_string
assert_equal __, java_string == ruby_string
# THINK ABOUT IT:
#
# Is there any possible way for this to be more wrong?
#
# SERIOUSLY, THINK ABOUT IT:
#
# Why do you suppose that Ruby and Java strings compare like that?
#
# ADVANCED THINK ABOUT IT:
#
# Is there a way to make Ruby/Java string comparisons commutative?
# How would you do it?
end
def test_however_most_methods_returning_strings_return_ruby_strings
java_array = java.util.ArrayList.new
assert_equal __, java_array.toString
assert_equal __, java_array.toString.is_a?(String)
assert_equal __, java_array.toString.is_a?(java.lang.String)
end
def test_java_collections_are_enumerable
java_array = java.util.ArrayList.new
java_array << "one" << "two" << "three"
assert_equal __, java_array.map { |item| item.upcase }
end
# ------------------------------------------------------------------
# Open the Java ArrayList class and add a new method.
class Java::JavaUtil::ArrayList
def multiply_all
result = 1
each do |item|
result *= item
end
result
end
end
def test_java_class_are_open_from_ruby
java_array = java.util.ArrayList.new
java_array.add_all([1,2,3,4,5])
assert_equal __, java_array.multiply_all
end
end

56
koans/about_objects.rb Normal file
View File

@@ -0,0 +1,56 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutObjects < EdgeCase::Koan
def test_everything_is_an_object
assert_equal __, 1.is_a?(Object)
assert_equal __, 1.5.is_a?(Object)
assert_equal __, "string".is_a?(Object)
assert_equal __, nil.is_a?(Object)
assert_equal __, Object.is_a?(Object)
end
def test_objects_can_be_converted_to_strings
assert_equal __, 123.to_s
assert_equal __, nil.to_s
end
def test_objects_can_be_inspected
assert_equal __, 123.inspect
assert_equal __, nil.inspect
end
def test_every_object_has_an_id
obj = Object.new
assert_equal __, obj.object_id.class
end
def test_every_object_has_different_id
obj = Object.new
another_obj = Object.new
assert_equal __, obj.object_id != another_obj.object_id
end
def test_some_system_objects_always_have_the_same_id
assert_equal __, false.object_id
assert_equal __, true.object_id
assert_equal __, nil.object_id
end
def test_small_integers_have_fixed_ids
assert_equal __, 0.object_id
assert_equal __, 1.object_id
assert_equal __, 2.object_id
assert_equal __, 100.object_id
# THINK ABOUT IT:
# What pattern do the object IDs for small integers follow?
end
def test_clone_creates_a_different_object
obj = Object.new
copy = obj.clone
assert_equal __, obj != copy
assert_equal __, obj.object_id != copy.object_id
end
end

View File

@@ -3,11 +3,11 @@ 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
assert_equal __, /pattern/.class
end
def test_a_regexp_can_search_a_string_for_matching_content
assert_equal "match", "some matching content"[/match/]
assert_equal __, "some matching content"[/match/]
end
def test_a_failed_match_returns_nil

View File

@@ -29,8 +29,8 @@ class AboutScope < EdgeCase::Koan
assert_equal __, fido.identify
assert_equal __, rover.identify
assert_not_equal fido.class, rover.class
assert_not_equal Jims::Dog, Joes::Dog
assert_equal __, fido.class != rover.class
assert_equal __, Jims::Dog != Joes::Dog
end
# ------------------------------------------------------------------

View File

@@ -182,4 +182,12 @@ EOS
words = ["Now", "is", "the", "time"]
assert_equal __, words.join(" ")
end
def test_strings_are_not_unique_objects
a = "a string"
b = "a string"
assert_equal __, a == b
assert_equal __, a.object_id == b.object_id
end
end

View File

@@ -19,21 +19,27 @@ class AboutSymbols < EdgeCase::Koan
symbol1 = :a_symbol
symbol2 = :a_symbol
assert symbol1.equal?(__)
assert_equal __, symbol2.object_id
assert_equal __, symbol1 == symbol2
assert_equal __, symbol1.object_id == symbol2.object_id
end
def test_method_names_become_symbols
all_symbols = Symbol.all_symbols
assert_equal __, all_symbols.include?(:test_method_names_are_symbols)
assert_equal __, all_symbols.include?(:test_method_names_become_symbols)
end
RubyConstant = "What is the sound of one hand clapping?"
def test_constants_become_symbols
all_symbols = Symbol.all_symbols
# THINK ABOUT IT:
#
# Why do we capture the list of symbols before we check for the
# method name?
assert_equal true, all_symbols.include?(__)
in_ruby_version("mri") do
RubyConstant = "What is the sound of one hand clapping?"
def test_constants_become_symbols
all_symbols = Symbol.all_symbols
assert_equal __, all_symbols.include?(__)
end
end
def test_symbols_can_be_made_from_strings
@@ -47,6 +53,13 @@ class AboutSymbols < EdgeCase::Koan
assert_equal symbol, __.to_sym
end
def test_symbols_with_interpolation_can_be_built
value = "and"
symbol = :"cats #{value} dogs"
assert_equal symbol, __.to_sym
end
def test_to_s_is_called_on_interpolated_symbols
symbol = :cats
string = "It is raining #{symbol} and dogs."
@@ -65,13 +78,23 @@ class AboutSymbols < EdgeCase::Koan
assert_equal __, symbol.respond_to?(:each_char)
assert_equal __, symbol.respond_to?(:reverse)
end
# It's important to realize that symbols are not "immutable
# strings", though they are immutable. None of the
# interesting string operations are available on symbols.
def test_symbols_cannot_be_concatenated
# Exceptions will be pondered further father down the path
assert_raise(___) do
:cats + :dogs
end
end
def test_symbols_can_be_dynamically_created
assert_equal __, ("cats" + "dogs").to_sym
end
# THINK ABOUT IT:
#
# Why is it not a good idea to dynamically create a lot of symbols?
end

View File

@@ -3,13 +3,25 @@
require 'test/unit/assertions'
# --------------------------------------------------------------------
# Support code for the Ruby Koans.
# --------------------------------------------------------------------
class FillMeInError < StandardError
end
def in_ruby_version(version)
yield if RUBY_VERSION =~ /^#{version}/
def ruby_version?(version)
RUBY_VERSION =~ /^#{version}/ ||
(version == 'jruby' && defined?(JRUBY_VERSION)) ||
(version == 'mri' && ! defined?(JRUBY_VERSION))
end
def in_ruby_version(*versions)
yield if versions.any? { |v| ruby_version?(v) }
end
# Standard, generic replacement value.
# If value19 is given, it is used inplace of value for Ruby 1.9.
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
@@ -18,6 +30,7 @@ def __(value="FILL ME IN", value19=:mu)
end
end
# Numeric replacement value.
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
@@ -26,10 +39,12 @@ def _n_(value=999999, value19=:mu)
end
end
# Error object replacement value.
def ___(value=FillMeInError)
value
end
# Method name replacement.
class Object
def ____(method=nil)
if method
@@ -42,7 +57,25 @@ class Object
end
end
class String
def side_padding(width)
extra = width - self.size
if width < 0
self
else
left_padding = extra / 2
right_padding = (extra+1)/2
(" " * left_padding) + self + (" " *right_padding)
end
end
end
module EdgeCase
class << self
def simple_output
ENV['SIMPLE_KOAN_OUTPUT'] == 'true'
end
end
module Color
#shamelessly stolen (and modified) from redgreen
@@ -60,16 +93,29 @@ module EdgeCase
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
if use_colors?
color(color_value) + string + color(COLORS[:clear])
else
string
end
end
def color(color_value)
"\e[#{color_value}m"
end
def use_colors?
return false if ENV['NO_COLOR']
if ENV['ANSI_COLOR'].nil?
! using_windows?
else
ENV['ANSI_COLOR'] =~ /^(t|y)/i
end
end
def using_windows?
File::ALT_SEPARATOR
end
end
class Sensei
@@ -170,6 +216,21 @@ module EdgeCase
end
def end_screen
if EdgeCase.simple_output
boring_end_screen
else
artistic_end_screen
end
end
def boring_end_screen
puts "Mountains are again merely mountains"
end
def artistic_end_screen
"JRuby 1.9.x Koans"
ruby_version = "(in #{'J' if defined?(JRUBY_VERSION)}Ruby #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION})"
ruby_version = ruby_version.side_padding(54)
completed = <<-ENDTEXT
,, , ,,
: ::::, :::,
@@ -186,8 +247,8 @@ module EdgeCase
,:::::::::::, ::::::::::::,
:::::::::::, ,::::::::::::
::::::::::::: ,::::::::::::
:::::::::::: Ruby Koans ::::::::::::,
:::::::::::: ,::::::::::::,
:::::::::::: Ruby Koans ::::::::::::,
::::::::::::#{ ruby_version },::::::::::::,
:::::::::::, , ::::::::::::
,:::::::::::::, brought to you by ,,::::::::::::,
:::::::::::::: ,::::::::::::
@@ -248,12 +309,13 @@ ENDTEXT
end
def indent(text)
text = text.split(/\n/) if text.is_a?(String)
text.collect{|t| " #{t}"}
end
def find_interesting_lines(backtrace)
backtrace.reject { |line|
line =~ /test\/unit\/|edgecase\.rb/
line =~ /test\/unit\/|edgecase\.rb|minitest/
}
end

View File

@@ -4,6 +4,7 @@ $LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_objects'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
@@ -30,4 +31,7 @@ require 'about_scope'
require 'about_class_methods'
require 'about_message_passing'
require 'about_proxy_object_project'
in_ruby_version("jruby") do
require 'about_java_interop'
end
require 'about_extra_credit'

33
rakelib/checks.rake Normal file
View File

@@ -0,0 +1,33 @@
namespace "check" do
desc "Check that the require files match the about_* files"
task :abouts do
about_files = Dir['src/about_*.rb'].size
about_requires = `grep require src/path_to_enlightenment.rb | wc -l`.to_i
puts "Checking path_to_enlightenment completeness"
puts "# of about files: #{about_files}"
puts "# of about requires: #{about_requires}"
if about_files > about_requires
puts "*** There seems to be requires missing in the path to enlightenment"
else
puts "OK"
end
puts
end
desc "Check that asserts have __ replacements"
task :asserts do
puts "Checking for asserts missing the replacement text:"
begin
sh "egrep -n 'assert( |_)' src/about_* | 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 consistancy checks"
task :check => ["check:abouts", "check:asserts"]

8
rakelib/run.rake Normal file
View File

@@ -0,0 +1,8 @@
RUBIES = ENV['KOAN_RUBIES'] || %w(ruby-1.8.7-p299,ruby-1.9.2-p0,jruby-1.5.2,jruby-head)
task :runall do
chdir('src') do
ENV['SIMPLE_KOAN_OUTPUT'] = 'true'
sh "rvm #{RUBIES} path_to_enlightenment.rb"
end
end

View File

@@ -18,13 +18,19 @@ class AboutArrayAssignment < EdgeCase::Koan
assert_equal __("Smith"), last_name
end
def test_parallel_assignments_with_extra_variables
def test_parallel_assignments_with_splat_operator
first_name, *last_name = ["John", "Smith", "III"]
assert_equal __("John"), first_name
assert_equal __(["Smith","III"]), last_name
end
def test_parallel_assignments_with_too_few_variables
first_name, last_name = ["Cher"]
assert_equal __("Cher"), first_name
assert_equal __(nil), last_name
end
def test_parallel_assignements_with_subarrays
def test_parallel_assignments_with_subarrays
first_name, last_name = [["Willie", "Rae"], "Johnson"]
assert_equal __(["Willie", "Rae"]), first_name
assert_equal __("Johnson"), last_name

View File

@@ -3,16 +3,16 @@ 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 __(Array), empty_array.class
assert_equal __(0), empty_array.size
end
def test_array_literals
array = Array.new
assert_equal [], array
assert_equal [], array # __
array[0] = 1
assert_equal [1], array
assert_equal [1], array # __
array[1] = 2
assert_equal [1, __(2)], array
@@ -45,9 +45,9 @@ class AboutArrays < EdgeCase::Koan
end
def test_arrays_and_ranges
assert_equal Range, (1..5).class
assert_not_equal [1,2,3,4,5], (1..5)
assert_equal [1,2,3,4,5], (1..5).to_a
assert_equal __(Range), (1..5).class
assert_not_equal [1,2,3,4,5], (1..5) # __
assert_equal __([1,2,3,4,5]), (1..5).to_a
assert_equal __([1,2,3,4]), (1...5).to_a
end

View File

@@ -130,7 +130,7 @@ class AboutClasses < EdgeCase::Koan
fido = Dog6.new("Fido")
rover = Dog6.new("Rover")
assert_not_equal rover.name, fido.name
assert_equal __(true), rover.name != fido.name
end
# ------------------------------------------------------------------
@@ -164,12 +164,12 @@ class AboutClasses < EdgeCase::Koan
def test_to_s_provides_a_string_version_of_the_object
fido = Dog7.new("Fido")
assert_equal "Fido", fido.to_s
assert_equal __("Fido"), fido.to_s
end
def test_to_s_is_used_in_string_interpolation
fido = Dog7.new("Fido")
assert_equal "My dog is Fido", "My dog is #{fido}"
assert_equal __("My dog is Fido"), "My dog is #{fido}"
end
def test_inspect_provides_a_more_complete_string_version

View File

@@ -22,10 +22,10 @@ class AboutExceptions < EdgeCase::Koan
assert_equal __(:exception_handled), result
assert ex.is_a?(StandardError), "Failure message."
assert ex.is_a?(RuntimeError), "Failure message."
assert_equal __(true), ex.is_a?(StandardError), "Should be a Standard Error"
assert_equal __(true), ex.is_a?(RuntimeError), "Should be a Runtime Error"
assert RuntimeError.ancestors.include?(StandardError),
assert RuntimeError.ancestors.include?(StandardError), # __
"RuntimeError is a subclass of StandardError"
assert_equal __("Oops"), ex.message
@@ -57,4 +57,12 @@ class AboutExceptions < EdgeCase::Koan
assert_equal __(:always_run), result
end
# Sometimes, we must know about the unknown
def test_asserting_an_error_is_raised # __
# A do-end is a block, a topic to explore more later
assert_raise(___(MySpecialError)) do
raise MySpecialError.new("New instances can be raised directly.")
end
end
end

View File

@@ -3,8 +3,8 @@ 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 __(Hash), empty_hash.class
assert_equal({}, empty_hash) # __
assert_equal __(0), empty_hash.size
end
@@ -25,7 +25,7 @@ class AboutHashes < EdgeCase::Koan
hash[:one] = "eins"
expected = { :one => __("eins"), :two => "dos" }
assert_equal expected, hash
assert_equal __(true), expected == hash
# Bonus Question: Why was "expected" broken out into a variable
# rather than used as a literal?
@@ -35,7 +35,7 @@ class AboutHashes < EdgeCase::Koan
hash1 = { :one => "uno", :two => "dos" }
hash2 = { :two => "dos", :one => "uno" }
assert_equal hash1, hash2
assert_equal __(true), hash1 == hash2
end
def test_hash_keys
@@ -43,7 +43,7 @@ class AboutHashes < EdgeCase::Koan
assert_equal __(2), hash.keys.size
assert_equal __(true), hash.keys.include?(:one)
assert_equal __(true), hash.keys.include?(:two)
assert_equal Array, hash.keys.class
assert_equal __(Array), hash.keys.class
end
def test_hash_values
@@ -51,16 +51,16 @@ class AboutHashes < EdgeCase::Koan
assert_equal __(2), hash.values.size
assert_equal __(true), hash.values.include?("uno")
assert_equal __(true), hash.values.include?("dos")
assert_equal Array, hash.values.class
assert_equal __(Array), hash.values.class
end
def test_combining_hashes
hash = { "jim" => 53, "amy" => 20, "dan" => 23 }
new_hash = hash.merge({ "jim" => 54, "jenny" => 26 })
assert_not_equal hash, new_hash
assert_equal __(true), hash != new_hash
expected = { "jim" => __(54), "amy" => 20, "dan" => 23, "jenny" => __(26) }
assert_equal expected, new_hash
assert_equal __(true), expected == new_hash
end
end

View File

@@ -12,7 +12,7 @@ class AboutIteration < EdgeCase::Koan
array.each do |item|
sum += item
end
assert_equal 6, sum
assert_equal __(6), sum
end
def test_each_can_use_curly_brace_blocks_too

124
src/about_java_interop.rb Normal file
View File

@@ -0,0 +1,124 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
include Java
# Concepts
# * Pull in a java class
# * calling a method, Camel vs snake
# * Resovling module/class name conflicts
# * Showing what gets returned
# * Ruby Strings VS Java Strings
# * Calling custom java class
# * Calling Ruby from java???
class AboutJavaInterop < EdgeCase::Koan
def test_using_a_java_library_class
java_array = java.util.ArrayList.new
assert_equal __(Java::JavaUtil::ArrayList), java_array.class
end
def test_java_class_can_be_referenced_using_both_ruby_and_java_like_syntax
assert_equal __(true), Java::JavaUtil::ArrayList == java.util.ArrayList
end
def test_include_class_includes_class_in_module_scope
assert_nil defined?(TreeSet) # __
include_class "java.util.TreeSet"
assert_equal __("constant"), defined?(TreeSet)
end
# THINK ABOUT IT:
#
# What if we use:
#
# include_class "java.lang.String"
#
# What would be the value of the String constant after this
# include_class is run? Would it be useful to provide a way of
# aliasing java classes to different names?
JString = java.lang.String
def test_also_java_class_can_be_given_ruby_aliases
java_string = JString.new("A Java String")
assert_equal __(java.lang.String), java_string.class
assert_equal __(java.lang.String), JString
end
def test_can_directly_call_java_methods_on_java_objects
java_string = JString.new("A Java String")
assert_equal __("a java string"), java_string.toLowerCase
end
def test_jruby_provides_snake_case_versions_of_java_methods
java_string = JString.new("A Java String")
assert_equal __("a java string"), java_string.to_lower_case
end
def test_jruby_provides_question_mark_versions_of_boolean_methods
java_string = JString.new("A Java String")
assert_equal __(true), java_string.endsWith("String")
assert_equal __(true), java_string.ends_with("String")
assert_equal __(true), java_string.ends_with?("String")
end
def test_java_string_are_not_ruby_strings
ruby_string = "A Java String"
java_string = java.lang.String.new(ruby_string)
assert_equal __(true), java_string.is_a?(java.lang.String)
assert_equal __(false), java_string.is_a?(String)
end
def test_java_strings_can_be_compared_to_ruby_strings_maybe
ruby_string = "A Java String"
java_string = java.lang.String.new(ruby_string)
assert_equal __(false), ruby_string == java_string
assert_equal __(true), java_string == ruby_string
# THINK ABOUT IT:
#
# Is there any possible way for this to be more wrong?
#
# 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_java_collections_are_enumerable
java_array = java.util.ArrayList.new
java_array << "one" << "two" << "three"
assert_equal __(["ONE", "TWO", "THREE"]), java_array.map { |item| item.upcase }
end
# ------------------------------------------------------------------
# Open the Java ArrayList class and add a new method.
class Java::JavaUtil::ArrayList
def multiply_all
result = 1
each do |item|
result *= item
end
result
end
end
def test_java_class_are_open_from_ruby
java_array = java.util.ArrayList.new
java_array.add_all([1,2,3,4,5])
assert_equal __(120), java_array.multiply_all
end
end

View File

@@ -11,19 +11,19 @@ class AboutMessagePassing < EdgeCase::Koan
def test_methods_can_be_called_directly
mc = MessageCatcher.new
assert mc.caught?
assert mc.caught? # __
end
def test_methods_can_be_invoked_by_sending_the_message
mc = MessageCatcher.new
assert mc.send(:caught?)
assert mc.send(:caught?) # __
end
def test_methods_can_be_invoked_more_dynamically
mc = MessageCatcher.new
assert mc.send("caught?")
assert mc.send("caught?") # __
assert mc.send("caught" + __("?") ) # What do you need to add to the first string?
assert mc.send("CAUGHT?".____(:downcase) ) # What would you need to do to the string?
end
@@ -74,7 +74,7 @@ class AboutMessagePassing < EdgeCase::Koan
exception = assert_raise(___(NoMethodError)) do
typical.foobar
end
assert_match(/foobar/, exception.message)
assert_match(/foobar/, exception.message) # __
end
def test_calling_method_missing_causes_the_no_method_error
@@ -83,7 +83,7 @@ class AboutMessagePassing < EdgeCase::Koan
exception = assert_raise(___(NoMethodError)) do
typical.method_missing(:foobar)
end
assert_match(/foobar/, exception.message)
assert_match(/foobar/, exception.message) # __
# THINK ABOUT IT:
#
@@ -122,7 +122,7 @@ class AboutMessagePassing < EdgeCase::Koan
def test_catching_messages_makes_respond_to_lie
catcher = AllMessageCatcher.new
assert_nothing_raised(NoMethodError) do
assert_nothing_raised(NoMethodError) do # __
catcher.any_method
end
assert_equal __(false), catcher.respond_to?(:any_method)

View File

@@ -19,10 +19,10 @@ class AboutMethods < EdgeCase::Koan
# considered to be syntactically invalid).
def test_sometimes_missing_parentheses_are_ambiguous
#--
eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK
eval "assert_equal 5, my_global_method(2, 3)" # REMOVE CHECK # __
if false
#++
eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK
eval "assert_equal 5, my_global_method 2, 3" # ENABLE CHECK # __
#--
end
#++
@@ -43,12 +43,15 @@ class AboutMethods < EdgeCase::Koan
exception = assert_raise(___(ArgumentError)) do
my_global_method
end
assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message)
#--
pattern = "wrong (number|#) of arguments"
#++
assert_match(/#{__(pattern)}/, exception.message)
exception = assert_raise(___(ArgumentError)) do
my_global_method(1,2,3)
end
assert_match(/#{__("wrong (number|#) of arguments")}/, exception.message)
assert_match(/#{__(pattern)}/, exception.message)
end
# ------------------------------------------------------------------

View File

@@ -44,7 +44,7 @@ class AboutModules < EdgeCase::Koan
def test_module_methods_are_also_availble_in_the_object
fido = Dog.new
assert_nothing_raised(Exception) do
assert_nothing_raised(Exception) do # __
fido.set_name("Rover")
end
end

56
src/about_objects.rb Normal file
View File

@@ -0,0 +1,56 @@
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
class AboutObjects < EdgeCase::Koan
def test_everything_is_an_object
assert_equal __(true), 1.is_a?(Object)
assert_equal __(true), 1.5.is_a?(Object)
assert_equal __(true), "string".is_a?(Object)
assert_equal __(true), nil.is_a?(Object)
assert_equal __(true), Object.is_a?(Object)
end
def test_objects_can_be_converted_to_strings
assert_equal __("123"), 123.to_s
assert_equal __(""), nil.to_s
end
def test_objects_can_be_inspected
assert_equal __("123"), 123.inspect
assert_equal __("nil"), nil.inspect
end
def test_every_object_has_an_id
obj = Object.new
assert_equal __(Fixnum), obj.object_id.class
end
def test_every_object_has_different_id
obj = Object.new
another_obj = Object.new
assert_equal __(true), obj.object_id != another_obj.object_id
end
def test_some_system_objects_always_have_the_same_id
assert_equal __(0), false.object_id
assert_equal __(2), true.object_id
assert_equal __(4), nil.object_id
end
def test_small_integers_have_fixed_ids
assert_equal __(1), 0.object_id
assert_equal __(3), 1.object_id
assert_equal __(5), 2.object_id
assert_equal __(201), 100.object_id
# THINK ABOUT IT:
# What pattern do the object IDs for small integers follow?
end
def test_clone_creates_a_different_object
obj = Object.new
copy = obj.clone
assert_equal __(true), obj != copy
assert_equal __(true), obj.object_id != copy.object_id
end
end

View File

@@ -3,11 +3,11 @@ 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
assert_equal __(Regexp), /pattern/.class
end
def test_a_regexp_can_search_a_string_for_matching_content
assert_equal "match", "some matching content"[/match/]
assert_equal __("match"), "some matching content"[/match/]
end
def test_a_failed_match_returns_nil

View File

@@ -29,8 +29,8 @@ class AboutScope < EdgeCase::Koan
assert_equal __(:jims_dog), fido.identify
assert_equal __(:joes_dog), rover.identify
assert_not_equal fido.class, rover.class
assert_not_equal Jims::Dog, Joes::Dog
assert_equal __(true), fido.class != rover.class
assert_equal __(true), Jims::Dog != Joes::Dog
end
# ------------------------------------------------------------------

View File

@@ -182,4 +182,12 @@ EOS
words = ["Now", "is", "the", "time"]
assert_equal __("Now is the time"), words.join(" ")
end
def test_strings_are_not_unique_objects
a = "a string"
b = "a string"
assert_equal __(true), a == b
assert_equal __(false), a.object_id == b.object_id
end
end

View File

@@ -19,8 +19,8 @@ class AboutSymbols < EdgeCase::Koan
symbol1 = :a_symbol
symbol2 = :a_symbol
assert symbol1.equal?(__(symbol2))
assert_equal __(symbol1.object_id), symbol2.object_id
assert_equal __(true), symbol1 == symbol2
assert_equal __(true), symbol1.object_id == symbol2.object_id
end
def test_method_names_become_symbols
@@ -53,7 +53,7 @@ class AboutSymbols < EdgeCase::Koan
assert_equal symbol, __("cats and dogs").to_sym
end
def test_symbols_with_spaces_can_be_built
def test_symbols_with_interpolation_can_be_built
value = "and"
symbol = :"cats #{value} dogs"

View File

@@ -3,6 +3,10 @@
require 'test/unit/assertions'
# --------------------------------------------------------------------
# Support code for the Ruby Koans.
# --------------------------------------------------------------------
class FillMeInError < StandardError
end
@@ -16,6 +20,8 @@ def in_ruby_version(*versions)
yield if versions.any? { |v| ruby_version?(v) }
end
# Standard, generic replacement value.
# If value19 is given, it is used inplace of value for Ruby 1.9.
def __(value="FILL ME IN", value19=:mu)
if RUBY_VERSION < "1.9"
value
@@ -24,6 +30,7 @@ def __(value="FILL ME IN", value19=:mu)
end
end
# Numeric replacement value.
def _n_(value=999999, value19=:mu)
if RUBY_VERSION < "1.9"
value
@@ -32,10 +39,12 @@ def _n_(value=999999, value19=:mu)
end
end
# Error object replacement value.
def ___(value=FillMeInError)
value
end
# Method name replacement.
class Object
def ____(method=nil)
if method
@@ -48,7 +57,25 @@ class Object
end
end
class String
def side_padding(width)
extra = width - self.size
if width < 0
self
else
left_padding = extra / 2
right_padding = (extra+1)/2
(" " * left_padding) + self + (" " *right_padding)
end
end
end
module EdgeCase
class << self
def simple_output
ENV['SIMPLE_KOAN_OUTPUT'] == 'true'
end
end
module Color
#shamelessly stolen (and modified) from redgreen
@@ -66,16 +93,29 @@ module EdgeCase
end
def colorize(string, color_value)
if ENV['NO_COLOR']
string
else
if use_colors?
color(color_value) + string + color(COLORS[:clear])
else
string
end
end
def color(color_value)
"\e[#{color_value}m"
end
def use_colors?
return false if ENV['NO_COLOR']
if ENV['ANSI_COLOR'].nil?
! using_windows?
else
ENV['ANSI_COLOR'] =~ /^(t|y)/i
end
end
def using_windows?
File::ALT_SEPARATOR
end
end
class Sensei
@@ -176,6 +216,21 @@ module EdgeCase
end
def end_screen
if EdgeCase.simple_output
boring_end_screen
else
artistic_end_screen
end
end
def boring_end_screen
puts "Mountains are again merely mountains"
end
def artistic_end_screen
"JRuby 1.9.x Koans"
ruby_version = "(in #{'J' if defined?(JRUBY_VERSION)}Ruby #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION})"
ruby_version = ruby_version.side_padding(54)
completed = <<-ENDTEXT
,, , ,,
: ::::, :::,
@@ -192,8 +247,8 @@ module EdgeCase
,:::::::::::, ::::::::::::,
:::::::::::, ,::::::::::::
::::::::::::: ,::::::::::::
:::::::::::: Ruby Koans ::::::::::::,
:::::::::::: ,::::::::::::,
:::::::::::: Ruby Koans ::::::::::::,
::::::::::::#{ ruby_version },::::::::::::,
:::::::::::, , ::::::::::::
,:::::::::::::, brought to you by ,,::::::::::::,
:::::::::::::: ,::::::::::::
@@ -260,7 +315,7 @@ ENDTEXT
def find_interesting_lines(backtrace)
backtrace.reject { |line|
line =~ /test\/unit\/|edgecase\.rb/
line =~ /test\/unit\/|edgecase\.rb|minitest/
}
end

View File

@@ -4,6 +4,7 @@ $LOAD_PATH << File.dirname(__FILE__)
require 'about_asserts'
require 'about_nil'
require 'about_objects'
require 'about_arrays'
require 'about_array_assignment'
require 'about_hashes'
@@ -30,4 +31,7 @@ require 'about_scope'
require 'about_class_methods'
require 'about_message_passing'
require 'about_proxy_object_project'
in_ruby_version("jruby") do
require 'about_java_interop'
end
require 'about_extra_credit'