Commits

Anonymous committed 5590b23

Added 'code' directory at root for end users. Small fix to build.py

Comments (0)

Files changed (119)

code/Comprehensions/CodeManager.py

+# comprehensions/CodeManager.py
+"""
+TODO: update() is still only in test mode; doesn't actually work yet.
+TODO: check() should generate deltas
+
+Extracts, checks and updates code examples in ReST files.
+
+You can just put in the codeMarker and the (indented) first line (containing the
+file path) into your ReST file, then run the update program to automatically
+insert the rest of the file.
+"""
+import os, re, sys, shutil, inspect, difflib
+
+restFiles = [os.path.join(d[0], f) for d in os.walk(".") if not "_test" in d[0]
+             for f in d[2] if f.endswith(".rst")]
+
+class Languages:
+    "Strategy design pattern"
+
+    class Python:
+        codeMarker = "::\n\n"
+        commentTag = "#"
+        listings = re.compile("::\n\n( {4}#.*(?:\n+ {4}.*)*)")
+
+    class Java:
+        codeMarker = "..  code-block:: java\n\n"
+        commentTag = "//"
+        listings = \
+            re.compile(".. *code-block:: *java\n\n( {4}//.*(?:\n+ {4}.*)*)")
+
+def shift(listing):
+    "Shift the listing left by 4 spaces"
+    return [x[4:] if x.startswith("    ") else x for x in listing.splitlines()]
+
+# TEST - makes duplicates of the rst files in a test directory to test update():
+dirs = set([os.path.join("_test", os.path.dirname(f)) for f in restFiles])
+if [os.makedirs(d) for d in dirs if not os.path.exists(d)]:
+    [shutil.copy(f, os.path.join("_test", f)) for f in restFiles]
+testFiles = [os.path.join(d[0], f) for d in os.walk("_test")
+             for f in d[2] if f.endswith(".rst")]
+
+class Commands:
+    """
+    Each static method can be called from the command line. Add a new static
+    method here to add a new command to the program.
+    """
+
+    @staticmethod
+    def display(language):
+        "Print all the code listings"
+        for f in restFiles:
+            listings = language.listings.findall(open(f).read())
+            if not listings: continue
+            print('=' * 60 + "\n" + f + "\n" + '=' * 60)
+            for n, l in enumerate(listings):
+                print("\n".join(shift(l)))
+                if n < len(listings) - 1:
+                    print('-' * 60)
+
+    @staticmethod
+    def extract(language):
+        """Pull the code listings from the ReST files and write each
+        listing into its own file"""
+        paths = set()
+        for f in restFiles:
+            for listing in language.listings.findall(open(f).read()):
+                listing = shift(listing)
+                path = listing[0][len(language.commentTag):].strip()
+                if path in paths:
+                    print("ERROR: Duplicate file name: %s" % path)
+                    sys.exit(1)
+                else:
+                    paths.add(path)
+                path = os.path.join("..", "code", path)
+                dirname = os.path.dirname(path)
+                if dirname:
+                    if not os.path.exists(dirname):
+                        os.makedirs(dirname)
+                file(path, 'w').write("\n".join(listing))
+
+    @staticmethod
+    def check(language):
+        "Ensure that external code files exist"
+        missing = []
+        for path in [code.splitlines()[0] for f in restFiles for code in
+                     language.listings.findall(open(f).read())]:
+            path = path.strip()[len(language.commentTag):].strip()
+            path = os.path.normpath(os.path.join("..", "code", path))
+            if not os.path.exists(path):
+                missing.append(path)
+        if missing:
+            print("Missing", language.__name__, "files:")
+            for p in missing:
+                print(p)
+        return missing
+
+    @staticmethod
+    def update(language): # Test until it is trustworthy
+        "Refresh external code files into ReST files"
+        if Commands.check(language):
+            print(language.__name__, "update aborted")
+            return
+        def _update(matchobj):
+            listing = shift(matchobj.group(1))
+            path = listing[0].strip()[len(language.commentTag):].strip()
+            filename = os.path.basename(path).split('.')[0]
+            path = os.path.join("..", "code", path)
+            code = open(path).read().splitlines()
+            for i in difflib.ndiff(listing, code):
+                if i.startswith("+ ") or i.startswith("- "):
+                    d = difflib.HtmlDiff()
+                    if not os.path.exists("_deltas"):
+                        os.makedirs("_deltas")
+                    open(os.path.join("_deltas", filename + ".html"), 'w')\
+                        .write(d.make_file(listing, code))
+                    break
+            return language.codeMarker + \
+                "\n".join([("    " + line).rstrip() for line in listing])
+        for f in testFiles:
+            updated = language.listings.sub(_update, open(f).read())
+            open(f, 'w').write(updated)
+
+if __name__ == "__main__":
+    commands = dict(inspect.getmembers(Commands, inspect.isfunction))
+    if len(sys.argv) < 2 or sys.argv[1] not in commands:
+        print("Command line options:")
+        for name in commands:
+            print(name + ": " + commands[name].__doc__)
+    else:
+        for language in inspect.getmembers(Languages, inspect.isclass):
+            commands[sys.argv[1]](language[1])
+
+       

code/Comprehensions/os_walk_comprehension.py

+# Comprehensions/os_walk_comprehension.py
+import os
+restFiles = [os.path.join(d[0], f) for d in os.walk(".")
+             for f in d[2] if f.endswith(".rst")]
+for r in restFiles:
+    print(r)

code/SanityCheck.py

+# SanityCheck.py
+#! /usr/bin/env python
+import string, glob, os
+# Do not include the following in the automatic
+# tests:
+exclude = ("SanityCheck.py", "BoxObserver.py",)
+
+def visitor(arg, dirname, names):
+    dir = os.getcwd()
+    os.chdir(dirname)
+    try:
+        pyprogs = [p for p in glob.glob('*.py')
+                   if p not in exclude ]
+        if not pyprogs: return
+        print('[' + os.getcwd() + ']')
+        for program in pyprogs:
+            print('\t', program)
+            os.system("python %s > tmp" % program)
+            file = open(program).read()
+            output = open('tmp').read()
+            # Append output if it's not already there:
+            if file.find("output = '''") == -1 and \
+              len(output) > 0:
+                divider = '#' * 50 + '\n'
+                file = file.replace('#' + ':~', '#<hr>\n')
+                file += "output = '''\n" + \
+                  open('tmp').read() + "'''\n"
+                open(program,'w').write(file)
+    finally:
+        os.chdir(dir)
+
+if __name__ == "__main__":
+    os.path.walk('.', visitor, None)

code/appFrameworks/TemplateMethod.py

+# appFrameworks/TemplateMethod.py
+# Simple demonstration of Template Method.
+
+class ApplicationFramework:
+    def __init__(self):
+        self.__templateMethod()
+    def __templateMethod(self):
+        for i in range(5):
+            self.customize1()
+            self.customize2()
+
+# Create an "application":
+class MyApp(ApplicationFramework):
+    def customize1(self):
+        print("Nudge, nudge, wink, wink! ",)
+    def customize2(self):
+        print("Say no more, Say no more!")
+
+MyApp()

code/changeInterface/Adapter.py

+# changeInterface/Adapter.py
+# Variations on the Adapter pattern.
+
+class WhatIHave:
+    def g(self): pass
+    def h(self): pass
+
+class WhatIWant:
+    def f(self): pass
+
+class ProxyAdapter(WhatIWant):
+    def __init__(self, whatIHave):
+        self.whatIHave = whatIHave
+
+    def f(self):
+        # Implement behavior using
+        # methods in WhatIHave:
+        self.whatIHave.g()
+        self.whatIHave.h()
+
+class WhatIUse:
+    def op(self, whatIWant):
+        whatIWant.f()
+
+# Approach 2: build adapter use into op():
+class WhatIUse2(WhatIUse):
+    def op(self, whatIHave):
+        ProxyAdapter(whatIHave).f()
+
+# Approach 3: build adapter into WhatIHave:
+class WhatIHave2(WhatIHave, WhatIWant):
+    def f(self):
+        self.g()
+        self.h()
+
+# Approach 4: use an inner class:
+class WhatIHave3(WhatIHave):
+    class InnerAdapter(WhatIWant):
+        def __init__(self, outer):
+            self.outer = outer
+        def f(self):
+            self.outer.g()
+            self.outer.h()
+
+    def whatIWant(self):
+        return WhatIHave3.InnerAdapter(self)
+
+whatIUse = WhatIUse()
+whatIHave = WhatIHave()
+adapt= ProxyAdapter(whatIHave)
+whatIUse2 = WhatIUse2()
+whatIHave2 = WhatIHave2()
+whatIHave3 = WhatIHave3()
+whatIUse.op(adapt)
+# Approach 2:
+whatIUse2.op(whatIHave)
+# Approach 3:
+whatIUse.op(whatIHave2)
+# Approach 4:
+whatIUse.op(whatIHave3.whatIWant())

code/changeInterface/Facade.py

+# changeInterface/Facade.py
+class A:
+    def __init__(self, x): pass
+class B:
+    def __init__(self, x): pass
+class C:
+    def __init__(self, x): pass
+
+# Other classes that aren't exposed by the
+# facade go here ...
+
+class Facade:
+    def makeA(x): return A(x)
+    makeA = staticmethod(makeA)
+    def makeB(x): return B(x)
+    makeB = staticmethod(makeB)
+    def makeC(x): return C(x)
+    makeC = staticmethod(makeC)
+
+# The client programmer gets the objects
+# by calling the static methods:
+a = Facade.makeA(1);
+b = Facade.makeB(1);
+c = Facade.makeC(1.0);

code/decorator/alldecorators/CoffeeShop.py

+# decorator/alldecorators/CoffeeShop.py
+# Coffee example using decorators
+
+class DrinkComponent:
+    def getDescription(self):
+        return self.__class__.__name__
+    def getTotalCost(self):
+        return self.__class__.cost
+
+class Mug(DrinkComponent):
+    cost = 0.0
+
+class Decorator(DrinkComponent):
+    def __init__(self, drinkComponent):
+        self.component = drinkComponent
+    def getTotalCost(self):
+        return self.component.getTotalCost() + \
+          DrinkComponent.getTotalCost(self)
+    def getDescription(self):
+        return self.component.getDescription() + \
+          ' ' + DrinkComponent.getDescription(self)
+
+class Espresso(Decorator):
+    cost = 0.75
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Decaf(Decorator):
+    cost = 0.0
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class FoamedMilk(Decorator):
+    cost = 0.25
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class SteamedMilk(Decorator):
+    cost = 0.25
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Whipped(Decorator):
+    cost = 0.25
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Chocolate(Decorator):
+    cost = 0.25
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+cappuccino = Espresso(FoamedMilk(Mug()))
+print(cappuccino.getDescription().strip() + \)
+  ": $" + `cappuccino.getTotalCost()`
+
+cafeMocha = Espresso(SteamedMilk(Chocolate(
+  Whipped(Decaf(Mug())))))
+
+print(cafeMocha.getDescription().strip() + \)
+  ": $" + `cafeMocha.getTotalCost()`

code/decorator/alldecorators/EspressoDecorator.py

+# decorator/alldecorators/EspressoDecorator.py
+
+class Espresso(Decorator):
+    cost = 0.75f
+    description = " espresso"
+    def __init__(DrinkComponent):
+        Decorator.__init__(self, component)
+
+    def getTotalCost(self):
+        return self.component.getTotalCost() + cost
+
+    def getDescription(self):
+        return self.component.getDescription() +
+            description

code/decorator/compromise/CoffeeShop.py

+# decorator/compromise/CoffeeShop.py
+# Coffee example with a compromise of basic
+# combinations and decorators
+
+class DrinkComponent:
+    def getDescription(self):
+        return self.__class__.__name__
+    def getTotalCost(self):
+        return self.__class__.cost
+
+class Espresso(DrinkComponent):
+    cost = 0.75
+
+class EspressoConPanna(DrinkComponent):
+    cost = 1.0
+
+class Cappuccino(DrinkComponent):
+    cost = 1.0
+
+class CafeLatte(DrinkComponent):
+    cost = 1.0
+
+class CafeMocha(DrinkComponent):
+    cost = 1.25
+
+class Decorator(DrinkComponent):
+    def __init__(self, drinkComponent):
+        self.component = drinkComponent
+    def getTotalCost(self):
+        return self.component.getTotalCost() + \
+          DrinkComponent.getTotalCost(self)
+    def getDescription(self):
+        return self.component.getDescription() + \
+          ' ' + DrinkComponent.getDescription(self)
+
+class ExtraEspresso(Decorator):
+    cost = 0.75
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Whipped(Decorator):
+    cost = 0.50
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Decaf(Decorator):
+    cost = 0.0
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Dry(Decorator):
+    cost = 0.0
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+class Wet(Decorator):
+    cost = 0.0
+    def __init__(self, drinkComponent):
+        Decorator.__init__(self, drinkComponent)
+
+cappuccino = Cappuccino()
+print(cappuccino.getDescription() + ": $" + \)
+  `cappuccino.getTotalCost()`
+
+cafeMocha = Whipped(Decaf(CafeMocha()))
+print(cafeMocha.getDescription() + ": $" + \)
+  `cafeMocha.getTotalCost()`

code/decorator/nodecorators/CoffeeShop.py

+# decorator/nodecorators/CoffeeShop.py
+# Coffee example with no decorators
+
+class Espresso: pass
+class DoubleEspresso: pass
+class EspressoConPanna: pass
+
+class Cappuccino:
+    def __init__(self):
+        self.cost = 1
+        self.description = "Cappucino"
+    def getCost(self):
+        return self.cost
+    def getDescription(self):
+        return self.description
+
+class CappuccinoDecaf: pass
+class CappuccinoDecafWhipped: pass
+class CappuccinoDry: pass
+class CappuccinoDryWhipped: pass
+class CappuccinoExtraEspresso: pass
+class CappuccinoExtraEspressoWhipped: pass
+class CappuccinoWhipped: pass
+
+class CafeMocha: pass
+class CafeMochaDecaf: pass
+class CafeMochaDecafWhipped:
+    def __init__(self):
+        self.cost = 1.25
+        self.description = \
+          "Cafe Mocha decaf whipped cream"
+    def getCost(self):
+        return self.cost
+    def getDescription(self):
+        return self.description
+
+class CafeMochaExtraEspresso: pass
+class CafeMochaExtraEspressoWhipped: pass
+class CafeMochaWet: pass
+class CafeMochaWetWhipped: pass
+class CafeMochaWhipped: pass
+
+class CafeLatte: pass
+class CafeLatteDecaf: pass
+class CafeLatteDecafWhipped: pass
+class CafeLatteExtraEspresso: pass
+class CafeLatteExtraEspressoWhipped: pass
+class CafeLatteWet: pass
+class CafeLatteWetWhipped: pass
+class CafeLatteWhipped: pass
+
+cappuccino = Cappuccino()
+print((cappuccino.getDescription() + ": $" +
+  `cappuccino.getCost()`))
+
+cafeMocha = CafeMochaDecafWhipped()
+print((cafeMocha.getDescription()
+  + ": $" + `cafeMocha.getCost()`))

code/factory/Games.py

+# factory/Games.py
+# An example of the Abstract Factory pattern.
+
+class Obstacle:
+    def action(self): pass
+
+class Character:
+    def interactWith(self, obstacle): pass
+
+class Kitty(Character):
+    def interactWith(self, obstacle):
+        print("Kitty has encountered a",
+        obstacle.action())
+
+class KungFuGuy(Character):
+    def interactWith(self, obstacle):
+        print("KungFuGuy now battles a",
+        obstacle.action())
+
+class Puzzle(Obstacle):
+    def action(self):
+        print("Puzzle")
+
+class NastyWeapon(Obstacle):
+    def action(self):
+        print("NastyWeapon")
+
+# The Abstract Factory:
+class GameElementFactory:
+    def makeCharacter(self): pass
+    def makeObstacle(self): pass
+
+# Concrete factories:
+class KittiesAndPuzzles(GameElementFactory):
+    def makeCharacter(self): return Kitty()
+    def makeObstacle(self): return Puzzle()
+
+class KillAndDismember(GameElementFactory):
+    def makeCharacter(self): return KungFuGuy()
+    def makeObstacle(self): return NastyWeapon()
+
+class GameEnvironment:
+    def __init__(self, factory):
+        self.factory = factory
+        self.p = factory.makeCharacter()
+        self.ob = factory.makeObstacle()
+    def play(self):
+        self.p.interactWith(self.ob)
+
+g1 = GameEnvironment(KittiesAndPuzzles())
+g2 = GameEnvironment(KillAndDismember())
+g1.play()
+g2.play()

code/factory/Games2.py

+# factory/Games2.py
+# Simplified Abstract Factory.
+
+class Kitty:
+    def interactWith(self, obstacle):
+        print("Kitty has encountered a",
+        obstacle.action())
+
+class KungFuGuy:
+    def interactWith(self, obstacle):
+        print("KungFuGuy now battles a",
+        obstacle.action())
+
+class Puzzle:
+    def action(self): print("Puzzle")
+
+class NastyWeapon:
+    def action(self): print("NastyWeapon")
+
+# Concrete factories:
+class KittiesAndPuzzles:
+    def makeCharacter(self): return Kitty()
+    def makeObstacle(self): return Puzzle()
+
+class KillAndDismember:
+    def makeCharacter(self): return KungFuGuy()
+    def makeObstacle(self): return NastyWeapon()
+
+class GameEnvironment:
+    def __init__(self, factory):
+        self.factory = factory
+        self.p = factory.makeCharacter()
+        self.ob = factory.makeObstacle()
+    def play(self):
+        self.p.interactWith(self.ob)
+
+g1 = GameEnvironment(KittiesAndPuzzles())
+g2 = GameEnvironment(KillAndDismember())
+g1.play()
+g2.play()

code/factory/shapefact1/NestedShapeFactory.py

+# factory/shapefact1/NestedShapeFactory.py
+import random
+
+class Shape(object):
+    types = []
+
+def factory(type):
+    class Circle(Shape):
+        def draw(self): print("Circle.draw")
+        def erase(self): print("Circle.erase")
+
+    class Square(Shape):
+        def draw(self): print("Square.draw")
+        def erase(self): print("Square.erase")
+
+    if type == "Circle": return Circle()
+    if type == "Square": return Square()
+    assert 0, "Bad shape creation: " + type
+
+def shapeNameGen(n):
+    for i in range(n):
+        yield factory(random.choice(["Circle", "Square"]))
+
+# Circle() # Not defined
+
+for shape in shapeNameGen(7):
+    shape.draw()
+    shape.erase()

code/factory/shapefact1/ShapeFactory1.py

+# factory/shapefact1/ShapeFactory1.py
+# A simple static factory method.
+from __future__ import generators
+import random
+
+class Shape(object):
+    # Create based on class name:
+    def factory(type):
+        #return eval(type + "()")
+        if type == "Circle": return Circle()
+        if type == "Square": return Square()
+        assert 0, "Bad shape creation: " + type
+    factory = staticmethod(factory)
+
+class Circle(Shape):
+    def draw(self): print("Circle.draw")
+    def erase(self): print("Circle.erase")
+
+class Square(Shape):
+    def draw(self): print("Square.draw")
+    def erase(self): print("Square.erase")
+
+# Generate shape name strings:
+def shapeNameGen(n):
+    types = Shape.__subclasses__()
+    for i in range(n):
+        yield random.choice(types).__name__
+
+shapes = \
+  [ Shape.factory(i) for i in shapeNameGen(7)]
+
+for shape in shapes:
+    shape.draw()
+    shape.erase()

code/factory/shapefact2/ShapeFactory2.py

+# factory/shapefact2/ShapeFactory2.py
+# Polymorphic factory methods.
+from __future__ import generators
+import random
+
+class ShapeFactory:
+    factories = {}
+    def addFactory(id, shapeFactory):
+        ShapeFactory.factories.put[id] = shapeFactory
+    addFactory = staticmethod(addFactory)
+    # A Template Method:
+    def createShape(id):
+        if not ShapeFactory.factories.has_key(id):
+            ShapeFactory.factories[id] = \
+              eval(id + '.Factory()')
+        return ShapeFactory.factories[id].create()
+    createShape = staticmethod(createShape)
+
+class Shape(object): pass
+
+class Circle(Shape):
+    def draw(self): print("Circle.draw")
+    def erase(self): print("Circle.erase")
+    class Factory:
+        def create(self): return Circle()
+
+class Square(Shape):
+    def draw(self):
+        print("Square.draw")
+    def erase(self):
+        print("Square.erase")
+    class Factory:
+        def create(self): return Square()
+
+def shapeNameGen(n):
+    types = Shape.__subclasses__()
+    for i in range(n):
+        yield random.choice(types).__name__
+
+shapes = [ ShapeFactory.createShape(i)
+           for i in shapeNameGen(7)]
+
+for shape in shapes:
+    shape.draw()
+    shape.erase()

code/fronting/ProxyDemo.py

+# fronting/ProxyDemo.py
+# Simple demonstration of the Proxy pattern.
+
+class Implementation:
+    def f(self):
+        print("Implementation.f()")
+    def g(self):
+        print("Implementation.g()")
+    def h(self):
+        print("Implementation.h()")
+
+class Proxy:
+    def __init__(self):
+        self.__implementation = Implementation()
+    # Pass method calls to the implementation:
+    def f(self): self.__implementation.f()
+    def g(self): self.__implementation.g()
+    def h(self): self.__implementation.h()
+
+p = Proxy()
+p.f(); p.g(); p.h()

code/fronting/ProxyDemo2.py

+# fronting/ProxyDemo2.py
+# Simple demonstration of the Proxy pattern.
+
+class Implementation2:
+    def f(self):
+        print("Implementation.f()")
+    def g(self):
+        print("Implementation.g()")
+    def h(self):
+        print("Implementation.h()")
+
+class Proxy2:
+    def __init__(self):
+        self.__implementation = Implementation2()
+    def __getattr__(self, name):
+        return getattr(self.__implementation, name)
+
+p = Proxy2()
+p.f(); p.g(); p.h();

code/fronting/StateDemo.py

+# fronting/StateDemo.py
+# Simple demonstration of the State pattern.
+
+class State_d:
+    def __init__(self, imp):
+        self.__implementation = imp
+    def changeImp(self, newImp):
+        self.__implementation = newImp
+    # Delegate calls to the implementation:
+    def __getattr__(self, name):
+        return getattr(self.__implementation, name)
+
+class Implementation1:
+    def f(self):
+        print("Fiddle de dum, Fiddle de dee,")
+    def g(self):
+        print("Eric the half a bee.")
+    def h(self):
+        print("Ho ho ho, tee hee hee,")
+
+class Implementation2:
+    def f(self):
+        print("We're Knights of the Round Table.")
+    def g(self):
+        print("We dance whene'er we're able.")
+    def h(self):
+        print("We do routines and chorus scenes")
+
+def run(b):
+    b.f()
+    b.g()
+    b.h()
+    b.g()
+
+b = State_d(Implementation1())
+run(b)
+b.changeImp(Implementation2())
+run(b)

code/functionObjects/ChainOfResponsibility.py

+# functionObjects/ChainOfResponsibility.py
+
+# Carry the information into the strategy:
+class Messenger: pass
+
+# The Result object carries the result data and
+# whether the strategy was successful:
+class Result:
+    def __init__(self):
+        self.succeeded = 0
+    def isSuccessful(self):
+        return self.succeeded
+    def setSuccessful(self, succeeded):
+        self.succeeded = succeeded
+
+class Strategy:
+    def __call__(messenger): pass
+    def __str__(self):
+        return "Trying " + self.__class__.__name__ \
+          + " algorithm"
+
+# Manage the movement through the chain and
+# find a successful result:
+class ChainLink:
+    def __init__(self, chain, strategy):
+        self.strategy = strategy
+        self.chain = chain
+        self.chain.append(self)
+
+    def next(self):
+        # Where this link is in the chain:
+        location = self.chain.index(self)
+        if not self.end():
+            return self.chain[location + 1]
+
+    def end(self):
+        return (self.chain.index(self) + 1 >=
+                len(self.chain))
+
+    def __call__(self, messenger):
+        r = self.strategy(messenger)
+        if r.isSuccessful() or self.end(): return r
+        return self.next()(messenger)
+
+# For this example, the Messenger
+# and Result can be the same type:
+class LineData(Result, Messenger):
+    def __init__(self, data):
+        self.data = data
+    def __str__(self): return `self.data`
+
+class LeastSquares(Strategy):
+    def __call__(self, messenger):
+        print(self)
+        linedata = messenger
+        # [ Actual test/calculation here ]
+        result = LineData([1.1, 2.2]) # Dummy data
+        result.setSuccessful(0)
+        return result
+
+class NewtonsMethod(Strategy):
+    def __call__(self, messenger):
+        print(self)
+        linedata = messenger
+        # [ Actual test/calculation here ]
+        result = LineData([3.3, 4.4]) # Dummy data
+        result.setSuccessful(0)
+        return result
+
+class Bisection(Strategy):
+    def __call__(self, messenger):
+        print(self)
+        linedata = messenger
+        # [ Actual test/calculation here ]
+        result = LineData([5.5, 6.6]) # Dummy data
+        result.setSuccessful(1)
+        return result
+
+class ConjugateGradient(Strategy):
+    def __call__(self, messenger):
+        print(self)
+        linedata = messenger
+        # [ Actual test/calculation here ]
+        result = LineData([7.7, 8.8]) # Dummy data
+        result.setSuccessful(1)
+        return result
+
+solutions = []
+ChainLink(solutions, LeastSquares()),
+ChainLink(solutions, NewtonsMethod()),
+ChainLink(solutions, Bisection()),
+ChainLink(solutions, ConjugateGradient())
+
+line = LineData([
+  1.0, 2.0, 1.0, 2.0, -1.0,
+  3.0, 4.0, 5.0, 4.0
+])
+
+print(solutions[0](line))

code/functionObjects/CommandPattern.py

+# functionObjects/CommandPattern.py
+
+class Command:
+    def execute(self): pass
+
+class Loony(Command):
+    def execute(self):
+        print("You're a loony.")
+
+class NewBrain(Command):
+    def execute(self):
+        print("You might even need a new brain.")
+
+class Afford(Command):
+    def execute(self):
+        print("I couldn't afford a whole new brain.")
+
+# An object that holds commands:
+class Macro:
+    def __init__(self):
+        self.commands = []
+    def add(self, command):
+        self.commands.append(command)
+    def run(self):
+        for c in self.commands:
+            c.execute()
+
+macro = Macro()
+macro.add(Loony())
+macro.add(NewBrain())
+macro.add(Afford())
+macro.run()

code/functionObjects/StrategyPattern.py

+# functionObjects/StrategyPattern.py
+
+# The strategy interface:
+class FindMinima:
+    # Line is a sequence of points:
+    def algorithm(self, line) : pass
+
+# The various strategies:
+class LeastSquares(FindMinima):
+    def algorithm(self, line):
+        return [ 1.1, 2.2 ] # Dummy
+
+class NewtonsMethod(FindMinima):
+    def algorithm(self, line):
+        return [ 3.3, 4.4 ]  # Dummy
+
+class Bisection(FindMinima):
+    def algorithm(self, line):
+        return [ 5.5, 6.6 ] # Dummy
+
+class ConjugateGradient(FindMinima):
+    def algorithm(self, line):
+        return [ 3.3, 4.4 ] # Dummy
+
+# The "Context" controls the strategy:
+class MinimaSolver:
+    def __init__(self, strategy):
+        self.strategy = strategy
+
+    def minima(self, line):
+        return self.strategy.algorithm(line)
+
+    def changeAlgorithm(self, newAlgorithm):
+        self.strategy = newAlgorithm
+
+solver = MinimaSolver(LeastSquares())
+line = [1.0, 2.0, 1.0, 2.0, -1.0, 3.0, 4.0, 5.0, 4.0]
+print(solver.minima(line))
+solver.changeAlgorithm(Bisection())
+print(solver.minima(line))

code/jython/GreenHouseController.java

+// jython/GreenHouseController.java
+package jython;
+import org.python.util.PythonInterpreter;
+import org.python.core.*;
+import junit.framework.*;
+
+public class
+GreenHouseController extends TestCase  {
+  PythonInterpreter interp =
+    new PythonInterpreter();
+  public void test() throws PyException  {
+    System.out.println(
+      "Loading GreenHouse Language");
+    interp.execfile("GreenHouseLanguage.py");
+    System.out.println(
+      "Loading GreenHouse Script");
+    interp.execfile("Schedule.ghs");
+    System.out.println(
+      "Executing GreenHouse Script");
+    interp.exec("run()");
+  }
+  public static void
+  main(String[] args) throws PyException  {
+    junit.textui.TestRunner.run(GreenHouseController.class);
+  }
+}

code/jython/GreenHouseLanguage.py

+# jython/GreenHouseLanguage.py
+
+class Event:
+    events = [] # static
+    def __init__(self, action, time):
+        self.action = action
+        self.time = time
+        Event.events.append(self)
+    # Used by sort(). This will cause
+    # comparisons to be based only on time:
+    def __cmp__ (self, other):
+        if self.time < other.time: return -1
+        if self.time > other.time: return 1
+        return 0
+    def run(self):
+        print("%.2f: %s" % (self.time, self.action))
+
+class LightOn(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Light on", time)
+
+class LightOff(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Light off", time)
+
+class WaterOn(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Water on", time)
+
+class WaterOff(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Water off", time)
+
+class ThermostatNight(Event):
+    def __init__(self, time):
+        Event.__init__(self,"Thermostat night", time)
+
+class ThermostatDay(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Thermostat day", time)
+
+class Bell(Event):
+    def __init__(self, time):
+        Event.__init__(self, "Ring bell", time)
+
+def run():
+    Event.events.sort();
+    for e in Event.events:
+        e.run()
+
+# To test, this will be run when you say:
+# python GreenHouseLanguage.py
+if __name__ == "__main__":
+    ThermostatNight(5.00)
+    LightOff(2.00)
+    WaterOn(3.30)
+    WaterOff(4.45)
+    LightOn(1.00)
+    ThermostatDay(6.00)
+    Bell(7.00)
+    run()

code/jython/JavaClassInPython.py

+# jython/JavaClassInPython.py
+# run with: jython.bat JavaClassInPython.py
+# Using Java classes within Jython
+from java.util import Date, HashSet, HashMap
+from jython.javaclass import JavaClass
+from math import sin
+
+d = Date() # Creating a Java Date object
+print(d) # Calls toString()
+
+# A "generator" to easily create data:
+class ValGen:
+    def __init__(self, maxVal):
+        self.val = range(maxVal)
+    # Called during 'for' iteration:
+    def __getitem__(self, i):
+        # Returns a tuple of two elements:
+        return self.val[i], sin(self.val[i])
+
+# Java standard containers:
+map = HashMap()
+set = HashSet()
+
+for x, y in ValGen(10):
+    map.put(x, y)
+    set.add(y)
+    set.add(y)
+
+print(map)
+print(set)
+
+# Iterating through a set:
+for z in set:
+    print(z, z.__class__)
+
+print(map[3]) # Uses Python dictionary indexing
+for x in map.keySet(): # keySet() is a Map method
+    print(x, map[x])
+
+# Using a Java class that you create yourself is
+# just as easy:
+jc = JavaClass()
+jc2 = JavaClass("Created within Jython")
+print(jc2.getVal())
+jc.setVal("Using a Java class is trivial")
+print(jc.getVal())
+print(jc.getChars())
+jc.val = "Using bean properties"
+print(jc.val)

code/jython/MultipleJythons.java

+// jython/MultipleJythons.java
+// You can run multiple interpreters, each
+// with its own name space.
+package jython;
+import org.python.util.PythonInterpreter;
+import org.python.core.*;
+import junit.framework.*;
+
+public class MultipleJythons extends TestCase  {
+  PythonInterpreter
+    interp1 =  new PythonInterpreter(),
+    interp2 =  new PythonInterpreter();
+  public void test() throws PyException {
+    interp1.set("a", new PyInteger(42));
+    interp2.set("a", new PyInteger(47));
+    interp1.exec("print(a)");
+    interp2.exec("print(a)");
+    PyObject x1 = interp1.get("a");
+    PyObject x2 = interp2.get("a");
+    System.out.println("a from interp1: " + x1);
+    System.out.println("a from interp2: " + x2);
+  }
+  public static void
+  main(String[] args) throws PyException  {
+    junit.textui.TestRunner.run(MultipleJythons.class);
+  }
+}

code/jython/PyUtil.java

+// jython/PyUtil.java
+// PythonInterpreter utilities
+package net.mindview.python;
+import org.python.util.PythonInterpreter;
+import org.python.core.*;
+import java.util.*;
+
+public class PyUtil {
+  /** Extract a Python tuple or array into a Java
+  List (which can be converted into other kinds
+  of lists and sets inside Java).
+  @param interp The Python interpreter object
+  @param pyName The id of the python list object
+  */
+  public static List
+  toList(PythonInterpreter interp, String pyName){
+    return new ArrayList(Arrays.asList(
+      (Object[])interp.get(
+        pyName, Object[].class)));
+  }
+  /** Extract a Python dictionary into a Java Map
+  @param interp The Python interpreter object
+  @param pyName The id of the python dictionary
+  */
+  public static Map
+  toMap(PythonInterpreter interp, String pyName){
+    PyList pa = ((PyDictionary)interp.get(
+      pyName)).items();
+    Map map = new HashMap();
+    while(pa.__len__() != 0) {
+      PyTuple po = (PyTuple)pa.pop();
+      Object first = po.__finditem__(0)
+        .__tojava__(Object.class);
+      Object second = po.__finditem__(1)
+        .__tojava__(Object.class);
+      map.put(first, second);
+    }
+    return map;
+  }
+  /** Turn a Java Map into a PyDictionary,
+  suitable for placing into a PythonInterpreter
+  @param map The Java Map object
+  */
+  public static PyDictionary
+  toPyDictionary(Map map) {
+    Map m = new HashMap();
+    Iterator it = map.entrySet().iterator();
+    while(it.hasNext()) {
+      Map.Entry e = (Map.Entry)it.next();
+      m.put(Py.java2py(e.getKey()),
+        Py.java2py(e.getValue()));
+    }
+    // PyDictionary constructor wants a Hashtable:
+    return new PyDictionary(new Hashtable(m));
+  }
+}

code/jython/PythonDialogs.py

+# jython/PythonDialogs.py
+# Dialogs.java from "Thinking in Java, 2nd
+# edition," Chapter 13, converted into Jython.
+# Don't run this as part of the automatic make:
+#=M @echo skipping PythonDialogs.py
+from java.awt import FlowLayout
+from javax.swing import JFrame, JDialog, JLabel
+from javax.swing import JButton
+
+class MyDialog(JDialog):
+    def __init__(self, parent=None):
+        JDialog.__init__(self,
+          title="My dialog", modal=1)
+        self.contentPane.layout = FlowLayout()
+        self.contentPane.add(JLabel("A dialog!"))
+        self.contentPane.add(JButton("OK",
+          actionPerformed =
+            lambda e, t=self: t.dispose()))
+        self.pack()
+
+frame = JFrame("Dialogs", visible=1,
+  defaultCloseOperation=JFrame.EXIT_ON_CLOSE)
+dlg = MyDialog()
+frame.contentPane.add(
+  JButton("Press here to get a Dialog Box",
+    actionPerformed = lambda e: dlg.show()))
+frame.pack()

code/jython/PythonInterpreterGetting.java

+// jython/PythonInterpreterGetting.java
+// Getting data from the PythonInterpreter object.
+package jython;
+import org.python.util.PythonInterpreter;
+import org.python.core.*;
+import java.util.*;
+import net.mindview.python.*;
+import junit.framework.*;
+
+public class
+PythonInterpreterGetting extends TestCase {
+  PythonInterpreter interp =
+    new PythonInterpreter();
+  public void test() throws PyException  {
+    interp.exec("a = 100");
+    // If you just use the ordinary get(),
+    // it returns a PyObject:
+    PyObject a = interp.get("a");
+    // There's not much you can do with a generic
+    // PyObject, but you can print it out:
+    System.out.println("a = " + a);
+    // If you know the type it's supposed to be,
+    // you can "cast" it using __tojava__() to
+    // that Java type and manipulate it in Java.
+    // To use 'a' as an int, you must use
+    // the Integer wrapper class:
+    int ai= ((Integer)a.__tojava__(Integer.class))
+      .intValue();
+    // There are also convenience functions:
+    ai = Py.py2int(a);
+    System.out.println("ai + 47 = " + (ai + 47));
+    // You can convert it to different types:
+    float af = Py.py2float(a);
+    System.out.println("af + 47 = " + (af + 47));
+    // If you try to cast it to an inappropriate
+    // type you'll get a runtime exception:
+    //! String as = (String)a.__tojava__(
+    //!   String.class);
+
+    // If you know the type, a more useful method
+    // is the overloaded get() that takes the
+    // desired class as the 2nd argument:
+    interp.exec("x = 1 + 2");
+    int x = ((Integer)interp
+      .get("x", Integer.class)).intValue();
+    System.out.println("x = " + x);
+
+    // Since Python is so good at manipulating
+    // strings and files, you will often need to
+    // extract an array of Strings. Here, a file
+    // is read as a Python array:
+    interp.exec("lines = " +
+      "open('PythonInterpreterGetting.java')" +
+      ".readlines()");
+    // Pull it in as a Java array of String:
+    String[] lines = (String[])
+      interp.get("lines", String[].class);
+    for(int i = 0; i < 10; i++)
+      System.out.print(lines[i]);
+
+    // As an example of useful string tools,
+    // global expansion of ambiguous file names
+    // using glob is very useful, but it's not
+    // part of the standard Jython package, so
+    // you'll have to make sure that your
+    // Python path is set to include these, or
+    // that you deliver the necessary Python
+    // files with your application.
+    interp.exec("from glob import glob");
+    interp.exec("files = glob('*.java')");
+    String[] files = (String[])
+      interp.get("files", String[].class);
+    for(int i = 0; i < files.length; i++)
+      System.out.println(files[i]);
+
+    // You can extract tuples and arrays into
+    // Java Lists with net.mindview.PyUtil:
+    interp.exec(
+      "tup = ('fee', 'fi', 'fo', 'fum', 'fi')");
+    List tup = PyUtil.toList(interp, "tup");
+    System.out.println(tup);
+    // It really is a list of String objects:
+    System.out.println(tup.get(0).getClass());
+    // You can easily convert it to a Set:
+    Set tups = new HashSet(tup);
+    System.out.println(tups);
+    interp.exec("ints=[1,3,5,7,9,11,13,17,19]");
+    List ints = PyUtil.toList(interp, "ints");
+    System.out.println(ints);
+    // It really is a List of Integer objects:
+    System.out.println((ints.get(1)).getClass());
+
+    // If you have a Python dictionary, it can
+    // be extracted into a Java Map, again with
+    // net.mindview.PyUtil:
+    interp.exec("dict = { 1 : 'a', 3 : 'b'," +
+      "5 : 'c', 9 : 'd', 11 : 'e' }");
+    Map map = PyUtil.toMap(interp, "dict");
+    System.out.println("map: " + map);
+    // It really is Java objects, not PyObjects:
+    Iterator it = map.entrySet().iterator();
+    Map.Entry e = (Map.Entry)it.next();
+    System.out.println(e.getKey().getClass());
+    System.out.println(e.getValue().getClass());
+  }
+  public static void
+  main(String[] args) throws PyException  {
+    junit.textui.TestRunner.run(
+      PythonInterpreterGetting.class);
+  }
+}

code/jython/PythonInterpreterSetting.java

+// jython/PythonInterpreterSetting.java
+// Passing data from Java to python when using
+// the PythonInterpreter object.
+package jython;
+import org.python.util.PythonInterpreter;
+import org.python.core.*;
+import java.util.*;
+import net.mindview.python.*;
+import junit.framework.*;
+
+public class
+PythonInterpreterSetting extends TestCase  {
+  PythonInterpreter interp =
+    new PythonInterpreter();
+  public void test() throws PyException  {
+    // It automatically converts Strings
+    // into native Python strings:
+    interp.set("a", "This is a test");
+    interp.exec("print(a)");
+    interp.exec("print(a[5:])"); // A slice
+    // It also knows what to do with arrays:
+    String[] s = { "How", "Do", "You", "Do?" };
+    interp.set("b", s);
+    interp.exec("for x in b: print(x[0], x)");
+    // set() only takes Objects, so it can't
+    // figure out primitives. Instead,
+    // you have to use wrappers:
+    interp.set("c", new PyInteger(1));
+    interp.set("d", new PyFloat(2.2));
+    interp.exec("print(c + d)");
+    // You can also use Java's object wrappers:
+    interp.set("c", new Integer(9));
+    interp.set("d", new Float(3.14));
+    interp.exec("print(c + d)");
+    // Define a Python function to print arrays:
+    interp.exec(
+      "def prt(x): \n" +
+      "  print(x)\n" +
+      "  for i in x: \n" +
+      "    print(i,)\n" +
+      "  print(x.__class__)\n");
+    // Arrays are Objects, so it has no trouble
+    // figuring out the types contained in arrays:
+    Object[] types = {
+      new boolean[]{ true, false, false, true },
+      new char[]{ 'a', 'b', 'c', 'd' },
+      new byte[]{ 1, 2, 3, 4 },
+      new int[]{ 10, 20, 30, 40 },
+      new long[]{ 100, 200, 300, 400 },
+      new float[]{ 1.1f, 2.2f, 3.3f, 4.4f },
+      new double[]{ 1.1, 2.2, 3.3, 4.4 },
+    };
+    for(int i = 0; i < types.length; i++) {
+      interp.set("e", types[i]);
+      interp.exec("prt(e)");
+    }
+    // It uses toString() to print Java objects:
+    interp.set("f", new Date());
+    interp.exec("print(f)");
+    // You can pass it a List
+    // and index into it...
+    List x = new ArrayList();
+    for(int i = 0; i < 10; i++)
+        x.add(new Integer(i * 10));
+    interp.set("g", x);
+    interp.exec("print(g)");
+    interp.exec("print(g[1])");
+    // ... But it's not quite smart enough
+    // to treat it as a Python array:
+    interp.exec("print(g.__class__)");
+    // interp.exec("print(g[5:])"); // Fails
+    // must extract the Java array:
+    System.out.println("ArrayList to array:");
+    interp.set("h", x.toArray());
+    interp.exec("print(h.__class__)");
+    interp.exec("print(h[5:])");
+    // Passing in a Map:
+    Map m = new HashMap();
+    m.put(new Integer(1), new Character('a'));
+    m.put(new Integer(3), new Character('b'));
+    m.put(new Integer(5), new Character('c'));
+    m.put(new Integer(7), new Character('d'));
+    m.put(new Integer(11), new Character('e'));
+    System.out.println("m: " + m);
+    interp.set("m", m);
+    interp.exec("print(m, m.__class__," +
+      "m[1], m[1].__class__)");
+    // Not a Python dictionary, so this fails:
+    //! interp.exec("for x in m.keys():" +
+    //!   "print(x, m[x])");
+    // To convert a Map to a Python dictionary,
+    // use net.mindview.python.PyUtil:
+    interp.set("m", PyUtil.toPyDictionary(m));
+    interp.exec("print(m, m.__class__, " +
+      "m[1], m[1].__class__)");
+    interp.exec("for x in m.keys():print(x,m[x])");
+  }
+  public static void
+  main(String[] args) throws PyException  {
+    junit.textui.TestRunner.run(
+      PythonInterpreterSetting.class);
+  }
+}

code/jython/PythonSwing.py

+# jython/PythonSwing.py
+# The HTMLButton.java example from
+# "Thinking in Java, 2nd edition," Chapter 13,
+# converted into Jython.
+# Don't run this as part of the automatic make:
+#=M @echo skipping PythonSwing.py
+from javax.swing import JFrame, JButton, JLabel
+from java.awt import FlowLayout
+
+frame = JFrame("HTMLButton", visible=1,
+  defaultCloseOperation=JFrame.EXIT_ON_CLOSE)
+
+def kapow(e):
+    frame.contentPane.add(JLabel("<html>"+
+      "<i><font size=+4>Kapow!"))
+    # Force a re-layout to
+    # include the new label:
+    frame.validate()
+
+button = JButton("<html><b><font size=+2>" +
+  "<center>Hello!<br><i>Press me now!",
+  actionPerformed=kapow)
+frame.contentPane.layout = FlowLayout()
+frame.contentPane.add(button)
+frame.pack()
+frame.size=200, 500

code/jython/PythonToJavaClass.py

+# jython/PythonToJavaClass.py
+#=T python\java\test\PythonToJavaClass.class
+#=M jythonc.bat --package python.java.test \
+#=M PythonToJavaClass.py
+# A Python class created to produce a Java class
+from jarray import array
+import java
+
+class PythonToJavaClass(java.lang.Object):
+    # The '@sig' signature string is used to create
+    # the proper signature in the resulting
+    # Java code:
+    def __init__(self):
+        "@sig public PythonToJavaClass()"
+        print("Constructor for PythonToJavaClass")
+
+    def simple(self):
+        "@sig public void simple()"
+        print("simple()")
+
+    # Returning values to Java:
+    def returnString(self):
+        "@sig public java.lang.String returnString()"
+        return "howdy"
+
+    # You must construct arrays to return along
+    # with the type of the array:
+    def returnArray(self):
+        "@sig public java.lang.String[] returnArray()"
+        test = [ "fee", "fi", "fo", "fum" ]
+        return array(test, java.lang.String)
+
+    def ints(self):
+        "@sig public java.lang.Integer[] ints()"
+        test = [ 1, 3, 5, 7, 11, 13, 17, 19, 23 ]
+        return array(test, java.lang.Integer)
+
+    def doubles(self):
+        "@sig public java.lang.Double[] doubles()"
+        test = [ 1, 3, 5, 7, 11, 13, 17, 19, 23 ]
+        return array(test, java.lang.Double)
+
+    # Passing arguments in from Java:
+    def argIn1(self, a):
+        "@sig public void argIn1(java.lang.String a)"
+        print("a: %s" % a)
+        print("a.__class__", a.__class__)
+
+    def argIn2(self, a):
+        "@sig public void argIn1(java.lang.Integer a)"
+        print("a + 100: %d" % (a + 100))
+        print("a.__class__", a.__class__)
+
+    def argIn3(self, a):
+        "@sig public void argIn3(java.util.List a)"
+        print("received List:", a, a.__class__)
+        print("element type:", a[0].__class__)
+        print("a[3] + a[5]:", a[5] + a[7])
+        #! print("a[2:5]:", a[2:5]) # Doesn't work
+
+    def argIn4(self, a):
+        "@sig public void \
+           argIn4(org.python.core.PyArray a)"
+        print("received type:", a.__class__)
+        print("a: ", a)
+        print("element type:", a[0].__class__)
+        print("a[3] + a[5]:", a[5] + a[7])
+        print("a[2:5]:", a[2:5] # A real Python array)
+
+    # A map must be passed in as a PyDictionary:
+    def argIn5(self, m):
+        "@sig public void \
+           argIn5(org.python.core.PyDictionary m)"
+        print("received Map: ", m, m.__class__)
+        print("m['3']:", m['3'])
+        for x in m.keys():
+            print(x, m[x])

code/jython/Schedule.ghs

+# jython/Schedule.ghs
+Bell(7.00)
+ThermostatDay(6.00)
+WaterOn(3.30)
+LightOn(1.00)
+ThermostatNight(5.00)
+LightOff(2.00)
+WaterOff(4.45)

code/jython/Test.java

+// jython/Test.java
+package net.mindview.python;
+import org.python.util.PythonInterpreter;
+import java.util.*;
+import junit.framework.*;
+
+public class Test extends TestCase  {
+  PythonInterpreter pi =
+    new PythonInterpreter();
+  public void test1() {
+    pi.exec("tup=('fee','fi','fo','fum','fi')");
+    List lst = PyUtil.toList(pi, "tup");
+    System.out.println(lst);
+    System.out.println(new HashSet(lst));
+  }
+  public void test2() {
+    pi.exec("ints=[1,3,5,7,9,11,13,17,19]");
+    List lst = PyUtil.toList(pi, "ints");
+    System.out.println(lst);
+  }
+  public void test3() {
+    pi.exec("dict = { 1 : 'a', 3 : 'b', " +
+      "5 : 'c', 9 : 'd', 11 : 'e'}");
+    Map mp = PyUtil.toMap(pi, "dict");
+    System.out.println(mp);
+  }
+  public void test4() {
+    Map m = new HashMap();
+    m.put("twas", new Integer(11));
+    m.put("brillig", new Integer(27));
+    m.put("and", new Integer(47));
+    m.put("the", new Integer(42));
+    m.put("slithy", new Integer(33));
+    m.put("toves", new Integer(55));
+    System.out.println(m);
+    pi.set("m", PyUtil.toPyDictionary(m));
+    pi.exec("print(m)");
+    pi.exec("print(m['slithy'])");
+  }
+  public static void main(String args[]) {
+    junit.textui.TestRunner.run(Test.class);
+  }
+}

code/jython/TestPythonToJavaClass.java

+// jython/TestPythonToJavaClass.java
+//+D python\java\test\PythonToJavaClass.class
+package jython;
+import java.lang.reflect.*;
+import java.util.*;
+import org.python.core.*;
+import junit.framework.*;
+import java.util.*;
+import net.mindview.python.*;
+// The package with the Python-generated classes:
+import python.java.test.*;
+
+public class
+TestPythonToJavaClass extends TestCase  {
+  PythonToJavaClass p2j = new PythonToJavaClass();
+  public void testDumpClassInfo() {
+    System.out.println(
+      Arrays.toString(
+        p2j.getClass().getConstructors()));
+    Method[] methods =
+      p2j.getClass().getMethods();
+    for(int i = 0; i < methods.length; i++) {
+      String nm = methods[i].toString();
+      if(nm.indexOf("PythonToJavaClass") != -1)
+        System.out.println(nm);
+    }
+  }
+  public void test1() {
+    p2j.simple();
+    System.out.println(p2j.returnString());
+    System.out.println(
+      Arrays.toString(p2j.returnArray()));
+    System.out.println(
+      Arrays.toString(p2j.ints());
+    System.out.println(
+      Arrays.toString(p2j.doubles()));
+    p2j.argIn1("Testing argIn1()");
+    p2j.argIn2(new Integer(47));
+    ArrayList a = new ArrayList();
+    for(int i = 0; i < 10; i++)
+      a.add(new Integer(i));
+    p2j.argIn3(a);
+    p2j.argIn4(
+      new PyArray(Integer.class, a.toArray()));
+    Map m = new HashMap();
+    for(int i = 0; i < 10; i++)
+      m.put("" + i, new Float(i));
+    p2j.argIn5(PyUtil.toPyDictionary(m));
+  }
+  public static void main(String[] args) {
+    junit.textui.TestRunner.run(
+      TestPythonToJavaClass.class);
+  }
+}

code/jython/javaclass/JavaClass.java

+// jython/javaclass/JavaClass.java
+package jython.javaclass;
+import junit.framework.*;
+import java.util.*;
+
+public class JavaClass {
+  private String s = "";
+  public JavaClass() {
+    System.out.println("JavaClass()");
+  }
+  public JavaClass(String a) {
+    s = a;
+    System.out.println("JavaClass(String)");
+  }
+  public String getVal() {
+    System.out.println("getVal()");
+    return s;
+  }
+  public void setVal(String a) {
+    System.out.println("setVal()");
+    s = a;
+  }
+  public Character[] getChars() {
+    System.out.println("getChars()");
+    Character[] r = new Character[s.length()];
+    for(int i = 0; i < s.length(); i++)
+      r[i] = new Character(s.charAt(i));
+    return r;
+  }
+  public static class Test extends TestCase  {
+    JavaClass
+      x1 = new JavaClass(),
+      x2 = new JavaClass("UnitTest");
+    public void test1() {
+      System.out.println(x2.getVal());
+      x1.setVal("SpamEggsSausageAndSpam");
+      System.out.println(
+        Arrays.toString(x1.getChars()));
+    }
+  }
+  public static void main(String[] args) {
+    junit.textui.TestRunner.run(Test.class);
+  }
+}

code/multipleDispatching/PaperScissorsRock.py

+# multipleDispatching/PaperScissorsRock.py
+# Demonstration of multiple dispatching.
+from __future__ import generators
+import random
+
+# An enumeration type:
+class Outcome:
+    def __init__(self, value, name):
+        self.value = value
+        self.name = name
+    def __str__(self): return self.name
+    def __eq__(self, other):
+        return self.value == other.value
+
+Outcome.WIN = Outcome(0, "win")
+Outcome.LOSE = Outcome(1, "lose")
+Outcome.DRAW = Outcome(2, "draw")
+
+class Item(object):
+    def __str__(self):
+        return self.__class__.__name__
+
+class Paper(Item):
+    def compete(self, item):
+        # First dispatch: self was Paper
+        return item.evalPaper(self)
+    def evalPaper(self, item):
+        # Item was Paper, we're in Paper
+        return Outcome.DRAW
+    def evalScissors(self, item):
+        # Item was Scissors, we're in Paper
+        return Outcome.WIN
+    def evalRock(self, item):
+        # Item was Rock, we're in Paper
+        return Outcome.LOSE
+
+class Scissors(Item):
+    def compete(self, item):
+        # First dispatch: self was Scissors
+        return item.evalScissors(self)
+    def evalPaper(self, item):
+        # Item was Paper, we're in Scissors
+        return Outcome.LOSE
+    def evalScissors(self, item):
+        # Item was Scissors, we're in Scissors
+        return Outcome.DRAW
+    def evalRock(self, item):
+        # Item was Rock, we're in Scissors
+        return Outcome.WIN
+
+class Rock(Item):
+    def compete(self, item):
+        # First dispatch: self was Rock
+        return item.evalRock(self)
+    def evalPaper(self, item):
+        # Item was Paper, we're in Rock
+        return Outcome.WIN
+    def evalScissors(self, item):
+        # Item was Scissors, we're in Rock
+        return Outcome.LOSE
+    def evalRock(self, item):
+        # Item was Rock, we're in Rock
+        return Outcome.DRAW
+
+def match(item1, item2):
+    print("%s <--> %s : %s" % (
+      item1, item2, item1.compete(item2)))
+
+# Generate the items:
+def itemPairGen(n):
+    # Create a list of instances of all Items:
+    Items = Item.__subclasses__()
+    for i in range(n):
+        yield (random.choice(Items)(),
+               random.choice(Items)())
+
+for item1, item2 in itemPairGen(20):
+    match(item1, item2)

code/multipleDispatching/PaperScissorsRock2.py

+# multipleDispatching/PaperScissorsRock2.py
+# Multiple dispatching using a table
+from __future__ import generators
+import random
+
+class Outcome:
+    def __init__(self, value, name):
+        self.value = value
+        self.name = name
+    def __str__(self): return self.name
+    def __eq__(self, other):
+        return self.value == other.value
+
+Outcome.WIN = Outcome(0, "win")
+Outcome.LOSE = Outcome(1, "lose")
+Outcome.DRAW = Outcome(2, "draw")
+
+class Item(object):
+    def compete(self, item):
+        # Use a tuple for table lookup:
+        return outcome[self.__class__, item.__class__]
+    def __str__(self):
+        return self.__class__.__name__
+
+class Paper(Item): pass
+class Scissors(Item): pass
+class Rock(Item): pass
+
+outcome = {
+  (Paper, Rock): Outcome.WIN,
+  (Paper, Scissors): Outcome.LOSE,
+  (Paper, Paper): Outcome.DRAW,
+  (Scissors, Paper): Outcome.WIN,
+  (Scissors, Rock): Outcome.LOSE,
+  (Scissors, Scissors): Outcome.DRAW,
+  (Rock, Scissors): Outcome.WIN,
+  (Rock, Paper): Outcome.LOSE,
+  (Rock, Rock): Outcome.DRAW,
+}
+
+def match(item1, item2):
+    print("%s <--> %s : %s" % (
+      item1, item2, item1.compete(item2)))
+
+# Generate the items:
+def itemPairGen(n):
+    # Create a list of instances of all Items:
+    Items = Item.__subclasses__()
+    for i in range(n):
+        yield (random.choice(Items)(),
+               random.choice(Items)())
+
+for item1, item2 in itemPairGen(20):
+    match(item1, item2)

code/observer/BoxObserver.py

+# observer/BoxObserver.py
+# Demonstration of Observer pattern using