mirror of
https://github.com/edgecase/ruby_koans.git
synced 2026-04-15 07:23:19 -04:00
Compare commits
42 Commits
output_ref
...
rubykoans-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
dist
|
dist
|
||||||
.project_env.rc
|
.project_env.rc
|
||||||
.path_progress
|
.path_progress
|
||||||
|
*.rbc
|
||||||
|
|||||||
75
Rakefile
75
Rakefile
@@ -11,18 +11,25 @@ DIST_DIR = 'dist'
|
|||||||
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"
|
today = Time.now.strftime("%Y-%m-%d")
|
||||||
ZIP_FILE = "#{DIST_DIR}/rubykoans.zip"
|
TAR_FILE = "#{DIST_DIR}/rubykoans-#{today}.tgz"
|
||||||
|
ZIP_FILE = "#{DIST_DIR}/rubykoans-#{today}.zip"
|
||||||
|
|
||||||
|
CLEAN.include("**/*.rbc")
|
||||||
CLOBBER.include(DIST_DIR)
|
CLOBBER.include(DIST_DIR)
|
||||||
|
|
||||||
module Koans
|
module Koans
|
||||||
|
# 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
|
||||||
|
|
||||||
@@ -51,6 +58,27 @@ 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/).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.6 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
|
||||||
@@ -83,14 +111,6 @@ task :upload => [TAR_FILE, ZIP_FILE] do
|
|||||||
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 +129,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") 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
|
||||||
|
|||||||
@@ -18,13 +18,19 @@ class AboutArrayAssignment < EdgeCase::Koan
|
|||||||
assert_equal __, last_name
|
assert_equal __, 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 __, first_name
|
||||||
|
assert_equal __, last_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_parallel_assignments_with_too_few_variables
|
||||||
first_name, last_name = ["Cher"]
|
first_name, last_name = ["Cher"]
|
||||||
assert_equal __, first_name
|
assert_equal __, first_name
|
||||||
assert_equal __, last_name
|
assert_equal __, 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 __, first_name
|
assert_equal __, first_name
|
||||||
assert_equal __, last_name
|
assert_equal __, last_name
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
class AboutArrays < EdgeCase::Koan
|
class AboutArrays < EdgeCase::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 __, empty_array.class
|
||||||
assert_equal __, empty_array.size
|
assert_equal __, empty_array.size
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -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 __, (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..5).to_a
|
||||||
assert_equal __, (1...5).to_a
|
assert_equal __, (1...5).to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ class AboutClasses < EdgeCase::Koan
|
|||||||
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 __, rover.name != fido.name
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -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.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}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_inspect_provides_a_more_complete_string_version
|
def test_inspect_provides_a_more_complete_string_version
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
||||||
|
|
||||||
class DiceSet
|
# Implement a DiceSet Class here:
|
||||||
attr_reader :values
|
#
|
||||||
def roll(n)
|
# class DiceSet
|
||||||
@values = (1..n).map { rand(6) + 1 }
|
# code ...
|
||||||
end
|
# end
|
||||||
end
|
|
||||||
|
|
||||||
class AboutDiceProject < EdgeCase::Koan
|
class AboutDiceProject < EdgeCase::Koan
|
||||||
def test_can_create_a_dice_set
|
def test_can_create_a_dice_set
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ class AboutExceptions < EdgeCase::Koan
|
|||||||
|
|
||||||
assert_equal __, result
|
assert_equal __, result
|
||||||
|
|
||||||
assert ex.is_a?(StandardError), "Failure message."
|
assert_equal __, ex.is_a?(StandardError), "Should be a Standard Error"
|
||||||
assert ex.is_a?(RuntimeError), "Failure message."
|
assert_equal __, 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"
|
||||||
@@ -57,4 +57,12 @@ class AboutExceptions < EdgeCase::Koan
|
|||||||
assert_equal __, result
|
assert_equal __, 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(___) do
|
||||||
|
raise MySpecialError.new("New instances can be raised directly.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
class AboutHashes < EdgeCase::Koan
|
class AboutHashes < EdgeCase::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 __, empty_hash.class
|
||||||
assert_equal({}, empty_hash)
|
assert_equal({}, empty_hash)
|
||||||
assert_equal __, empty_hash.size
|
assert_equal __, empty_hash.size
|
||||||
end
|
end
|
||||||
@@ -25,7 +25,7 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
hash[:one] = "eins"
|
hash[:one] = "eins"
|
||||||
|
|
||||||
expected = { :one => __, :two => "dos" }
|
expected = { :one => __, :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 +35,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 __, hash1 == hash2
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hash_keys
|
def test_hash_keys
|
||||||
@@ -43,7 +43,7 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
assert_equal __, hash.keys.size
|
assert_equal __, hash.keys.size
|
||||||
assert_equal __, hash.keys.include?(:one)
|
assert_equal __, hash.keys.include?(:one)
|
||||||
assert_equal __, hash.keys.include?(:two)
|
assert_equal __, hash.keys.include?(:two)
|
||||||
assert_equal Array, hash.keys.class
|
assert_equal __, hash.keys.class
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_hash_values
|
def test_hash_values
|
||||||
@@ -51,16 +51,16 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
assert_equal __, hash.values.size
|
assert_equal __, hash.values.size
|
||||||
assert_equal __, hash.values.include?("uno")
|
assert_equal __, hash.values.include?("uno")
|
||||||
assert_equal __, hash.values.include?("dos")
|
assert_equal __, hash.values.include?("dos")
|
||||||
assert_equal Array, hash.values.class
|
assert_equal __, 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 __, hash != new_hash
|
||||||
|
|
||||||
expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
|
expected = { "jim" => __, "amy" => 20, "dan" => 23, "jenny" => __ }
|
||||||
assert_equal expected, new_hash
|
assert_equal __, expected == new_hash
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class AboutIteration < EdgeCase::Koan
|
|||||||
array.each do |item|
|
array.each do |item|
|
||||||
sum += item
|
sum += item
|
||||||
end
|
end
|
||||||
assert_equal 6, sum
|
assert_equal __, sum
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_each_can_use_curly_brace_blocks_too
|
def test_each_can_use_curly_brace_blocks_too
|
||||||
|
|||||||
137
koans/about_java_interop.rb
Normal file
137
koans/about_java_interop.rb
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
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_some_ruby_objects_can_be_coerced_to_java
|
||||||
|
assert_equal __, "ruby string".to_java.class
|
||||||
|
assert_equal __, 1.to_java.class
|
||||||
|
assert_equal __, 9.32.to_java.class
|
||||||
|
assert_equal __, false.to_java.class
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_some_ruby_objects_are_not_coerced_to_what_you_might_expect
|
||||||
|
assert_equal __, [].to_java.class == Java::JavaUtil::ArrayList
|
||||||
|
assert_equal __, {}.to_java.class == Java::JavaUtil::HashMap
|
||||||
|
assert_equal __, Object.new.to_java.class == Java::JavaLang::Object
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_java_collections_are_enumerable
|
||||||
|
java_array = java.util.ArrayList.new
|
||||||
|
java_array << "one" << "two" << "three"
|
||||||
|
assert_equal __, java_array.map { |item| item.upcase }
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Open the Java ArrayList class and add a new method.
|
||||||
|
class Java::JavaUtil::ArrayList
|
||||||
|
def multiply_all
|
||||||
|
result = 1
|
||||||
|
each do |item|
|
||||||
|
result *= item
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_java_class_are_open_from_ruby
|
||||||
|
java_array = java.util.ArrayList.new
|
||||||
|
java_array.add_all([1,2,3,4,5])
|
||||||
|
|
||||||
|
assert_equal __, java_array.multiply_all
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
56
koans/about_objects.rb
Normal file
56
koans/about_objects.rb
Normal 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
|
||||||
@@ -3,11 +3,11 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
|
|
||||||
class AboutRegularExpressions < EdgeCase::Koan
|
class AboutRegularExpressions < EdgeCase::Koan
|
||||||
def test_a_pattern_is_a_regular_expression
|
def test_a_pattern_is_a_regular_expression
|
||||||
assert_equal Regexp, /pattern/.class
|
assert_equal __, /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 __, "some matching content"[/match/]
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_a_failed_match_returns_nil
|
def test_a_failed_match_returns_nil
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class AboutScope < EdgeCase::Koan
|
|||||||
assert_equal __, fido.identify
|
assert_equal __, fido.identify
|
||||||
assert_equal __, rover.identify
|
assert_equal __, rover.identify
|
||||||
|
|
||||||
assert_not_equal fido.class, rover.class
|
assert_equal __, fido.class != rover.class
|
||||||
assert_not_equal Jims::Dog, Joes::Dog
|
assert_equal __, Jims::Dog != Joes::Dog
|
||||||
end
|
end
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -182,4 +182,12 @@ EOS
|
|||||||
words = ["Now", "is", "the", "time"]
|
words = ["Now", "is", "the", "time"]
|
||||||
assert_equal __, words.join(" ")
|
assert_equal __, words.join(" ")
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -11,29 +11,35 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
symbol2 = :a_symbol
|
symbol2 = :a_symbol
|
||||||
symbol3 = :something_else
|
symbol3 = :something_else
|
||||||
|
|
||||||
assert symbol1 == __
|
assert_equal __, symbol1 == symbol2
|
||||||
assert symbol1 != __
|
assert_equal __, 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?(__)
|
assert_equal __, symbol1 == symbol2
|
||||||
assert_equal __, symbol2.object_id
|
assert_equal __, 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 __, symbols_as_strings.include?("test_method_names_become_symbols")
|
||||||
assert_equal __, all_symbols.include?(:test_method_names_are_symbols)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# THINK ABOUT IT:
|
||||||
|
#
|
||||||
|
# Why do we convert the list of symbols to strings and then compare
|
||||||
|
# against the string value rather than against symbols?
|
||||||
|
|
||||||
|
in_ruby_version("mri") do
|
||||||
RubyConstant = "What is the sound of one hand clapping?"
|
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 = Symbol.all_symbols
|
||||||
|
|
||||||
assert_equal true, all_symbols.include?(__)
|
assert_equal __, all_symbols.include?(__)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_symbols_can_be_made_from_strings
|
def test_symbols_can_be_made_from_strings
|
||||||
@@ -47,6 +53,13 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
assert_equal symbol, __.to_sym
|
assert_equal symbol, __.to_sym
|
||||||
end
|
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
|
def test_to_s_is_called_on_interpolated_symbols
|
||||||
symbol = :cats
|
symbol = :cats
|
||||||
string = "It is raining #{symbol} and dogs."
|
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?(:each_char)
|
||||||
assert_equal __, symbol.respond_to?(:reverse)
|
assert_equal __, symbol.respond_to?(:reverse)
|
||||||
end
|
end
|
||||||
|
|
||||||
# It's important to realize that symbols are not "immutable
|
# It's important to realize that symbols are not "immutable
|
||||||
# strings", though they are immutable. None of the
|
# strings", though they are immutable. None of the
|
||||||
# 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 father down the path
|
||||||
assert_raise(___) do
|
assert_raise(___) do
|
||||||
:cats + :dogs
|
:cats + :dogs
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|||||||
54
koans/about_to_str.rb
Normal file
54
koans/about_to_str.rb
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
||||||
|
|
||||||
|
class AboutToStr < EdgeCase::Koan
|
||||||
|
|
||||||
|
class CanNotBeTreatedAsString
|
||||||
|
def to_s
|
||||||
|
"non-string-like"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s_returns_a_string_representation
|
||||||
|
not_like_a_string = CanNotBeTreatedAsString.new
|
||||||
|
assert_equal __, not_like_a_string.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_normally_objects_cannot_be_used_where_strings_are_expected
|
||||||
|
assert_raise(___) do
|
||||||
|
File.exist?(CanNotBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CanBeTreatedAsString
|
||||||
|
def to_s
|
||||||
|
"string-like"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_str
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_str_also_returns_a_string_representation
|
||||||
|
like_a_string = CanBeTreatedAsString.new
|
||||||
|
assert_equal __, like_a_string.to_str
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_str_allows_objects_to_be_treated_as_strings
|
||||||
|
assert_equal __, File.exist?(CanBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def acts_like_a_string?(string)
|
||||||
|
string = string.to_str if string.respond_to?(:to_str)
|
||||||
|
string.is_a?(String)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_user_defined_code_can_check_for_to_str
|
||||||
|
assert_equal __, acts_like_a_string?(CanNotBeTreatedAsString.new)
|
||||||
|
assert_equal __, acts_like_a_string?(CanBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,13 +3,25 @@
|
|||||||
|
|
||||||
require 'test/unit/assertions'
|
require 'test/unit/assertions'
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# Support code for the Ruby Koans.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
class FillMeInError < StandardError
|
class FillMeInError < StandardError
|
||||||
end
|
end
|
||||||
|
|
||||||
def in_ruby_version(version)
|
def ruby_version?(version)
|
||||||
yield if RUBY_VERSION =~ /^#{version}/
|
RUBY_VERSION =~ /^#{version}/ ||
|
||||||
|
(version == 'jruby' && defined?(JRUBY_VERSION)) ||
|
||||||
|
(version == 'mri' && ! defined?(JRUBY_VERSION))
|
||||||
end
|
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)
|
def __(value="FILL ME IN", value19=:mu)
|
||||||
if RUBY_VERSION < "1.9"
|
if RUBY_VERSION < "1.9"
|
||||||
value
|
value
|
||||||
@@ -18,6 +30,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
|
||||||
@@ -26,10 +39,12 @@ def _n_(value=999999, value19=:mu)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Error object replacement value.
|
||||||
def ___(value=FillMeInError)
|
def ___(value=FillMeInError)
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Method name replacement.
|
||||||
class Object
|
class Object
|
||||||
def ____(method=nil)
|
def ____(method=nil)
|
||||||
if method
|
if method
|
||||||
@@ -42,7 +57,25 @@ class Object
|
|||||||
end
|
end
|
||||||
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
|
module EdgeCase
|
||||||
|
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
|
||||||
@@ -60,16 +93,29 @@ 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?
|
||||||
|
! using_windows?
|
||||||
|
else
|
||||||
|
ENV['ANSI_COLOR'] =~ /^(t|y)/i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def using_windows?
|
||||||
|
File::ALT_SEPARATOR
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Sensei
|
class Sensei
|
||||||
@@ -170,6 +216,21 @@ module EdgeCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def end_screen
|
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
|
completed = <<-ENDTEXT
|
||||||
,, , ,,
|
,, , ,,
|
||||||
: ::::, :::,
|
: ::::, :::,
|
||||||
@@ -187,7 +248,7 @@ module EdgeCase
|
|||||||
:::::::::::, ,::::::::::::
|
:::::::::::, ,::::::::::::
|
||||||
::::::::::::: ,::::::::::::
|
::::::::::::: ,::::::::::::
|
||||||
:::::::::::: Ruby Koans ::::::::::::,
|
:::::::::::: Ruby Koans ::::::::::::,
|
||||||
:::::::::::: ,::::::::::::,
|
::::::::::::#{ ruby_version },::::::::::::,
|
||||||
:::::::::::, , ::::::::::::
|
:::::::::::, , ::::::::::::
|
||||||
,:::::::::::::, brought to you by ,,::::::::::::,
|
,:::::::::::::, brought to you by ,,::::::::::::,
|
||||||
:::::::::::::: ,::::::::::::
|
:::::::::::::: ,::::::::::::
|
||||||
@@ -248,12 +309,13 @@ ENDTEXT
|
|||||||
end
|
end
|
||||||
|
|
||||||
def indent(text)
|
def indent(text)
|
||||||
|
text = text.split(/\n/) if text.is_a?(String)
|
||||||
text.collect{|t| " #{t}"}
|
text.collect{|t| " #{t}"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_interesting_lines(backtrace)
|
def find_interesting_lines(backtrace)
|
||||||
backtrace.reject { |line|
|
backtrace.reject { |line|
|
||||||
line =~ /test\/unit\/|edgecase\.rb/
|
line =~ /test\/unit\/|edgecase\.rb|minitest/
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ $LOAD_PATH << File.dirname(__FILE__)
|
|||||||
|
|
||||||
require 'about_asserts'
|
require 'about_asserts'
|
||||||
require 'about_nil'
|
require 'about_nil'
|
||||||
|
require 'about_objects'
|
||||||
require 'about_arrays'
|
require 'about_arrays'
|
||||||
require 'about_array_assignment'
|
require 'about_array_assignment'
|
||||||
require 'about_hashes'
|
require 'about_hashes'
|
||||||
@@ -30,4 +31,8 @@ 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
|
||||||
require 'about_extra_credit'
|
require 'about_extra_credit'
|
||||||
|
|||||||
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_* | 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
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
|
||||||
@@ -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_variables
|
||||||
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
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
class AboutArrays < EdgeCase::Koan
|
class AboutArrays < EdgeCase::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
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ class AboutClasses < EdgeCase::Koan
|
|||||||
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
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -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,5 +1,12 @@
|
|||||||
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
||||||
|
|
||||||
|
# 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,6 +14,7 @@ class DiceSet
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#++
|
||||||
class AboutDiceProject < EdgeCase::Koan
|
class AboutDiceProject < EdgeCase::Koan
|
||||||
def test_can_create_a_dice_set
|
def test_can_create_a_dice_set
|
||||||
dice = DiceSet.new
|
dice = DiceSet.new
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
class AboutHashes < EdgeCase::Koan
|
class AboutHashes < EdgeCase::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
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class AboutHashes < EdgeCase::Koan
|
|||||||
hash[:one] = "eins"
|
hash[:one] = "eins"
|
||||||
|
|
||||||
expected = { :one => __("eins"), :two => "dos" }
|
expected = { :one => __("eins"), :two => "dos" }
|
||||||
assert_equal expected, hash
|
assert_equal __(true), 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 +35,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 +43,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 +51,16 @@ 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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ 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
|
||||||
|
|||||||
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__) + '/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_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
|
||||||
@@ -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
|
||||||
@@ -74,7 +74,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 +83,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:
|
||||||
#
|
#
|
||||||
@@ -122,7 +122,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(NoMethodError) 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)
|
||||||
|
|||||||
@@ -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
|
||||||
#++
|
#++
|
||||||
@@ -43,12 +43,15 @@ class AboutMethods < EdgeCase::Koan
|
|||||||
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
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class AboutModules < EdgeCase::Koan
|
|||||||
|
|
||||||
def test_module_methods_are_also_availble_in_the_object
|
def test_module_methods_are_also_availble_in_the_object
|
||||||
fido = Dog.new
|
fido = Dog.new
|
||||||
assert_nothing_raised(Exception) do
|
assert_nothing_raised(Exception) do # __
|
||||||
fido.set_name("Rover")
|
fido.set_name("Rover")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
56
src/about_objects.rb
Normal file
56
src/about_objects.rb
Normal 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
|
||||||
@@ -3,11 +3,11 @@ require File.expand_path(File.dirname(__FILE__) + '/edgecase')
|
|||||||
|
|
||||||
class AboutRegularExpressions < EdgeCase::Koan
|
class AboutRegularExpressions < EdgeCase::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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
@@ -182,4 +182,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_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
|
end
|
||||||
|
|||||||
@@ -11,27 +11,27 @@ 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?"
|
||||||
@@ -53,7 +53,7 @@ class AboutSymbols < EdgeCase::Koan
|
|||||||
assert_equal symbol, __("cats and dogs").to_sym
|
assert_equal symbol, __("cats and dogs").to_sym
|
||||||
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"
|
||||||
|
|
||||||
|
|||||||
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__) + '/edgecase')
|
||||||
|
|
||||||
|
class AboutToStr < EdgeCase::Koan
|
||||||
|
|
||||||
|
class CanNotBeTreatedAsString
|
||||||
|
def to_s
|
||||||
|
"non-string-like"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_s_returns_a_string_representation
|
||||||
|
not_like_a_string = CanNotBeTreatedAsString.new
|
||||||
|
assert_equal __("non-string-like"), not_like_a_string.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_normally_objects_cannot_be_used_where_strings_are_expected
|
||||||
|
assert_raise(___(TypeError)) do
|
||||||
|
File.exist?(CanNotBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
class CanBeTreatedAsString
|
||||||
|
def to_s
|
||||||
|
"string-like"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_str
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_str_also_returns_a_string_representation
|
||||||
|
like_a_string = CanBeTreatedAsString.new
|
||||||
|
assert_equal __("string-like"), like_a_string.to_str
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_str_allows_objects_to_be_treated_as_strings
|
||||||
|
assert_equal __(false), File.exist?(CanBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def acts_like_a_string?(string)
|
||||||
|
string = string.to_str if string.respond_to?(:to_str)
|
||||||
|
string.is_a?(String)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_user_defined_code_can_check_for_to_str
|
||||||
|
assert_equal __(false), acts_like_a_string?(CanNotBeTreatedAsString.new)
|
||||||
|
assert_equal __(true), acts_like_a_string?(CanBeTreatedAsString.new)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
require 'test/unit/assertions'
|
require 'test/unit/assertions'
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# Support code for the Ruby Koans.
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
class FillMeInError < StandardError
|
class FillMeInError < StandardError
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -16,6 +20,8 @@ def in_ruby_version(*versions)
|
|||||||
yield if versions.any? { |v| ruby_version?(v) }
|
yield if versions.any? { |v| ruby_version?(v) }
|
||||||
end
|
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)
|
def __(value="FILL ME IN", value19=:mu)
|
||||||
if RUBY_VERSION < "1.9"
|
if RUBY_VERSION < "1.9"
|
||||||
value
|
value
|
||||||
@@ -24,6 +30,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 +39,12 @@ def _n_(value=999999, value19=:mu)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Error object replacement value.
|
||||||
def ___(value=FillMeInError)
|
def ___(value=FillMeInError)
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Method name replacement.
|
||||||
class Object
|
class Object
|
||||||
def ____(method=nil)
|
def ____(method=nil)
|
||||||
if method
|
if method
|
||||||
@@ -48,7 +57,25 @@ class Object
|
|||||||
end
|
end
|
||||||
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
|
module EdgeCase
|
||||||
|
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,16 +93,29 @@ 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?
|
||||||
|
! using_windows?
|
||||||
|
else
|
||||||
|
ENV['ANSI_COLOR'] =~ /^(t|y)/i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def using_windows?
|
||||||
|
File::ALT_SEPARATOR
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Sensei
|
class Sensei
|
||||||
@@ -176,6 +216,21 @@ module EdgeCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def end_screen
|
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
|
completed = <<-ENDTEXT
|
||||||
,, , ,,
|
,, , ,,
|
||||||
: ::::, :::,
|
: ::::, :::,
|
||||||
@@ -193,7 +248,7 @@ module EdgeCase
|
|||||||
:::::::::::, ,::::::::::::
|
:::::::::::, ,::::::::::::
|
||||||
::::::::::::: ,::::::::::::
|
::::::::::::: ,::::::::::::
|
||||||
:::::::::::: Ruby Koans ::::::::::::,
|
:::::::::::: Ruby Koans ::::::::::::,
|
||||||
:::::::::::: ,::::::::::::,
|
::::::::::::#{ ruby_version },::::::::::::,
|
||||||
:::::::::::, , ::::::::::::
|
:::::::::::, , ::::::::::::
|
||||||
,:::::::::::::, brought to you by ,,::::::::::::,
|
,:::::::::::::, brought to you by ,,::::::::::::,
|
||||||
:::::::::::::: ,::::::::::::
|
:::::::::::::: ,::::::::::::
|
||||||
@@ -260,7 +315,7 @@ ENDTEXT
|
|||||||
|
|
||||||
def find_interesting_lines(backtrace)
|
def find_interesting_lines(backtrace)
|
||||||
backtrace.reject { |line|
|
backtrace.reject { |line|
|
||||||
line =~ /test\/unit\/|edgecase\.rb/
|
line =~ /test\/unit\/|edgecase\.rb|minitest/
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ $LOAD_PATH << File.dirname(__FILE__)
|
|||||||
|
|
||||||
require 'about_asserts'
|
require 'about_asserts'
|
||||||
require 'about_nil'
|
require 'about_nil'
|
||||||
|
require 'about_objects'
|
||||||
require 'about_arrays'
|
require 'about_arrays'
|
||||||
require 'about_array_assignment'
|
require 'about_array_assignment'
|
||||||
require 'about_hashes'
|
require 'about_hashes'
|
||||||
@@ -30,4 +31,8 @@ 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
|
||||||
require 'about_extra_credit'
|
require 'about_extra_credit'
|
||||||
|
|||||||
Reference in New Issue
Block a user