Package: megrok.resource
megrok.resourceis a package destined to integratehurry.resourceandz3c.hashedresourceinto Grok applications.SetupLet’s import and init the necessary work environment:>>> import grokcore.component as grok
>>> from zope.testbrowser.testing import Browser

>>> browser = Browser()
>>> browser.handleErrors = FalseLibraryA Library is a component meant to expose a folder containing
resources:>>> from megrok import resource

>>> class SomeCSS(resource.Library):
...    resource.path('ftests/css')

>>> grok.testing.grok_component('somecss', SomeCSS)
TrueOnce grokked, the library provides the ILibrary interface and gets an
accessible name:>>> from megrok.resource import ILibrary
>>> ILibrary.providedBy(SomeCSS)
True

>>> SomeCSS.name
'somecss'At this point, it should be accessible via the component architecture
as a named adapter:>>> from zope.component import getAdapter
>>> from zope.publisher.browser import TestRequest
>>> library = getAdapter(TestRequest(), name='somecss')
>>> library
<grokcore.view.components.DirectoryResource object at ...>ResourcesSimple resourcesResources can be declared as part of their library, with their
dependencies:>>> css_a = resource.ResourceInclusion(SomeCSS, 'a.css')
>>> css_b = resource.ResourceInclusion(SomeCSS, 'b.css')Grouping resourcesSometimes, resources need to be grouped logically. They can be
declared in a group inclusion:>>> css_group = resource.GroupInclusion([css_a, css_b])
>>> css_group.inclusions()
[<ResourceInclusion 'a.css' in library 'somecss'>,
 <ResourceInclusion 'b.css' in library 'somecss'>]Library resourceSometimes, it can be too cumbersome to declare the resources and the
library separatly. When the resource is not destined to be re-used, it
can be tempting to register everything with a single declaration. The
ResourceLibrary component is what you need in these situations.A Resource library is a mix between a library and a group
inclusion. You need to define the usual path and name and then, the
linked resources:>>> class EasyResources(resource.ResourceLibrary):
...    resource.path('ftests/css')
...    resource.resource('a.css')
...    resource.resource('b.css')

>>> grok.testing.grok_component('someresources', EasyResources)
TrueOnce the component has been grokked, the resources are available:>>> EasyResources.inclusions()
[<ResourceInclusion 'a.css' in library 'easyresources'>,
 <ResourceInclusion 'b.css' in library 'easyresources'>]Including resources in componentsWhen rendering a web page we want to be able to include the resources
where we need them.There are several ways to include them. It can be done automatically
upon traversal on any IResourcesIncluder component, or manually specified.Traversal inclusionFor this example, we’ll create a view and use the automatic inclusion,
using theincludedirective:>>> from grokcore import view
>>> from zope.interface import Interface

>>> class MyView(view.View):
...   grok.context(Interface)
...   resource.include(css_a)
...
...   def render(self): return ""For the resources to be automatically included during the traversal,
we need to inform the publishing machinery that our component (the
view), is a IResourcesIncluder. This is done automatically, when using
the “include” directive:>>> resource.IResourcesIncluder.implementedBy(MyView)
TrueOf course, this should not remove the existing interfaces
implementations:>>> from zope.interface import Interface
>>> class IMySuperIface(Interface): pass

>>> class MyView(view.View):
...   grok.context(Interface)
...   grok.implements(IMySuperIface)
...   resource.include(css_a)
...
...   def render(self): return "<html><head></head></html>"

>>> resource.IResourcesIncluder.implementedBy(MyView)
True
>>> IMySuperIface.implementedBy(MyView)
TrueTheincludedirective can be stacked, if several resources are to be
included:>>> class AnotherView(MyView):
...   resource.include(css_a)
...   resource.include(css_b)

>>> grok.testing.grok_component('AnotherView', AnotherView)
True

>>> browser.open('http://localhost/@@anotherview')
>>> print browser.contents
<html><head>
  <link... href="http://localhost/@@/++noop++.../somecss/a.css" />
  <link... href="http://localhost/@@/++noop++.../somecss/b.css" />
</head></html>A ResourceLibrary component can be included just like a normal resource:>>> class YetAnotherView(view.View):
...   grok.context(Interface)
...   resource.include(EasyResources)
...
...   def render(self):
...     return u"<html><head></head></html>"

>>> grok.testing.grok_component('yav', YetAnotherView)
True

>>> browser.open('http://localhost/@@yetanotherview')
>>> print browser.contents
<html><head>
  <link... href="http://localhost/@@/++noop++.../easyresources/a.css" />
  <link... href="http://localhost/@@/++noop++.../easyresources/b.css" />
</head></html>Include validationTheincludedirective will raise an error if the provided value is
not a valid inclusion object:>>> sneaky = object()

>>> class FailingView(view.View):
...   grok.context(Interface)
...   resource.include(sneaky)
...
...   def render(self):
...     return u""
Traceback (most recent call last):
...
ValueError: You can only include IInclusion or ResourceLibrary components.It should accept non-grokked ResourceLibraries as valid inclusions:>>> class OtherResources(resource.ResourceLibrary):
...    resource.path('ftests/css')
...    resource.resource('a.css')

>>> class TolerantView(view.View):
...   grok.context(Interface)
...   resource.include(OtherResources)
...
...   def render(self):
...     return u""Remote inclusionUntil now, we’ve seen that the resource inclusion could be made using
theincludedirective. However, it can be very useful to be able to
set inclusion on classes we don’t “own”. This “remote” inclusion is
done using thecomponent_includesfunction.We first register a view that includes no resources:>>> class DummyView(view.View):
...   grok.context(Interface)
...
...   def render(self):
...     return u"<html><head></head></html>"

>>> grok.testing.grok_component('dummy', DummyView)
TrueThe view class doesn’t implement the needed interface:>>> resource.IResourcesIncluder.implementedBy(DummyView)
FalseNow, we can use the remote inclusion function, to enable resources:>>> resource.component_includes(DummyView, css_group)
>>> resource.IResourcesIncluder.implementedBy(DummyView)
True
>>> resource.include.bind().get(DummyView)
[<hurry.resource.core.GroupInclusion object at ...>]This function can be used either on a class or an instance:>>> class UselessView(view.View):
...   grok.context(Interface)
...
...   def render(self): return u""

>>> grok.testing.grok_component('useless', UselessView)
True

>>> from zope.component import getMultiAdapter
>>> useless = getMultiAdapter(
...             (object(), TestRequest()), name="uselessview")
>>> useless
<megrok.resource.ftests.UselessView object at ...>

>>> resource.component_includes(useless, css_group)
>>> resource.IResourcesIncluder.providedBy(useless)
True
>>> resource.include.bind().get(useless)
(<hurry.resource.core.GroupInclusion object at ...>,)Cache and hashYou probably noticed the “++noop++” traverser, in the resource
URL. This is used to provide a hash and therefore, a unique URL. It
can be very useful to work with caches and avoid outdated resources to
be served.However, it can happen that this behavior (by default) is unwanted. To
disable the use of the hashed URL, we can use theuse_hashdirective
and set its value to False. This can be done either in the class
definition or by using the directivesetmethod:>>> from megrok.resource import use_hash
>>> use_hash.set(SomeCSS, False)

>>> browser.open('http://localhost/@@anotherview')
>>> print browser.contents
<html><head>
  <link... href="http://localhost/@@/somecss/a.css" />
  <link... href="http://localhost/@@/somecss/b.css" />
</head></html>Changelog0.5 (2010-07-24)Removed specific ILibrary interface and now use the one from hurry.resource
so the ILibraryUrl adapter found is the same for megrok.resource.Library and
hurry.resource.Library. You need hurry.zoperesource 0.5 to have hashed
resource for hurry.resource.Library instances.0.4.1 (2010-02-19)Fixed the case where a ResourceLibrary is included using the
“include” directive, in the same package. It was triggering an error
because a non-grokked ResourceLibrary does not provideIInclusion. The directive now checks the subclass of the value to
determine if the given inclusion is a validIInclusionor a
ResourceLibrary sub-class.0.4 (2010-02-18)Cleaned the dependencies : everything is declared as it
should.zope.siteis now a main and not test dependency.Renamed module “traversal” to “url”, to describe accurately what the
module is about : url computation.“mode” fromhurry.resourceis now exposed by the package.0.3 (2009-12-23)The IResourcesIncluder interface is now automatically implemented
by the class while using theincludedirective. This makes the
whole system a lot more natural.The interfaces have been moved to a dedicated module. If you used
to import fromcomponents, please, correct your code.0.2 (2009-12-22)Added a ResourceLibrary component that is a mix between a Library
and a GroupInclusion. It allows to declare both the Library and the
Resources in a single class but impacts the re-usability.Library now directly inherits from grokcore.view.DirectoryResource,
to inherit thegetmethod behavior. This inheritance was avoided
to prevent grokkers clash (grokcore.view.DirectoryResource grokker
doesn’t have a fallback for thenamedirective.). Our grokker has
now the priority and explicitly set thenamedirective value.0.1 (2009-12-21)Initial release