Commits

Anonymous committed 869da7f

Raising exception on handling tuple assignments in encapsulate field

Comments (0)

Files changed (6)

 hope in soon future, somewhere about version 0.4, *rope* would be
 mature enough for being extended easily in those parts.
 
-Right now contributions are really needed in UI part and patches and
-extensions in the UI part are extremely welcome.  Have a look at the
-UI enhancement stories (docs/stories.txt).  Send your patches in
+Right now contributions are really needed in the UI part and patches
+and extensions in the UI part are extremely welcome.  Have a look at
+the UI enhancement stories (docs/stories.txt).  Send your patches in
 sourceforge.net project page, http://sf.net/projects/rope.  Patches
 should use python coding style, :PEP:`8`, and should have good unit
 tests.  *rope* uses a local repository right now, but it will be moved

docs/overview.txt

 --------------
 
 The position of the mark would be region start and the current
-cursor position would be region end. (The same as emacs copy and
-paste). ::
+cursor position would be region end. (You can set the mark as in
+emacs copy and paste with ``C-space``). ::
   
   def a_func():
       a = 1

docs/workingon.txt

 Encapsulate Field
 =================
 
-- `AugAssign` nodes
-
-* Tuple assignments
+- Tuple assignments in encapsulate field
 
 * Handling `AssList` for inline variable and encapsulate field
 * Changing refactor modules to use `sourcetools.add_methods`

rope/refactor/encapsulate_field.py

 import rope.refactor.occurrences
 
 from rope.refactor import sourceutils
-from rope.refactor.rename import RenameInModule
 from rope.refactor.change import ChangeSet, ChangeFileContents
 
 
     def _is_an_attribute(self, pyname):
         if pyname is not None and isinstance(pyname, rope.pynames.AssignedName):
             defining_pymodule, defining_line = self.pyname.get_definition_location()
-            defining_scope = defining_pymodule.get_scope().get_inner_scope_for_line(defining_line)
+            defining_scope = defining_pymodule.get_scope().\
+                             get_inner_scope_for_line(defining_line)
             parent = defining_scope.parent
             if defining_scope.get_kind() == 'Class' or \
                (parent is not None and parent.get_kind() == 'Class'):
     def get_changed_module(self):
         result = []
         line_finder = None
+        word_finder = rope.codeanalyze.WordRangeFinder(self.source)
         for occurrence in self.occurrences_finder.find_occurrences(self.resource,
                                                                    self.pymodule):
             start, end = occurrence.get_word_range()
                 continue
             self._manage_writes(start, result)
             result.append(self.source[self.last_modified:start])
+            if self._is_assigned_in_a_tuple_assignment(occurrence):
+                raise rope.exceptions.RefactoringException(
+                    'Cannot handle tuple assignments in encapsulate field.') 
             if occurrence.is_written():
-                assignment_type = occurrence.get_assignment_type()
+                assignment_type = word_finder.get_assignment_type(start)
                 if assignment_type == '=':
                     result.append(self.setter + '(')
                 else:
             result.append(self.source[self.last_modified:])
             return ''.join(result)
         return None
+    
+    def _is_assigned_in_a_tuple_assignment(self, occurance):
+        line_finder = rope.codeanalyze.LogicalLineFinder(self.lines)
+        offset = occurance.get_word_range()[0]
+        lineno = self.lines.get_line_number(offset)
+        start_line, end_line = line_finder.get_logical_line_in(lineno)
+        start_offset = self.lines.get_line_start(start_line)
+        
+        line = self.source[start_offset:self.lines.get_line_end(end_line)]
+        word_finder = rope.codeanalyze.WordRangeFinder(line)
+        
+        relative_offset = offset - start_offset
+        relative_primary_start = occurance.get_primary_range()[0] - start_offset
+        relative_primary_end = occurance.get_primary_range()[1] - start_offset
+        prev_char_offset = word_finder._find_last_non_space_char(relative_primary_start - 1)
+        next_char_offset = word_finder._find_first_non_space_char(relative_primary_end)
+        next_char = prev_char = ''
+        if prev_char_offset >= 0:
+            prev_char = line[prev_char_offset]
+        if next_char_offset < len(line):
+            next_char = line[next_char_offset]
+        try:
+            equals_offset = line.index('=')
+        except ValueError:
+            return False
+        return relative_offset < equals_offset and (prev_char == ',' or next_char in ',)')
 
     def _manage_writes(self, offset, result):
         if self.last_set is not None and self.last_set <= offset:

rope/refactor/occurrences.py

     
     def is_written(self):
         return self.tools.word_finder.is_assigned_here(self.offset)
-    
-    def get_assignment_type(self):
-        if not self.is_written():
-            return None
-        return self.tools.word_finder.get_assignment_type(self.offset)
 
 
 class FilteredOccurrenceFinder(object):
     word_finder = property(get_word_finder)
     source_code = property(get_source_code)
     
-

ropetest/refactor/__init__.py

         self.mod1.write('attr = 10')
         self.refactoring.encapsulate_field(self.mod1, self.mod1.read().index('attr') + 1)
 
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_on_tuple_assignments(self):
+        self.mod.write(self.a_class)
+        self.mod1.write('import mod\na_var = mod.A()\na_var.attr = 1\na_var.attr, b = 1, 2\n')
+        self.refactoring.encapsulate_field(self.mod1, self.mod1.read().index('attr') + 1)
+
+    @testutils.assert_raises(RefactoringException)
+    def test_raising_exception_on_tuple_assignments2(self):
+        self.mod.write(self.a_class)
+        self.mod1.write('import mod\na_var = mod.A()\na_var.attr = 1\nb, a_var.attr = 1, 2\n')
+        self.refactoring.encapsulate_field(self.mod1, self.mod1.read().index('attr') + 1)
+
+    def test_tuple_assignments(self):
+        self.mod1.write('import mod\na_var = mod.A()\na, b = a_var.attr, 1\n')
+        self.mod.write(self.a_class)
+        self.refactoring.encapsulate_field(self.mod, self.mod.read().index('attr') + 1)
+        self.assertEquals(
+            'import mod\na_var = mod.A()\na, b = a_var.get_attr(), 1\n',
+            self.mod1.read())
+    
     def test_changing_augmented_assignments(self):
         self.mod1.write('import mod\na_var = mod.A()\na_var.attr += 1\n')
         self.mod.write(self.a_class)