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.

Reply via email to