Commits

Moorsalin Munshi committed c425951

initial commit

Comments (0)

Files changed (136)

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+import unittest
+
+from runner.runner_tests.test_mountain import TestMountain
+from runner.runner_tests.test_sensei import TestSensei
+from runner.runner_tests.test_helper import TestHelper
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain))
+    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei))
+    suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper))
+    return suite
+
+if __name__ == '__main__':
+    unittest.TextTestRunner(verbosity=2).run(suite())
+    

contemplate_koans.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Acknowledgment:
+#
+# Python Koans is a port of Ruby Koans originally written by Jim Weirich
+# and Joe O'brien of Edgecase. There are some differences and tweaks specific
+# to the Python language, but a great deal of it has been copied wholesale.
+# So thank guys!
+#
+
+import unittest
+import sys
+
+
+if __name__ == '__main__':        
+    if sys.version_info >= (3, 0):
+        print("\nThis is the Python 2 version of Python Koans, but you are " +
+            "running it with Python 3 or newer!\n\n"
+            "Did you accidentally use the wrong python script? \nTry:\n\n" +
+            "    python contemplate_koans.py\n")
+    else:
+        if sys.version_info < (2, 6):
+            print("\n" +
+                "********************************************************\n" +
+                "WARNING:\n" +
+                "This version of Python Koans was designed for " +
+                "Python 2.6 or greater.\n" +
+                "Your version of Python is older, so this is unlikely " +
+                "to work!\n\n" +
+                "But lets see how far we get...\n" +
+                "********************************************************\n")
+        
+        from runner.mountain import Mountain
+
+        Mountain().walk_the_path(sys.argv)

Binary file added.

+this
+is
+a
+test

koans/GREEDS_RULES.txt

+= Playing Greed
+
+Greed is a dice game played among 2 or more players, using 5
+six-sided dice.
+
+== Playing Greed
+
+Each player takes a turn consisting of one or more rolls of the dice.
+On the first roll of the game, a player rolls all five dice which are
+scored according to the following:
+
+  Three 1's => 1000 points
+  Three 6's =>  600 points
+  Three 5's =>  500 points
+  Three 4's =>  400 points
+  Three 3's =>  300 points
+  Three 2's =>  200 points
+  One   1   =>  100 points
+  One   5   =>   50 points
+
+A single die can only be counted once in each roll.  For example,
+a "5" can only count as part of a triplet (contributing to the 500
+points) or as a single 50 points, but not both in the same roll.
+
+Example Scoring
+
+   Throw       Score
+   ---------   ------------------
+   5 1 3 4 1   50 + 2 * 100 = 250
+   1 1 1 3 1   1000 + 100 = 1100
+   2 4 4 5 4   400 + 50 = 450
+
+The dice not contributing to the score are called the non-scoring
+dice.  "3" and "4" are non-scoring dice in the first example.  "3" is
+a non-scoring die in the second, and "2" is a non-score die in the
+final example.
+
+After a player rolls and the score is calculated, the scoring dice are
+removed and the player has the option of rolling again using only the
+non-scoring dice. If all of the thrown dice are scoring, then the
+player may roll all 5 dice in the next roll.
+
+The player may continue to roll as long as each roll scores points. If
+a roll has zero points, then the player loses not only their turn, but
+also accumulated score for that turn. If a player decides to stop
+rolling before rolling a zero-point roll, then the accumulated points
+for the turn is added to his total score.
+
+== Getting "In The Game"
+
+Before a player is allowed to accumulate points, they must get at
+least 300 points in a single turn. Once they have achieved 300 points
+in a single turn, the points earned in that turn and each following
+turn will be counted toward their total score.
+
+== End Game
+
+Once a player reaches 3000 (or more) points, the game enters the final
+round where each of the other players gets one more turn. The winner
+is the player with the highest score after the final round.
+
+== References
+
+Greed is described on Wikipedia at
+http://en.wikipedia.org/wiki/Greed_(dice_game), however the rules are
+a bit different from the rules given here.

koans/__init__.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# koans

Binary file added.

koans/a_normal_folder/a_module.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+class Duck(object):
+    @property
+    def name(self):
+        return "Howard"

koans/a_package_folder/__init__.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+an_attribute = 1984
Add a comment to this file

koans/a_package_folder/__init__.pyc

Binary file added.

koans/a_package_folder/a_module.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+class Duck(object):
+    @property
+    def name(self):
+        return "Donald"
Add a comment to this file

koans/a_package_folder/a_module.pyc

Binary file added.

koans/about_asserts.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutAsserts(Koan):
+
+    def test_assert_truth(self):
+        """
+        We shall contemplate truth by testing reality, via asserts.
+        """
+        self.assertTrue(True)  # This should be true
+
+    def test_assert_with_message(self):
+        """
+        Enlightenment may be more easily achieved with appropriate messages.
+        """
+        self.assertTrue(True, "This should be true -- Please fix this")
+
+    def test_fill_in_values(self):
+        """
+        Sometimes we will ask you to fill in the values
+        """
+        self.assertEqual(2, 1 + 1)
+
+    def test_assert_equality(self):
+        """
+        To understand reality, we must compare our expectations against
+        reality.
+        """
+        expected_value = 2
+        actual_value = 1 + 1
+        self.assertTrue(expected_value == actual_value)
+
+    def test_a_better_way_of_asserting_equality(self):
+        """
+        Some ways of asserting equality are better than others.
+        """
+        expected_value = 2
+        actual_value = 1 + 1
+
+        self.assertEqual(expected_value, actual_value)
+
+    def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self):
+        """
+        Knowing how things really work is half the battle
+        """
+
+        # This throws an AssertionError exception
+        assert True
Add a comment to this file

koans/about_asserts.pyc

Binary file added.

koans/about_attribute_access.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Partially based on AboutMessagePassing in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutAttributeAccess(Koan):
+
+    class TypicalObject(object):
+        pass
+
+    def test_calling_undefined_functions_normally_results_in_errors(self):
+        typical = self.TypicalObject()
+
+        try:
+            typical.foobar()
+        except Exception as exception:
+            self.assertEqual(__, type(exception).__name__)
+            self.assertMatch(__, exception[0])
+
+    def test_calling_getattribute_causes_an_attribute_error(self):
+        typical = self.TypicalObject()
+
+        try:
+            typical.__getattribute__('foobar')
+        except AttributeError as exception:
+            self.assertMatch(__, exception[0])
+
+        # THINK ABOUT IT:
+        #
+        # If the method __getattribute__() causes the AttributeError, then
+        # what would happen if we redefine __getattribute__()?
+
+    # ------------------------------------------------------------------
+
+    class CatchAllAttributeReads(object):
+        def __getattribute__(self, attr_name):
+            return "Someone called '" + attr_name + \
+                "' and it could not be found"
+
+    def test_all_attribute_reads_are_caught(self):
+        catcher = self.CatchAllAttributeReads()
+
+        self.assertMatch(__, catcher.foobar)
+
+    def test_intercepting_return_values_can_disrupt_the_call_chain(self):
+        catcher = self.CatchAllAttributeReads()
+
+        self.assertMatch(__, catcher.foobaz)  # This is fine
+
+        try:
+            catcher.foobaz(1)
+        except TypeError as ex:
+            self.assertMatch(__, ex[0])
+
+        # foobaz returns a string. What happens to the '(1)' part?
+        # Try entering this into a python console to reproduce the issue:
+        #
+        #     "foobaz"(1)
+        #
+
+    def test_changing_getattribute_will_affect__the_getattr_function(self):
+        catcher = self.CatchAllAttributeReads()
+
+        self.assertMatch(__, getattr(catcher, 'any_attribute'))
+
+    # ------------------------------------------------------------------
+
+    class WellBehavedFooCatcher(object):
+        def __getattribute__(self, attr_name):
+            if attr_name[:3] == "foo":
+                return "Foo to you too"
+            else:
+                return \
+                    super(AboutAttributeAccess.WellBehavedFooCatcher, self). \
+                    __getattribute__(attr_name)
+
+    def test_foo_attributes_are_caught(self):
+        catcher = self.WellBehavedFooCatcher()
+
+        self.assertEqual(__, catcher.foo_bar)
+        self.assertEqual(__, catcher.foo_baz)
+
+    def test_non_foo_messages_are_treated_normally(self):
+        catcher = self.WellBehavedFooCatcher()
+
+        try:
+            catcher.normal_undefined_attribute
+        except AttributeError as ex:
+            self.assertMatch(__, ex[0])
+
+    # ------------------------------------------------------------------
+
+    global stack_depth
+    stack_depth = 0
+
+    class RecursiveCatcher(object):
+        def __init__(self):
+            global stack_depth
+            stack_depth = 0
+            self.no_of_getattribute_calls = 0
+
+        def __getattribute__(self, attr_name):
+            #Uncomment for debugging info:
+            #print 'Debug __getattribute__(' + type(self).__name__ + \
+            #    "." + attr_name + ") dict=" + str(self.__dict__)
+
+            # We need something that is outside the scope of this class:
+            global stack_depth
+            stack_depth += 1
+
+            if stack_depth <= 10:  # to prevent a stack overflow
+                self.no_of_getattribute_calls += 1
+                # Oops! We just accessed an attribute: no_of_getattribute_calls
+                # Guess what happens when self.no_of_getattribute_calls is
+                # accessed?
+
+            # Using 'object' directly because using super() here will also
+            # trigger a __getattribute__() call.
+            return object.__getattribute__(self, attr_name)
+
+        def my_method(self):
+            pass
+
+    def test_getattribute_is_a_bit_overzealous_sometimes(self):
+        catcher = self.RecursiveCatcher()
+        catcher.my_method()
+        global stack_depth
+        self.assertEqual(__, stack_depth)
+
+    # ------------------------------------------------------------------
+
+    class MinimalCatcher(object):
+        class DuffObject(object):
+            pass
+
+        def __init__(self):
+            self.no_of_getattr_calls = 0
+
+        def __getattr__(self, attr_name):
+            self.no_of_getattr_calls += 1
+            return self.DuffObject
+
+        def my_method(self):
+            pass
+
+    def test_getattr_ignores_known_attributes(self):
+        catcher = self.MinimalCatcher()
+        catcher.my_method()
+
+        self.assertEqual(__, catcher.no_of_getattr_calls)
+
+    def test_getattr_only_catches_unknown_attributes(self):
+        catcher = self.MinimalCatcher()
+        catcher.purple_flamingos()
+        catcher.free_pie()
+
+        self.assertEqual(__,
+            type(catcher.give_me_duff_or_give_me_death()).__name__)
+
+        self.assertEqual(__, catcher.no_of_getattr_calls)
+
+    # ------------------------------------------------------------------
+
+    class PossessiveSetter(object):
+        def __setattr__(self, attr_name, value):
+            new_attr_name = attr_name
+
+            if attr_name[-5:] == 'comic':
+                new_attr_name = "my_" + new_attr_name
+            elif attr_name[-3:] == 'pie':
+                new_attr_name = "a_" + new_attr_name
+
+            object.__setattr__(self, new_attr_name, value)
+
+    def test_setattr_intercepts_attribute_assignments(self):
+        fanboy = self.PossessiveSetter()
+
+        fanboy.comic = 'The Laminator, issue #1'
+        fanboy.pie = 'blueberry'
+
+        self.assertEqual(__, fanboy.a_pie)
+
+        prefix = '__'
+        self.assertEqual(
+            "The Laminator, issue #1",
+            getattr(fanboy, prefix + '_comic'))
+
+    # ------------------------------------------------------------------
+
+    class ScarySetter(object):
+        def __init__(self):
+            self.num_of_coconuts = 9
+            self._num_of_private_coconuts = 2
+
+        def __setattr__(self, attr_name, value):
+            new_attr_name = attr_name
+
+            if attr_name[0] != '_':
+                new_attr_name = "altered_" + new_attr_name
+
+            object.__setattr__(self, new_attr_name, value)
+
+    def test_it_modifies_external_attribute_as_expected(self):
+        setter = self.ScarySetter()
+        setter.e = "mc hammer"
+
+        self.assertEqual(__, setter.altered_e)
+
+    def test_it_mangles_some_internal_attributes(self):
+        setter = self.ScarySetter()
+
+        try:
+            coconuts = setter.num_of_coconuts
+        except AttributeError:
+            self.assertEqual(__, setter.altered_num_of_coconuts)
+
+    def test_in_this_case_private_attributes_remain_unmangled(self):
+        setter = self.ScarySetter()
+
+        self.assertEqual(__, setter._num_of_private_coconuts)
Add a comment to this file

koans/about_attribute_access.pyc

Binary file added.

koans/about_class_attributes.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Based on AboutClassMethods in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutClassAttributes(Koan):
+    class Dog(object):
+        pass
+
+    def test_new_style_class_objects_are_objects(self):
+        # Note: Old style class instances are not objects but they are being
+        # phased out it Python 3.
+
+        fido = self.Dog()
+        self.assertEqual(__, isinstance(fido, object))
+
+    def test_classes_are_types(self):
+        self.assertEqual(__, self.Dog.__class__ == type)
+
+    def test_classes_are_objects_too(self):
+        self.assertEqual(__, issubclass(self.Dog, object))
+
+    def test_objects_have_methods(self):
+        fido = self.Dog()
+        self.assertEqual(__, len(dir(fido)))
+
+    def test_classes_have_methods(self):
+        self.assertEqual(__, len(dir(self.Dog)))
+
+    def test_creating_objects_without_defining_a_class(self):
+        singularity = object()
+        self.assertEqual(__, len(dir(singularity)))
+
+    def test_defining_attributes_on_individual_objects(self):
+        fido = self.Dog()
+        fido.legs = 4
+
+        self.assertEqual(__, fido.legs)
+
+    def test_defining_functions_on_individual_objects(self):
+        fido = self.Dog()
+        fido.wag = lambda: 'fidos wag'
+
+        self.assertEqual(__, fido.wag())
+
+    def test_other_objects_are_not_affected_by_these_singleton_functions(self):
+        fido = self.Dog()
+        rover = self.Dog()
+
+        def wag():
+            return 'fidos wag'
+        fido.wag = wag
+
+        try:
+            rover.wag()
+        except Exception as ex:
+            self.assertMatch(__, ex[0])
+
+    # ------------------------------------------------------------------
+
+    class Dog2(object):
+        def wag(self):
+            return 'instance wag'
+
+        def bark(self):
+            return "instance bark"
+
+        def growl(self):
+            return "instance growl"
+
+        @staticmethod
+        def bark():
+            return "staticmethod bark, arg: None"
+
+        @classmethod
+        def growl(cls):
+            return "classmethod growl, arg: cls=" + cls.__name__
+
+    def test_like_all_objects_classes_can_have_singleton_methods(self):
+        self.assertMatch(__, self.Dog2.growl())
+
+    def test_classmethods_are_not_independent_of_instance_methods(self):
+        fido = self.Dog2()
+        self.assertMatch(__, fido.growl())
+        self.assertMatch(__, self.Dog2.growl())
+
+    def test_staticmethods_are_unbound_functions_housed_in_a_class(self):
+        self.assertMatch(__, self.Dog2.bark())
+
+    def test_staticmethods_also_overshadow_instance_methods(self):
+        fido = self.Dog2()
+        self.assertMatch(__, fido.bark())
+
+    # ------------------------------------------------------------------
+
+    class Dog3(object):
+        def __init__(self):
+            self._name = None
+
+        def get_name_from_instance(self):
+            return self._name
+
+        def set_name_from_instance(self, name):
+            self._name = name
+
+        @classmethod
+        def get_name(cls):
+            return cls._name
+
+        @classmethod
+        def set_name(cls, name):
+            cls._name = name
+
+        name = property(get_name, set_name)
+        name_from_instance = property(
+            get_name_from_instance, set_name_from_instance)
+
+    def test_classmethods_can_not_be_used_as_properties(self):
+        fido = self.Dog3()
+        try:
+            fido.name = "Fido"
+        except Exception as ex:
+            self.assertMatch(__, ex[0])
+
+    def test_classes_and_instances_do_not_share_instance_attributes(self):
+        fido = self.Dog3()
+        fido.set_name_from_instance("Fido")
+        fido.set_name("Rover")
+        self.assertEqual(__, fido.get_name_from_instance())
+        self.assertEqual(__, self.Dog3.get_name())
+
+    def test_classes_and_instances_do_share_class_attributes(self):
+        fido = self.Dog3()
+        fido.set_name("Fido")
+        self.assertEqual(__, fido.get_name())
+        self.assertEqual(__, self.Dog3.get_name())
+
+    # ------------------------------------------------------------------
+
+    class Dog4(object):
+        def a_class_method(cls):
+            return 'dogs class method'
+
+        def a_static_method():
+            return 'dogs static method'
+
+        a_class_method = classmethod(a_class_method)
+        a_static_method = staticmethod(a_static_method)
+
+    def test_you_can_define_class_methods_without_using_a_decorator(self):
+        self.assertEqual(__, self.Dog4.a_class_method())
+
+    def test_you_can_define_static_methods_without_using_a_decorator(self):
+        self.assertEqual(__, self.Dog4.a_static_method())
+
+    # ------------------------------------------------------------------
+
+    def test_you_can_explicitly_call_class_methods_from_instance_methods(self):
+        fido = self.Dog4()
+        self.assertEqual(__, fido.__class__.a_class_method())
Add a comment to this file

koans/about_class_attributes.pyc

Binary file added.

koans/about_classes.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutClasses(Koan):
+    class Dog(object):
+        "Dogs need regular walkies. Never, ever let them drive."
+
+    def test_instances_of_classes_can_be_created_adding_parentheses(self):
+        fido = self.Dog()
+        self.assertEqual(__, type(fido).__name__)
+
+    def test_classes_have_docstrings(self):
+        self.assertMatch(__, self.Dog.__doc__)
+
+    # ------------------------------------------------------------------
+
+    class Dog2(object):
+        def __init__(self):
+            self._name = 'Paul'
+
+        def set_name(self, a_name):
+            self._name = a_name
+
+    def test_init_method_is_the_constructor(self):
+        dog = self.Dog2()
+        self.assertEqual(__, dog._name)
+
+    def test_private_attributes_are_not_really_private(self):
+        dog = self.Dog2()
+        dog.set_name("Fido")
+        self.assertEqual(__, dog._name)
+        # The _ prefix in _name implies private ownership, but nothing is truly
+        # private in Python.
+
+    def test_you_can_also_access_the_value_out_using_getattr_and_dict(self):
+        fido = self.Dog2()
+        fido.set_name("Fido")
+
+        self.assertEqual(__, getattr(fido, "_name"))
+        # getattr(), setattr() and delattr() are a way of accessing attributes
+        # by method rather than through assignment operators
+
+        self.assertEqual(__, fido.__dict__["_name"])
+        # Yes, this works here, but don't rely on the __dict__ object! Some
+        # class implementations use optimization which result in __dict__ not
+        # showing everything.
+
+    # ------------------------------------------------------------------
+
+    class Dog3(object):
+        def __init__(self):
+            self._name = None
+
+        def set_name(self, a_name):
+            self._name = a_name
+
+        def get_name(self):
+            return self._name
+
+        name = property(get_name, set_name)
+
+    def test_that_name_can_be_read_as_a_property(self):
+        fido = self.Dog3()
+        fido.set_name("Fido")
+
+        self.assertEqual(__, fido.get_name())  # access as method
+        self.assertEqual(__, fido.name)        # access as property
+
+    # ------------------------------------------------------------------
+
+    class Dog4(object):
+        def __init__(self):
+            self._name = None
+
+        @property
+        def name(self):
+            return self._name
+
+        @name.setter
+        def name(self, a_name):
+            self._name = a_name
+
+    def test_creating_properties_with_decorators_is_slightly_easier(self):
+        fido = self.Dog4()
+
+        fido.name = "Fido"
+        self.assertEqual(__, fido.name)
+
+    # ------------------------------------------------------------------
+
+    class Dog5(object):
+        def __init__(self, initial_name):
+            self._name = initial_name
+
+        @property
+        def name(self):
+            return self._name
+
+    def test_init_provides_initial_values_for_instance_variables(self):
+        fido = self.Dog5("Fido")
+        self.assertEqual(__, fido.name)
+
+    def test_args_must_match_init(self):
+        self.assertRaises(___, self.Dog5)  # Evaluates self.Dog5()
+
+        # THINK ABOUT IT:
+        # Why is this so?
+
+    def test_different_objects_have_difference_instance_variables(self):
+        fido = self.Dog5("Fido")
+        rover = self.Dog5("Rover")
+
+        self.assertEqual(____, rover.name == fido.name)
+
+    # ------------------------------------------------------------------
+
+    class Dog6(object):
+        def __init__(self, initial_name):
+            self._name = initial_name
+
+        def get_self(self):
+            return self
+
+        def __str__(self):
+            return __
+
+        def __repr__(self):
+            return "<Dog named '" + self._name + "'>"
+
+    def test_inside_a_method_self_refers_to_the_containing_object(self):
+        fido = self.Dog6("Fido")
+
+        self.assertEqual(__, fido.get_self())  # Not a string!
+
+    def test_str_provides_a_string_version_of_the_object(self):
+        fido = self.Dog6("Fido")
+        self.assertEqual("Fido", str(fido))
+
+    def test_str_is_used_explicitly_in_string_interpolation(self):
+        fido = self.Dog6("Fido")
+        self.assertEqual(__, "My dog is " + str(fido))
+
+    def test_repr_provides_a_more_complete_string_version(self):
+        fido = self.Dog6("Fido")
+        self.assertEqual(__, repr(fido))
+
+    def test_all_objects_support_str_and_repr(self):
+        seq = [1, 2, 3]
+
+        self.assertEqual(__, str(seq))
+        self.assertEqual(__, repr(seq))
+
+        self.assertEqual(__, str("STRING"))
+        self.assertEqual(__, repr("STRING"))
Add a comment to this file

koans/about_classes.pyc

Binary file added.

koans/about_control_statements.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutControlStatements(Koan):
+
+    def test_if_then_else_statements(self):
+        if True:
+            result = 'true value'
+        else:
+            result = 'false value'
+        self.assertEqual(__, result)
+
+    def test_if_then_statements(self):
+        result = 'default value'
+        if True:
+            result = 'true value'
+        self.assertEqual(__, result)
+
+    def test_while_statement(self):
+        i = 1
+        result = 1
+        while i <= 10:
+            result = result * i
+            i += 1
+        self.assertEqual(__, result)
+
+    def test_break_statement(self):
+        i = 1
+        result = 1
+        while True:
+            if i > 10: break
+            result = result * i
+            i += 1
+        self.assertEqual(__, result)
+
+    def test_continue_statement(self):
+        i = 0
+        result = []
+        while i < 10:
+            i += 1
+            if (i % 2) == 0: continue
+            result.append(i)
+        self.assertEqual(__, result)
+
+    def test_for_statement(self):
+        phrase = ["fish", "and", "chips"]
+        result = []
+        for item in phrase:
+            result.append(item.upper())
+        self.assertEqual([__, __, __], result)
+
+    def test_for_statement_with_tuples(self):
+        round_table = [
+            ("Lancelot", "Blue"),
+            ("Galahad", "I don't know!"),
+            ("Robin", "Blue! I mean Green!"),
+            ("Arthur", "Is that an African Swallow or Amazonian Swallow?")
+        ]
+        result = []
+        for knight, answer in round_table:
+            result.append("Contestant: '" + knight + \
+            "'   Answer: '" + answer + "'")
+
+        text = __
+
+        self.assertMatch(text, result[2])
+
+        self.assertNoMatch(text, result[0])
+        self.assertNoMatch(text, result[1])
+        self.assertNoMatch(text, result[3])
Add a comment to this file

koans/about_control_statements.pyc

Binary file added.

koans/about_decorating_with_classes.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+import functools
+
+
+class AboutDecoratingWithClasses(Koan):
+    def maximum(self, a, b):
+        if a > b:
+            return a
+        else:
+            return b
+
+    def test_partial_that_wrappers_no_args(self):
+        """
+        Before we can understand this type of decorator we need to consider
+        the partial.
+        """
+        max = functools.partial(self.maximum)
+        
+        self.assertEqual(__, max(7, 23))
+        self.assertEqual(__, max(10, -10))
+        
+    def test_partial_that_wrappers_first_arg(self):
+        max0 = functools.partial(self.maximum, 0)
+
+        self.assertEqual(__, max0(-4))
+        self.assertEqual(__, max0(5))
+
+    def test_partial_that_wrappers_all_args(self):
+        always99 = functools.partial(self.maximum, 99, 20)
+        always20 = functools.partial(self.maximum, 9, 20)
+
+        self.assertEqual(__, always99())
+        self.assertEqual(__, always20())
+
+    # ------------------------------------------------------------------
+
+    class doubleit(object):
+        def __init__(self, fn):
+            self.fn = fn
+    
+        def __call__(self, *args):
+            return self.fn(*args) + ', ' + self.fn(*args)
+    
+        def __get__(self, obj, cls=None):
+            if not obj:
+                # Decorating an unbound function
+                return self
+            else:
+                # Decorating a bound method
+                return functools.partial(self, obj)
+
+    @doubleit
+    def foo(self):
+        return "foo"
+    
+    @doubleit
+    def parrot(self, text):
+        return text.upper()
+                
+    def test_decorator_with_no_arguments(self):
+        # To clarify: the decorator above the function has no arguments, even
+        # if the decorated function does
+                
+        self.assertEqual(__, self.foo())
+        self.assertEqual(__, self.parrot('pieces of eight'))
+
+    # ------------------------------------------------------------------
+
+    def sound_check(self):
+        #Note: no decorator
+        return "Testing..."
+
+    def test_what_a_decorator_is_doing_to_a_function(self):
+        #wrap the function with the decorator
+        self.sound_check = self.doubleit(self.sound_check)
+        
+        self.assertEqual(__, self.sound_check())
+
+    # ------------------------------------------------------------------
+
+    class documenter(object):
+        def __init__(self, *args):
+            self.fn_doc = args[0]
+    
+        def __call__(self, fn):
+            def decorated_function(*args):
+                return fn(*args)
+                
+            if fn.__doc__:
+                decorated_function.__doc__ = fn.__doc__ + ": " + self.fn_doc
+            else:
+                decorated_function.__doc__ = self.fn_doc
+            return decorated_function
+        
+    @documenter("Increments a value by one. Kind of.")
+    def count_badly(self, num):
+        num += 1
+        if num == 3:
+            return 5
+        else:
+            return num
+
+    @documenter("Does nothing")
+    def idler(self, num):
+        "Idler"
+        pass
+
+    def test_decorator_with_an_argument(self):
+        self.assertEqual(__, self.count_badly(2))
+        self.assertEqual(__, self.count_badly.__doc__)
+
+    def test_documentor_which_already_has_a_docstring(self):
+        self.assertEqual(__, self.idler.__doc__)
+
+    # ------------------------------------------------------------------
+        
+    @documenter("DOH!")
+    @doubleit
+    @doubleit
+    def homer(self):
+        return "D'oh"
+
+    def test_we_can_chain_decorators(self):
+        self.assertEqual(__, self.homer())
+        self.assertEqual(__, self.homer.__doc__)
Add a comment to this file

koans/about_decorating_with_classes.pyc

Binary file added.

koans/about_decorating_with_functions.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+            
+class AboutDecoratingWithFunctions(Koan):
+    def addcowbell(fn):
+        fn.wow_factor = 'COWBELL BABY!'
+        return fn
+            
+    @addcowbell
+    def mediocre_song(self):
+        return "o/~ We all live in a broken submarine o/~"
+                
+    def test_decorators_can_modify_a_function(self):
+        self.assertMatch(__, self.mediocre_song())
+        self.assertEqual(__, self.mediocre_song.wow_factor)
+    
+    # ------------------------------------------------------------------
+
+    def xmltag(fn):
+        def func(*args):
+            return '<' + fn(*args) + '/>'
+        return func
+            
+    @xmltag
+    def render_tag(self, name):
+        return name
+    
+    def test_decorators_can_change_a_function_output(self):
+        self.assertEqual(__, self.render_tag('llama'))
Add a comment to this file

koans/about_decorating_with_functions.pyc

Binary file added.

koans/about_deleting_objects.py

+    #!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutDeletingObjects(Koan):
+    def test_del_can_remove_slices(self):
+        lottery_nums = [4, 8, 15, 16, 23, 42]
+        del lottery_nums[1]
+        del lottery_nums[2:4]
+        
+        self.assertEqual(__, lottery_nums)
+        
+    def test_del_can_remove_entire_lists(self):
+        lottery_nums = [4, 8, 15, 16, 23, 42]
+        del lottery_nums
+        try:
+            win = lottery_nums
+        except Exception as e:
+            pass
+        self.assertMatch(__, e[0])
+        
+    # --------------------------------------------------------------------
+        
+    class ClosingSale(object):
+        def __init__(self):
+            self.hamsters = 7
+            self.zebras = 84
+            
+        def cameras(self):
+            return 34
+        
+        def toilet_brushes(self):
+            return 48
+        
+        def jellies(self):
+            return 5
+        
+    def test_del_can_remove_attributes(self):
+        crazy_discounts = self.ClosingSale()
+        del self.ClosingSale.toilet_brushes
+        del crazy_discounts.hamsters
+        
+        try:
+            still_available = crazy_discounts.toilet_brushes()
+        except AttributeError as e:
+            err_msg1 = e.args[0]
+
+        try:
+            still_available = crazy_discounts.hamsters
+        except AttributeError as e:
+            err_msg2 = e.args[0]
+        
+        self.assertMatch(__, err_msg1)
+        self.assertMatch(__, err_msg2)
+
+    # --------------------------------------------------------------------
+
+    class ClintEastwood(object):
+        def __init__(self):
+            self._name = None
+            
+        def get_name(self):
+            try:
+                return self._name
+            except:
+                return "The man with no name"
+
+        def set_name(self, name):
+            self._name = name
+            
+        def del_name(self):
+            del self._name
+            
+        name = property(get_name, set_name, del_name, \
+            "Mr Eastwood's current alias")
+            
+    def test_del_works_with_properties(self):
+        cowboy = self.ClintEastwood()
+        cowboy.name = 'Senor Ninguno'
+        self.assertEqual('Senor Ninguno', cowboy.name)
+
+        del cowboy.name
+        self.assertEqual(__, cowboy.name)
+        
+    # --------------------------------------------------------------------
+
+    class Prisoner(object):
+        def __init__(self):
+            self._name = None
+        
+        @property
+        def name(self):
+            return self._name
+
+        @name.setter
+        def name(self, name):
+            self._name = name
+            
+        @name.deleter
+        def name(self):
+            self._name = 'Number Six'
+                        
+    def test_another_way_to_make_a_deletable_property(self):
+        citizen = self.Prisoner()
+        citizen.name = "Patrick"
+        self.assertEqual('Patrick', citizen.name)
+
+        del citizen.name
+        self.assertEqual(__, citizen.name)
+
+    # --------------------------------------------------------------------
+        
+    class MoreOrganisedClosingSale(ClosingSale):
+        def __init__(self):
+            self.last_deletion = None
+            super(AboutDeletingObjects.ClosingSale, self).__init__()
+        
+        def __delattr__(self, attr_name):
+            self.last_deletion = attr_name
+
+    def tests_del_can_be_overriden(self):
+        sale = self.MoreOrganisedClosingSale()
+        self.assertEqual(5, sale.jellies())
+        del sale.jellies
+        self.assertEqual(__, sale.last_deletion)
Add a comment to this file

koans/about_deleting_objects.pyc

Binary file added.

koans/about_dice_project.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+import random
+
+
+class DiceSet(object):
+    def __init__(self):
+        self._values = None
+    
+    @property
+    def values(self):
+        return self._values
+              
+    def roll(self, n):
+        # Needs implementing!
+        # Tip: random.randint(min, max) can be used to generate random numbers
+        pass
+
+
+class AboutDiceProject(Koan):
+    def test_can_create_a_dice_set(self):
+        dice = DiceSet()
+        self.assertTrue(dice)
+
+    def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6(self):
+        dice = DiceSet()
+        
+        dice.roll(5)
+        self.assertTrue(isinstance(dice.values, list), "should be a list")
+        self.assertEqual(5, len(dice.values))
+        for value in dice.values:
+            self.assertTrue(
+                value >= 1 and value <= 6,
+                "value " + str(value) + " must be between 1 and 6")
+        
+    def test_dice_values_do_not_change_unless_explicitly_rolled(self):
+        dice = DiceSet()
+        dice.roll(5)
+        first_time = dice.values
+        second_time = dice.values
+        self.assertEqual(first_time, second_time)
+        
+    def test_dice_values_should_change_between_rolls(self):
+        dice = DiceSet()
+        
+        dice.roll(5)
+        first_time = dice.values
+        
+        dice.roll(5)
+        second_time = dice.values
+        
+        self.assertNotEqual(first_time, second_time, \
+            "Two rolls should not be equal")
+        
+        # THINK ABOUT IT:
+        #
+        # If the rolls are random, then it is possible (although not
+        # likely) that two consecutive rolls are equal.  What would be a
+        # better way to test this?
+        
+    def test_you_can_roll_different_numbers_of_dice(self):
+        dice = DiceSet()
+        
+        dice.roll(3)
+        self.assertEqual(3, len(dice.values))
+        
+        dice.roll(1)
+        self.assertEqual(1, len(dice.values))
Add a comment to this file

koans/about_dice_project.pyc

Binary file added.

koans/about_dictionaries.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Based on AboutHashes in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutDictionaries(Koan):
+    def test_creating_dictionaries(self):
+        empty_dict = dict()
+        self.assertEqual(dict, type(empty_dict))
+        self.assertEqual(dict(), empty_dict)
+        self.assertEqual(__, len(empty_dict))
+        
+    def test_dictionary_literals(self):
+        empty_dict = {}
+        self.assertEqual(dict, type(empty_dict))
+        babel_fish = {'one': "uno", 'two': "dos"}
+        self.assertEqual(__, len(babel_fish))
+        
+    def test_accessing_dictionaries(self):
+        babel_fish = {'one': "uno", 'two': "dos"}
+        self.assertEqual(__, babel_fish['one'])
+        self.assertEqual(__, babel_fish['two'])
+        
+    def test_changing_dictionaries(self):
+        babel_fish = {'one': "uno", 'two': "dos"}
+        babel_fish['one'] = "eins"
+        
+        expected = {'two': "dos", 'one': __}
+        self.assertEqual(expected, babel_fish)
+        
+    def test_dictionary_is_unordered(self):
+        dict1 = {'one': "uno", 'two': "dos"}
+        dict2 = {'two': "dos", 'one': "uno"}
+        
+        self.assertEqual(____, dict1 == dict2)
+        
+    def test_dictionary_keys(self):
+        babel_fish = {'one': "uno", 'two': "dos"}
+        self.assertEqual(__, len(babel_fish.keys()))
+        self.assertEqual(__, 'one' in babel_fish)
+        self.assertEqual(__, 'two' in babel_fish)
+        self.assertEqual(list, babel_fish.keys().__class__)
+        
+    def test_dictionary_values(self):
+        babel_fish = {'one': "uno", 'two': "dos"}
+        self.assertEqual(__, len(babel_fish.values()))
+        self.assertEqual(__, 'uno' in babel_fish.values())
+        self.assertEqual(__, 'dos' in babel_fish.values())
+        self.assertEqual(list, babel_fish.values().__class__)
+        
+    def test_making_a_dictionary_from_a_sequence_of_keys(self):
+        cards = {}.fromkeys(
+            ("red warrior", "green elf", "blue valkyrie", "yellow dwarf",
+             "confused looking zebra"),
+            42)
+        
+        self.assertEqual(__, len(cards))
+        self.assertEqual(__, cards["green elf"])
+        self.assertEqual(__, cards["yellow dwarf"])
Add a comment to this file

koans/about_dictionaries.pyc

Binary file added.

koans/about_exceptions.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutExceptions(Koan):
+
+    class MySpecialError(RuntimeError):
+        pass
+    
+    def test_exceptions_inherit_from_exception(self):
+        mro = self.MySpecialError.__mro__
+        self.assertEqual(__, mro[1].__name__)
+        self.assertEqual(__, mro[2].__name__)
+        self.assertEqual(__, mro[3].__name__)
+        self.assertEqual(__, mro[4].__name__)
+    
+    def test_try_clause(self):
+        result = None
+        try:
+            self.fail("Oops")
+        except StandardError as ex:
+            result = 'exception handled'
+        
+        self.assertEqual(__, result)
+    
+        self.assertEqual(____, isinstance(ex, StandardError))
+        self.assertEqual(____, isinstance(ex, RuntimeError))
+    
+        self.assertTrue(issubclass(RuntimeError, StandardError), \
+            "RuntimeError is a subclass of StandardError")
+        
+        self.assertEqual(__, ex[0])
+    
+    def test_raising_a_specific_error(self):
+        result = None
+        try:
+            raise self.MySpecialError, "My Message"
+        except self.MySpecialError as ex:
+            result = 'exception handled'
+  
+        self.assertEqual(__, result)
+        self.assertEqual(__, ex[0])
+
+    def test_else_clause(self):
+        result = None
+        try:
+            pass
+        except RuntimeError:
+            result = 'it broke'
+            pass
+        else:
+            result = 'no damage done'
+      
+        self.assertEqual(__, result)
+    
+    def test_finally_clause(self):
+        result = None
+        try:
+            self.fail("Oops")
+        except:
+            # no code here
+            pass
+        finally:
+            result = 'always run'
+      
+        self.assertEqual(__, result)
Add a comment to this file

koans/about_exceptions.pyc

Binary file added.

koans/about_extra_credit.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# EXTRA CREDIT:
+#
+# Create a program that will play the Greed Game.
+# Rules for the game are in GREED_RULES.TXT.
+#
+# You already have a DiceSet class and score function you can use.
+# Write a player class and a Game class to complete the project.  This
+# is a free form assignment, so approach it however you desire.
+
+from runner.koan import *
+
+
+class AboutExtraCredit(Koan):
+    # Write tests here. If you need extra test classes add them to the
+    # test suite in runner/path_to_enlightenment.py
+    def test_extra_credit_task(self):
+        pass
Add a comment to this file

koans/about_extra_credit.pyc

Binary file added.

koans/about_generators.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Written in place of AboutBlocks in the Ruby Koans
+#
+# Note: Both blocks and generators use a yield keyword, but they behave
+# a lot differently
+#
+
+from runner.koan import *
+
+
+class AboutGenerators(Koan):
+        
+    def test_generating_values_on_the_fly(self):
+        result = list()
+        bacon_generator = (n + ' bacon' for \
+                n in ['crunchy', 'veggie', 'danish'])
+        for bacon in bacon_generator:
+            result.append(bacon)
+        self.assertEqual(__, result)
+            
+    def test_generators_are_different_to_list_comprehensions(self):
+        num_list = [x * 2 for x in range(1, 3)]
+        num_generator = (x * 2 for x in range(1, 3))
+        
+        self.assertEqual(2, num_list[0])
+        
+        # A generator has to be iterated through.
+        self.assertRaises(___, num_generator[0]) # Evaluates num_generator[0]
+        self.assertEqual(__, list(num_generator)[0]) # This works though
+        
+        # Both list comprehensions and generators can be iterated
+        # though. However, a generator function is only called on the
+        # first iteration. The values are generated on the fly instead
+        # of stored.
+        #
+        # Generators are more memory friendly, but less versatile
+
+    def test_generator_expressions_are_a_one_shot_deal(self):
+        dynamite = ('Boom!' for n in range(3))
+
+        attempt1 = list(dynamite)
+        attempt2 = list(dynamite)
+        
+        self.assertEqual(__, list(attempt1))
+        self.assertEqual(__, list(attempt2))
+    
+    # ------------------------------------------------------------------
+    
+    def simple_generator_method(self):
+        yield 'peanut'
+        yield 'butter'
+        yield 'and'
+        yield 'jelly'
+        
+    def test_generator_method_will_yield_values_during_iteration(self):
+        result = list()
+        for item in self.simple_generator_method():
+            result.append(item)
+        self.assertEqual(__, result)
+
+    def test_coroutines_can_take_arguments(self):
+        result = self.simple_generator_method()
+        self.assertEqual(__, next(result))
+        self.assertEqual(__, next(result))
+        result.close()
+        
+    # ------------------------------------------------------------------
+
+    def square_me(self, seq):
+        for x in seq:
+            yield x * x
+
+    def test_generator_method_with_parameter(self):
+        result = self.square_me(range(2, 5))
+        self.assertEqual(__, list(result))
+
+    # ------------------------------------------------------------------
+
+    def sum_it(self, seq):
+        value = 0
+        for num in seq:
+            # The local state of 'value' will be retained between iterations
+            value += num
+            yield value
+
+    def test_generator_keeps_track_of_local_variables(self):
+        result = self.sum_it(range(2, 5))
+        self.assertEqual(__, list(result))
+
+    # ------------------------------------------------------------------
+        
+    def generator_with_coroutine(self):
+        result = yield
+        yield result
+    
+    def test_generators_can_take_coroutines(self):
+        generator = self.generator_with_coroutine()
+
+        # THINK ABOUT IT:
+        # Why is this line necessary?
+        #
+        # Hint: Read the "Specification: Sending Values into Generators"
+        #       section of http://www.python.org/dev/peps/pep-0342/
+        next(generator)
+
+        self.assertEqual(__, generator.send(1 + 2))
+
+    def test_before_sending_a_value_to_a_generator_next_must_be_called(self):
+        generator = self.generator_with_coroutine()
+
+        try:
+            generator.send(1 + 2)
+        except TypeError as ex:
+            self.assertMatch(__, ex[0])
+
+    # ------------------------------------------------------------------
+    
+    def yield_tester(self):
+        value = yield
+        if value:
+            yield value
+        else:
+            yield 'no value'
+    
+    def test_generators_can_see_if_they_have_been_called_with_a_value(self):
+        generator = self.yield_tester()
+        next(generator)
+        self.assertEqual('with value', generator.send('with value'))
+                         
+        generator2 = self.yield_tester()
+        next(generator2)
+        self.assertEqual(__, next(generator2))
+
+    def test_send_none_is_equivelant_to_next(self):
+        generator = self.yield_tester()
+        
+        next(generator)
+        # 'next(generator)' is exactly equivelant to 'generator.send(None)'
+        self.assertEqual(__, generator.send(None))
Add a comment to this file

koans/about_generators.pyc

Binary file added.

koans/about_inheritance.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutInheritance(Koan):
+    class Dog(object):
+        def __init__(self, name):
+            self._name = name
+
+        @property
+        def name(self):
+            return self._name
+            
+        def bark(self):
+            return "WOOF"
+  
+    class Chihuahua(Dog):
+        def wag(self):
+            return "happy"
+    
+        def bark(self):
+            return "yip"
+  
+    def test_subclasses_have_the_parent_as_an_ancestor(self):
+        self.assertEqual(____, issubclass(self.Chihuahua, self.Dog))
+  
+    def test_this_subclass_ultimately_inherits_from_object_class(self):
+        self.assertEqual(____, issubclass(self.Chihuahua, object))
+                         
+    def test_instances_inherit_behavior_from_parent_class(self):
+        chico = self.Chihuahua("Chico")
+        self.assertEqual(__, chico.name)
+  
+    def test_subclasses_add_new_behavior(self):
+        chico = self.Chihuahua("Chico")
+        self.assertEqual(__, chico.wag())
+    
+        try:
+            fido = self.Dog("Fido")
+            fido.wag()
+        except StandardError as ex:
+            self.assertMatch(__, ex[0])
+  
+    def test_subclasses_can_modify_existing_behavior(self):
+        chico = self.Chihuahua("Chico")
+        self.assertEqual(__, chico.bark())
+    
+        fido = self.Dog("Fido")
+        self.assertEqual(__, fido.bark())
+  
+    # ------------------------------------------------------------------
+  
+    class BullDog(Dog):
+        def bark(self):
+            return super(AboutInheritance.BullDog, self).bark() + ", GRR"
+  
+    def test_subclasses_can_invoke_parent_behavior_via_super(self):
+        ralph = self.BullDog("Ralph")
+        self.assertEqual(__, ralph.bark())
+  
+    # ------------------------------------------------------------------
+  
+    class GreatDane(Dog):
+        def growl(self):
+            return super(AboutInheritance.GreatDane, self).bark() + ", GROWL"
+  
+    def test_super_works_across_methods(self):
+        george = self.GreatDane("George")
+        self.assertEqual(__, george.growl())
+
+    # ---------------------------------------------------------
+    
+    class Pug(Dog):
+        def __init__(self, name):
+            pass
+        
+    class Greyhound(Dog):
+        def __init__(self, name):
+            super(AboutInheritance.Greyhound, self).__init__(name)
+
+    def test_base_init_does_not_get_called_automatically(self):
+        snoopy = self.Pug("Snoopy")
+        try:
+            name = snoopy.name
+        except Exception as ex:
+            self.assertMatch(__, ex[0])
+        
+    def test_base_init_has_to_be_called_explicitly(self):
+        boxer = self.Greyhound("Boxer")
+        self.assertEqual(__, boxer.name)
Add a comment to this file

koans/about_inheritance.pyc

Binary file added.

koans/about_iteration.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from runner.koan import *
+
+
+class AboutIteration(Koan):
+
+    def test_iterators_are_a_type(self):
+        it = iter(range(1, 6))
+        
+        fib = 0
+        
+        for num in it:
+            fib += num
+            
+        self.assertEqual(__, fib)
+
+    def test_iterating_with_next(self):
+        stages = iter(['alpha', 'beta', 'gamma'])
+
+        try:
+            self.assertEqual(__, next(stages))
+            next(stages)
+            self.assertEqual(__, next(stages))
+            next(stages)
+        except StopIteration as ex:
+            err_msg = 'Ran out of iterations'
+            
+        self.assertMatch(__, err_msg)
+
+    # ------------------------------------------------------------------
+
+    def add_ten(self, item):
+        return item + 10
+
+    def test_map_transforms_elements_of_a_list(self):
+        seq = [1, 2, 3]
+   
+        mapped_seq = map(self.add_ten, seq)
+        self.assertEqual(__, mapped_seq)
+        
+    def test_filter_selects_certain_items_from_a_list(self):
+        def is_even(item):
+            return (item % 2) == 0
+
+        seq = [1, 2, 3, 4, 5, 6]
+   
+        even_numbers = filter(is_even, seq)
+        self.assertEqual(__, even_numbers)
+    
+    def test_just_return_first_item_found(self):
+        def is_big_name(item):
+            return len(item) > 4
+        
+        names = ["Jim", "Bill", "Clarence", "Doug", "Eli"]
+    
+        # NOTE This still iterates through the whole names, so not particularly
+        # efficient
+        self.assertEqual([__], filter(is_big_name, names)[:1])
+        
+        # Boring but effective
+        for item in names:
+            if is_big_name(item):
+                self.assertEqual(__, item)
+                break
+
+    # ------------------------------------------------------------------
+
+    def add(self, accum, item):
+        return accum + item
+
+    def multiply(self, accum, item):
+        return accum * item
+        
+    def test_reduce_will_blow_your_mind(self):
+        result = reduce(self.add, [2, 3, 4])
+        self.assertEqual(__, result)
+    
+        result2 = reduce(self.multiply, [2, 3, 4], 1)
+        self.assertEqual(__, result2)
+    
+        # Extra Credit:
+        # Describe in your own words what reduce does.
+    
+    # ------------------------------------------------------------------
+
+    def test_creating_lists_with_list_comprehensions(self):
+        feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals',
+            'fruit bats']
+        
+        comprehension = [delicacy.capitalize() for delicacy in feast]
+        
+        self.assertEqual(__, comprehension[0])
+        self.assertEqual(__, comprehension[2])
+        
+    def test_use_pass_for_iterations_with_no_body(self):
+        for num in range(1, 5):
+            pass
+                
+        self.assertEqual(__, num)
+        
+    # ------------------------------------------------------------------
+        
+    def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self):
+        # Ranges are an iteratable sequence
+        result = map(self.add_ten, range(1, 4))
+        self.assertEqual(__, list(result))
+
+        try:
+            f = open("example_file.txt")
+
+            try:   
+                def make_upcase(line):
+                    return line.strip().upper()
+                upcase_lines = map(make_upcase, f.readlines())
+                self.assertEqual(__, list(upcase_lines))
+            finally:
+                # Arg, this is ugly.
+                # We will figure out how to fix this later.
+                f.close()
+        except IOError:
+            # should never happen
+            self.fail()
Add a comment to this file

koans/about_iteration.pyc

Binary file added.

koans/about_lambdas.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Based slightly on the lambdas section of AboutBlocks in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutLambdas(Koan):
+    def test_lambdas_can_be_assigned_to_variables_and_called_explicitly(self):
+        add_one = lambda n: n + 1
+        self.assertEqual(__, add_one(10))
+
+    # ------------------------------------------------------------------
+    
+    def make_order(self, order):
+        return lambda qty: str(qty) + " " + order + "s"
+            
+    def test_accessing_lambda_via_assignment(self):
+        sausages = self.make_order('sausage')
+        eggs = self.make_order('egg')
+        
+        self.assertEqual(__, sausages(3))
+        self.assertEqual(__, eggs(2))
+
+    def test_accessing_lambda_without_assignment(self):
+        self.assertEqual(__, self.make_order('spam')(39823))
Add a comment to this file

koans/about_lambdas.pyc

Binary file added.

koans/about_list_assignments.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Based on AboutArrayAssignments in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutListAssignments(Koan):
+    def test_non_parallel_assignment(self):
+        names = ["John", "Smith"]
+        self.assertEqual(__, names)
+        
+    def test_parallel_assignments(self):
+        first_name, last_name = ["John", "Smith"]
+        self.assertEqual(__, first_name)
+        self.assertEqual(__, last_name)
+                        
+    def test_parallel_assignments_with_sublists(self):
+        first_name, last_name = [["Willie", "Rae"], "Johnson"]
+        self.assertEqual(__, first_name)
+        self.assertEqual(__, last_name)
+                
+    def test_swapping_with_parallel_assignment(self):
+        first_name = "Roy"
+        last_name = "Rob"
+        first_name, last_name = last_name, first_name
+        self.assertEqual(__, first_name)
+        self.assertEqual(__, last_name)
Add a comment to this file

koans/about_list_assignments.pyc

Binary file added.

koans/about_lists.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#
+# Based on AboutArrays in the Ruby Koans
+#
+
+from runner.koan import *
+
+
+class AboutLists(Koan):
+    def test_creating_lists(self):
+        empty_list = list()
+        self.assertEqual(list, type(empty_list))
+        self.assertEqual(0, len(empty_list))
+
+    def test_list_literals(self):
+        nums = list()
+        self.assertEqual([], nums)
+        
+        nums[0:] = [1]
+        self.assertEqual([1], nums)
+        
+        nums[1:] = [2]
+        self.assertEqual([1, 2], nums)
+        
+        nums.append(333)
+        self.assertEqual([1, 2, 333], nums)
+    
+    def test_accessing_list_elements(self):
+        noms = ['peanut', 'butter', 'and', 'jelly']
+        
+        self.assertEqual('peanut', noms[0])
+        self.assertEqual('jelly', noms[3])
+        self.assertEqual('jelly', noms[-1])
+        self.assertEqual('butter', noms[-3])
+    
+    def test_slicing_lists(self):
+        noms = ['peanut', 'butter', 'and', 'jelly']
+        
+        self.assertEqual(['peanut'], noms[0:1])
+        self.assertEqual(['peanut', 'butter'], noms[0:2])
+        self.assertEqual([], noms[2:2])
+        self.assertEqual(['and', 'jelly'], noms[2:20])
+        self.assertEqual([], noms[4:0])
+        self.assertEqual([], noms[4:100])
+        self.assertEqual([], noms[5:0])
+
+    def test_slicing_to_the_edge(self):
+        noms = ['peanut', 'butter', 'and', 'jelly']
+
+        self.assertEqual(['and', 'jelly'], noms[2:])
+        self.assertEqual(['peanut', 'butter'], noms[:2])
+    
+    def test_lists_and_ranges(self):
+        self.assertEqual(list, type(range(5)))
+        self.assertEqual([0,1,2,3,4], range(5))
+        self.assertEqual([5,6,7,8], range(5, 9))
+
+    def test_ranges_with_steps(self):
+        self.assertEqual([0,2,4,6], range(0, 8, 2))
+        self.assertEqual([1,4,7], range(1, 8, 3))
+        self.assertEqual([5,1,-3], range(5, -7, -4))
+        self.assertEqual([5,1,-3,-7], range(5, -8, -4))
+
+    def test_insertions(self):
+        knight = ['you', 'shall', 'pass']
+        knight.insert(2, 'not')
+        self.assertEqual(['you', 'shall','not', 'pass'], knight)
+
+        knight.insert(0, 'Arthur')
+        self.assertEqual(['Arthur','you', 'shall','not', 'pass'], knight)
+            
+    def test_popping_lists(self):
+        stack = [10, 20, 30, 40]
+        stack.append('last')
+        
+        self.assertEqual([10, 20, 30, 40,'last'], stack)
+        
+        popped_value = stack.pop()
+        self.assertEqual('last', popped_value)
+        self.assertEqual([10, 20, 30, 40], stack)
+        
+        popped_value = stack.pop(1)
+        self.assertEqual(20, popped_value)
+        self.assertEqual([10, 30, 40], stack)
+        
+        # Notice that there is a "pop" but no "push" in python?
+