Commits

Ali Gholami Rudi  committed e1a6268

The main project may not contain the definitions in cross-project refactorings

  • Participants
  • Parent commits d3cda29

Comments (0)

Files changed (4)

File docs/dev/todo.txt

   imports
 
 
+* Inlining a single occurrence
+
+
 > Public Release 0.7.2 : December 13, 2007
-
-
-* Inlining a single occurrence

File docs/library.txt

 `rope.refactor.multiproject` can be used to perform a refactoring
 across multiple projects.
 
-Before we begin, note that there should always be a main project.
-That is the project that contains the definition of the changing
-python name.  Other projects depend on the main one and uses of the
-changed name in them should be updated.
+Usually refactorings have a main project.  That is the project that
+contains the definition of the changing python name.  Other projects
+depend on the main one and uses of the changed name in them should be
+updated.
 
 Each refactoring changes only one project (the project passed to its
 constructor).  But we can use `MultiProjectRefactoring` proxy to
 perform a refactoring on other projects, too.
 
-First we need create a multi-project refactoring constructor.  As an
-example consider we want to perform a rename refactoring::
+First we need to create a multi-project refactoring constructor.  As
+an example consider we want to perform a rename refactoring::
 
   from rope.refactor import multiproject, rename
 
 We create the rename refactoring as we do for normal refactorings.
 Note that `project` is the main project.
 
+As mentioned above, other projects use the main project; rope
+automatically adds the main project to the python path of other
+projects.
+
 Finally we can calculate the changes.  But instead of calling
-`get_changes()` (which returns main project changes, only), we should
+`get_changes()` (which returns main project changes, only), we can
 call `get_all_changes()` with the same arguments.  It returns a list
 of ``(project, changes)`` tuples.  You can perform them manually by
 calling ``project.do(changes)`` for each tuple or use

File rope/refactor/multiproject.py

 
 """
 
-from rope.base import resources, project
+from rope.base import resources, project, libutils
 
 
 class MultiProjectRefactoring(object):
 
     def __call__(self, project, *args, **kwds):
         """Create the refactoring"""
-        return _MultiRefactoring(self.refactoring, self.projects, self.addpath,
-                                 project, *args, **kwds)
+        return _MultiRefactoring(self.refactoring, self.projects,
+                                 self.addpath, project, *args, **kwds)
 
 
 class _MultiRefactoring(object):
     def __init__(self, refactoring, other_projects, addpath,
                  project, *args, **kwds):
         self.refactoring = refactoring
-        self.projects = other_projects
-        self.project = project
-        for other_project in self.projects:
-            other_project.get_prefs().add('python_path', self.project.address)
-        self.main_refactoring = self.refactoring(project, *args, **kwds)
-        args, kwds = self._change_project_resources_for_args(args, kwds)
-        self.other_refactorings = [self.refactoring(other, *args, **kwds)
-                                   for other in self.projects]
+        self.projects = [project] + other_projects
+        for other_project in other_projects:
+            for folder in self.project.pycore.get_source_folders():
+                other_project.get_prefs().add('python_path', folder.real_path)
+        self.refactorings = []
+        for other in self.projects:
+            args, kwds = self._resources_for_args(other, args, kwds)
+            self.refactorings.append(
+                self.refactoring(other, *args, **kwds))
 
     def get_all_changes(self, *args, **kwds):
         """Get a project to changes dict"""
         result = []
-        result.append((self.project,
-                       self.main_refactoring.get_changes(*args, **kwds)))
-        args, kwds = self._change_project_resources_for_args(args, kwds)
-        for project, refactoring in zip(self.projects,
-                                        self.other_refactorings):
+        for project, refactoring in zip(self.projects, self.refactorings):
+            args, kwds = self._resources_for_args(project, args, kwds)
             result.append((project, refactoring.get_changes(*args, **kwds)))
         return result
 
     def __getattr__(self, name):
         return getattr(self.main_refactoring, name)
 
-    def _change_project_resources_for_args(self, args, kwds):
-        newargs = [self._change_project_resource(arg) for arg in args]
-        newkwds = dict((name, self._change_project_resource(value))
+    def _resources_for_args(self, project, args, kwds):
+        newargs = [self._change_project_resource(project, arg) for arg in args]
+        newkwds = dict((name, self._change_project_resource(project, value))
                        for name, value in kwds.items())
         return newargs, newkwds
         
-    def _change_project_resource(self, obj):
+    def _change_project_resource(self, project, obj):
         if isinstance(obj, resources.Resource) and \
-           obj.project == self.project:
-            return project.get_no_project().get_resource(obj.real_path)
+           obj.project != project:
+            return libutils.path_to_resource(project, obj.real_path)
         return obj
 
+    @property
+    def project(self):
+        return self.projects[0]
+
+    @property
+    def main_refactoring(self):
+        return self.refactorings[0]
+
 
 def perform(project_changes):
     for project, changes in project_changes:

File ropetest/refactor/multiprojecttest.py

             'import mod1\nimport other\nmyvar = other.a_func()\n',
             self.mod2.read())
 
+    def test_rename_from_the_project_not_containing_the_change(self):
+        self.project2.get_prefs().add('python_path', self.project1.address)
+        self.mod1.write('var = 1\n')
+        self.mod2.write('import mod1\nmyvar = mod1.var\n')
+        refactoring = multiproject.MultiProjectRefactoring(
+            rename.Rename, [self.project1])
+        renamer = refactoring(self.project2, self.mod2,
+                              self.mod2.read().rindex('var'))
+        multiproject.perform(renamer.get_all_changes('newvar'))
+        self.assertEquals('newvar = 1\n', self.mod1.read())
+        self.assertEquals('import mod1\nmyvar = mod1.newvar\n',
+                          self.mod2.read())
+
 
 if __name__ == '__main__':
     unittest.main()