Added option to local_and_global_search() for matching against the value

of any desired attribute. Default is searching by name, as before. This
makes it easy for admins to search for objects and also for using other
attributes than names as primary identifiers (short descriptions comes to
mind).
/Griatch
This commit is contained in:
Griatch 2009-09-05 21:59:12 +00:00
parent afc463f975
commit b95d45e251
2 changed files with 69 additions and 55 deletions

View file

@ -154,20 +154,22 @@ class ObjectManager(models.Manager):
defines_global.OTYPE_GOING]) defines_global.OTYPE_GOING])
def list_search_object_namestr(self, searchlist, ostring, dbref_only=False, def list_search_object_namestr(self, searchlist, ostring, dbref_only=False,
limit_types=False, match_type="fuzzy"): limit_types=False, match_type="fuzzy",
attribute_name=None):
""" """
Iterates through a list of objects and returns a list of Iterates through a list of objects and returns a list of
name matches. name matches.
This version handles search criteria of the type keyword-N, this is used This version handles search criteria of the type N-keyword, this is used
to differentiate several objects of the exact same name, e.g. box-1, box-2 etc. to differentiate several objects of the exact same name, e.g. 1-box, 2-box etc.
searchlist: (List of Objects) The objects to perform name comparisons on. searchlist: (List of Objects) The objects to perform name comparisons on.
ostring: (string) The string to match against. ostring: (string) The string to match against.
dbref_only: (bool) Only compare dbrefs. dbref_only: (bool) Only compare dbrefs.
limit_types: (list of int) A list of Object type numbers to filter by. limit_types: (list of int) A list of Object type numbers to filter by.
match_type: (string) 'exact' or 'fuzzy' matching. match_type: (string) 'exact' or 'fuzzy' matching.
attribute_name: (string) attribute name to search, if None, 'name' is used.
Note that the fuzzy matching gives precedence to exact matches; so if your Note that the fuzzy matching gives precedence to exact matches; so if your
search query matches an object in the list exactly, it will be the only result. search query matches an object in the list exactly, it will be the only result.
@ -189,19 +191,25 @@ class ObjectManager(models.Manager):
#search by name - this may return multiple matches. #search by name - this may return multiple matches.
results = self._list_search_helper1(searchlist,ostring,dbref_only, results = self._list_search_helper1(searchlist,ostring,dbref_only,
limit_types, match_type) limit_types, match_type,
attribute_name=attribute_name)
match_number = None match_number = None
if not results: if not results:
#if we have no match, check if we are dealing #if we have no match, check if we are dealing
#with a "keyword-N" query - if so, strip it and run again. #with a "N-keyword" query - if so, strip it and run again.
match_number, ostring = self._list_search_helper2(ostring) match_number, ostring = self._list_search_helper2(ostring)
if match_number != None and ostring: if match_number != None and ostring:
results = self._list_search_helper1(searchlist,ostring,dbref_only, results = self._list_search_helper1(searchlist,ostring,dbref_only,
limit_types, match_type) limit_types, match_type,
attribute_name=attribute_name)
if match_type == "fuzzy": if match_type == "fuzzy":
#fuzzy matching; run second sweep to catch exact matches #fuzzy matching; run second sweep to catch exact matches
exact_results = [prospect for prospect in results if attribute_name:
if prospect.name_match(ostring, match_type="exact")] exact_results = [prospect for prospect in results
if ostring == prospect.get_attribute_value(attribute_name)]
else:
exact_results = [prospect for prospect in results
if prospect.name_match(ostring, match_type="exact")]
if exact_results: if exact_results:
results = exact_results results = exact_results
if len(results) > 1 and match_number != None: if len(results) > 1 and match_number != None:
@ -212,19 +220,41 @@ class ObjectManager(models.Manager):
pass pass
return results return results
def _list_search_helper1(self,searchlist,ostring,dbref_only, def _list_search_helper1(self, searchlist, ostring, dbref_only,
limit_types,match_type): limit_types, match_type,
attribute_name=None):
""" """
Helper function for list_search_object_namestr - Helper function for list_search_object_namestr -
does name matching through a list of objects. does name/attribute matching through a list of objects.
""" """
if limit_types: if attribute_name:
return [prospect for prospect in searchlist #search an arbitrary attribute name.
if prospect.name_match(ostring, match_type=match_type) if limit_types:
and prospect.type in limit_types] if match_type == "exact":
return [prospect for prospect in searchlist
if prospect.type in limit_types and
ostring == prospect.get_attribute_value(attribute_name)]
else:
return [prospect for prospect in searchlist
if prospect.type in limit_types and
ostring in str(prospect.get_attribute_value(attribute_name))]
else:
if match_type == "exact":
return [prospect for prospect in searchlist
if ostring == str(prospect.get_attribute_value(attribute_name))]
else:
print [type(p) for p in searchlist]
return [prospect for prospect in searchlist
if ostring in str(prospect.get_attribute_value(attribute_name))]
else: else:
return [prospect for prospect in searchlist #search the default "name" attribute
if prospect.name_match(ostring, match_type=match_type)] if limit_types:
return [prospect for prospect in searchlist
if prospect.type in limit_types and
prospect.name_match(ostring, match_type=match_type)]
else:
return [prospect for prospect in searchlist
if prospect.name_match(ostring, match_type=match_type)]
def _list_search_helper2(self, ostring): def _list_search_helper2(self, ostring):
""" """
@ -242,6 +272,7 @@ class ObjectManager(models.Manager):
return None, ostring return None, ostring
except IndexError: except IndexError:
return None, ostring return None, ostring
def player_alias_search(self, searcher, ostring): def player_alias_search(self, searcher, ostring):
""" """
@ -286,7 +317,7 @@ class ObjectManager(models.Manager):
def local_and_global_search(self, searcher, ostring, search_contents=True, def local_and_global_search(self, searcher, ostring, search_contents=True,
search_location=True, dbref_only=False, search_location=True, dbref_only=False,
limit_types=False): limit_types=False, attribute_name=None):
""" """
Searches an object's location then globally for a dbref or name match. Searches an object's location then globally for a dbref or name match.
@ -296,6 +327,8 @@ class ObjectManager(models.Manager):
search_location: (bool) While true, check the searcher's surroundings. search_location: (bool) While true, check the searcher's surroundings.
dbref_only: (bool) Only compare dbrefs. dbref_only: (bool) Only compare dbrefs.
limit_types: (list of int) A list of Object type numbers to filter by. limit_types: (list of int) A list of Object type numbers to filter by.
attribute_name: (string) Which attribute to search in each object.
If None, the default 'name' attribute is used.
""" """
search_query = str(ostring).strip() search_query = str(ostring).strip()
@ -329,7 +362,8 @@ class ObjectManager(models.Manager):
if search_location: if search_location:
local_objs.extend(searcher.get_location().get_contents()) local_objs.extend(searcher.get_location().get_contents())
return self.list_search_object_namestr(local_objs, search_query, return self.list_search_object_namestr(local_objs, search_query,
limit_types=limit_types) limit_types=limit_types,
attribute_name=attribute_name)
# #
# ObjectManager Create methods # ObjectManager Create methods

View file

@ -153,16 +153,23 @@ class Object(models.Model):
""" """
def search_for_object(self, ostring, emit_to_obj=None, search_contents=True, def search_for_object(self, ostring, emit_to_obj=None, search_contents=True,
search_location=True, dbref_only=False, search_location=True, dbref_only=False,
limit_types=False, search_aliases=False): limit_types=False, search_aliases=False,
attribute_name=None):
""" """
Perform a standard object search, handling multiple Perform a standard object search, handling multiple
results and lack thereof gracefully. results and lack thereof gracefully.
source_object: (Object) The Object doing the searching
ostring: (str) The string to match object names against. ostring: (str) The string to match object names against.
Obs - To find a player Obs - To find a player, append * to the start of ostring.
append * to the start of ostring. emit_to_obj: (obj) An object (instead of caller) to receive search feedback
search_contents: (bool) Search the caller's inventory
search_location: (bool) Search the caller's location
dbref_only: (bool) Requires ostring to be a #dbref
limit_types: (list) Object identifiers from defines_global.OTYPE:s
search_aliases: (bool) Search player aliases first
attribute_name: (string) Which attribute to match (if None, uses default 'name')
""" """
# This is the object that gets the duplicate/no match emits. # This is the object that gets the duplicate/no match emits.
if not emit_to_obj: if not emit_to_obj:
emit_to_obj = self emit_to_obj = self
@ -177,12 +184,14 @@ class Object(models.Model):
search_contents=search_contents, search_contents=search_contents,
search_location=search_location, search_location=search_location,
dbref_only=dbref_only, dbref_only=dbref_only,
limit_types=limit_types) limit_types=limit_types,
attribute_name=attribute_name)
if len(results) > 1: if len(results) > 1:
emit_to_obj.emit_to("More than one match for '%s' (please narrow target):" % ostring) s = "More than one match for '%s' (please narrow target):" % ostring
for num, result in enumerate(results): for num, result in enumerate(results):
emit_to_obj.emit_to(" %i-%s" % (num+1,result.get_name(show_dbref=False))) s += "\n %i-%s" % (num+1, result.get_name(show_dbref=False))
emit_to_obj.emit_to(s)
return False return False
elif len(results) == 0: elif len(results) == 0:
emit_to_obj.emit_to("I don't see that here.") emit_to_obj.emit_to("I don't see that here.")
@ -416,35 +425,6 @@ class Object(models.Model):
else: else:
return "%s%s" % (parse_ansi(name_string.split(';')[0], return "%s%s" % (parse_ansi(name_string.split(';')[0],
strip_ansi=no_ansi), dbref_string) strip_ansi=no_ansi), dbref_string)
## def set_description(self, new_desc=''):
## """
## Set an objects description
## """
## if not new_desc:
## self.set_attribute('desc', 'Nothing special')
## #self.description = None
## else:
## self.set_attribute('desc', new_desc)
## #self.description = new_desc
## self.save()
## def get_description(self, no_parsing=False, wrap_text=False):
## """
## Returns an object's ANSI'd description or None if description is not
## set.
## """
## desc = self.get_attribute_value('desc')
## if desc:
## if not no_parsing:
## desc = parse_ansi(desc)
## if wrap_text:
## return functions_general.word_wrap(desc)
## else:
## return desc
## else:
## # No description attribute present, return empty string.
## return ""
def get_flags(self): def get_flags(self):
""" """