Commits

Anonymous committed 108b904

Showing initial names for rename refactoring

Comments (0)

Files changed (9)

 * Inline method
 
 
-> Public Release 0.3rc1 : October 29, 2006
-
-
 * Enhancing module running
 
   * Showing running status in the GUI
   * Running last run
 
 
+> Public Release 0.3rc1 : October 29, 2006
+
+
 * Running unit tests view
 
 
+* Previewing refactoring changes
+
+
 Remaining Stories
 -----------------
 

docs/workingon.txt

-- Calling `sys.settrace` for all threads in `rope.runmod` module
+Refactoring
+===========
+
+* Refactor the refactoring modules
+  
+  * What changes the most? refactoring kinds
+  * Designing refactorings for IDE's
+
 
 Before 0.3 Release
 ==================
 
 * ``overview.txt``
+* Encodings
 
 
 Remaining Stories

rope/codeanalyze.py

     
     def _find_word_start(self, offset):
         current_offset = offset
-        while current_offset >= 0 and (self.source_code[current_offset].isalnum() or
-                                       self.source_code[current_offset] in '_'):
+        while current_offset >= 0 and self._is_id_char(current_offset):
             current_offset -= 1;
         return current_offset + 1
     
     def _find_word_end(self, offset):
         current_offset = offset + 1
         while current_offset < len(self.source_code) and \
-              (self.source_code[current_offset].isalnum() or
-               self.source_code[current_offset] == '_'):
+              self._is_id_char(current_offset):
             current_offset += 1;
         return current_offset - 1
 
     def get_word_before(self, offset):
         return self.source_code[self._find_word_start(offset - 1):offset]
     
+
     def get_word_at(self, offset):
-        return self.source_code[self._find_word_start(offset - 1):
-                                self._find_word_end(offset - 1) + 1]
+        offset = self._get_fixed_offset(offset)
+        return self.source_code[self._find_word_start(offset):
+                                self._find_word_end(offset) + 1]
+
+    def _get_fixed_offset(self, offset):
+        if offset >= len(self.source_code):
+            return offset - 1
+        if not self._is_id_char(offset):
+            if offset > 0 and self._is_id_char(offset - 1):
+                return offset - 1
+            if offset < len(self.source_code) - 1 and self._is_id_char(offset + 1):
+                return offset + 1
+        return offset
+    
+    def _is_id_char(self, offset):
+        return self.source_code[offset].isalnum() or self.source_code[offset] == '_'
     
     def _find_string_start(self, offset):
         kind = self.source_code[offset]
             return self._find_string_start(offset)
         if self.source_code[offset] in ')]}':
             return self._find_parens_start(offset)
-        if self.source_code[offset].isalnum() or self.source_code[offset] == '_':
+        if self._is_id_char(offset):
             return self._find_word_start(offset)
         return old_offset
     
 
         if current_offset > 0 and self.source_code[current_offset] in '\'"':
             return self._find_string_start(current_offset)
-        elif current_offset > 0 and (self.source_code[current_offset].isalnum() or \
-                                     self.source_code[current_offset] == '_'):
+        elif current_offset > 0 and self._is_id_char(current_offset):
             return self._find_word_start(current_offset)
         return last_parens
 
     def _find_primary_start(self, offset):
+        if offset >= len(self.source_code):
+            offset = len(self.source_code) - 1
         current_offset = offset + 1
         if self.source_code[offset] != '.':
             current_offset = self._find_primary_without_dot_start(offset)
             dot_position = self._find_last_non_space_char(current_offset - 1)
             current_offset = self._find_primary_without_dot_start(dot_position - 1)
             
-            first_char = self.source_code[current_offset]
-            if first_char != '_' and not first_char.isalnum():
+            if not self._is_id_char(current_offset):
                 break
 
         return current_offset
     
     def get_primary_at(self, offset):
-        return self.source_code[self._find_primary_start(offset - 1):
-                                self._find_word_end(offset - 1) + 1].strip()
+        offset = self._get_fixed_offset(offset)
+        return self.source_code[self._find_primary_start(offset):
+                                self._find_word_end(offset) + 1].strip()
 
     def get_splitted_primary_before(self, offset):
         """returns expression, starting, starting_offset

rope/refactor/__init__.py

     def local_rename(self, resource, offset, new_name):
         changes = RenameRefactoring(self.pycore, resource, offset).\
                   local_rename(new_name)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def rename(self, resource, offset, new_name):
         changes = RenameRefactoring(self.pycore, resource, offset).\
                   rename(new_name)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def extract_method(self, resource, start_offset, end_offset,
                        extracted_name):
         changes = ExtractMethodRefactoring(self.pycore, resource,
                                            start_offset, end_offset).\
                                            extract_method(extracted_name)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def extract_variable(self, resource, start_offset, end_offset,
                          extracted_name):
         changes = ExtractMethodRefactoring(self.pycore, resource,
                                            start_offset, end_offset).\
                                            extract_variable(extracted_name)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def transform_module_to_package(self, resource):
         changes = ChangeSet()
         changes.add_change(CreateFolder(parent, name))
         new_path = parent.get_path() + '/%s/__init__.py' % name
         changes.add_change(MoveResource(resource, new_path))
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def _transform_relatives_to_absolute(self, resource):
         pymodule = self.pycore.resource_to_pyobject(resource)
                                                          resource, offset)
         changes = factory_introducer.introduce_factory(factory_name,
                                                        global_factory)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def move(self, resource, offset, dest_resource):
         changes = MoveRefactoring(self.pycore, resource, offset).\
                   move(dest_resource)
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def inline_local_variable(self, resource, offset):
         changes = InlineRefactoring(self.pycore, resource, offset).inline()
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def encapsulate_field(self, resource, offset):
         changes = EncapsulateFieldRefactoring(self.pycore, resource, offset).\
                   encapsulate_field()
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
     
     def convert_local_variable_to_field(self, resource, offset):
         changes = ConvertLocalToFieldRefactoring(self.pycore, resource, offset).\
                   convert_local_variable_to_field()
-        self._add_and_commit_changes(changes)
+        self.add_and_commit_changes(changes)
         
-    def _add_and_commit_changes(self, changes):
+    def add_and_commit_changes(self, changes):
         self._undo.add_change(changes)
         changes.do()
         
         if source is not None:
             changes = ChangeSet()
             changes.add_change(ChangeFileContents(resource, source))
-            self.refactoring._add_and_commit_changes(changes)
+            self.refactoring.add_and_commit_changes(changes)
 
     def expand_star_imports(self, resource):
         source = self._perform_command_on_module_with_imports(
         if source is not None:
             changes = ChangeSet()
             changes.add_change(ChangeFileContents(resource, source))
-            self.refactoring._add_and_commit_changes(changes)
+            self.refactoring.add_and_commit_changes(changes)
 
     def transform_froms_to_imports(self, resource):
         pymodule = self.pycore.resource_to_pyobject(resource)
         if result is not None:
             changes = ChangeSet()
             changes.add_change(ChangeFileContents(resource, result))
-            self.refactoring._add_and_commit_changes(changes)
+            self.refactoring.add_and_commit_changes(changes)
 
     def transform_relatives_to_absolute(self, resource):
         pymodule = self.pycore.resource_to_pyobject(resource)
         if result is not None:
             changes = ChangeSet()
             changes.add_change(ChangeFileContents(resource, result))
-            self.refactoring._add_and_commit_changes(changes)
+            self.refactoring.add_and_commit_changes(changes)
     
 
 class NoRefactoring(object):

rope/refactor/rename.py

 import rope.codeanalyze
 import rope.pynames
 import rope.pyobjects
+import rope.exceptions
 from rope.refactor.change import (ChangeSet, ChangeFileContents,
                                   MoveResource, CreateFolder)
 import rope.refactor.occurrences
         self.pycore = pycore
         self.resource = resource
         self.offset = offset
+        self.old_name = rope.codeanalyze.get_name_at(self.resource, self.offset)
+        self.old_pyname = rope.codeanalyze.get_pyname_at(self.pycore, resource,
+                                                         offset)
+        if self.old_pyname is None:
+            raise rope.exceptions.RefactoringException(
+                'Rename refactoring should be performed on python identifiers.')
     
     def local_rename(self, new_name):
         return self._rename(new_name, True)
     def rename(self, new_name):
         return self._rename(new_name)
     
+    def get_old_name(self):
+        return self.old_name
+    
     def _rename(self, new_name, in_file=False):
-        old_name = rope.codeanalyze.get_name_at(self.resource, self.offset)
-        old_pynames = self._get_old_pynames(self.offset, self.resource, in_file, old_name)
+        old_pynames = self._get_old_pynames(in_file)
         if not old_pynames:
             return None
         # HACK: Do a local rename for names defined in function scopes.
         # XXX: This might cause problems for global keyword usages.
         if not in_file and len(old_pynames) == 1 and \
-           self._is_renaming_a_function_local_name(old_pynames[0]):
+           self._is_renaming_a_function_local_name():
             in_file = True
-        files = self._get_interesting_files(self.resource, in_file)
+        files = self._get_interesting_files(in_file)
         changes = ChangeSet()
         for file_ in files:
-            new_content = RenameInModule(self.pycore, old_pynames, old_name, new_name).\
+            new_content = RenameInModule(self.pycore, old_pynames, self.old_name, new_name).\
                           get_changed_module(file_)
             if new_content is not None:
                 changes.add_change(ChangeFileContents(file_, new_content))
         
-        if self._is_renaming_a_module(old_pynames):
+        if self._is_renaming_a_module():
             changes.add_change(self._rename_module(old_pynames[0].get_object(), new_name))
         return changes
     
-    def _is_renaming_a_function_local_name(self, pyname):
-        module, lineno = pyname.get_definition_location()
+    def _is_renaming_a_function_local_name(self):
+        module, lineno = self.old_pyname.get_definition_location()
         if lineno is None:
             return False
         scope = module.get_scope().get_inner_scope_for_line(lineno)
-        if isinstance(pyname, rope.pynames.DefinedName) and \
+        if isinstance(self.old_pyname, rope.pynames.DefinedName) and \
            scope.get_kind() in ('Function', 'Class'):
             scope = scope.parent
         return scope.get_kind() == 'Function' and \
-               pyname in scope.get_names().values() and \
-               isinstance(pyname, rope.pynames.AssignedName)
+               self.old_pyname in scope.get_names().values() and \
+               isinstance(self.old_pyname, rope.pynames.AssignedName)
     
-    def _is_renaming_a_module(self, old_pynames):
-        if len(old_pynames) == 1 and \
-           old_pynames[0].get_object().get_type() == rope.pycore.PyObject.get_base_type('Module'):
+    def _is_renaming_a_module(self):
+        if self.old_pyname.get_object().get_type() == rope.pycore.PyObject.get_base_type('Module'):
             return True
         return False
 
-    def _get_old_pynames(self, offset, resource, in_file, old_name):
-        old_pyname = rope.codeanalyze.get_pyname_at(self.pycore, resource,
-                                                    offset)
-        if old_pyname is None:
+    def _get_old_pynames(self, in_file):
+        if self.old_pyname is None:
             return []
-        if self._is_a_class_method(old_pyname) and not in_file:
-            return self._get_all_methods_in_hierarchy(old_pyname.get_object().
-                                                      parent, old_name)
+        if self._is_a_class_method() and not in_file:
+            return self._get_all_methods_in_hierarchy(self.old_pyname.get_object().
+                                                      parent, self.old_name)
         else:
-            return [old_pyname]
+            return [self.old_pyname]
 
-    def _get_interesting_files(self, resource, in_file):
+    def _get_interesting_files(self, in_file):
         if not in_file:
             return self.pycore.get_python_files()
-        return [resource]
+        return [self.resource]
     
-    def _is_a_class_method(self, pyname):
+    def _is_a_class_method(self):
+        pyname = self.old_pyname
         return isinstance(pyname, rope.pynames.DefinedName) and \
                pyname.get_object().get_type() == rope.pyobjects.PyObject.get_base_type('Function') and \
                pyname.get_object().parent.get_type() == rope.pyobjects.PyObject.get_base_type('Type')
             return True
         
         def _is_code_inside_project(self, code):
-            #source = code.co_filename
-            source = inspect.getsourcefile(code)
+            source = code.co_filename
+            #source = inspect.getsourcefile(code)
             return source and source.endswith('.py') and \
                    os.path.abspath(source).startswith(self.project_root)
     

rope/ui/refactor.py

         ok_button.focus_set()
 
 
-def _rename_dialog(do_rename, title):
+def _rename_dialog(context, title, is_local=False):
+    resource = context.get_active_editor().get_file()
+    editor = context.get_active_editor().get_editor()
+    renamer = rope.refactor.rename.RenameRefactoring(
+        context.get_core().get_open_project().get_pycore(), 
+        resource, editor.get_current_offset())
     toplevel = Tkinter.Toplevel()
     toplevel.title(title)
     frame = Tkinter.Frame(toplevel)
     label = Tkinter.Label(frame, text='New Name :')
     label.grid(row=0, column=0)
     new_name_entry = Tkinter.Entry(frame)
+    new_name_entry.insert(0, renamer.get_old_name())
+    new_name_entry.select_range(0, Tkinter.END)
     new_name_entry.grid(row=0, column=1)
+    def do_rename(new_name):
+        if not is_local:
+            changes = renamer.rename(new_name)
+        else:
+            changes = renamer.local_rename(new_name)
+        editor.refactoring.add_and_commit_changes(changes)
     def ok(event=None):
         do_rename(new_name_entry.get())
         toplevel.destroy()
     new_name_entry.focus_set()
 
 def rename(context):
-    def do_rename(new_name):
-        resource = context.get_active_editor().get_file()
-        editor = context.get_active_editor().get_editor()
-        editor.refactoring.rename(resource,
-                                  editor.get_current_offset(),
-                                  new_name)
-    _rename_dialog(do_rename, 'Rename Refactoring')
+    _rename_dialog(context, 'Rename Refactoring')
+
+def local_rename(context):
+    _rename_dialog(context, 'Rename Variable In File', True)
 
 def transform_module_to_package(context):
     if context.get_active_editor():
         editor = fileeditor.get_editor()
         editor.refactoring.transform_module_to_package(resource)
 
-def local_rename(context):
-    def do_rename(new_name):
-        resource = context.get_active_editor().get_file()
-        editor = context.get_active_editor().get_editor()
-        editor.refactoring.local_rename(resource,
-                                        editor.get_current_offset(),
-                                        new_name)
-    _rename_dialog(do_rename, 'Rename Variable In File')
-
 def _extract_dialog(do_extract, kind):
     toplevel = Tkinter.Toplevel()
     toplevel.title('Extract ' + kind)

ropetest/codeanalyzetest.py

         word_finder = WordRangeFinder('a_var.an_attr')
         self.assertEquals('a_var.an_attr', word_finder.get_primary_at(10))
     
+    def test_word_finder_on_word_beginning(self):
+        code = 'print a_var\n'
+        word_finder = WordRangeFinder(code)
+        self.assertEquals('a_var', word_finder.get_word_at(code.index('a_var')))
+    
+    def test_word_finder_on_primary_beginning(self):
+        code = 'print a_var\n'
+        word_finder = WordRangeFinder(code)
+        self.assertEquals('a_var', word_finder.get_primary_at(code.index('a_var')))
+    
+    def test_word_finder_on_word_ending(self):
+        code = 'print a_var\n'
+        word_finder = WordRangeFinder(code)
+        self.assertEquals('a_var', word_finder.get_word_at(code.index('a_var') + 5))
+    
+    def test_word_finder_on_primary_ending(self):
+        code = 'print a_var\n'
+        word_finder = WordRangeFinder(code)
+        self.assertEquals('a_var', word_finder.get_primary_at(code.index('a_var') + 5))
+    
     def test_strings(self):
         word_finder = WordRangeFinder('"a string".split()')
         self.assertEquals('"a string".split', word_finder.get_primary_at(14))

ropetest/pycoretest.py

 
     @testutils.assert_raises(ModuleNotFoundException)
     def test_non_existant_module(self):
-        self.pycore.get_module('mod')
+        self.pycore.get_module('doesnotexistmodule')
 
     def test_imported_names(self):
         self.pycore.create_module(self.project.get_root_folder(), 'mod1')