Skip to content

Commit

Permalink
refactored plugin resolver to handle session plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
igorsobreira committed Sep 21, 2010
1 parent a451dc4 commit 955663d
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 26 deletions.
79 changes: 65 additions & 14 deletions eizzek/lib/resolver.py
@@ -1,18 +1,47 @@
from eizzek.lib.registry import registry from eizzek.lib.registry import registry, session_registry
from eizzek.lib.persistence import session


class PluginResolver(object): class PluginResolver(object):
''' '''
This has a way to find and call plugins. The way to find and call plugins.
''' '''


def resolve(self, string, connection_data): def resolve(self, message, connection_data):
''' '''
Returns the result of a plugin call. ``string`` is the Returns the result of a plugin call. ``message`` is the
message body received by the bot. message body received by the bot.
Raises ``LookupError`` if the plugin is not found. Searches for simple plugins then session plugins. If a simple
plugin is found just call the callable passing the connection
dict and arguments from the regex.
If a session plugin is found verify if the session is
open, if it is, call the ``handle()`` method of the plugin passing
the connection dict and the raw message received.
If the session is not open yet, open it and call the ``begin()`` method
passing the connection dict and arguments from the regex.
Raises ``LookupError`` if no plugin is not found.
'''
try:
return self._resolve_simple_plugin(message, connection_data)
except LookupError:
return self._resolve_session_plugin(message, connection_data)

def handle_session_plugin(self, message, connection_data):
''' '''
func, match = self.find(string) This method is called when a new message arrives and there is
an open session for the JID.
'''
jid = connection_data['message']['from']
plugin_name = session.get_current(jid)['plugin']
_, plugin_class = session_registry.plugins[plugin_name]
plugin = plugin_class()
return plugin.handle(connection_data, message)

def _resolve_simple_plugin(self, message, connection_data):
func, match = self.find(message, registry)


kwargs = self._clear_kwargs(match.groupdict()) kwargs = self._clear_kwargs(match.groupdict())
if kwargs: if kwargs:
Expand All @@ -24,19 +53,41 @@ def resolve(self, string, connection_data):


return func(connection_data) return func(connection_data)


def find(self, string): def _resolve_session_plugin(self, message, connection_data):
''' klass, match = self.find(message, session_registry)
Returns a tuple: the plugin callable and the match result object. plugin = klass()
``string`` is the message body received by the bot. jid = connection_data.get('message',{}).get('from', '')

if session.is_open(jid):
session.end(jid)

session.begin(jid, plugin.name)


Raises ``LookupError`` if the plugin is not found. kwargs = self._clear_kwargs(match.groupdict())
if kwargs:
return plugin.begin(connection_data, **kwargs)

args = self._clear_args(match.groups())
if args:
return plugin.begin(connection_data, *args)

return plugin.begin(connection_data)

def find(self, message, registry):
'''
Searches for a plugin in ``registry`` trying to match on each
regex. If found, returns a tuple (callable_obj, match). Else,
raises ``LookupError``.
Where ``message`` is the message body received by the bot.
''' '''
for name, (regex, func) in registry.plugins.items(): for name, (regex, callable_obj) in registry.plugins.items():
match = regex.match(string) match = regex.match(message)
if match: break if match: break
else: else:
raise LookupError(u"Plugin not found") raise LookupError(u"Plugin not found")
return func, match return callable_obj, match


def _clear_kwargs(self, kwargs): def _clear_kwargs(self, kwargs):
''' Don't pass parameters where the value is None ''' ''' Don't pass parameters where the value is None '''
Expand Down
109 changes: 97 additions & 12 deletions tests/functional/test_resolver.py
@@ -1,12 +1,28 @@
import unittest import unittest
import redis


from eizzek import PluginResolver, plugin, registry from eizzek import config, PluginResolver, plugin, session_plugin, registry, session_registry
from eizzek.lib.persistence import SessionPersistence


class PluginResolverTest(unittest.TestCase): class PluginResolverTest(unittest.TestCase):


def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
self._redis = redis.Redis(host=config.REDIS_HOST, port=config.REDIS_PORT, db=config.REDIS_DB)
self.session = SessionPersistence()

def setUp(self): def setUp(self):
registry.clear() registry.clear()

session_registry.clear()
self._create_simple_plugins()
self._create_session_plugins()
self.resolver = PluginResolver()

self.jid = 'igor@igorsobreira.com/Adium1234'
self.conn_data = {'message': {'from': self.jid}}
self._redis.hdel(self.jid, 'plugin')

def _create_simple_plugins(self):
@plugin(r"age (\d+)") @plugin(r"age (\d+)")
def age(conn, num): def age(conn, num):
return "you're %d" % int(num) return "you're %d" % int(num)
Expand All @@ -18,38 +34,107 @@ def age_default(conn, num=0):
@plugin(r"hello ?(?P<name>\w+)?") @plugin(r"hello ?(?P<name>\w+)?")
def hello(conn, name='stranger'): def hello(conn, name='stranger'):
return "hello %s" % name return "hello %s" % name

def _create_session_plugins(self):
@session_plugin
class Translate(object):
name = 'translate'
regex = '^translate (?P<from_lang>[\w-]+) (?P<to_lang>[\w-]+)$'

def begin(self, conn, from_lang, to_lang):
return u"translating from %s to %s" % (from_lang, to_lang)

def handle(self, conn, msg):
return u"qual o seu nome?"

@session_plugin
class Twitter(object):
name = 'twitter'
regex = '^twitter (\w+)$'

def begin(self, conn, account):
return u"twitter account @%s" % account

def handle(self, conn, msg):
return u"message: '%s'" % msg

@session_plugin
class DummyPlugin(object):
name = 'dummy'
regex = r'^dummy$'

def begin(self, conn):
return u"I'm dummy"

def handle(self, conn, msg):
return "message: '%s'" % msg

# tests for simple plugins


self.resolver = PluginResolver()

def test_dont_find_plugin(self): def test_dont_find_plugin(self):
try: try:
self.resolver.resolve("no plugin", {}) self.resolver.resolve("no plugin", self.conn_data)
assert 0, u"Shouldn't find any plugin" assert 0, u"Shouldn't find any plugin"
except LookupError: except LookupError:
pass pass


def test_call_plugin_with_args(self): def test_call_plugin_with_args(self):
result = self.resolver.resolve('age 22', {}) result = self.resolver.resolve('age 22', self.conn_data)


assert u"you're 22" == result assert u"you're 22" == result


def test_call_plugin_with_kwargs(self): def test_call_plugin_with_kwargs(self):
result = self.resolver.resolve('hello igor', {}) result = self.resolver.resolve('hello igor', self.conn_data)


assert u"hello igor" == result assert u"hello igor" == result


def test_call_plugin_with_kwargs_and_default_argument(self): def test_call_plugin_with_kwargs_and_default_argument(self):
result = self.resolver.resolve('hello', {}) result = self.resolver.resolve('hello', self.conn_data)


assert u"hello stranger" == result assert u"hello stranger" == result


def test_call_plugin_with_args_and_default_argument(self): def test_call_plugin_with_args_and_default_argument(self):
result = self.resolver.resolve('aged', {}) result = self.resolver.resolve('aged', self.conn_data)


assert "you're 0" assert "you're 0"

# tests for session plugins

def test_session_plugin_with_kwargs(self):
result = self.resolver.resolve('twitter igorsobreira', self.conn_data)

assert u"twitter account @igorsobreira" == result

def test_session_plugin_with_kwargs(self):
result = self.resolver.resolve('translate en pt-br', self.conn_data)

assert u"translating from en to pt-br" == result

def test_session_plugin_with_no_arguments(self):
result = self.resolver.resolve('dummy', self.conn_data)

assert u"I'm dummy" == result


def test_find_callable_function(self): def test_session_plugin_starts_session(self):
func, _ = self.resolver.find('age 22') result = self.resolver.resolve('translate en pt-br', self.conn_data)

assert u"translating from en to pt-br" == result
assert u"translate" == self._redis.hget(self.jid, 'plugin')

def test_trying_to_start_two_sessions_closes_the_first_one(self):
result = self.resolver.resolve('translate en pt-br', self.conn_data)

assert u"translating from en to pt-br" == result
assert u"translate" == self._redis.hget(self.jid, 'plugin')


assert 'age' == func.__name__ result = self.resolver.resolve('twitter igorsobreira', self.conn_data)

assert u"twitter account @igorsobreira" == result
assert u"twitter" == self._redis.hget(self.jid, 'plugin')

def test_handle_session_plugin_should_call_handle_method_of_the_plugin(self):
self.resolver.resolve('translate en pt-br', self.conn_data)
result = self.resolver.handle_session_plugin("what's your name?", self.conn_data)

assert u"qual o seu nome?" == result


0 comments on commit 955663d

Please sign in to comment.