From 9a9c525326c217c2f54737d63b442ac16cf645f2 Mon Sep 17 00:00:00 2001 From: Crista Lopes Date: Sat, 30 Nov 2013 19:05:07 -0800 Subject: [PATCH] OK, so explaining the passive aggressive style with monadic exceptions in a language that already has exceptions does not work. Back to regular exceptions in style 23. I left the monadic version as an academically interesting variation. In the process of returning to basic exceptions, I needed to clarify the tantrum style a little better too. --- 22-tantrum/README.md | 10 +-- 22-tantrum/tf-22.py | 22 ++++--- 23-passive-aggressive/README.md | 11 ++-- 23-passive-aggressive/tf-23-monadic.py | 85 ++++++++++++++++++++++++++ 23-passive-aggressive/tf-23.py | 35 +++-------- 5 files changed, 122 insertions(+), 41 deletions(-) create mode 100644 23-passive-aggressive/tf-23-monadic.py diff --git a/22-tantrum/README.md b/22-tantrum/README.md index 3bb3547..8b4eaa6 100644 --- a/22-tantrum/README.md +++ b/22-tantrum/README.md @@ -1,13 +1,15 @@ -Style #21 +Style #22 ============================== Constraints: - Every single procedure and function checks the sanity of its - arguments and refuses to work when the arguments are unreasonable + arguments and refuses to continue when the arguments are + unreasonable, throwing an exception -- All code blocks check for all possible errors and refuse to continue - when things go wrong +- All code blocks check for all possible errors, print out + context-specific messages when errors occur, and pass the exceptions + up the function call chain Possible names: diff --git a/22-tantrum/tf-22.py b/22-tantrum/tf-22.py index 44cabb4..d537f4e 100755 --- a/22-tantrum/tf-22.py +++ b/22-tantrum/tf-22.py @@ -59,15 +59,23 @@ def sort(word_freq): assert(type(word_freq) is dict), "I need a dictionary! I quit!" assert(word_freq <> {}), "I need a non-empty dictionary! I quit!" - return sorted(word_freq.iteritems(), key=operator.itemgetter(1), reverse=True) + try: + return sorted(word_freq.iteritems(), key=operator.itemgetter(1), reverse=True) + except Exception as e: + print "Sorted threw {0}: {1}".format(e) + raise e # # The main function # -assert(len(sys.argv) > 1), "You idiot! I need an input file! I quit!" -word_freqs = sort(frequencies(extract_words(sys.argv[1]))) - -assert(len(word_freqs) > 25), "OMG! Less than 25 words! I QUIT!" -for tf in word_freqs[0:25]: - print tf[0], ' - ', tf[1] +try: + assert(len(sys.argv) > 1), "You idiot! I need an input file! I quit!" + word_freqs = sort(frequencies(extract_words(sys.argv[1]))) + assert(type(word_freqs) is list), "OMG! This is not a list! I quit!" + assert(len(word_freqs) > 25), "SRSLY? Less than 25 words! I QUIT!" + for tf in word_freqs[0:25]: + print tf[0], ' - ', tf[1] +except Exception as e: + print "Something wrong: {0}".format(e) + diff --git a/23-passive-aggressive/README.md b/23-passive-aggressive/README.md index ddd60e6..603b8d2 100644 --- a/23-passive-aggressive/README.md +++ b/23-passive-aggressive/README.md @@ -3,15 +3,16 @@ Style #23 Constraints: -- A sequence of functions should not proceed if preconditions aren't - met or if errors occur +- Every single procedure and function checks the sanity of its + arguments and refuses to continue when the arguments are + unreasonable, throwing an exception -- Core program functions have no exception handling, not even the main function +- When calling out other functions, core program functions don't check for errors -- The final result of the function chain should show the failure, if one occurred +- Exception handling occurs only at the top level of a function call chain Possible names: - Passive aggressive -- Monadic Exceptions + diff --git a/23-passive-aggressive/tf-23-monadic.py b/23-passive-aggressive/tf-23-monadic.py new file mode 100644 index 0000000..b69e6fe --- /dev/null +++ b/23-passive-aggressive/tf-23-monadic.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +import sys, re, operator, string + +# +# The PassiveAggressive class for this example +# +class TFPassiveAggressive: + def __init__(self, v): + self._e = None + self._offending_func = None + self._value = v + + def bind(self, func): + if self._e == None: + try: + self._value = func(self._value) + except Exception as e: + self._e = e + self._offending_func = func + return self + + def printme(self): + if self._e == None: + print self._value + else: + print self._e, " in ", self._offending_func.__name__ + +# +# The functions +# +def get_input(arg): + assert(len(sys.argv) > 1), "You idiot! I need an input file! I quit!" + return sys.argv[1] + +def extract_words(path_to_file): + assert(type(path_to_file) is str), "I need a string! I quit!" + assert(path_to_file), "I need a non-empty string! I quit!" + + with open(path_to_file) as f: + data = f.read() + pattern = re.compile('[\W_]+') + word_list = pattern.sub(' ', data).lower().split() + return word_list + +def remove_stop_words(word_list): + assert(type(word_list) is list), "I need a list! I quit!" + + with open('../stop_words.txt') as f: + stop_words = f.read().split(',') + # add single-letter words + stop_words.extend(list(string.ascii_lowercase)) + return [w for w in word_list if not w in stop_words] + +def frequencies(word_list): + assert(type(word_list) is list), "I need a list! I quit!" + assert(word_list <> []), "I need a non-empty list! I quit!" + + word_freqs = {} + for w in word_list: + if w in word_freqs: + word_freqs[w] += 1 + else: + word_freqs[w] = 1 + return word_freqs + +def sort(word_freqs): + assert(type(word_freqs) is dict), "I need a dictionary! I quit!" + assert(word_freqs <> {}), "I need a non-empty dictionary! I quit!" + + return sorted(word_freqs.iteritems(), key=operator.itemgetter(1), reverse=True) + +def top25_freqs(word_freqs): + assert(type(word_freqs) is list), "I need a list! I quit!" + assert(word_freqs <> {}), "I need a non-empty dictionary! I quit!" + + top25 = "" + for tf in word_freqs[0:25]: + top25 += str(tf[0]) + ' - ' + str(tf[1]) + '\n' + return top25 + +# +# The main function +# +TFPassiveAggressive(None).bind(get_input).bind(extract_words).bind(remove_stop_words).bind(frequencies).bind(sort).bind(top25_freqs).printme() + diff --git a/23-passive-aggressive/tf-23.py b/23-passive-aggressive/tf-23.py index b69e6fe..e5f5447 100644 --- a/23-passive-aggressive/tf-23.py +++ b/23-passive-aggressive/tf-23.py @@ -1,30 +1,6 @@ #!/usr/bin/env python import sys, re, operator, string -# -# The PassiveAggressive class for this example -# -class TFPassiveAggressive: - def __init__(self, v): - self._e = None - self._offending_func = None - self._value = v - - def bind(self, func): - if self._e == None: - try: - self._value = func(self._value) - except Exception as e: - self._e = e - self._offending_func = func - return self - - def printme(self): - if self._e == None: - print self._value - else: - print self._e, " in ", self._offending_func.__name__ - # # The functions # @@ -81,5 +57,14 @@ def top25_freqs(word_freqs): # # The main function # -TFPassiveAggressive(None).bind(get_input).bind(extract_words).bind(remove_stop_words).bind(frequencies).bind(sort).bind(top25_freqs).printme() +try: + assert(len(sys.argv) > 1), "You idiot! I need an input file! I quit!" + word_freqs = sort(frequencies(extract_words(sys.argv[1]))) + + assert(len(word_freqs) > 25), "OMG! Less than 25 words! I QUIT!" + for tf in word_freqs[0:25]: + print tf[0], ' - ', tf[1] +except Exception as e: + print "Something wrong: {0}".format(e) +