1. zjes
  2. rope_py3k

Commits

Ali Gholami Rudi  committed 8bb9881

Added convert local variable to field refactoring

  • Participants
  • Parent commits 0cc2ace
  • Branches trunk

Comments (0)

Files changed (9)

File docs/done.txt

View file
  • Ignore whitespace
 ===========
 
 
+- Convert local variable to field refactoring : October 18, 2006
+
+
 > Public Release 0.3m5 : October 15, 2006
 
 

File docs/issues.txt

View file
  • Ignore whitespace
 To Be Discussed
 ===============
 
+* Showing available refactorings for a place
 * Rope's preference saving system: format, location
+
+* Indexing source files for faster occurrence finding
 * Having a persistant format for PyNames and PyObjects for saving
   hard to compute information like class hierarchies
 * Using a modification of `compiler` AST for simplifying refactorings
-* Indexing source files for faster occurrence finding
 
 
 Undo Unification

File docs/stories.txt

View file
  • Ignore whitespace
 * Static type inference
 
 
+* Updating similarly named variables and methods in rename refactoring
+
+
 * Enhancing editor
 
   * Clearing selection if something happens
   Do not show submodules that are not imported yet as attributes.
 
 
+* Introduce parameter
+  Change global accesses or attributes accesses to parameters
+
+
+* Pull up method
+
+
+* Push down method
+
+
 * Show PyDoc reST highlighting
 
 
 > Public Release 0.3rc1 : October 29, 2006
 
 
-* Change local variable to field refactoring
-
-
 * Enhancing module running
 
   * Showing running status in the GUI

File docs/workingon.txt

View file
  • Ignore whitespace
+Change Local Variable to Field Refactoring
+==========================================
+
+- Check for being a local variable in side a method
+- Check that there is no other attribute with the same name
+- Other names than `self` first parameter
+- Adding `localtofield` module
+- Adding to ui
+
+* Refactoring common testcase setUps and tearDowns into a decorators;
+  We'll miss code assists in tests.
+
+
 Encapsulate Field
 =================
 
 * Adding ``add_statements(method, statements)``
 * Changing `Rename` to take an `OccuranceFinder`
 * Caching `Occurrence` fields
+
+
+Before 0.3 Release
+==================
+
 * Better refactoring categoriztion
 
 

File rope/refactor/__init__.py

View file
  • Ignore whitespace
 from rope.refactor.move import MoveRefactoring
 from rope.refactor.inline import InlineRefactoring
 from rope.refactor.encapsulate_field import EncapsulateFieldRefactoring
+from rope.refactor.localtofield import ConvertLocalToFieldRefactoring
 
 
 class PythonRefactoring(object):
         changes = EncapsulateFieldRefactoring(self.pycore, resource, offset).\
                   encapsulate_field()
         self._add_and_commit_changes(changes)
-            
-
+    
+    def convert_local_variable_to_field(self, resource, offset):
+        changes = ConvertLocalToFieldRefactoring(self.pycore).\
+                  convert_local_variable_to_field(resource, offset)
+        self._add_and_commit_changes(changes)
+        
     def _add_and_commit_changes(self, changes):
         self._undo.add_change(changes)
         changes.do()

File rope/refactor/localtofield.py

View file
  • Ignore whitespace
+from rope.refactor.rename import RenameRefactoring
+import rope.codeanalyze
+from rope.refactor.change import (ChangeSet, ChangeFileContents,
+                                  MoveResource, CreateFolder)
+
+
+class ConvertLocalToFieldRefactoring(object):
+    
+    def __init__(self, pycore):
+        self.pycore = pycore
+    
+    def convert_local_variable_to_field(self, resource, offset):
+        name = rope.codeanalyze.get_name_at(resource, offset)
+        pyname = rope.codeanalyze.get_pyname_at(self.pycore, resource, offset)
+        if not self._is_a_method_local(pyname):
+            raise rope.exceptions.RefactoringException(
+                'Convert local variable to field should be performed on \n'
+                'the a local variable of a method.')
+        
+        pymodule, lineno = pyname.get_definition_location()
+        function_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+        class_scope = function_scope.parent
+        if name in class_scope.pyobject.get_attributes():
+            raise rope.exceptions.RefactoringException(
+                'The field %s already exists' % name)
+        
+        new_name = self._get_field_name(function_scope.pyobject, name)
+        changes = RenameRefactoring(self.pycore).local_rename(resource, offset,
+                                                              new_name)
+        return changes
+
+    def _get_field_name(self, pyfunction, name):
+        self_name = pyfunction.parameters[0]
+        new_name = self_name + '.' + name
+        return new_name
+    
+    def _is_a_method_local(self, pyname):
+        pymodule, lineno = pyname.get_definition_location()
+        holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
+        parent = holding_scope.parent
+        return isinstance(pyname, rope.pynames.AssignedName) and \
+               pyname in holding_scope.get_names().values() and \
+               holding_scope.get_kind() == 'Function' and \
+               parent is not None and parent.get_kind() == 'Class'
+

File rope/refactor/rename.py

View file
  • Ignore whitespace
             scope = scope.parent
         return scope.get_kind() == 'Function' and \
                pyname in scope.get_names().values() and \
-               pyname not in scope.pyobject.get_parameters().values()
+               isinstance(pyname, rope.pynames.AssignedName)
     
     def _is_renaming_a_module(self, old_pynames):
         if len(old_pynames) == 1 and \

File rope/ui/refactor.py

View file
  • Ignore whitespace
         editor = fileeditor.get_editor()
         editor.refactoring.encapsulate_field(resource, editor.get_current_offset())
     
-    
+def convert_local_to_field(context):
+    if context.get_active_editor():
+        fileeditor = context.get_active_editor()
+        resource = fileeditor.get_file()
+        editor = fileeditor.get_editor()
+        editor.refactoring.convert_local_variable_to_field(
+            resource, editor.get_current_offset())
+
 
 actions = []
 actions.append(SimpleAction('Rename Refactoring', ConfirmAllEditorsAreSaved(rename), 'M-R',
                             ConfirmAllEditorsAreSaved(encapsulate_field), None,
                             MenuAddress(['Refactor', 'Encapsulate Field'], 'n', 1),
                             ['python']))
+actions.append(SimpleAction('Convert Local Variable to Field', 
+                            ConfirmAllEditorsAreSaved(convert_local_to_field), None,
+                            MenuAddress(['Refactor', 'Convert Local Variable to Field'], None, 1),
+                            ['python']))
 actions.append(SimpleAction('Transform Module to Package', 
                             ConfirmAllEditorsAreSaved(transform_module_to_package), None,
                             MenuAddress(['Refactor', 'Transform Module to Package'], 't', 1), 

File ropetest/refactor/__init__.py

View file
  • Ignore whitespace
         self.refactoring.encapsulate_field(self.mod1, self.mod1.read().index('attr') + 1)
 
 
+class LocalToFieldTest(unittest.TestCase):
+
+    def setUp(self):
+        super(LocalToFieldTest, self).setUp()
+        self.project_root = 'sampleproject'
+        testutils.remove_recursively(self.project_root)
+        self.project = Project(self.project_root)
+        self.pycore = self.project.get_pycore()
+        self.refactoring = self.project.get_pycore().get_refactoring()
+        self.mod = self.pycore.create_module(self.project.get_root_folder(), 'mod')
+
+    def tearDown(self):
+        testutils.remove_recursively(self.project_root)
+        super(LocalToFieldTest, self).tearDown()
+    
+    def test_simple_local_to_field(self):
+        code = 'class A(object):\n    def a_func(self):\n' \
+               '        var = 10\n'
+        self.mod.write(code)
+        self.refactoring.convert_local_variable_to_field(self.mod,
+                                                         code.index('var') + 1)
+        expected = 'class A(object):\n    def a_func(self):\n' \
+                   '        self.var = 10\n'
+        self.assertEquals(expected, self.mod.read())
+    
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_when_performed_on_a_global_var(self):
+        self.mod.write('var = 10\n')
+        self.refactoring.convert_local_variable_to_field(
+            self.mod, self.mod.read().index('var') + 1)
+
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_when_performed_on_field(self):
+        code = 'class A(object):\n    def a_func(self):\n' \
+               '        self.var = 10\n'
+        self.mod.write(code)
+        self.refactoring.convert_local_variable_to_field(
+            self.mod, self.mod.read().index('var') + 1)
+
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_when_performed_on_a_parameter(self):
+        code = 'class A(object):\n    def a_func(self, var):\n' \
+               '        a = var\n'
+        self.mod.write(code)
+        self.refactoring.convert_local_variable_to_field(
+            self.mod, self.mod.read().index('var') + 1)
+
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_when_there_is_a_field_with_the_same_name(self):
+        code = 'class A(object):\n    def __init__(self):\n        self.var = 1\n' \
+               '    def a_func(self):\n        var = 10\n'
+        self.mod.write(code)
+        self.refactoring.convert_local_variable_to_field(
+            self.mod, self.mod.read().rindex('var') + 1)
+
+    def test_local_to_field_with_self_renamed(self):
+        code = 'class A(object):\n    def a_func(myself):\n' \
+               '        var = 10\n'
+        self.mod.write(code)
+        self.refactoring.convert_local_variable_to_field(self.mod,
+                                                         code.index('var') + 1)
+        expected = 'class A(object):\n    def a_func(myself):\n' \
+                   '        myself.var = 10\n'
+        self.assertEquals(expected, self.mod.read())
+    
+
 def suite():
     result = unittest.TestSuite()
     result.addTests(unittest.makeSuite(ropetest.refactor.renametest.RenameRefactoringTest))
     result.addTests(unittest.makeSuite(RefactoringUndoTest))
     result.addTests(unittest.makeSuite(ropetest.refactor.inlinetest.InlineLocalVariableTest))
     result.addTests(unittest.makeSuite(EncapsulateFieldTest))
+    result.addTests(unittest.makeSuite(LocalToFieldTest))
     return result