Commits

Anonymous committed 77edbdf

Handling multiple parameters when moving methods

Comments (0)

Files changed (4)

docs/dev/issues.txt

 ===============
 
 * `Memory management`_
-* `Better occurrence finding`_
 * `Getting ready for Python 3.0`_
 * `Python's implicit interfaces`_
-* Decorators and method refactorings
 * Should `rope.base` be thread safe? which parts?
 
 
 decisions.
 
 
-Better SOI
-==========
-
-Returned Object SOI
--------------------
-
-Since we're passed the objects parameters hold, we can perform a
-better returned object SOI.  We can do that by giving parameter
-objects passed and infer the object of local names once more.
-
-Actually we have to perform two things.  We have to ask scope
-`PyName`\s to forget their concluded data and change the parameters to
-return what we want.
-
-So to make it we have:
-
-* Used `PyFunction._set_parameter_pyobjects()` to set the type
-  of parameters
-* Added `FunctionScope.invalidate_data()` to invalidate the
-  pyobjects `AssignedName`\s and `EvaluatedName`\s hold.
-
-And after implementing these we thought of treating function scopes
-specially, since the names there cannot be accessed from outside.
-
-
-Function Scopes
----------------
-
-Another issue for implementing this feature is that function scope
-variable types are dependent on the type of the parameters and should
-change.  This issue seem to have some relations with implicit
-interfaces.
-
-These two problems(in the above section) points us to treating
-function scopes specially.  Since function names are not accessible
-from outside that function, we can perform all calculations in a
-temporary place.
-
-The problem gets worse when there are defined objects in a function
-scope.  Maybe we can change pynames to support function scopes.
-
-
-Enhancing `ObjectInfoManager`
-=============================
-
-* Changing `callinfo` to match similar args
-* Returning a `Generator` for unknown generator functions?
-* Validating call infos
-
-
 Better Concluded Data
 =====================
 
 * PyPackage: ``__init__.py`` attributes
 
 
-Marking Errors And Warnings In GUI
-==================================
-
-* Marking the occurrence in the buffer
-* When to analyze the code?
-
-  * When the user asks
-  * When saving
-
-* Saving error/warning information
-* ``C-,``, ``C-.``
-* ``C-c a p``, ``C-c a n``
-
-
-Better Occurrence Finding
-=========================
-
-The current implementation for finding occurrences of a `PyName` is to
-test every textual occurrence of that name has the same `PyName` or
-not.  This approach does not work when a name is repeated many times
-in the source.  For example renaming `self`\s are very time consuming.
-
-Maybe we can use one of these solutions:
-
-* Checking pyname equality only once for each scope
-
-  This way we check each name only once for each scope.  But this is
-  not applicable for attributes.  What's more `PyName`\s seem to
-  cache their types already.
-
-* Limiting the places to search for a name
-
-  For example for renaming a parameter we search the body of that
-  function and the keyword arguments passed to functions.  As another
-  example function parameters never appear as attributes and class
-  variables and methods never are referenced directly except in class
-  body.  The search locations include:
-
-  * module bodies
-  * class bodies
-  * function bodies
-
-  Access methods include:
-
-  * function call keyword
-  * normal name access
-  * attribute access
-
-* Excluding unimported modules
-
-  This does not seem to be a good solution.  One reason is that the
-  imports might be indirect.  So we have to put a long time for
-  creating import trees.
-
-Or maybe we can use a strategy object for searching.
-
-
 Getting Ready For Python 3.0
 ============================
 

docs/dev/workingon.txt

 Small Stories
 =============
 
-- Handling `__call__` in staticoi
-
 * Handling strings in following lines in `patchedast`
 * Extracting subexpressions; look at `extracttest` for more info
 * Create ... and implicit interfaces
 
 * More documentation for using rope as a library
 * Document features and organize them
-* Describe why rope does not stop the user from performing wrong
-  refactorings
+* Explain why rope does not stop users from performing wrong
+  refactorings

rope/refactor/move.py

 from rope.base import pyobjects, codeanalyze, exceptions, pynames, taskhandle
 from rope.base.change import ChangeSet, ChangeContents, MoveResource
 from rope.refactor import (importutils, rename, occurrences, sourceutils,
-                           functionutils, inline)
+                           functionutils, inline, extract)
 
 
 def create_move(project, resource, offset=None):
         pyname = codeanalyze.get_pyname_at(project.pycore, resource, offset)
         self.method_name = codeanalyze.get_name_at(resource, offset)
         self.pyfunction = pyname.get_object()
+        if extract._get_method_kind(self.pyfunction.get_scope()) != 'normal':
+            raise exceptions.RefactoringError('Only normal methods'
+                                              ' can be moved.')
 
     def get_changes(self, dest_attr, new_name,
                     task_handle=taskhandle.NullTaskHandle()):
         definition_info = functionutils.DefinitionInfo.read(self.pyfunction)
         others = definition_info.arguments_to_string(1)
         if others:
-            result += ', ' + others
+            if result:
+                result += ', '
+            result += others
         return result
 
     def _is_host_used(self):

ropetest/refactor/movetest.py

             'class B(object):\n\n    def new_method(self):\n        return 1\n',
             self.mod2.read())
 
+    def test_moving_methods_and_source_class_with_parameters(self):
+        self.mod2.write('class B(object):\n    pass\n')
+        code = 'import mod2\n\nclass A(object):\n    attr = mod2.B()\n' \
+               '    def a_method(self, p):\n        return p\n'
+        self.mod1.write(code)
+        mover = move.create_move(self.project, self.mod1,
+                                 code.index('a_method'))
+        mover.get_changes('attr', 'new_method').do()
+        self.assertEquals(
+            'import mod2\n\nclass A(object):\n    attr = mod2.B()\n'
+            '    def a_method(self, p):\n        return self.attr.new_method(p)\n',
+            self.mod1.read())
+        self.assertEquals(
+            'class B(object):\n\n    def new_method(self, p):\n        return p\n',
+            self.mod2.read())
+
 
 if __name__ == '__main__':
     unittest.main()