Public methods: verb_templates() Get verb templates verb_info(template) Get {method, remote} local_verb_info(template) Get {method, remote} locally Owner methods: add_verb(template, method, remote) Add a verb del_verb(method) Remove a verb Protected methods: verbs_changed_on_leaf() Verbs changed on leaf object Private methods (non-overridable): verbs_changed() Indicates verbs changed Verbs: list_verb @list * on %this List method show_verb @show %this Show object params_verb @params %this Show parameters methods_verb @methods %this Show method names verbs_verb @verbs %this Show verbs parent root object verbs var verbs verbs 0 method init arg ancestors; (> pass(ancestors) <); if (definer() in ancestors) verbs = #[]; . eval .initialize(); .set_name("Generic verb-containing object"); . method verb_templates return dict_keys(verbs); . method add_verb arg template, method, remote; var words, pos; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); // Check argument types. if (type(template) != 'string) throw(~type, "Template is not a string."); if (type(method) != 'symbol) throw(~type, "Method name is not a symbol."); if (remote != 'remote && remote != 'noremote) throw(~type, "Remote specifier is neither 'remote nor 'noremote"); // Make sure there's exactly one "%this" in the template, as a word by // itself. words = explode(template); if (words[1] == "%this" || words[1] == "*" || words[1] == "*=*") throw(~template, "Template begins with wildcard."); pos = "%this" in words; if (!pos || "%this" in sublist(words, pos + 1)) throw(~template, "Template does not contain exactly one \"%this\"."); // Add the verbs to the dictionary. verbs = dict_add(verbs, template, [method, remote]); if (remote == 'remote) $sys.new_remote_template(template); else .verbs_changed(); . method remove_verb arg template; var verb_info; if (!.is_owned_by(sender())) throw(~perm, "Sender is not an owner."); catch ~keynf { verb_info = verbs[template]; verbs = dict_del(verbs, template); if (verb_info[1] == 'remote) $sys.removed_remote_template(template); else .verbs_changed(); } with handler { throw(~verbnf, "No verb with template " + tostr(template) + "."); } . method verbs_changed disallow_overrides; var loc, p; if (sender() != this() || caller() != definer()) throw(~perm, "Invalid call to private method."); // If this object has children, up the system verb consistency clock, // forcing all users to update their command lists next time they process // a command. if (children()) { for p in ($sys.connected_users()) p.invalidate_verb_cache(); } // The verbs changed on a leaf. Delegate this to the subclasses; located // objects will want to deal with it one way, exits another. .verbs_changed_on_leaf(); . method verbs_changed_on_leaf if (sender() != this()) throw(~perm, "Sender not this."); . method verb_info disallow_overrides; arg template; var verb_info, anc; if (dict_contains(verbs, template)) return verbs[template]; for anc in (ancestors()) { verb_info = (| anc.local_verb_info(template) |); if (verb_info) return verb_info; } throw(~verbnf, "No verb with template " + template); . method local_verb_info disallow_overrides; arg template; catch ~keynf { return verbs[template]; } with handler { throw(~verbnf, "No verb with template " + template); } .