Commits

Anonymous committed d4a653a

Moving write to FileSystemCommands

  • Participants
  • Parent commits 395cec3

Comments (0)

Files changed (10)

docs/dev/issues.txt

 Hot Topics
 ==========
 
+* `Releasing library package`_
+* `Library And Sharing File Changes`_
 
 To Be Discussed
 ===============
 
-* `Releasing library package`_
 * `Memory management`_
 * `Getting ready for Python 3.0`_
 * Should `rope.base` be thread safe? which parts?
 
 
+Library And Sharing File Changes
+================================
+
+The problem is that rope needs to perform some of the changes to
+activate some of its features like automatic SOI.  But other tools
+might want to perform the changes themselves.  There are two problems.
+
+* Informing others about the changes rope performs
+* Tools should inform rope about the changes they want to perform
+
+One way is to collect all file-system operations inside
+`FileSystemCommands`.
+
+Actions that change the file-system:
+
+* move
+* create_file
+* create_folder
+* remove
+* write
+
+Actions that read the file-system:
+
+* read
+* get_children
+* is_folder
+* exists
+* abspath
+
+Note that we don't need to put the actions that don't change the state
+of FS in the `FileSystemCommands`.  Since rope knows that it is
+working on a real file-system.
+
+
 Releasing Library Package
 =========================
 
 
 I think it is now the time.
 
-Things to do:
-
 * A new ``setup.py`` for making and registering library package
 * The library package will contain `rope`, `rope.base`, and
   `rope.refactor` packages
+* The name of packages: using ``rope`` for the library and
+  ``ropeide`` for the IDE
 
 Issues:
 
-* Two separate README files?
-* The name of packages: using ``rope`` for the library and
-  ``ropeide``, ``rope_ide``, ``rope-ide`` or ``pyrope`` for the IDE
+* Two separate ``README.txt`` files?
 * Should the IDE contain the library?
 * Separating common, library, and IDE documents
 
 ====================
 
 In order to simplify problems a bit, rope makes some assumptions about
-the source code.  In futures some of this restrictions might be
+the source code.  In future some of this restrictions might be
 removed.
 
 * All files that end with ``.py`` are considered to be python files

docs/dev/stories.txt

 * Enhanced occurrence finding
 
 
-* Enhancing open project dialog
-
-
 * Move refactoring and moving a group of elements together
 
 
 * Lambdas as functions; consider their parameters
 
 
-> Public Release 0.6m4 : July 1, 2007
+* Enhancing open project dialog
 
 
 * Split tuple assignment refactoring
+
+
+> Public Release 0.6m4 : July 1, 2007

docs/dev/workingon.txt

-Small Stories
-=============
+Being A Better Library
+======================
+
+- Moving write to `FileSystemCommands`
 
 * Handling strings in following lines in `patchedast`
 * Extracting subexpressions; look at `extracttest` for more info
-* Create ... and implicit interfaces
+* Create ... and implicit interfaces?
 * Add custom refactoring section to ``overview.txt`` file;
   Extract field refactoring
 * Handle tuple parameters?
 `screenshots`_.
 
 .. _overview.txt: user/overview.html
-.. _`screenshots`: screenshots/screenshots.html
+.. _screenshots: screenshots/screenshots.html
 
 
 Download

rope/base/change.py

 import os
 import time
 
+import rope.base.fscommands
 from rope.base import taskhandle
 from rope.base.exceptions import RopeError
-from rope.base.fscommands import FileSystemCommands
 
 
 class Change(object):
     def __init__(self, project, fscommands):
         self.project = project
         self.fscommands = fscommands
-        self.direct_commands = FileSystemCommands()
+        self.direct_commands = rope.base.fscommands.FileSystemCommands()
 
     def _get_fscommands(self, resource):
         if self.project.is_ignored(resource):
         return self.fscommands
 
     def write_file(self, resource, contents):
-        self.project.file_access.write(resource.real_path, contents)
+        data = rope.base.fscommands.unicode_to_file_data(contents)
+        fscommands = self._get_fscommands(resource)
+        fscommands.write(resource.real_path, data)
         for observer in list(self.project.observers):
             observer.resource_changed(resource)
 

rope/base/fscommands.py

         else:
             shutil.rmtree(path)
 
+    def write(self, path, data):
+        file_ = open(path, 'w')
+        try:
+            file_.write(data)
+        finally:
+            file_.close()
+
 
 class SubversionCommands(object):
 
     def remove(self, path):
         self.client.remove(path, force=True)
 
+    def write(self, path, data):
+        self.normal_actions.write(path, data)
+
 
 class MercurialCommands(object):
 
     def remove(self, path):
         self.client.remove(self.ui, self.repo, path)
 
+    def write(self, path, data):
+        self.normal_actions.write(path, data)
 
-class FileAccess(object):
 
-    def read(self, path):
-        """Read the content of the file at `path`.
+def unicode_to_file_data(contents):
+    return _TransformUnicode.get_instance().unicode_to_file_data(contents)
 
-        Returns a `Unicode` object
-        """
-        source_bytes = open(path, 'U').read()
-        return self._file_data_to_unicode(source_bytes)
 
-    def _file_data_to_unicode(self, data):
+def file_data_to_unicode(contents):
+    return _TransformUnicode.get_instance().file_data_to_unicode(contents)
+
+
+class _TransformUnicode(object):
+
+    def unicode_to_file_data(self, contents):
+        encoding = self._conclude_file_encoding(contents)
+        if encoding is not None and isinstance(contents, unicode):
+            return contents.encode(encoding)
+        try:
+            return contents.encode()
+        except UnicodeEncodeError:
+            return contents.encode('utf-8')
+
+    def file_data_to_unicode(self, data):
         encoding = self._conclude_file_encoding(data)
         if encoding is not None:
             return unicode(data, encoding)
 
     def _conclude_file_encoding(self, source_bytes):
         first_two_lines = source_bytes[:self._get_second_line_end(source_bytes)]
-        match = FileAccess.encoding_pattern.search(first_two_lines)
+        match = _TransformUnicode.encoding_pattern.search(first_two_lines)
         if match is not None:
             return match.group(1)
 
-    def write(self, path, contents):
-        """Write the `contents` to the file at `path`.
+    file_access = None
 
-        contents should be a `Unicode` object.
-        """
-        file_ = open(path, 'w')
-        encoding = self._conclude_file_encoding(contents)
-        if encoding is not None and isinstance(contents, unicode):
-            contents = contents.encode(encoding)
-        try:
-            file_.write(contents)
-        except UnicodeEncodeError:
-            # Using ``utf-8`` if guessed encoding fails
-            file_.write(contents.encode('utf-8'))
-        file_.close()
+    @classmethod
+    def get_instance(cls):
+        if cls.file_access is None:
+            cls.file_access = _TransformUnicode()
+        return cls.file_access

rope/base/project.py

 
     def __init__(self, fscommands):
         self.observers = []
-        self.file_access = rope.base.fscommands.FileAccess()
         self._history = None
         self.operations = rope.base.change._ResourceOperations(self, fscommands)
         self.prefs = rope.base.prefs.Prefs()

rope/base/pycore.py

                 old_contents = self.project.history.get_prev_contents(resource)
                 new_contents = resource.read()
                 # detecting changes in new_contents relative to old_contents
-                detector = TextChangeDetector(new_contents, old_contents)
+                detector = _TextChangeDetector(new_contents, old_contents)
                 def should_analyze(pydefined):
                     scope = pydefined.get_scope()
                     return detector.is_changed(scope.get_start(),
     def analyze_module(self, resource, should_analyze=None):
         """Analyze `resource` module for static object inference
 
-        This function forces rope to analyze this module to concluded
-        information about function calls.
+        This function forces rope to analyze this module to collect
+        information about function calls.  `should_analyze` is a
+        function that is called with a `DefinedObject` argument.  If
+        it returns `True` the element is analyzed.  If it is `None` or
+        returns `False` the element is not searched.
 
         """
         pymodule = self.resource_to_pyobject(resource)
             return self.class_lines
 
 
-class TextChangeDetector(object):
+class _TextChangeDetector(object):
 
     def __init__(self, old, new):
         self.old = old

rope/base/resources.py

 import os
 
 import rope.base.change
+import rope.base.fscommands
 from rope.base.exceptions import RopeError
 
 
         super(File, self).__init__(project, name)
 
     def read(self):
-        return self.project.file_access.read(self.real_path)
+        data = open(self.real_path, 'U').read()
+        return rope.base.fscommands.file_data_to_unicode(data)
 
     def write(self, contents):
         try:

ropetest/pycoretest.py

 import sys
 import unittest
 
-from rope.base.pycore import ModuleNotFoundError, TextChangeDetector
+from rope.base.pycore import ModuleNotFoundError, _TextChangeDetector
 from rope.base.pyobjects import get_base_type
 from ropetest import testutils
 
 class TextChangeDetectorTest(unittest.TestCase):
 
     def test_trivial_case(self):
-        detector = TextChangeDetector('\n', '\n')
+        detector = _TextChangeDetector('\n', '\n')
         self.assertFalse(detector.is_changed(1, 1))
 
     def test_one_line_change(self):
-        detector = TextChangeDetector('1\n2\n', '1\n3\n')
+        detector = _TextChangeDetector('1\n2\n', '1\n3\n')
         self.assertFalse(detector.is_changed(1, 1))
         self.assertTrue(detector.is_changed(2, 2))
 
     def test_line_expansion(self):
-        detector = TextChangeDetector('1\n2\n', '1\n3\n4\n2\n')
+        detector = _TextChangeDetector('1\n2\n', '1\n3\n4\n2\n')
         self.assertFalse(detector.is_changed(1, 1))
         self.assertFalse(detector.is_changed(2, 2))
 
     def test_line_removals(self):
-        detector = TextChangeDetector('1\n3\n4\n2\n', '1\n2\n')
+        detector = _TextChangeDetector('1\n3\n4\n2\n', '1\n2\n')
         self.assertFalse(detector.is_changed(1, 1))
         self.assertTrue(detector.is_changed(2, 3))
         self.assertFalse(detector.is_changed(4, 4))
 
     def test_multi_line_checks(self):
-        detector = TextChangeDetector('1\n2\n', '1\n3\n')
+        detector = _TextChangeDetector('1\n2\n', '1\n3\n')
         self.assertTrue(detector.is_changed(1, 2))