Commits

Anonymous committed 473365a

Considering function headers in function scopes

Comments (0)

Files changed (5)

docs/workingon.txt

 Renaming Global Functions/Classes
 =================================
 
-- Add ``refactoring.rename_local_name(source_code, offset, new_name)``
-- Add ``refactoring.rename(resource, offset, new_name)``
-- Handle from import
-- Renaming from another module
-- Committing all changes together
+* Faster implementation of `GlobalScope.get_inner_scope_for_line`
+* Optimize `SourceLinesAdapter` methods
 
 * Undoing refactorings
 * Refactoring `rope.refactoring` module; removing duplication
 * Addition to UI
 
-* Faster implementation of `GlobalScope.get_inner_scope_for_line`
 * Review `rope.codeanalyze`; module there seems to be many places to refactor
-* Optimize `SourceLinesAdapter` methods
+* Add run module to menus
 
 
 Remaining Stories

rope/codeanalyze.py

     
     def __init__(self, source_code):
         self.source_code = source_code
+        self.line_starts = None
+        self._initialize_line_starts()
+    
+    def _initialize_line_starts(self):
+        self.line_starts = []
+        self.line_starts.append(0)
+        for i, c in enumerate(self.source_code):
+            if c == '\n':
+                self.line_starts.append(i + 1)
+        self.line_starts.append(len(self.source_code) + 1)
     
     def get_line(self, line_number):
-        return self.source_code.split('\n')[line_number - 1]
+        return self.source_code[self.line_starts[line_number - 1]:self.line_starts[line_number] - 1]
     
     def length(self):
-        return len(self.source_code.split('\n'))
+        return len(self.line_starts) - 1
 
     def get_line_number(self, offset):
-        return len(self.source_code[:offset].split('\n'))
+        down = 0
+        up = len(self.line_starts)
+        current = (down + up) / 2
+        while down <= current < up:
+            if self.line_starts[current] <= offset < self.line_starts[current + 1]:
+                return current + 1
+            if offset < self.line_starts[current]:
+                up = current - 1
+            else:
+                down = current + 1
+            current = (down + up) / 2
+        return current + 1
 
     def get_line_start(self, line_number):
-        if line_number == 1:
-            return 0
-        current_line = 1
-        current_pos = 0
-        for c in self.source_code:
-            current_pos += 1
-            if c == '\n':
-                current_line += 1
-                if current_line == line_number:
-                    return current_pos
-        return current_pos
-    
+        return self.line_starts[line_number - 1]
+
     def get_line_end(self, line_number):
-        current_line = 0
-        current_pos = 0
-        for c in self.source_code:
-            current_pos += 1
-            if c == '\n':
-                current_line += 1
-                if current_line == line_number:
-                    return current_pos - 1
-        return current_pos
-    
+        return self.line_starts[line_number] - 1
+
 
 class ArrayLinesAdapter(Lines):
 
         current_scope = module_scope
         while current_scope is not None and \
               (current_scope.get_kind() == 'Module' or
-               self._get_scope_indents(current_scope) < line_indents):
-            while len(scopes) > 1 and \
-                  self._get_scope_indents(scopes[-1]) >= self._get_scope_indents(current_scope):
-                scopes.pop()
+               self._get_scope_indents(current_scope) <= line_indents):
             scopes.append(current_scope)
             new_scope = None
             for scope in current_scope.get_scopes():
             if self.lines.get_line(l).strip() != '' and \
                not self.lines.get_line(l).strip().startswith('#'):
                 min_indents = min(min_indents, self.get_indents(l))
-        while len(scopes) > 1 and min_indents <= self._get_scope_indents(scopes[-1]):
+        while len(scopes) > 1 and \
+              (min_indents <= self._get_scope_indents(scopes[-1]) and
+               not (min_indents == self._get_scope_indents(scopes[-1]) and
+                    lineno == scopes[-1].get_start())):
             scopes.pop()
         return scopes[-1]
     

ropetest/codeanalyzetest.py

     def test_source_lines_get_line_number(self):
         to_lines = SourceLinesAdapter('line1\nline2\n')
         self.assertEquals(1, to_lines.get_line_number(0))
+        self.assertEquals(1, to_lines.get_line_number(5))
         self.assertEquals(2, to_lines.get_line_number(7))
+        self.assertEquals(3, to_lines.get_line_number(12))
 
     def test_source_lines_get_line_start(self):
         to_lines = SourceLinesAdapter('line1\nline2\n')

ropetest/refactoringtest.py

         self.assertEquals('if True:\n    new_var = 1\nelse:\n    new_var = 20\n',
                           refactored)
     
+    def test_renaming_a_variable_with_arguement_name(self):
+        code = 'a_var = 10\ndef a_func(a_var):\n    print a_var\n'
+        refactored = self.refactoring.local_rename(code, 1, 'new_var')
+        self.assertEquals('new_var = 10\ndef a_func(a_var):\n    print a_var\n',
+                          refactored)
+    
+    def test_renaming_an_arguement_with_variable_name(self):
+        code = 'a_var = 10\ndef a_func(a_var):\n    print a_var\n'
+        refactored = self.refactoring.local_rename(code, len(code) - 3, 'new_var')
+        self.assertEquals('a_var = 10\ndef a_func(new_var):\n    print new_var\n',
+                          refactored)
+    
+    # FIXME: Function headers are in function scopes
+    def xxx_test_renaming_function_with_local_variable_name(self):
+        code = 'def a_func():\n    a_func=20\na_func()'
+        refactored = self.refactoring.local_rename(code, len(code) - 3, 'new_func')
+        self.assertEquals('def new_func():\n    a_func=20\nnew_func()',
+                          refactored)
+    
     def test_renaming_functions(self):
         code = 'def a_func():\n    pass\na_func()\n'
         refactored = self.refactoring.local_rename(code, len(code) - 5, 'new_func')