From 45f94d4b14923e834cc027830b27e0d9a0725225 Mon Sep 17 00:00:00 2001 From: Crista Lopes Date: Wed, 23 Oct 2013 11:19:12 -0700 Subject: [PATCH] Added free agents style --- 25-free-agents/README.md | 26 ++++++++ 25-free-agents/tf-25.py | 138 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 25-free-agents/README.md create mode 100644 25-free-agents/tf-25.py diff --git a/25-free-agents/README.md b/25-free-agents/README.md new file mode 100644 index 0000000..b32672e --- /dev/null +++ b/25-free-agents/README.md @@ -0,0 +1,26 @@ +Style #25 +============================== + +Similar to the letterbox style, but where the 'things' have +independent threads of execution. + +Constraints: + +- The larger problem is decomposed into 'things' that make sense for + the problem domain + +- Each 'thing' is a capsule of data that exposes one single procedure, + namely the ability to receive and dispatch messages that are sent to + it + +- Each 'thing' has its own thread of execution independent of the others + +- Each 'thing' has a queue where messages to it are placed + +- Message dispatch can result in sending the message to another 'thing' + +Possible names: + +- Free agents +- Active letterbox +- Actors diff --git a/25-free-agents/tf-25.py b/25-free-agents/tf-25.py new file mode 100644 index 0000000..6458929 --- /dev/null +++ b/25-free-agents/tf-25.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python + +import sys, re, operator, string +from threading import Thread +from Queue import Queue + +class ActiveWFObject(Thread): + def __init__(self): + Thread.__init__(self) + self.name = str(type(self)) + self.queue = Queue() + self._stop = False + self.start() + + def run(self): + while not self._stop: + message = self.queue.get() + self.dispatch(message) + if message[0] == 'die': + self._stop = True + +class DataStorageManager(ActiveWFObject): + _queue = Queue() + """ Models the contents of the file """ + _data = '' + + def dispatch(self, message): + if message[0] == 'init': + self._init(message[1:]) + elif message[0] == 'send_word_freqs': + self._process_words(message[1:]) + else: + # forward + self._stop_word_manager.queue.put(message) + + def _init(self, message): + path_to_file = message[0] + self._stop_word_manager = message[1] + f = open(path_to_file) + self._data = f.read() + f.close() + pattern = re.compile('[\W_]+') + self._data = pattern.sub(' ', self._data).lower() + + def _process_words(self, message): + recipient = message[0] + data_str = ''.join(self._data) + words = data_str.split() + for w in words: + self._stop_word_manager.queue.put(['filter', w]) + self._stop_word_manager.queue.put(['top25', recipient]) + + +class StopWordManager(ActiveWFObject): + """ Models the stop word filter """ + _stop_words = [] + + def dispatch(self, message): + if message[0] == 'init': + self._init(message[1:]) + elif message[0] == 'filter': + return self._filter(message[1:]) + else: + # forward + self._word_freqs_manager.queue.put(message) + + def _init(self, message): + f = open('../stop_words.txt') + self._stop_words = f.read().split(',') + f.close() + self._stop_words.extend(list(string.ascii_lowercase)) + self._word_freqs_manager = message[0] + + def _filter(self, message): + word = message[0] + if word not in self._stop_words: + self._word_freqs_manager.queue.put(['word', word]) + +class WordFrequencyManager(ActiveWFObject): + """ Keeps the word frequency data """ + _word_freqs = {} + + def dispatch(self, message): + if message[0] == 'word': + self._increment_count(message[1:]) + elif message[0] == 'top25': + self._top25(message[1:]) + + def _increment_count(self, message): + word = message[0] + if word in self._word_freqs: + self._word_freqs[word] += 1 + else: + self._word_freqs[word] = 1 + + def _top25(self, message): + recipient = message[0] + freqs_sorted = sorted(self._word_freqs.iteritems(), key=operator.itemgetter(1), reverse=True) + recipient.queue.put(['top25', freqs_sorted]) + +class WordFrequencyController(ActiveWFObject): + + def dispatch(self, message): + if message[0] == 'run': + self._run(message[1:]) + elif message[0] == 'top25': + self._display(message[1:]) + else: + raise Exception("Message not understood " + message[0]) + + def _run(self, message): + self._storage_manager = message[0] + self._storage_manager.queue.put(['send_word_freqs', self]) + + def _display(self, message): + word_freqs = message[0] + for (w, f) in word_freqs[0:25]: + print w, ' - ', f + self._storage_manager.queue.put(['die']) + self._stop = True + + +# +# The main function +# +word_freq_manager = WordFrequencyManager() + +stop_word_manager = StopWordManager() +stop_word_manager.queue.put(['init', word_freq_manager]) + +storage_manager = DataStorageManager() +storage_manager.queue.put(['init', sys.argv[1], stop_word_manager]) + +wfcontroller = WordFrequencyController() +wfcontroller.dispatch(['run', storage_manager]) + +# Wait for the active objects to finish +[t.join() for t in [word_freq_manager, stop_word_manager, storage_manager, wfcontroller]]