Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

generated koans

  • Loading branch information...
commit 452f4e1eff78afec9005db7737815985e393f50c 1 parent ba9ff94
@sathish316 sathish316 authored
View
12 koans/Rakefile
@@ -0,0 +1,12 @@
+#!/usr/bin/env ruby
+# -*- ruby -*-
+
+require 'rake/clean'
+require 'rake/testtask'
+
+task :default => :test
+
+task :test do
+ ruby 'path_to_enlightenment.rb'
+end
+
View
62 koans/about_binding.rb
@@ -0,0 +1,62 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutBinding < EdgeCase::Koan
+
+ class Foo
+ def initialize
+ @ivar = 22
+ end
+
+ def bar(param)
+ lvar = 11
+ binding
+ end
+ end
+
+ def test_binding_binds_method_parameters
+ binding = Foo.new.bar(99)
+ assert_equal __, eval("param", binding)
+ end
+
+ def test_binding_binds_local_vars
+ binding = Foo.new.bar(99)
+ assert_equal __, eval("lvar", binding)
+ end
+
+ def test_binding_binds_instance_vars
+ binding = Foo.new.bar(99)
+ assert_equal __, eval("@ivar", binding)
+ end
+
+ def test_binding_binds_blocks
+ binding = Foo.new.bar(99) { 33 }
+ assert_equal __, eval("yield", binding)
+ end
+
+ def test_binding_binds_self
+ foo = Foo.new
+ binding = foo.bar(99)
+ assert_equal __, eval("self", binding)
+ end
+
+ def n_times(n)
+ lambda {|value| n * value}
+ end
+
+ def test_lambda_binds_to_the_surrounding_context
+ two_times = n_times(2)
+ assert_equal __, two_times.call(3)
+ end
+
+ def count_with_increment(start, inc)
+ lambda { start += inc}
+ end
+
+ def test_lambda_remembers_state_of_bound_variables
+ counter = count_with_increment(7, 3)
+ assert_equal __, counter.call
+ assert_equal __, counter.call
+ assert_equal __, counter.call
+ end
+
+end
View
60 koans/about_blocks.rb
@@ -0,0 +1,60 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutBlocks < EdgeCase::Koan
+
+ def test_calling_a_lambda
+ l = lambda {|a| a + 1}
+ assert_equal __, l.call(99)
+ end
+
+ def test_calling_a_proc
+ p = Proc.new {|a| a + 1}
+ assert_equal __, p.call(99)
+ end
+
+ def convert(&block)
+ block
+ end
+
+ def test_block_is_proc
+ b = convert {|a| a + 1}
+ assert_equal __, b.class
+ assert_equal __, b.call(99)
+ end
+
+ def test_proc_takes_fewer_or_more_arguments
+ p = Proc.new {|a, b, c| a.to_i + b.to_i + c.to_i}
+ assert_equal __, p.call(1,2)
+ assert_equal __, p.call(1,2,3,4)
+ end
+
+ def test_lambda_does_not_take_fewer_or_more_arguments
+ l = lambda {|a, b, c| a.to_i + b.to_i + c.to_i}
+ assert_raises(ArgumentError) do
+ l.call(1, 2)
+ end
+
+ assert_raises(ArgumentError) do
+ l.call(1,2,3,4)
+ end
+ end
+
+ def method(lambda_or_proc)
+ lambda_or_proc.call
+ :from_method
+ end
+
+ def test_return_inside_lambda_returns_from_the_lambda
+ l = lambda { return :from_lambda }
+ result = method(l)
+ assert_equal __, result
+ end
+
+ def test_return_inside_proc_returns_from_the_context
+ p = Proc.new { return :from_proc }
+ result = method(p)
+ # The execution never reaches this line because Proc returns
+ # outside the test method
+ assert_equal __, p.call
+ end
+end
View
53 koans/about_class_as_constant.rb
@@ -0,0 +1,53 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutClassAsConstant < EdgeCase::Koan
+
+ class Foo
+ def say_hello
+ "Hi"
+ end
+ end
+
+ def test_defined_tells_if_a_class_is_defined_or_not
+ assert_not_nil defined?(Foo)
+ assert_nil defined?(Bar)
+ end
+
+ def test_class_is_a_constant
+ assert_equal __, defined?(Foo)
+ end
+
+ def test_class_constant_can_be_assigned_to_var
+ my_class = Foo
+ assert_equal __, my_class.new.say_hello
+ end
+
+ @@return_value_of_class =
+ class Baz
+ def say_hi
+ "Hello"
+ end
+ 99
+ end
+
+ def test_class_definitions_are_active
+ assert_equal __, @@return_value_of_class
+ end
+
+ @@self_inside_a_class =
+ class Baz
+ def say_hi
+ "Hi"
+ end
+ self
+ end
+
+ def test_self_inside_class_is_class_itself
+ assert_equal __, @@self_inside_a_class
+ end
+
+ def test_class_is_an_object_of_type_class_and_can_be_created_dynamically
+ cls = Class.new
+ assert_match /__/, cls.to_s
+ end
+end
View
27 koans/about_class_inheritance.rb
@@ -0,0 +1,27 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutClassInheritance < EdgeCase::Koan
+
+ def test_singleton_class_can_be_used_to_define_singleton_methods
+ animal = "cat"
+ class << animal
+ def speak
+ "miaow"
+ end
+ end
+ assert_equal __, animal.speak
+ end
+
+ class Foo
+ class << self
+ def say_hello
+ "Hello"
+ end
+ end
+ end
+
+ def test_singleton_class_can_be_used_to_define_class_methods
+ assert_equal __, Foo.say_hello
+ end
+
+end
View
23 koans/about_class_methods.rb
@@ -0,0 +1,23 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutClassMethods < EdgeCase::Koan
+
+ class Foo
+ def self.say_hello
+ "Hello"
+ end
+ end
+
+ def test_class_is_an_instance_of_class_Class
+ assert_equal __, Foo.class == Class
+ end
+
+ def test_class_methods_are_just_singleton_methods_on_the_class
+ assert_equal __, Foo.say_hello
+ end
+
+ def test_classes_are_not_special_and_are_just_like_other_objects
+ assert_equal __, Foo.is_a?(Object)
+ assert_equal __, Foo.superclass == Object
+ end
+end
View
87 koans/about_define_method.rb
@@ -0,0 +1,87 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutDefineMethod < EdgeCase::Koan
+
+ class Example
+ def start
+ def stop
+ :stopped
+ end
+ :started
+ end
+ end
+
+ def test_methods_can_define_other_methods
+ o = Example.new
+ assert_raises(NoMethodError) do
+ o.stop
+ end
+
+ o.start
+
+ assert_equal __, o.stop
+ end
+
+ class Example
+ def foo
+ def foo
+ :new_value
+ end
+ :first_value
+ end
+ end
+
+ def test_methods_can_redefine_themselves
+ o = Example.new
+ assert_equal __, o.foo
+ assert_equal __, o.foo
+ end
+
+ class Multiplier
+ def self.create_multiplier(n)
+ define_method "times_#{n}" do |val|
+ val * n
+ end
+ end
+
+ 10.times {|i| create_multiplier(i) }
+ end
+
+ def test_define_method_creates_methods_dynamically
+ m = Multiplier.new
+ assert_equal __, m.times_3(10)
+ assert_equal __, m.times_6(10)
+ assert_equal __, m.times_9(10)
+ end
+
+ module Accessor
+ def my_writer(name)
+ ivar_name = "@#{name}"
+ define_method "#{name}=" do |value|
+ #Write code here to set value of ivar
+ instance_variable_set(ivar_name, value)
+ end
+ end
+
+ def my_reader(name)
+ ivar_name = "@#{name}"
+ define_method name do
+ #Write code here to get value of ivar
+ instance_variable_get(ivar_name)
+ end
+ end
+ end
+
+ class Cat
+ extend Accessor
+ my_writer :name
+ my_reader :name
+ end
+
+ def test_instance_variable_set_and_instance_variable_get_can_be_used_to_access_ivars
+ cat = Cat.new
+ cat.name = 'Fred'
+ assert_equal __, cat.name
+ end
+end
+
View
92 koans/about_hook_methods.rb
@@ -0,0 +1,92 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutHookMethods < EdgeCase::Koan
+
+ module Bar
+ def self.included(klass)
+ @included = true
+ end
+
+ def self.included?
+ @included
+ end
+ end
+
+ class Foo
+ include Bar
+ end
+
+ def test_included_hook_method_is_called_when_module_is_included_in_class
+ assert_equal __, Bar.included?
+ end
+
+ class Parent
+ def self.inherited(klass)
+ @inherited = true
+ end
+
+ def self.inherited?
+ @inherited
+ end
+ end
+
+ class Child < Parent
+ end
+
+ def test_inherited_hook_method_is_called_when_class_is_subclassed
+ assert_equal __, Parent.inherited?
+ end
+
+ class ::Struct
+ @children = []
+
+ def self.inherited(klass)
+ @children << klass
+ end
+
+ def self.children
+ @children
+ end
+ end
+
+ Cat = Struct.new(:name, :tail)
+ Dog = Struct.new(:name, :legs)
+
+ def test_inherited_can_track_subclasses
+ assert_equal [Cat, Dog], Struct.children
+ end
+
+ class ::Module
+ def const_missing(name)
+ if name.to_s =~ /(X?)(IX|IV|(V?)(I{0,3}))/
+ to_roman($~)
+ end
+ end
+ end
+
+ def test_const_missing_hook_method_can_be_used_to_dynamically_evaluate_constants
+ assert_equal __, VIII
+ end
+
+ class Color
+ def self.const_missing(name)
+ const_set(name, new)
+ end
+
+ end
+
+ def test_const_set_can_be_used_to_dynamically_create_constants
+ Color::Red
+ assert_equal __, defined?(Color::Red)
+ end
+end
+
+def to_roman(match)
+ value = 0
+ value += 10 if match[1] == 'X'
+ value += 9 if match[2] == 'IX'
+ value += 4 if match[2] == 'IV'
+ value += 5 if match[3] == 'V'
+ value += match[4].chars.count if match[4]
+ value
+end
View
166 koans/about_instance_eval_and_class_eval.rb
@@ -0,0 +1,166 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutInstanceEvalAndClassEval < EdgeCase::Koan
+
+ def test_instance_eval_executes_block_in_the_context_of_the_receiver
+ assert_equal __, "cat".instance_eval { upcase }
+ end
+
+ class Foo
+ def initialize
+ @ivar = 99
+ end
+ end
+
+ def test_instance_eval_can_access_instance_variables
+ assert_equal __, Foo.new.instance_eval { @ivar }
+ end
+
+ class Foo
+ private
+ def secret
+ 123
+ end
+ end
+
+ def test_instance_eval_can_access_private_methods
+ assert_equal __, Foo.new.instance_eval { secret }
+ end
+
+ def test_instance_eval_can_be_used_to_define_singleton_methods
+ animal = "cat"
+ animal.instance_eval do
+ def speak
+ "miaow"
+ end
+ end
+ assert_equal __, animal.speak
+ end
+
+ class Cat
+ end
+
+ def test_instance_eval_can_be_used_to_define_class_methods
+ Cat.instance_eval do
+ def say_hello
+ "Hello"
+ end
+ end
+
+ assert_equal __, Cat.say_hello
+ end
+
+ def test_class_eval_executes_block_in_the_context_of_class_or_module
+ assert_equal __, Cat.class_eval { self }
+ end
+
+ def test_class_eval_can_be_used_to_define_instance_methods
+ Cat.class_eval do
+ def speak
+ "miaow"
+ end
+ end
+ assert_equal __, Cat.new.speak
+ end
+
+ def test_module_eval_is_same_as_class_eval
+ Cat.module_eval do
+ def miaow
+ "miaow"
+ end
+ end
+ assert_equal __, Cat.new.miaow
+ end
+
+ module Accessor
+ def my_eval_accessor(name)
+ # WRITE code here to generate accessors
+ class_eval %{
+ def #{name}
+ @#{name}
+ end
+
+ def #{name}=(val)
+ @#{name} = val
+ end
+ }
+ end
+ end
+
+ class Cat
+ extend Accessor
+ my_eval_accessor :name
+ end
+
+ def test_class_eval_can_be_used_to_create_instance_methods_like_accessors
+ cat = Cat.new
+ cat.name = 'Frisky'
+ assert_equal __, cat.name
+ end
+
+ module Hello
+ def say_hello
+ "hi"
+ end
+ end
+
+ def test_class_eval_can_be_used_to_call_private_methods_on_class
+ String.class_eval { include Hello }
+ assert_equal __, "hello".say_hello
+ end
+
+ class Turtle
+ attr_reader :path
+ def initialize
+ @path = ""
+ end
+
+ def right(n=1)
+ @path << 'r' * n
+ end
+
+ def up(n=1)
+ @path << 'u' * n
+ end
+ end
+
+ class Turtle
+ def move_yield(&block)
+ yield
+ end
+ end
+
+ def test_yield_executes_block_with_self_as_caller
+ t = Turtle.new
+ here = :here
+ assert_equal __, t.move_yield { here }
+ end
+
+ class Turtle
+ def move_eval(&block)
+ instance_eval(&block)
+ end
+ end
+
+ def test_instance_eval_executes_block_with_self_as_called_object
+ t = Turtle.new
+ t.move_eval do
+ right(3)
+ up(2)
+ right(1)
+ end
+ assert_equal __, t.path
+ end
+
+ class Turtle
+ def move_eval_yield(&block)
+ instance_eval { yield }
+ end
+ end
+
+ def test_yield_inside_instance_eval_executes_block_with_self_as_caller
+ still_here = :still_here
+ t = Turtle.new
+ assert_equal __, t.move_eval_yield { still_here }
+ end
+end
View
335 koans/about_metaclass.rb
@@ -0,0 +1,335 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+# Based on _why's article: Seeing Metaclasses clearly
+# http://dannytatom.github.com/metaid/
+
+class AboutMetaclass < EdgeCase::Koan
+
+ class MailTruck
+ attr_accessor :driver, :route
+ def initialize(driver = nil, route = nil)
+ @driver, @route = driver, route
+ end
+ end
+
+ def setup
+ @truck = MailTruck.new("Harold", ['12 Corrigan way', '23 Antler Ave'])
+ end
+
+ def test_class_of_an_object
+ assert_equal __, @truck.class
+ end
+
+ def test_class_of_a_class
+ assert_equal __, MailTruck.class
+ end
+
+ def test_object_is_a_storage_for_variables
+ assert_equal __, @truck.driver
+ end
+
+ def test_object_can_hold_any_other_instance_variables
+ @truck.instance_variable_set("@speed", 45)
+ assert_equal __, @truck.instance_variable_get("@speed")
+ end
+
+ def test_attr_accessor_defines_reader_and_writer
+ @truck.driver = 'Kumar'
+ assert_equal __, @truck.driver
+ end
+
+ def test_classes_store_methods
+ assert_equal __, MailTruck.instance_methods.include?(:driver)
+ end
+
+=begin
+
+BasicObject
+ |
+ Object
+ |
+ Module
+ |
+ Class
+
+=end
+
+ def test_class_is_an_object
+ assert_equal __, Class.is_a?(Object)
+ assert_equal __, Class.superclass
+ assert_equal __, Class.superclass.superclass
+ end
+
+ def test_class_has_object_id
+ assert_equal __, @truck.object_id > 0
+ assert_equal __, MailTruck.object_id > 0
+ end
+
+ def test_Object_class_is_Class
+ assert_equal __, Object.class
+ end
+
+ def test_Object_inherits_from_Basic_Object
+ assert_equal __, Object.superclass
+ end
+
+ def test_Basic_Object_sits_at_the_very_top
+ assert_equal __, BasicObject.superclass
+ end
+
+ class MailTruck
+ def has_mail?
+ !(@mails.nil? || @mails.empty?)
+ end
+ end
+
+ def test_metaclass_is_a_class_which_an_object_uses_to_redefine_itself
+ assert_equal __, @truck.has_mail?
+ end
+
+ class ::Class
+ def is_everything_an_object?
+ true
+ end
+ end
+
+ def test_metaclass_is_a_class_which_even_Class_uses_to_redefine_itself
+ assert_equal __, Class.is_everything_an_object?
+ assert_equal __, MailTruck.is_everything_an_object?
+ end
+
+ def test_singleton_methods_are_defined_only_for_that_instance
+ red_truck = MailTruck.new
+ blue_truck = MailTruck.new
+ def red_truck.honk
+ "Honk!Honk!"
+ end
+
+ assert_equal __, red_truck.honk
+ assert_raises(NoMethodError) do
+ blue_truck.honk
+ end
+ end
+
+=begin
+
+ MailTruck
+ |
+ Metaclass
+ |
+ @truck
+
+=end
+
+ def test_metaclass_sits_between_object_and_class
+ assert_equal __, @truck.metaclass.superclass
+ end
+
+ def test_singleton_methods_are_defined_in_metaclass
+ def @truck.honk
+ "Honk"
+ end
+ assert_equal __, @truck.honk
+ assert_equal __, @truck.metaclass.instance_methods.include?(:honk)
+ assert_equal __, @truck.singleton_methods.include?(:honk)
+ end
+
+ class ::Object
+ def metaclass
+ class << self ; self ; end
+ end
+ end
+
+ def test_class_lt_lt_m_opens_up_metaclass
+ klass = class << @truck ; self ; end
+ assert_equal __, klass == @truck.metaclass
+ end
+
+ def test_metaclass_can_have_metaclass_ad_infinitum
+ assert_equal __, @truck.metaclass.metaclass.nil?
+ assert_equal __, @truck.metaclass.metaclass.metaclass.nil?
+ end
+
+ def test_metaclass_of_a_metaclass_does_not_affect_the_original_object
+ def @truck.honk
+ "Honk"
+ end
+
+ metaclass = @truck.metaclass
+ def metaclass.honk_honk
+ "Honk Honk"
+ end
+
+ assert_equal __, @truck.honk
+ assert_equal __, @truck.meta_eval { honk_honk }
+ assert_raises(NoMethodError) do
+ @truck.honk_honk
+ end
+ end
+
+=begin
+ MailTruck
+ |
+ Metaclass -> Metaclass -> Metaclass ...
+ |
+ @truck
+
+=end
+ class MailTruck
+ @@trucks = []
+
+ def MailTruck.add_truck(truck)
+ @@trucks << truck
+ end
+
+ def MailTruck.count_trucks
+ @@trucks.count
+ end
+ end
+
+ def test_classes_can_have_class_variables
+ red_truck = MailTruck.new
+ blue_truck = MailTruck.new
+ MailTruck.add_truck(red_truck)
+ MailTruck.add_truck(blue_truck)
+
+ assert_equal __, MailTruck.count_trucks
+ end
+
+ class MailTruck
+ @trucks = []
+
+ def MailTruck.add_a_truck(truck)
+ @trucks << truck
+ end
+
+ def MailTruck.total_trucks
+ @trucks.count
+ end
+ end
+
+ def test_classes_can_have_instance_variables
+ red_truck = MailTruck.new
+ blue_truck = MailTruck.new
+ green_truck = MailTruck.new
+ MailTruck.add_a_truck(red_truck)
+ MailTruck.add_a_truck(blue_truck)
+ MailTruck.add_a_truck(green_truck)
+
+ assert_equal __, MailTruck.total_trucks
+ end
+
+ def test_class_variable_and_class_instance_variable_are_not_the_same
+ assert_equal __, MailTruck.count_trucks == MailTruck.total_trucks
+ end
+
+ class MailTruck
+ def say_hi
+ "Hi! I'm one of #{@@trucks.length} trucks"
+ end
+ end
+
+ def test_only_class_variables_can_be_accessed_by_instances_of_class
+ MailTruck.add_truck(@truck)
+ assert_equal __, @truck.say_hi
+ end
+
+ def test_class_methods_are_defined_in_metaclass_of_class
+ assert_equal __, MailTruck.metaclass.instance_methods.include?(:add_truck)
+ assert_equal __, MailTruck.metaclass.instance_methods.include?(:add_a_truck)
+ end
+
+ class MailTruck
+ def self.add_another_truck(truck)
+ @@trucks << truck
+ end
+ end
+
+ def test_class_methods_can_also_be_defined_using_self
+ MailTruck.add_another_truck(MailTruck.new)
+ assert_equal __, MailTruck.count_trucks
+ end
+
+ def test_all_class_methods_are_defined_in_metaclass_of_class
+ assert_equal __, MailTruck.metaclass.instance_methods.include?(:add_another_truck)
+ end
+
+ class ::Object
+ def meta_eval(&block)
+ metaclass.instance_eval(&block)
+ end
+ # Add methods to metaclass
+ def meta_def name, &block
+ meta_eval { define_method name, &block }
+ end
+ end
+
+ class MailTruck
+ def self.made_by(name)
+ meta_def :company do
+ name
+ end
+ end
+ end
+
+ class ManualTruck < MailTruck
+ made_by "TrucksRUs"
+ end
+
+ class RobotTruck < MailTruck
+ made_by "Lego"
+ end
+
+ def test_meta_def_can_be_used_to_add_methods_dynamically_to_metaclass
+ assert_equal __, ManualTruck.company
+ assert_equal __, RobotTruck.company
+ end
+
+ class ::Object
+ # Defines an instance method within a class
+ def class_def name, &block
+ class_eval { define_method name, &block }
+ end
+ end
+
+ class MailTruck
+ def self.check_for(attr)
+ class_def :can_drive? do
+ instance_variable_get("@#{attr}") != nil
+ end
+ end
+ end
+
+ class ManualTruck < MailTruck
+ check_for :driver
+ end
+
+ class RobotTruck < MailTruck
+ check_for :route
+ end
+
+ def test_class_def_can_be_used_to_add_instance_methods_dynamically
+ assert_equal __, ManualTruck.new.can_drive?
+ assert_equal __, RobotTruck.new.can_drive?
+
+ assert_equal __, ManualTruck.new('Harold', nil).can_drive?
+ assert_equal __, RobotTruck.new(nil, ['SF']).can_drive?
+ end
+
+ class ::Object
+ def meta_eval(&block)
+ metaclass.instance_eval(&block)
+ end
+
+ # Add methods to metaclass
+ def meta_def name, &block
+ meta_eval { define_method name, &block }
+ end
+
+ # Defines an instance method within a class
+ def class_def name, &block
+ class_eval { define_method name, &block }
+ end
+ end
+
+end
View
26 koans/about_method_added.rb
@@ -0,0 +1,26 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutMethodAdded < EdgeCase::Koan
+
+ class Cat
+ @num_of_methods = 0
+
+ def self.method_added(name)
+ @num_of_methods += 1
+ end
+
+ def miaow
+ end
+
+ def speak
+ end
+
+ def self.num_of_methods
+ @num_of_methods
+ end
+ end
+
+ def test_method_added_hook_method_is_called_for_new_methods
+ assert_equal __, Cat.num_of_methods
+ end
+end
View
7 koans/about_method_missing.rb
@@ -0,0 +1,7 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutMethodMissing < EdgeCase::Koan
+
+ def test_foo
+ end
+end
View
87 koans/about_modules.rb
@@ -0,0 +1,87 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutModules < EdgeCase::Koan
+
+ module Greeting
+ def say_hello
+ "Hello"
+ end
+ end
+
+ class Foo
+ include Greeting
+ end
+
+ module Greeting
+ def say_hello
+ "Hi"
+ end
+ end
+
+ def test_module_methods_are_active
+ assert_equal __, Foo.new.say_hello
+ end
+
+ def test_extend_adds_singleton_methods
+ animal = "cat"
+ animal.extend Greeting
+
+ assert_equal __, animal.say_hello
+ end
+
+ def test_another_way_to_add_singleton_methods_from_module
+ animal = "cat"
+ class << animal
+ include Greeting
+ end
+
+ assert_equal __, animal.say_hello
+ end
+
+ class Bar
+ extend Greeting
+ end
+
+ def test_extend_adds_class_methods_or_singleton_methods_on_the_class
+ assert_equal __, Bar.say_hello
+ end
+
+ module Moo
+ def instance_method
+ :instance_value
+ end
+
+ module ClassMethods
+ def class_method
+ :class_value
+ end
+ end
+ end
+
+ class Baz
+ include Moo
+ extend Moo::ClassMethods
+ end
+
+ def test_include_instance_methods_and_extend_class_methods
+ assert_equal __, Baz.new.instance_method
+ assert_equal __, Baz.class_method
+ end
+
+ module Moo
+ def self.included(klass)
+ #WRITE CODE HERE
+ klass.extend(ClassMethods)
+ end
+ end
+
+ class Foo
+ include Moo
+ end
+
+ def test_included_is_a_hook_method_that_can_be_used_to_extend_automatically
+ assert_equal __, Foo.new.instance_method
+ assert_equal __, Foo.class_method
+ end
+
+end
View
42 koans/about_prototype_inheritance.rb
@@ -0,0 +1,42 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutPrototypeInheritance < EdgeCase::Koan
+
+ def test_clone_copies_singleton_methods
+ animal = "cat"
+ def animal.speak
+ "miaow"
+ end
+ other = animal.clone
+ assert_equal __, other.speak
+ end
+
+ def test_dup_does_not_copy_singleton_methods
+ animal = "cat"
+ def animal.speak
+ "miaow"
+ end
+ other = animal.dup
+ assert_raises(NoMethodError) do
+ other.speak
+ end
+ end
+
+ def test_state_is_inherited_in_prototype_inheritance
+ animal = Object.new
+ def animal.num_of_lives=(lives)
+ @num_of_lives = lives
+ end
+
+ def animal.num_of_lives
+ @num_of_lives
+ end
+
+ cat = animal.clone
+ cat.num_of_lives = 9
+
+ felix = cat.clone
+ assert_equal __, felix.num_of_lives
+ end
+
+end
View
33 koans/about_singleton_methods.rb
@@ -0,0 +1,33 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutSingletonMethods < EdgeCase::Koan
+
+ def test_instance_method_calls_method_on_class
+ animal = "cat"
+ assert_equal __, animal.upcase
+ end
+
+ def test_instance_method_calls_method_on_parent_class_if_not_found_in_class
+ animal = "cat"
+ assert_equal __, animal.frozen?
+ end
+
+ def test_singleton_method_calls_method_on_anonymous_or_ghost_or_eigen_class
+ animal = "cat"
+ def animal.speak
+ "miaow"
+ end
+ assert_equal __, animal.speak
+ end
+
+ def test_singleton_method_is_available_only_on_that_instance
+ cat = "cat"
+ def cat.speak
+ "miaow"
+ end
+ dog = "dog"
+ assert_raises(NoMethodError) do
+ dog.speak
+ end
+ end
+end
View
8 koans/about_template.rb
@@ -0,0 +1,8 @@
+require File.expand_path(File.dirname(__FILE__) + '/edgecase')
+
+class AboutTemplate < EdgeCase::Koan
+
+ def test_foo
+ assert_equal __, true
+ end
+end
View
471 koans/edgecase.rb
@@ -0,0 +1,471 @@
+#!/usr/bin/env ruby
+# -*- ruby -*-
+
+require 'test/unit/assertions'
+
+# --------------------------------------------------------------------
+# Support code for the Ruby Koans.
+# --------------------------------------------------------------------
+
+class FillMeInError < StandardError
+end
+
+def ruby_version?(version)
+ RUBY_VERSION =~ /^#{version}/ ||
+ (version == 'jruby' && defined?(JRUBY_VERSION)) ||
+ (version == 'mri' && ! defined?(JRUBY_VERSION))
+end
+
+def in_ruby_version(*versions)
+ yield if versions.any? { |v| ruby_version?(v) }
+end
+
+# Standard, generic replacement value.
+# If value19 is given, it is used in place of value for Ruby 1.9.
+def __(value="FILL ME IN", value19=:mu)
+ if RUBY_VERSION < "1.9"
+ value
+ else
+ (value19 == :mu) ? value : value19
+ end
+end
+
+# Numeric replacement value.
+def _n_(value=999999, value19=:mu)
+ if RUBY_VERSION < "1.9"
+ value
+ else
+ (value19 == :mu) ? value : value19
+ end
+end
+
+# Error object replacement value.
+def ___(value=FillMeInError)
+ value
+end
+
+# Method name replacement.
+class Object
+ def ____(method=nil)
+ if method
+ self.send(method)
+ end
+ end
+
+ in_ruby_version("1.9") do
+ public :method_missing
+ end
+end
+
+class String
+ def side_padding(width)
+ extra = width - self.size
+ if width < 0
+ self
+ else
+ left_padding = extra / 2
+ right_padding = (extra+1)/2
+ (" " * left_padding) + self + (" " *right_padding)
+ end
+ end
+end
+
+module EdgeCase
+ class << self
+ def simple_output
+ ENV['SIMPLE_KOAN_OUTPUT'] == 'true'
+ end
+ end
+
+ module Color
+ #shamelessly stolen (and modified) from redgreen
+ COLORS = {
+ :clear => 0, :black => 30, :red => 31,
+ :green => 32, :yellow => 33, :blue => 34,
+ :magenta => 35, :cyan => 36,
+ }
+
+ module_function
+
+ COLORS.each do |color, value|
+ module_eval "def #{color}(string); colorize(string, #{value}); end"
+ module_function color
+ end
+
+ def colorize(string, color_value)
+ if use_colors?
+ color(color_value) + string + color(COLORS[:clear])
+ else
+ string
+ end
+ end
+
+ def color(color_value)
+ "\e[#{color_value}m"
+ end
+
+ def use_colors?
+ return false if ENV['NO_COLOR']
+ if ENV['ANSI_COLOR'].nil?
+ ! using_windows?
+ else
+ ENV['ANSI_COLOR'] =~ /^(t|y)/i
+ end
+ end
+
+ def using_windows?
+ File::ALT_SEPARATOR
+ end
+ end
+
+ class Sensei
+ attr_reader :failure, :failed_test, :pass_count
+
+ in_ruby_version("1.8") do
+ AssertionError = Test::Unit::AssertionFailedError
+ end
+
+ in_ruby_version("1.9") do
+ if defined?(MiniTest)
+ AssertionError = MiniTest::Assertion
+ else
+ AssertionError = Test::Unit::AssertionFailedError
+ end
+ end
+
+ def initialize
+ @pass_count = 0
+ @failure = nil
+ @failed_test = nil
+ @observations = []
+ end
+
+ PROGRESS_FILE_NAME = '.path_progress'
+
+ def add_progress(prog)
+ @_contents = nil
+ exists = File.exists?(PROGRESS_FILE_NAME)
+ File.open(PROGRESS_FILE_NAME,'a+') do |f|
+ f.print "#{',' if exists}#{prog}"
+ end
+ end
+
+ def progress
+ if @_contents.nil?
+ if File.exists?(PROGRESS_FILE_NAME)
+ File.open(PROGRESS_FILE_NAME,'r') do |f|
+ @_contents = f.read.to_s.gsub(/\s/,'').split(',')
+ end
+ else
+ @_contents = []
+ end
+ end
+ @_contents
+ end
+
+ def observe(step)
+ if step.passed?
+ @pass_count += 1
+ if @pass_count > progress.last.to_i
+ @observations << Color.green("#{step.koan_file}##{step.name} has expanded your awareness.")
+ end
+ else
+ @failed_test = step
+ @failure = step.failure
+ add_progress(@pass_count)
+ @observations << Color.red("#{step.koan_file}##{step.name} has damaged your karma.")
+ throw :edgecase_exit
+ end
+ end
+
+ def failed?
+ ! @failure.nil?
+ end
+
+ def assert_failed?
+ failure.is_a?(AssertionError)
+ end
+
+ def instruct
+ if failed?
+ @observations.each{|c| puts c }
+ encourage
+ guide_through_error
+ a_zenlike_statement
+ show_progress
+ else
+ end_screen
+ end
+ end
+
+ def show_progress
+ bar_width = 50
+ total_tests = EdgeCase::Koan.total_tests
+ scale = bar_width.to_f/total_tests
+ print Color.green("your path thus far [")
+ happy_steps = (pass_count*scale).to_i
+ happy_steps = 1 if happy_steps == 0 && pass_count > 0
+ print Color.green('.'*happy_steps)
+ if failed?
+ print Color.red('X')
+ print Color.cyan('_'*(bar_width-1-happy_steps))
+ end
+ print Color.green(']')
+ print " #{pass_count}/#{total_tests}"
+ puts
+ end
+
+ def end_screen
+ 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
+ ,, , ,,
+ : ::::, :::,
+ , ,,: :::::::::::::,, :::: : ,
+ , ,,, ,:::::::::::::::::::, ,: ,: ,,
+ :, ::, , , :, ,::::::::::::::::::, ::: ,::::
+ : : ::, ,:::::::: ::, ,::::
+ , ,::::: :,:::::::,::::,
+ ,: , ,:,,: :::::::::::::
+ ::,: ,,:::, ,::::::::::::,
+ ,:::, :,,::: ::::::::::::,
+ ,::: :::::::, Mountains are again merely mountains ,::::::::::::
+ :::,,,:::::: ::::::::::::
+ ,:::::::::::, ::::::::::::,
+ :::::::::::, ,::::::::::::
+::::::::::::: ,::::::::::::
+:::::::::::: Ruby Metaprogramming Koans ::::::::::::,
+::::::::::::#{ ruby_version },::::::::::::,
+:::::::::::, , ::::::::::::
+,:::::::::::::, ,,::::::::::::,
+:::::::::::::: ,::::::::::::
+ ::::::::::::::, ,:::::::::::::
+ ::::::::::::, , ::::::::::::
+ :,::::::::: :::: :::::::::::::
+ ,::::::::::: ,: ,,:::::::::::::,
+ :::::::::::: ,::::::::::::::,
+ :::::::::::::::::, ::::::::::::::::
+ :::::::::::::::::::, ::::::::::::::::
+ ::::::::::::::::::::::, ,::::,:, , ::::,:::
+ :::::::::::::::::::::::, ::,: ::,::, ,,: ::::
+ ,:::::::::::::::::::: ::,, , ,, ,::::
+ ,:::::::::::::::: ::,, , ,:::,
+ ,:::: , ,,
+ ,,,
+ENDTEXT
+ puts completed
+ end
+
+ def encourage
+ puts
+ puts "The Master says:"
+ puts Color.cyan(" You have not yet reached enlightenment.")
+ if ((recents = progress.last(5)) && recents.size == 5 && recents.uniq.size == 1)
+ puts Color.cyan(" I sense frustration. Do not be afraid to ask for help.")
+ elsif progress.last(2).size == 2 && progress.last(2).uniq.size == 1
+ puts Color.cyan(" Do not lose hope.")
+ elsif progress.last.to_i > 0
+ puts Color.cyan(" You are progressing. Excellent. #{progress.last} completed.")
+ end
+ end
+
+ def guide_through_error
+ puts
+ puts "The answers you seek..."
+ puts Color.red(indent(failure.message).join)
+ puts
+ puts "Please meditate on the following code:"
+ if assert_failed?
+ puts embolden_first_line_only(indent(find_interesting_lines(failure.backtrace)))
+ else
+ puts embolden_first_line_only(indent(failure.backtrace))
+ end
+ puts
+ end
+
+ def embolden_first_line_only(text)
+ first_line = true
+ text.collect { |t|
+ if first_line
+ first_line = false
+ Color.red(t)
+ else
+ Color.cyan(t)
+ end
+ }
+ end
+
+ def indent(text)
+ text = 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|minitest/
+ }
+ end
+
+ # Hat's tip to Ara T. Howard for the zen statements from his
+ # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html)
+ def a_zenlike_statement
+ if !failed?
+ zen_statement = "Mountains are again merely mountains"
+ else
+ zen_statement = case (@pass_count % 10)
+ when 0
+ "mountains are merely mountains"
+ when 1, 2
+ "learn the rules so you know how to break them properly"
+ when 3, 4
+ "remember that silence is sometimes the best answer"
+ when 5, 6
+ "sleep is the best meditation"
+ when 7, 8
+ "when you lose, don't lose the lesson"
+ else
+ "things are not what they appear to be: nor are they otherwise"
+ end
+ end
+ puts Color.green(zen_statement)
+ end
+ end
+
+ class Koan
+ include Test::Unit::Assertions
+
+ attr_reader :name, :failure, :koan_count, :step_count, :koan_file
+
+ def initialize(name, koan_file=nil, koan_count=0, step_count=0)
+ @name = name
+ @failure = nil
+ @koan_count = koan_count
+ @step_count = step_count
+ @koan_file = koan_file
+ end
+
+ def passed?
+ @failure.nil?
+ end
+
+ def failed(failure)
+ @failure = failure
+ end
+
+ def setup
+ end
+
+ def teardown
+ end
+
+ def meditate
+ setup
+ begin
+ send(name)
+ rescue StandardError, EdgeCase::Sensei::AssertionError => ex
+ failed(ex)
+ ensure
+ begin
+ teardown
+ rescue StandardError, EdgeCase::Sensei::AssertionError => ex
+ failed(ex) if passed?
+ end
+ end
+ self
+ end
+
+ # Class methods for the EdgeCase test suite.
+ class << self
+ def inherited(subclass)
+ subclasses << subclass
+ end
+
+ def method_added(name)
+ testmethods << name if !tests_disabled? && Koan.test_pattern =~ name.to_s
+ end
+
+ def end_of_enlightenment
+ @tests_disabled = true
+ end
+
+ def command_line(args)
+ args.each do |arg|
+ case arg
+ when /^-n\/(.*)\/$/
+ @test_pattern = Regexp.new($1)
+ when /^-n(.*)$/
+ @test_pattern = Regexp.new(Regexp.quote($1))
+ else
+ if File.exist?(arg)
+ load(arg)
+ else
+ fail "Unknown command line argument '#{arg}'"
+ end
+ end
+ end
+ end
+
+ # Lazy initialize list of subclasses
+ def subclasses
+ @subclasses ||= []
+ end
+
+ # Lazy initialize list of test methods.
+ def testmethods
+ @test_methods ||= []
+ end
+
+ def tests_disabled?
+ @tests_disabled ||= false
+ end
+
+ def test_pattern
+ @test_pattern ||= /^test_/
+ end
+
+ def total_tests
+ self.subclasses.inject(0){|total, k| total + k.testmethods.size }
+ end
+ end
+ end
+
+ class ThePath
+ def walk
+ sensei = EdgeCase::Sensei.new
+ each_step do |step|
+ sensei.observe(step.meditate)
+ end
+ sensei.instruct
+ end
+
+ def each_step
+ catch(:edgecase_exit) {
+ step_count = 0
+ EdgeCase::Koan.subclasses.each_with_index do |koan,koan_index|
+ koan.testmethods.each do |method_name|
+ step = koan.new(method_name, koan.to_s, koan_index+1, step_count+=1)
+ yield step
+ end
+ end
+ }
+ end
+ end
+end
+
+END {
+ EdgeCase::Koan.command_line(ARGV)
+ EdgeCase::ThePath.new.walk
+}
View
18 koans/path_to_enlightenment.rb
@@ -0,0 +1,18 @@
+# The path to Ruby Metaprogramming Enlightenment starts with the following:
+
+$LOAD_PATH << File.dirname(__FILE__)
+
+require 'about_metaclass'
+require 'about_singleton_methods'
+require 'about_class_as_constant'
+require 'about_class_methods'
+require 'about_prototype_inheritance'
+require 'about_class_inheritance'
+require 'about_modules'
+require 'about_blocks'
+require 'about_binding'
+require 'about_define_method'
+require 'about_instance_eval_and_class_eval'
+require 'about_hook_methods'
+require 'about_method_added'
+require 'about_method_missing'
View
7 koans/test_helper.rb
@@ -0,0 +1,7 @@
+require 'test/unit'
+
+def __
+ "FILL ME IN"
+end
+
+EdgeCase = Test::Unit
Please sign in to comment.
Something went wrong with that request. Please try again.