| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- import warnings
- from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze
- from rope.refactor import sourceutils, occurrences, rename
- class MethodObject(object):
- def __init__(self, project, resource, offset):
- self.pycore = project.pycore
- this_pymodule = self.pycore.resource_to_pyobject(resource)
- pyname = evaluate.eval_location(this_pymodule, offset)
- if pyname is None or not isinstance(pyname.get_object(),
- pyobjects.PyFunction):
- raise exceptions.RefactoringError(
- 'Replace method with method object refactoring should be '
- 'performed on a function.')
- self.pyfunction = pyname.get_object()
- self.pymodule = self.pyfunction.get_module()
- self.resource = self.pymodule.get_resource()
- def get_new_class(self, name):
- body = sourceutils.fix_indentation(
- self._get_body(), sourceutils.get_indent(self.pycore) * 2)
- return 'class %s(object):\n\n%s%sdef __call__(self):\n%s' % \
- (name, self._get_init(),
- ' ' * sourceutils.get_indent(self.pycore), body)
- def get_changes(self, classname=None, new_class_name=None):
- if new_class_name is not None:
- warnings.warn(
- 'new_class_name parameter is deprecated; use classname',
- DeprecationWarning, stacklevel=2)
- classname = new_class_name
- collector = codeanalyze.ChangeCollector(self.pymodule.source_code)
- start, end = sourceutils.get_body_region(self.pyfunction)
- indents = sourceutils.get_indents(
- self.pymodule.lines, self.pyfunction.get_scope().get_start()) + \
- sourceutils.get_indent(self.pycore)
- new_contents = ' ' * indents + 'return %s(%s)()\n' % \
- (classname, ', '.join(self._get_parameter_names()))
- collector.add_change(start, end, new_contents)
- insertion = self._get_class_insertion_point()
- collector.add_change(insertion, insertion,
- '\n\n' + self.get_new_class(classname))
- changes = change.ChangeSet('Replace method with method object refactoring')
- changes.add_change(change.ChangeContents(self.resource,
- collector.get_changed()))
- return changes
- def _get_class_insertion_point(self):
- current = self.pyfunction
- while current.parent != self.pymodule:
- current = current.parent
- end = self.pymodule.lines.get_line_end(current.get_scope().get_end())
- return min(end + 1, len(self.pymodule.source_code))
- def _get_body(self):
- body = sourceutils.get_body(self.pyfunction)
- for param in self._get_parameter_names():
- body = param + ' = None\n' + body
- pymod = self.pycore.get_string_module(body, self.resource)
- pyname = pymod[param]
- finder = occurrences.create_finder(self.pycore, param, pyname)
- result = rename.rename_in_module(finder, 'self.' + param,
- pymodule=pymod)
- body = result[result.index('\n') + 1:]
- return body
- def _get_init(self):
- params = self._get_parameter_names()
- indents = ' ' * sourceutils.get_indent(self.pycore)
- if not params:
- return ''
- header = indents + 'def __init__(self'
- body = ''
- for arg in params:
- new_name = arg
- if arg == 'self':
- new_name = 'host'
- header += ', %s' % new_name
- body += indents * 2 + 'self.%s = %s\n' % (arg, new_name)
- header += '):'
- return '%s\n%s\n' % (header, body)
- def _get_parameter_names(self):
- return self.pyfunction.get_param_names()
|