Christian Boos wrote:
> Hello Alec,
>
> On Oct 30, 5:45 pm, "Alec Thomas" <[EMAIL PROTECTED]> wrote:
>   
>>     Is it a big deal if we put this logic into the constructor? The only
>>     difference will be that it will always return a new object rather
>>     than sometimes returning the resource object passed in.
>>
>>     This would leave us with:
>>
>>       - Resource(realm, id, version)
>>       - Resource(resource)
>>     
>
> Well, the only purpose of Resource.from_spec was to avoid the
> Resource(resource) case and the creation of an unneeded object.
> But there's a simple trick here to return resource itself in the
> second case, so it might be worth doing it.
>   

See attached patch. Would that be OK?

>>     Which I think is a lot cleaner and simpler.
>>
>>   - I'd prefer it if Resource.__call__() was renamed to clone, duplicate or
>>     copy or something.
>>     
>
> Any would be fine for me, like copy(). OK, then we need to do the same
> on Context. 

Actually, with the patch above, such a method wouldn't be needed 
anymore, doing a copy + override can be a simple call to 
Resource(resource, version=None), for example. But the change would be 
rather involved, as I would need to go through all the resource() calls.

For context, it's a bit different, on second thought I think it's 
actually better kept like this, as we have plenty of calls to e.g. 
context('ticket', id) in the templates, which are nicer than e.g. 
context.subcontext('ticket', id), I think.

-- Christian


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac 
Development" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/trac-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

context-refactoring: removed `Resource.from_spec` in favor of an improved 
Resource() constructor call, based on `Resource.__new__`.

We also put the emphasis here on using `False` for the default argument for 
`id` and `version`.
This is especially important for `version`, where an explicit `None` value can 
be given, in order to specify the "latest" version.

diff -r 95d92e41b15e trac/mimeview/api.py
--- a/trac/mimeview/api.py      Tue Oct 30 19:48:51 2007 +0100
+++ b/trac/mimeview/api.py      Wed Oct 31 14:07:52 2007 +0100
@@ -116,11 +116,11 @@ class Context(object):
                      generated output to "authorized" informations only
         """
         self.parent = None #: The parent context, if any
-        self.resource = Resource.from_spec(resource)
+        self.resource = resource
         self.href = href
         self.perm = perm
 
-    def from_request(cls, req, resource=None, id=None, version=None,
+    def from_request(cls, req, resource=None, id=False, version=False,
                      absurls=False):
         """Create a rendering context from a request.
 
@@ -151,8 +151,8 @@ class Context(object):
         else:
             href = None
             perm = None
-        self = cls(Resource.from_spec(resource, id=id, version=version),
-                   href=href, perm=perm)
+        self = cls(Resource(resource, id=id, version=version), href=href,
+                   perm=perm)
         self.req = req
         return self
     from_request = classmethod(from_request)
@@ -166,7 +166,7 @@ class Context(object):
             context = context.parent
         return '<%s %s>' % (type(self).__name__, ' - '.join(reversed(path)))
 
-    def __call__(self, resource, id=None, version=None):
+    def __call__(self, resource, id=False, version=False):
         """Create a nested rendering context.
 
         `self` will be the parent for the new nested context.
@@ -183,12 +183,10 @@ class Context(object):
         >>> ticket1 = Resource('ticket', 1)
         >>> context('ticket', 1).resource == ticket1
         True
-        >>> context(ticket1).resource == ticket1
-        True
-        >>> context(ticket1).resource == ticket1
+        >>> context(ticket1).resource is ticket1
         True
         """
-        resource = Resource.from_spec(resource, id=id, version=version)
+        resource = Resource(resource, id=id, version=version)
         context = Context(resource, href=self.href, perm=self.perm)
         context.parent = self
 
@@ -197,7 +195,7 @@ class Context(object):
         # object being available, but that will hopefully improve in the
         # future
         if hasattr(self, 'req'):
-            context.req = self. req
+            context.req = self.req
 
         return context
 
diff -r 95d92e41b15e trac/mimeview/tests/api.py
--- a/trac/mimeview/tests/api.py        Tue Oct 30 19:48:51 2007 +0100
+++ b/trac/mimeview/tests/api.py        Wed Oct 31 14:07:52 2007 +0100
@@ -11,11 +11,13 @@
 # individuals. For the exact contribution history, see the revision
 # history and logs, available at http://trac.edgewall.org/log/.
 
+import doctest
 import unittest
 from StringIO import StringIO
 
 from trac.core import *
 from trac.test import EnvironmentStub
+from trac.mimeview import api
 from trac.mimeview.api import get_mimetype, IContentConverter, Mimeview, \
                               _group_lines
 from genshi import Stream, Namespace
@@ -210,6 +212,7 @@ class GroupLinesTestCase(unittest.TestCa
 
 def suite():
     suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(api))
     suite.addTest(unittest.makeSuite(GetMimeTypeTestCase, 'test'))
     suite.addTest(unittest.makeSuite(MimeviewTestCase, 'test'))
     suite.addTest(unittest.makeSuite(GroupLinesTestCase, 'test'))
diff -r 95d92e41b15e trac/perm.py
--- a/trac/perm.py      Tue Oct 30 19:48:51 2007 +0100
+++ b/trac/perm.py      Wed Oct 31 14:07:52 2007 +0100
@@ -447,11 +447,11 @@ class PermissionCache(object):
 
     def _normalize_resource(self, realm_or_resource, id, version):
         if realm_or_resource:
-            return Resource.from_spec(realm_or_resource, id, version)
+            return Resource(realm_or_resource, id, version)
         else:
             return self._resource
 
-    def __call__(self, realm_or_resource, id=None, version=None):
+    def __call__(self, realm_or_resource, id=False, version=False):
         """Convenience function for using thus: 
             'WIKI_VIEW' in perm(context) 
         or 
@@ -460,11 +460,11 @@ class PermissionCache(object):
             'WIKI_VIEW' in perm(resource)
 
         """
-        resource = Resource.from_spec(realm_or_resource, id, version)
+        resource = Resource(realm_or_resource, id, version)
         return PermissionCache(self.env, self.username, resource, self._cache)
 
-    def has_permission(self, action, realm_or_resource=None, id=None,
-                       version=None):
+    def has_permission(self, action, realm_or_resource=None, id=False,
+                       version=False):
         resource = self._normalize_resource(realm_or_resource, id, version)
         return self._has_permission(action, resource)
 
@@ -485,7 +485,7 @@ class PermissionCache(object):
             return decision
     __contains__ = has_permission
 
-    def require(self, action, realm_or_resource=None, id=None, version=None):
+    def require(self, action, realm_or_resource=None, id=False, version=False):
         resource = self._normalize_resource(realm_or_resource, id, version)
         if not self._has_permission(action, resource):
             raise PermissionError(action, resource)
diff -r 95d92e41b15e trac/resource.py
--- a/trac/resource.py  Tue Oct 30 19:48:51 2007 +0100
+++ b/trac/resource.py  Wed Oct 31 14:07:52 2007 +0100
@@ -93,15 +93,6 @@ class Resource(object):
     the real work to the Resource's manager.
     """
 
-    def __init__(self, realm, id=None, version=None, parent=None):
-        """Create a resource identifier."""
-        if not isinstance(realm, basestring):
-            raise TypeError("realm must be a string, got " + repr(realm))
-        self.realm = realm
-        self.id = id
-        self.version = version
-        self.parent = parent
-
     def __repr__(self):
         path = []
         r = self
@@ -132,52 +123,68 @@ class Resource(object):
 
     # -- methods for creating other Resource identifiers
 
-    def from_spec(cls, resource_or_realm, id=None, version=None):
+    def __new__(cls, resource_or_realm=False, id=False, version=False,
+                parent=False):
         """Create a new Resource object from a specification.
 
-        :param spec: this can be one of the following:
-                     - a `basestring`, which can be used to specify a `realm`
-                     - a `tuple`, which can be used to specify either a 
-                       resource `(realm,id)` or a specific version of a
-                       resource `(realm,id,version)`
-                     - `''` or `None`, which can be used to specify the
-                       whole environment
+        :param resource_or_realm: this can be either:
+                                   - a `Resource`, which is then used as a
+                                     base for making a copy
+                                   - a `basestring`, used to specify a `realm`
+        :param id: the resource identifier
+        :param version: the version or `None` for indicating the latest version
+
+        If `id` is overriden, then the original `version` value will not be
+        reused.
+
+        >>> main = Resource('wiki', 'WikiStart')
+        >>> repr(main)
+        "<Resource u'wiki:WikiStart'>"
+        
+        >>> Resource(main) is main
+        True
+
+        >>> repr(Resource(main, version=3))
+        "<Resource u'wiki:[EMAIL PROTECTED]'>"
+        
         """
+        realm = resource_or_realm
         if isinstance(resource_or_realm, Resource):
-            return resource_or_realm
-        if isinstance(resource_or_realm, tuple):
-            version = None
-            if len(resource_or_realm) == 3:
-                realm, id, version = resource_or_realm
-            elif len(resource_or_realm) == 2:
-                realm, id = resource_or_realm
+            if (id, version, parent) == (False, False, False):
+                return resource_or_realm
+            else: # copy and override
+                realm = resource_or_realm.realm
+            if id is False:
+                id = resource_or_realm.id
+            if version is False:
+                if id == resource_or_realm.id:
+                    version = resource_or_realm.version # could be 0...
+                else:
+                    version = None
+            if parent is False:
+                parent = resource_or_realm.parent
         else:
-            realm = resource_or_realm
-        return Resource(realm or '', id, version)
-    from_spec = classmethod(from_spec)
+            if id is False:
+                id = None
+            if version is False:
+                version = None
+            if parent is False:
+                parent = None
+        resource = super(Resource, cls).__new__(cls)
+        resource.realm = realm
+        resource.id = id
+        resource.version = version
+        resource.parent = parent
+        return resource
+
 
     def __call__(self, realm=False, id=False, version=False, parent=False):
         """Create a new Resource using the current resource as a template.
 
         Optional keyword arguments can be given to override `id` and
         `version`.
-        If `realm` is changed, then the original `id` and `version` values
-        will not be reused.
-        If `id` is changed, then the original `version` value will not be
-        reused.
         """
-        if realm is False:  # i.e. not set, so we stay in the same realm
-            realm = self.realm
-        if realm != self.realm:
-            return Resource(realm or '', id or None, version or None, parent)
-        else:
-            if id is False:
-                id = self.id
-            if version is False:
-                version = id == self.id and self.version or None
-            if parent is False:
-                parent = self.parent
-            return Resource(realm, id, version, parent)
+        return Resource(realm is False and self or realm, id, version, parent)
 
     # -- methods for retrieving children Resource identifiers
     
@@ -265,7 +272,7 @@ def get_resource_url(env, resource, href
     '/trac.cgi/generic/Main?action=diff&version=5'
     
     """
-    manager = ResourceSystem(env).get_resource_manager(resource.realm)    
+    manager = ResourceSystem(env).get_resource_manager(resource.realm)
     if not manager or not hasattr(manager, 'get_resource_url'):
         args = {'version': resource.version}
         args.update(kwargs)

Reply via email to