Commits

Ali Gholami Rudi  committed d15bfee

Handling constructors in SOI
Allowing nonexistent resources
Generating variables/classes/modules/packages

  • Participants
  • Parent commits 76ab590

Comments (0)

Files changed (9)

File docs/dev/issues.txt

 good idea.
 
 
+Inserting Blank Lines
+---------------------
+
+The blank lines inserted for an element depends on not only the
+element itself, but on the location is is being inserted, too.  Not
+thinking about the element inself the blank spaces can be specified
+so:
+
+* Module elements: 2 blank line
+* Class and function elements: 1 blank line
+
+But the trick here is that when we are insertion an element is the
+current scope these blank lines should be inserted at the end of the
+definition and otherwise it should be inserted at the beginning of it.
+
+
 Supporting Registers
 ====================
 
 * Use new function signature
 
 
-Allowing Non-Existent Resources
-===============================
-
-Instead of doing::
-
-  parent = project.get_resource('my_folder')
-  new_file = parent.create_file('my_file.txt')
-
-We can do::
-
-  new_file = project.get_file('my_folder/my_file.txt')
-  new_file.create(create_folders=False)
-
-
 Having Virtual `PyModule`\s
 ===========================
 

File docs/dev/workingon.txt

+Allowing Non-Existent Resources
+===============================
+
+- Handling constructors in SOI
+- `File.create`
+- `Folder.create`
+- Raising exception when resource already exists
+- Raising exception when the folder does not exist
+
+* Changing `CreateFile` and `CreateFolder` to require only one argument
+
+
+
 Generate Element
 ================
 
-- `get_location()`
-- Removing ``pass`` when adding the first entry to a class
+- Handling blank lines
+- Generating variables inside packages
+- Generating classes
+- Generating modules
+- Generating packages
 
-* Handling blank lines
-* Generating globals
-* Blanks before and after
-* A class with a single pass
-* Adding `generatetest` to testsuite
-* Generating variables inside packages
+* Generating functions
 * Generating methods
 * Generating `staticmethod`\s
+* Generating constructors
+
+* Moving `generate` to `rope.ide`?
+* Adding `generatetest` to testsuite
 * Error: already exists
 * Error: cannot be determined
 * Error: not a package
+* Adding `generate(kind)` factory
 
 * Recursive SOI; Go where the calls go
 * Adding an option not to collect per name information

File rope/base/evaluate.py

                 result.append(pyname.get_object())
         return result
 
+    def get_pynames(self, parameters):
+        return self.pynames
+
     def get_instance_pyname(self):
         return self.pynames[0]
 
 
+class MixedArguments(object):
+
+    def __init__(self, pyname, args, scope):
+        self.pyname = pyname
+        self.args = Arguments(args, scope)
+
+    def get_pynames(self, parameters):
+        return [self.pyname] + self.args.get_pynames(parameters[1:])
+
+    def get_arguments(self, parameters):
+        result = []
+        for pyname in self.get_pynames(parameters):
+            if pyname is None:
+                result.append(None)
+            else:
+                result.append(pyname.get_object())
+        return result
+
+    def get_instance_pyname(self):
+        return self.pyname
+
+
 def create_arguments(primary, pyfunction, call_func_node, scope):
     """A factory for creating `Arguments`'"""
     args = call_func_node.args

File rope/base/oi/staticoi.py

         if pyname is None:
             return
         pyfunction = pyname.get_object()
-        if '__call__' in pyfunction.get_attributes():
+        if not isinstance(pyfunction, pyobjects.PyClass) and \
+           '__call__' in pyfunction.get_attributes():
             pyfunction = pyfunction.get_attribute('__call__')
-        if not isinstance(pyfunction, pyobjects.AbstractFunction):
+        if isinstance(pyfunction, pyobjects.AbstractFunction):
+            args = evaluate.create_arguments(primary, pyfunction, node, scope)
+        elif isinstance(pyfunction, pyobjects.PyClass):
+            pyclass = pyfunction
+            if '__init__' in pyfunction.get_attributes():
+                pyfunction = pyfunction.get_attribute('__init__').get_object()
+            pyname = pynames.UnboundName(pyobjects.PyObject(pyclass))
+            args = evaluate.MixedArguments(pyname, node.args, scope)
+        else:
             return
-        args = evaluate.create_arguments(primary, pyfunction, node, scope)
         self._call(pyfunction, args)
 
     def _call(self, pyfunction, args):
             pyfunction.get_returned_object(args)
 
     def visitAssign(self, node):
+        for child in node.getChildNodes():
+            compiler.walk(child, self)
         visitor = _SOIAssignVisitor()
         nodes = []
         for child in node.nodes:

File rope/base/project.py

     def get_pycore(self):
         return self.pycore
 
+    def get_file(self, path):
+        return File(self, path)
+
+    def get_folder(self, path):
+        return Folder(self, path)
+
     def _get_resource_path(self, name):
         pass
 
     def is_folder(self):
         """Return true if the resource is a folder"""
 
+    def create(self):
+        """Create this resource"""
+
     def exists(self):
         return os.path.exists(self.real_path)
 
     def is_folder(self):
         return False
 
+    def create(self):
+        self.parent.create_file(self.name)
+
 
 class Folder(Resource):
     """Represents a folder"""
             return False
         return self.path == '' or resource.path.startswith(self.path + '/')
 
+    def create(self):
+        self.parent.create_folder(self.name)
+
 
 class ResourceObserver(object):
     """Provides the interface for observing resources

File rope/refactor/generate.py

 from rope.refactor import sourceutils
 
 
-class GenerateVariable(object):
+class _Generate(object):
 
     def __init__(self, project, resource, offset):
+        self.project = project
         self.insertion_location = _InsertionLocation(project.pycore,
                                                      resource, offset)
         self.name = codeanalyze.get_name_at(resource, offset)
 
     def get_changes(self):
-        changes = change.ChangeSet('Generate Variable %s' % self.name)
+        changes = change.ChangeSet('Generate %s <%s>' %
+                                   (self._get_element_kind(), self.name))
         indents = self.insertion_location.get_scope_indents()
-        definition = sourceutils.fix_indentation('%s = None\n' % self.name,
-                                                 indents)
+        blanks = self.insertion_location.get_blank_lines()
+        base_definition = sourceutils.fix_indentation(self._get_element(), indents)
+        definition = '\n' * blanks[0] + base_definition + '\n' * blanks[1]
 
         resource = self.insertion_location.get_insertion_resource()
         start, end = self.insertion_location.get_insertion_offsets()
         return (self.insertion_location.get_insertion_resource(),
                 self.insertion_location.get_insertion_lineno())
 
+    def _get_element_kind(self):
+        raise NotImplementedError()
+
+    def _get_element(self):
+        raise NotImplementedError()
+
+
+class GenerateVariable(_Generate):
+
+    def _get_element(self):
+        return '%s = None\n' % self.name
+
+    def _get_element_kind(self):
+        return 'Class'
+
+
+class GenerateClass(_Generate):
+
+    def _get_element(self):
+        return 'class %s(object):\n    pass\n' % self.name
+
+    def _get_element_kind(self):
+        return 'Class'
+
+
+class GenerateModule(_Generate):
+
+    def get_changes(self):
+        package = self.insertion_location.get_package()
+        changes = change.ChangeSet('Generate Module <%s>' % self.name)
+        changes.add_change(change.CreateFile(package, '%s.py' % self.name))
+        return changes
+
+    def get_location(self):
+        package = self.insertion_location.get_package()
+        return (package.get_child('%s.py' % self.name) , 1)
+
+
+class GeneratePackage(_Generate):
+
+    def get_changes(self):
+        package = self.insertion_location.get_package()
+        changes = change.ChangeSet('Generate Package <%s>' % self.name)
+        changes.add_change(change.CreateFolder(package, '%s' % self.name))
+        child = self.project.get_folder(package.path + '/' + self.name)
+        changes.add_change(change.CreateFile(child, '__init__.py'))
+        return changes
+
+    def get_location(self):
+        package = self.insertion_location.get_package()
+        child = package.get_child(self.name)
+        return (child.get_child('__init__.py') , 1)
+
 
 class _InsertionLocation(object):
 
             return 0
         return sourceutils.get_indents(self.goal_pymodule.lines,
                                        self.goal_scope.get_start()) + 4
+
+    def get_blank_lines(self):
+        if self.goal_scope.get_kind() == 'Module':
+            base_blanks = 2
+            if self.goal_pymodule.source_code.strip() == '':
+                base_blanks = 0
+        if self.goal_scope.get_kind() == 'Class':
+            base_blanks = 1
+        if self.goal_scope.get_kind() == 'Function':
+            base_blanks = 0
+        if self.goal_scope == self.source_scope:
+            return (0, base_blanks)
+        return (base_blanks, 0)
+
+    def get_package(self):
+        primary = self.primary
+        if primary and isinstance(primary.get_object(), pyobjects.PyPackage):
+            return primary.get_object().get_resource()

File ropetest/objectinfertest.py

         a_var = pymod.get_attribute('a_var').get_object()
         self.assertEquals(c1_class, a_var.get_type())
 
+    def test_soi_on_constructors(self):
+        code = 'class C1(object):\n    pass\n' \
+               'class C2(object):\n' \
+               '    def __init__(self, arg):\n        self.attr = arg\n' \
+               'c2 = C2(C1())\na_var = c2.attr'
+        self.mod.write(code)
+        self.pycore.analyze_module(self.mod)
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        c1_class = pymod.get_attribute('C1').get_object()
+        a_var = pymod.get_attribute('a_var').get_object()
+        self.assertEquals(c1_class, a_var.get_type())
+
 
 class DynamicOITest(unittest.TestCase):
 

File ropetest/projecttest.py

         project_file = 'NewFile.txt'
         parent_folder = self.project.get_resource(self.sample_folder)
         parent_folder.create_file(project_file)
-        newFile = self.project.get_resource(self.sample_folder
+        new_file = self.project.get_resource(self.sample_folder
                                             + '/' + project_file)
         self.assertTrue(new_file is not None and not new_file.is_folder())
 
-    def test_folder_creating_files(self):
+    def test_folder_creating_files2(self):
         projectFile = 'newfolder'
         self.project.root.create_folder(projectFile)
         new_folder = self.project.get_resource(projectFile)
         self.assertTrue(new_folder is not None and new_folder.is_folder())
 
-    def test_folder_creating_nested_files(self):
+    def test_folder_creating_nested_files2(self):
         project_file = 'newfolder'
         parent_folder = self.project.get_resource(self.sample_folder)
         parent_folder.create_folder(project_file)
         file.close()
         self.assertEquals(contents, sample_file.read())
 
+    def test_using_project_get_file(self):
+        myfile = self.project.get_file(self.sample_file)
+        self.assertTrue(myfile.exists())
+
+    def test_using_file_create(self):
+        myfile = self.project.get_file('myfile.txt')
+        self.assertFalse(myfile.exists())
+        myfile.create()
+        self.assertTrue(myfile.exists())
+        self.assertFalse(myfile.is_folder())
+
+    def test_using_folder_create(self):
+        myfolder = self.project.get_folder('myfolder')
+        self.assertFalse(myfolder.exists())
+        myfolder.create()
+        self.assertTrue(myfolder.exists())
+        self.assertTrue(myfolder.is_folder())
+
+    @testutils.assert_raises(RopeError)
+    def test_exception_when_creating_twice(self):
+        myfile = self.project.get_file('myfile.txt')
+        myfile.create()
+        myfile.create()
+
+    @testutils.assert_raises(RopeError)
+    def test_exception_when_parent_does_not_exist(self):
+        myfile = self.project.get_file('myfolder/myfile.txt')
+        myfile.create()
+
 
 class ResourceObserverTest(unittest.TestCase):
 

File ropetest/refactor/generatetest.py

         self.pycore = self.project.get_pycore()
         self.mod = self.pycore.create_module(self.project.root, 'mod1')
         self.mod2 = self.pycore.create_module(self.project.root, 'mod2')
+        self.pkg = self.pycore.create_package(self.project.root, 'pkg')
 
     def tearDown(self):
         ropetest.testutils.remove_recursively(self.project_root)
     def _get_generate(self, offset):
         return generate.GenerateVariable(self.project, self.mod, offset)
 
+    def _get_generate_class(self, offset):
+        return generate.GenerateClass(self.project, self.mod, offset)
+
+    def _get_generate_module(self, offset):
+        return generate.GenerateModule(self.project, self.mod, offset)
+
+    def _get_generate_package(self, offset):
+        return generate.GeneratePackage(self.project, self.mod, offset)
+
     def test_getting_location(self):
         code = 'a_var = name\n'
         self.mod.write(code)
         self.mod.write(code)
         changes = self._get_generate(code.index('name')).get_changes()
         self.project.do(changes)
-        self.assertEquals('name = None\na_var = name\n', self.mod.read())
+        self.assertEquals('name = None\n\n\na_var = name\n', self.mod.read())
 
     def test_generating_variable_inserting_before_statement(self):
         code = 'c = 1\nc = b\n'
         self.mod.write(code)
         changes = self._get_generate(code.index('b')).get_changes()
         self.project.do(changes)
-        self.assertEquals('c = 1\nb = None\nc = b\n', self.mod.read())
-
-    def test_generating_variable_in_local_scopes(self):
-        code = 'def f():\n    c = 1\n    c = b\n'
-        self.mod.write(code)
-        changes = self._get_generate(code.index('b')).get_changes()
-        self.project.do(changes)
-        self.assertEquals('def f():\n    c = 1\n    b = None\n    c = b\n',
-                          self.mod.read())
+        self.assertEquals('c = 1\nb = None\n\n\nc = b\n', self.mod.read())
 
     def test_generating_variable_in_local_scopes(self):
         code = 'def f():\n    c = 1\n    c = b\n'
         changes = self._get_generate(code.index('attr')).get_changes()
         self.project.do(changes)
         self.assertEquals(
-            'class C(object):\n    def f(self):\n        pass\n    attr = None\n' \
+            'class C(object):\n    def f(self):\n        pass\n\n    attr = None\n' \
             'c = C()\na_var = c.attr', self.mod.read())
 
     def test_generating_variable_in_classes_removing_pass(self):
         self.mod.write(code)
         changes = self._get_generate(code.index('attr')).get_changes()
         self.project.do(changes)
-        self.assertEquals('class C(object):\n    attr = None\n' \
+        self.assertEquals('class C(object):\n\n    attr = None\n' \
                           'c = C()\na_var = c.attr', self.mod.read())
 
+    def test_generating_variable_in_packages(self):
+        code = 'import pkg\na = pkg.a\n'
+        self.mod.write(code)
+        generator = self._get_generate(code.rindex('a'))
+        self.project.do(generator.get_changes())
+        init = self.pkg.get_child('__init__.py')
+        self.assertEquals((init, 1), generator.get_location())
+        self.assertEquals('a = None\n', init.read())
+
+    def test_generating_classes(self):
+        code = 'c = C()\n'
+        self.mod.write(code)
+        changes = self._get_generate_class(code.index('C')).get_changes()
+        self.project.do(changes)
+        self.assertEquals('class C(object):\n    pass\n\n\nc = C()\n',
+                          self.mod.read())
+
+    def test_generating_modules(self):
+        code = 'import pkg\npkg.mod\n'
+        self.mod.write(code)
+        generator = self._get_generate_module(code.rindex('mod'))
+        self.project.do(generator.get_changes())
+        mod = self.pkg.get_child('mod.py')
+        self.assertEquals((mod, 1), generator.get_location())
+
+    def test_generating_packages(self):
+        code = 'import pkg\npkg.pkg2\n'
+        self.mod.write(code)
+        generator = self._get_generate_package(code.rindex('pkg2'))
+        self.project.do(generator.get_changes())
+        pkg2 = self.pkg.get_child('pkg2')
+        init = pkg2.get_child('__init__.py')
+        self.assertEquals((init, 1), generator.get_location())
+
 
 if __name__ == '__main__':
     unittest.main()