Language Python
(Advanced, extensible beer/wall framework)
| Date: | 05/17/06 |
| Author: | Jamie Turner |
| URL: | http://jamwt.com |
| Comments: | 7 |
| Info: | http://python.org |
| Score: |
'''An extensible framework for simulated bottle buying,
putting away, taking down, and drinking.
'''
import sys
def vernacularFilter(f):
'''Let's say "no more" instead of "zero"
'''
def _f(*args, **kw):
word = f(*args, **kw)
if word == 'zero':
return 'no more'
return word
return _f
class LanguageTranslationError(Exception): pass
class NumToLanguageTranslator:
'''Translate integers to spoken words, for various locales.
'''
DEFAULT_LOCALE = 'en-US'
def __init__(self, locale=DEFAULT_LOCALE):
self.translate = getattr(self, 'translate_%s' %
locale.lower().replace('-','_'))
if not self.translate:
raise LanguageTranslationError, \
"Missing locale translation tables for numeric values"
# en-US section. More to follow
EN_US_SINGLETON = {
0: 'zero',
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five',
6: 'six',
7: 'seven',
8: 'eight',
9: 'nine',
10: 'ten',
11: 'eleven',
12: 'twelve',
20: 'twenty',
30: 'thirty',
40: 'fourty',
50: 'fifty',
60: 'sixty',
70: 'seventy',
80: 'eighty',
90: 'ninety',
}
EN_US_TEENS = (13,20)
EN_US_TEEN_SPECIAL_PFX = {
3: 'thir',
4: 'four',
5: 'fif',
8: 'eigh',
}
EN_US_RANGE = (0, 100)
EN_US_TEEN_SFX = 'teen'
@vernacularFilter
def translate_en_us(self, num):
'''Translations for en-US; currently only 0-99
are supported. That should be enough bottles
for anyone.
'''
if num not in range(*self.EN_US_RANGE):
raise LanguageTranslationError, \
"Cannot tranlsate: number out of range"
if num in self.EN_US_SINGLETON:
return self.EN_US_SINGLETON[num]
remainder = num % 10
if num in range(*self.EN_US_TEENS):
return '%s%s' % (
self.EN_US_TEEN_SPECIAL_PFX.get(remainder,
self.EN_US_SINGLETON[remainder]),
self.EN_US_TEEN_SFX)
return '%s-%s' % (self.EN_US_SINGLETON[num / 10 * 10],
self.EN_US_SINGLETON[remainder])
def joinStringList(strings):
'''Take care of those pesky contractions.
'''
if len(strings) == 1:
return strings[0]
return '%s and %s' % (','.join(strings[:-1]), strings[-1])
class Collection:
'''A collection of items, complete with
a few common actions (taking down, passing around,
putting away) and extensive logging.
'''
def __init__(self, itemClass, emptyClass,
translator=NumToLanguageTranslator(), logfd=sys.stdout):
self.itemClass = itemClass
self.emptyClass = emptyClass
self.items = []
self.location = None
self.numTranslator = translator
self.logfd = logfd
def _get_description(self):
return '%s %s' % (self.numTranslator.translate(len(self.items)),
self.itemClass.name(plural=len(self.items) != 1))
description = property(_get_description)
def _get_longDescription(self):
return '%s %s' % (self.description, self.location)
longDescription = property(_get_longDescription)
def putAway(self, items, location):
self.items.extend(items)
self.location = location
(EVENT_TAKE_ONE_DOWN,
EVENT_PASS_IT_AROUND) = range(2)
def takeOneDown(self, actor):
'''Get an item and log its removal and distribution.
'''
try:
item_to_discard = self.items.pop(0)
except IndexError:
raise self.emptyClass
self.logEvents(
[self.EVENT_TAKE_ONE_DOWN,
self.EVENT_PASS_IT_AROUND,
], actor)
return item_to_discard
LOG_MESSAGES = {
EVENT_TAKE_ONE_DOWN: 'take one down',
EVENT_PASS_IT_AROUND: 'pass it around',
}
def logEvents(self, events, actor):
self.logfd.write('%s%s, ' % (
actor and (str(actor) + ' ') or '',
joinStringList(map(lambda x: self.LOG_MESSAGES[x], events))
))
class Item:
'''Any damn thing.
'''
@staticmethod
def name(plural=False):
raise NotImplementedError, "Override me!"
class Person:
'''Someone, but specifically someone with a name.
'''
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class TheStore:
'''The source of many things. At the moment, only beer.
TODO: pretzels.
'''
@staticmethod
def buyBeer(howMuch):
return [BeerBottle() for x in range(howMuch)]
## Our application: Separate module??
class OutOfBeer(Exception):
'''For resonable handling of a terrible situation.
'''
def __str__(self):
return "Go to the store and buy some more"
class BeerBottle(Item):
'''A potential item for collecting, passing around, etc.
'''
@staticmethod
def name(plural=False):
return 'bottle%s of beer' % (plural and 's' or '')
def drink(self):
pass # Mmm. Beer.
def letsDrink(who, howMuch, whereToKeep):
'''A "sample" application, if you will, of this framework in use.
Scales easily up to 99 bottles.
'''
assert 1 <= howMuch <= 99
actor = Person(who)
collection = Collection(BeerBottle, OutOfBeer)
def refill():
collection.putAway(TheStore.buyBeer(howMuch), whereToKeep)
refill()
try:
while True:
print collection.longDescription.capitalize() + ', ' + collection.description + '.'
bottle = collection.takeOneDown(actor)
print collection.longDescription + '.'
bottle.drink()
print ''
except OutOfBeer, e:
sys.stdout.write(str(e))
# Lets be polite and leave the wall full!
refill()
print ',', collection.longDescription + '.'
# --oh wait, GC. damn
if __name__ == "__main__":
# test
letsDrink('You', 99, 'on the wall')
Download Source | Write Comment
Alternative Versions
| Version | Author | Date | Comments | Rate |
|---|---|---|---|---|
| This example demonstrates the simplicity | Gerold Penz | 07/23/05 | 15 | |
| Creative version | Schizo | 11/06/05 | 16 | |
| using lambda in LISP style | J Adrian Zimmer | 11/14/06 | 2 | |
| minimal version | Oliver Xymoron | 04/20/05 | 5 | |
| functional, w/o variables or procedures | Ivan Tkatchev | 07/14/05 | 2 | |
| Fully compliant version | Ricardo Garcia Gonzalez | 01/15/06 | 7 | |
| minimal version with singular | Emlyn Jones | 06/13/05 | 3 | |
| Exception based | Michael Galpin | 02/08/08 | 0 | |
| Using a iterator class | Eric Moritz | 01/20/06 | 2 | |
| New conditional expressions in 2.5 | Ezequiel Pochiero | 12/18/06 | 1 |
Download Source | Write Comment
Add Comment
Please provide a value for the fields Name,
Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.
Please don't post large portions of code here! Use the form to submit new examples or updates instead!
Comments
Keep up the good work!
Hilarious.
Critical Hit!
http://www.godswmobile.com/