Merge lp:~isoschiz/endroid/lp1047334 into lp:~ben-hutchings/endroid/roomowner

Proposed by Martin Morrison
Status: Merged
Approved by: Ben Hutchings
Approved revision: 77
Merged at revision: 77
Proposed branch: lp:~isoschiz/endroid/lp1047334
Merge into: lp:~ben-hutchings/endroid/roomowner
Diff against target: 261 lines (+91/-41)
2 files modified
src/endroid/plugins/command.py (+58/-12)
src/endroid/plugins/memo.py (+33/-29)
To merge this branch: bzr merge lp:~isoschiz/endroid/lp1047334
Reviewer Review Type Date Requested Status
Ben Hutchings Approve
Review via email: mp+179709@code.launchpad.net

Description of the change

Fixes to the memo plugin

To post a comment you must log in.
Revision history for this message
Ben Hutchings (ben-hutchings) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/endroid/plugins/command.py'
2--- src/endroid/plugins/command.py 2013-08-06 10:32:33 +0000
3+++ src/endroid/plugins/command.py 2013-08-12 13:56:25 +0000
4@@ -9,6 +9,7 @@
5
6 __all__ = (
7 'CommandPlugin',
8+ 'command',
9 )
10
11 # A single registration
12@@ -24,13 +25,52 @@
13 # - subcommands is a dict of subcommand (simple str) to Handlers object
14 Handlers = namedtuple('Handlers', ('handlers', 'subcommands'))
15
16+def command(wrapped=None, synonyms=(), helphint="", hidden=False, chat_only=False,
17+ muc_only=False):
18+ """
19+ Decorator used to mark command functions in subclasses of CommandPlugin.
20+
21+ In it's simplest form, can be used to mark a function as a command:
22+
23+ >>> class Foo(CommandPlugin):
24+ ... @command
25+ ... def foo_bar(self, msg, args):
26+ ... do_stuff_here()
27+
28+ This will register the command string ("foo", "bar") with the Command plugin
29+ when the Foo plugin is initialised.
30+
31+ The decorator also takes a series of optional keyword arguments to control
32+ the behaviour of the registration:
33+
34+ synonyms: sequence of synonyms (either strings, or sequences of strings)
35+ helphint: a helpful hint to display in help for the command
36+ hidden: whether the command is hidden in the help
37+ chat_only: set to True if the command should only be registered in chat
38+ muc_only: set to True if the command should only be registered in muc
39+
40+ """
41+ def decorator(fn):
42+ fn.is_command = True
43+ fn.synonyms = synonyms
44+ fn.helphint = helphint
45+ fn.hidden = hidden
46+ fn.chat_only = chat_only
47+ fn.muc_only = muc_only
48+ return fn
49+ if wrapped is None:
50+ return decorator
51+ else:
52+ return decorator(wrapped)
53+
54 class CommandPluginMeta(PluginMeta):
55 """
56 Metaclass to support simple command-driven plugins. This should not be used
57 directly, but rather by subclassing from CommandPlugin rather than Plugin.
58 """
59 def __new__(meta, name, bases, dct):
60- cmds = dict((c, f) for c, f in dct.items() if c.startswith("cmd_"))
61+ cmds = dict((c, f) for c, f in dct.items()
62+ if c.startswith("cmd_") or getattr(c, "is_command", False))
63 init = dct.get('endroid_init', lambda _: None)
64 def endroid_init(self):
65 com = self.get('endroid.plugins.command')
66@@ -41,7 +81,10 @@
67 reg_fn = com.register_muc
68 else:
69 reg_fn = com.register_both
70- reg_fn(getattr(self, cmd), cmd.split("_")[1:],
71+ words = cmd.split("_")
72+ if not getattr(cmd, "is_command", False):
73+ words = words[1:]
74+ reg_fn(getattr(self, cmd), words,
75 helphint=getattr(fn, "helphint", ""),
76 hidden=getattr(fn, "hidden", False),
77 synonyms=getattr(fn, "synonyms", ()))
78@@ -49,17 +92,20 @@
79 dct['endroid_init'] = endroid_init
80 dct['dependencies'] = tuple(dct.get('dependencies', ()) +
81 ('endroid.plugins.command',))
82- return PluginMeta.__new__(meta, name, bases, dct)
83+ return super(CommandPluginMeta, meta).__new__(meta, name, bases, dct)
84
85 class CommandPlugin(Plugin):
86 """
87 Parent class for simple command-driven plugins. Such plugins don't need to
88 explicitly register their commands. Instead, they can just define methods
89- prefixed with "cmd_" and they will automatically be registered. Any
90- additional underscores in the method name will be converted to spaces in
91- the registration (so cmd_foo_bar is registered as ('foo', 'bar')).
92-
93- In addition, certain options can be passed by adding fields to the methods:
94+ prefixed with "cmd_" or decorated with the 'command' decorator, and they
95+ will automatically be registered. Any additional underscores in the method
96+ name will be converted to spaces in the registration (so cmd_foo_bar is
97+ registered as ('foo', 'bar')).
98+
99+ In addition, certain options can be passed by adding fields to the methods,
100+ or as keyword arguments to the decorator:
101+
102 - hidden: don't show the command in help if set to True.
103 - synonyms: an iterable of alternative keyword sequences to register the
104 method against. All synonyms are hidden.
105@@ -169,14 +215,14 @@
106 # -------------------------------------------------------------------------
107 # Registration methods
108
109- def register_handler(self, callback, cmd, helphint, hidden, handlers,
110+ def _register_handler(self, callback, cmd, helphint, hidden, handlers,
111 synonyms=()):
112 """
113 Register a new handler.
114
115 callback is the callback handle to call.
116 command is either a single keyword, or a sequence of keywords to match.
117- helphint and hidden are argument to the Registration object.
118+ helphint and hidden are arguments to the Registration object.
119 handlers are the top-level handlers to add the registration to.
120 """
121 # Register any synonyms (done before we frig with the handlers)
122@@ -194,13 +240,13 @@
123 def register_muc(self, callback, command, helphint="", hidden=False,
124 synonyms=()):
125 """Register a new handler for MUC messages."""
126- self.register_handler(callback, command, helphint, hidden,
127+ self._register_handler(callback, command, helphint, hidden,
128 self._muc_handlers, synonyms)
129
130 def register_chat(self, callback, command, helphint="", hidden=False,
131 synonyms=()):
132 """Register a new handler for chat messages."""
133- self.register_handler(callback, command, helphint, hidden,
134+ self._register_handler(callback, command, helphint, hidden,
135 self._chat_handlers, synonyms)
136
137 def register_both(self, callback, command, helphint="", hidden=False,
138
139=== modified file 'src/endroid/plugins/memo.py'
140--- src/endroid/plugins/memo.py 2013-07-30 11:25:48 +0000
141+++ src/endroid/plugins/memo.py 2013-08-12 13:56:25 +0000
142@@ -8,7 +8,7 @@
143 See MESSAGES['usage'] for details.
144 """
145
146-from endroid.pluginmanager import Plugin
147+from endroid.plugins.command import CommandPlugin, command
148 from endroid.database import Database
149 from endroid.database import EndroidUniqueID
150
151@@ -26,11 +26,12 @@
152 memo usage - Output this message
153 memo [list] - List messages in inbox
154 memo send <recipient> <message> - Send a message
155-memo {view|delete} <message-id> -Handle a specific message""",
156+memo {view|delete} <message-id> - Handle a specific message""",
157
158 'usage-send' : "memo send <recipient> <message> \t Send a message",
159 'usage-view' : "memo view <message-id> \t View a specific message",
160 'usage-delete' : "memo delete <message-id> \t Delete a specific message",
161+
162 'duplicate-id-error' : "Error: There are messages sharing the same PK id",
163 'id-not-found-error' : "There is no message with id {0}. Try 'memo list'.",
164 'deletion-sucess' : "Sucessfully deleted one message",
165@@ -44,33 +45,21 @@
166 }
167
168
169-class Memo(Plugin):
170+class Memo(CommandPlugin):
171 name = "memo"
172-
173- def dependencies(self):
174- return ('endroid.plugins.command',)
175-
176- def enInit(self):
177- com = self.get('endroid.plugins.command')
178- com.register_chat(self._handle_list, 'memo', '[list]')
179- com.register_chat(self._handle_list, ('memo', 'list'), hidden=True)
180- com.register_chat(self._handle_send, ('memo', 'send'),
181- '<recipient> <message>')
182- com.register_chat(self._handle_view, ('memo', 'view'), '<message-id>')
183- com.register_chat(self._handle_delete, ('memo', 'delete'),
184- '<message-id>')
185- com.register_chat(lambda m, _: m.reply(MESSAGES['usage']),
186- ('memo', 'usage'))
187+ help_topics = {
188+ '': lambda _: MESSAGES['help'],
189+ 'usage': lambda _: MESSAGES['usage'],
190+ 'send': lambda _: MESSAGES['usage-send'],
191+ 'view': lambda _: MESSAGES['usage-view'],
192+ 'delete': lambda _: MESSAGES['usage-delete'],
193+ }
194+
195+ def endroid_init(self):
196 self.db = Database(DB_NAME)
197- self.setup_db()
198-
199- def setup_db(self):
200 if not self.db.table_exists(DB_TABLE):
201 self.db.create_table(DB_TABLE, DB_COLUMNS)
202
203- def help(self):
204- return MESSAGES['help']
205-
206 def _message_text_summary(self, text):
207 # First assume text is too long, try to shorten.
208 summary = ""
209@@ -81,8 +70,13 @@
210 summary += word + ' '
211 # Looks like memo is already short enough. Return it.
212 return summary[:-1]
213-
214- def _handle_delete(self, msg, args):
215+
216+ @command
217+ def memo_usage(self, msg, args):
218+ msg.reply(MESSAGES['usage'])
219+
220+ @command(helphint="<message-id>")
221+ def memo_delete(self, msg, args):
222 args = args.split()
223 if len(args) != 1 or not args[0].isdigit():
224 msg.reply(MESSAGES['usage-delete'])
225@@ -99,7 +93,15 @@
226 self.db.delete(DB_TABLE, {EndroidUniqueID : int(args[0])})
227 msg.reply(MESSAGES['deletion-sucess'])
228
229- def _handle_list(self, msg, args):
230+ @command(helphint="[list]")
231+ def memo(self, msg, args):
232+ args = args.split()
233+ if len(args) > 0 and args[0] in {"send", "view", "delete", "usage"}:
234+ msg.unhandled()
235+ return
236+ if len(args) > 1 or (len(args) == 1 and args[0] != "list"):
237+ msg.reply(MESSAGES['usage'])
238+ return
239 memos = []
240 cond = {"recipient" : msg.sender}
241 rows = self.db.fetch(DB_TABLE, DB_COLUMNS, cond)
242@@ -114,7 +116,8 @@
243 else:
244 msg.reply(MESSAGES['inbox-empty'])
245
246- def _handle_view(self, msg, args):
247+ @command(helphint="<message-id>")
248+ def memo_view(self, msg, args):
249 args = args.split()
250 if len(args) != 1 or not args[0].isdigit():
251 msg.reply(MESSAGES['usage-view'])
252@@ -132,7 +135,8 @@
253 data = (row["sender"], row["text"])
254 msg.reply(MESSAGES['view-message'].format(*data))
255
256- def _handle_send(self, msg, args):
257+ @command(helphint="<recipient> <message>")
258+ def memo_send(self, msg, args):
259 args = args.split()
260 if len(args) < 2:
261 msg.reply(MESSAGES['usage-send'])

Subscribers

People subscribed via source and target branches

to all changes: