Note: I wrote this "in context" of another mail, but the scope of the
question and my answer belongs more to Trac-dev...
On 4/20/2010 1:27 PM, Remy Blank wrote:
osimons wrote:
That still upholds the rule of the layer
whereby a resource should not be used to get the underlying model
object, and generally stay ignorant of the contruction and usage of
the model objects.
I wasn't yet involved in Trac when this was discussed, so excuse my
ignorance. What's the reason for not wanting a resource to be used to
get the underlying model object?
I'm not sure either if that was explicitly "forbidden".
Even the sample code in
http://trac.edgewall.org/wiki/TracDev/ContextRefactoring#ContextFactoriesandSubclasses
has such a method:
IResourceManager.resolve_resource(descriptor)
(verifying in the original Google doc where the above page was initially
elaborated, this was indeed written by cmlenz, #170)
I have often thought that a
resource_get_model(resource) function that gets the model object through
the relevant resource manager would be extremely useful.
Well, as you can't really call anything in a generic way from that model
object, it wouldn't be that useful, otherwise you risk to end up writing
things like: `if realm == 'wiki': (model is a WikiPage) elif realm ==
'ticket': (model is a ticket) ...`
Not good. But once you know you can call things like `model.exists`, or
you can do other useful things with a model object then it will make
sense. But maybe you had some other use cases in mind?
The other related use cases I can think of are the
IResourceChangeListener (discussed in
http://trac.edgewall.org/ticket/8834) and the IPermissionPolicy
interfaces. The components implementing these interfaces often have to
instantiate a model from the resource. But there, we always *know* which
class we have to instantiate, as we're anyway going to manipulate the
API specific to the realm. In this situation what's problematic is not
so much the possibility to create a model from a resource in a generic
way, but the fact that this creation has to be *repeated* over and over
again. This was often pointed out by Felix Schwartz, on #8834 and mails
on Trac-dev. There are several possibilities to fix this, either by
passing the model explicitly alongside the resource (but if the model is
not always needed, this will have an adverse effect on performance), or
by making it possible to retrieve the instance from the resource in an
efficient way: a) by attaching the model to the instance once we have it
(resource.model, initially None), or b) your
resource_get_model(resource), which could use a trac.util.ThreadLocal cache.
The advantage of a) is that it would be more explicit, we can better
track where a model has been instantiated the first time, whereas with
b) this might be more fuzzy, the instantiation might happen in unrelated
part of the code, so probably not a good idea.
a) alone would be cumbersome (`if resource.model is None: resource.model
= WikiPage(...)` all over the place), b) without caching would not solve
the problem of repeated instantiations, but a) and b) together might fit
the bill: when accessing resource.model the first time, a call to
`resource_get_model` could be made, binding the model to the resource.
Of course, this would be even nicer if we could write `resource.model`
instead of `resource.get_model(env)`. Storing the env in the resource
would make this possible. Not only that, but it would also make it
possible to have all the trac.resource helper functions as methods or
properties (`get_resource_url`, `get_resource_...` and even the
`resource_exists` introduced in my other mail, changed to an `exists`
property). I don't think this would add much to the memory usage, and
will certainly make the code nicer (e.g. `res.url(href)` instead of
`get_resource_url(env, res, href)`). I suppose there were some reasons
why this was frowned upon (having a `Resource.env`), but I don't really
remember what. Not to mention that if we would store the resource
manager itself instead of the env, we would avoid a component lookup
each time one of these helper is called...
-- 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.