Package: megrok.resourcelibrary
megrok.resourcelibrary: Resources in GrokIntroductionGrok already comes equipped with a simple way to expose static file
resources, thestaticdirectory.megrok.resourcelibraryallows the more flexible inclusion of
static file resources in Grok. It uses thezc.resourcelibrarypackage to do this.A resource library is essentially like a directory like thestaticdirectory of a package, full of static resources, such as CSS files,
javascript files and images. Resources are intended to be used from
HTML pages, as additional resources to help display a particular
layout or user interface.How ismegrok.resourcelibrarymore flexible than Grok’s defaultstaticdirectory?A resource library can be in a layer.A resource library can have a non-public permission.A resource library can more easily be packaged for reuse by other
libraries. Resource libraries have unique names under the control of
the developer.A resource library can automatically include some resources (such as
javascript or css) in theheadsection of a web page whenever a
particular widget needs it.A resource library can also depend on other libraries.Basic exampleLet’s see how this all works. First we need to grok this package
itself (this is normally done from ZCML):>>> from grok.testing import grok
>>> grok('megrok.resourcelibrary.meta')Now we can set up a simple resource library:>>> import grok
>>> import megrok.resourcelibrary
>>> class SomeLibrary(megrok.resourcelibrary.ResourceLibrary):
...     megrok.resourcelibrary.directory('tests/example')We need to grok this to make it available (in normal use this is done
automatically for you):>>> from grok.testing import grok_component
>>> grok_component('SomeLibrary', SomeLibrary)
TrueThe resources in this directory are now published, by default under
the class name of the library, lower cased (thereforesomelibrary):>>> from zope.testbrowser.testing import Browser
>>> browser = Browser()
>>> browser.open('http://localhost/@@/somelibrary/my-lib/included.js')
>>> print browser.contents
    function be_annoying() {
    alert('Hi there!');
}The default name can be overridden by using thegrok.namedirective:>>> class SomeLibrary2(megrok.resourcelibrary.ResourceLibrary):
...     grok.name('some-library')
...     megrok.resourcelibrary.directory('tests/example')
>>> grok_component('SomeLibrary2', SomeLibrary2)
True
>>> browser.open('http://localhost/@@/some-library/my-lib/included.js')
>>> print browser.contents
    function be_annoying() {
    alert('Hi there!');
}It’s an error to point to a directory that doesn’t exist:>>> class WrongDirectory(megrok.resourcelibrary.ResourceLibrary):
...     grok.name('wrong-directory')
...     megrok.resourcelibrary.directory('tests/doesnt_exist')
>>> grok_component('WrongDirectory', WrongDirectory)
Traceback (most recent call last):
  ...
GrokError: Directory 'tests/doesnt_exist' is not a valid directory passed to the 'wrong-directory' directive.Automactic inclusion of resourcesWe now set up a resource library that automatically includes two
resources whenever it is used in a web page, namelyincluded.jsandincluded.css:>>> class MyLib(megrok.resourcelibrary.ResourceLibrary):
...    grok.name('my-lib')
...    megrok.resourcelibrary.directory('tests/example/my-lib')
...    megrok.resourcelibrary.include('included.js')
...    megrok.resourcelibrary.include('included.css')
>>> grok_component('MyLib', MyLib)
TrueThis is how you require the library to be loaded in a particular page
template:<tal:block replace="resource_library:my-lib"/>test_template_2makes this requirement, so the included Javascript
should be included:>>> browser.open('http://localhost/zc.resourcelibrary.test_template_2')
>>> '/@@/my-lib/included.js' in browser.contents
TrueAnd the resource is also published:>>> browser.open('/@@/my-lib/included.js')
>>> print browser.contents
    function be_annoying() {
    alert('Hi there!');
}A reference to the CSS is also inserted into the HTML:>>> browser.open('http://localhost/zc.resourcelibrary.test_template_2')
>>> '/@@/my-lib/included.css' in browser.contents
TrueAnd the CSS is available from the URL referenced:>>> browser.open('/@@/my-lib/included.css')
>>> print browser.contents
div .border {
    border: 1px silid black;
}Programmatically signalling resource requirementsAbove we’ve demonstrated the use of theresource_librarynamespace
in ZPT. Library usage can also be signalled programmatically, for
instance in a view:>>> import grok
>>> from zope.interface import Interface
>>> class View(grok.View):
...   grok.context(Interface)
...   def render(self):
...      MyLib.need()
...      return '<html><head></head><body>Example</body></html>'
>>> grok_component('View', View)
True

>>> browser.open('http://localhost/view')
>>> '/@@/my-lib/included.js' in browser.contents
TrueThis also works for libraries which don’t have an explicitgrok.name:>>> class MyLib2(megrok.resourcelibrary.ResourceLibrary):
...    megrok.resourcelibrary.directory('tests/example/my-lib')
...    megrok.resourcelibrary.include('included.js')
...    megrok.resourcelibrary.include('included.css')
>>> grok_component('MyLib2', MyLib2)
True

>>> class View2(grok.View):
...   grok.context(Interface)
...   def render(self):
...      MyLib2.need()
...      return '<html><head></head><body>Example</body></html>'
>>> grok_component('View2', View2)
True

>>> browser.open('http://localhost/view2')
>>> '/@@/mylib2/included.js' in browser.contents
TrueYou can also signal inclusion by library name instead (like is done in page templates):>>> class View3(grok.View):
...   grok.context(Interface)
...   def render(self):
...      megrok.resourcelibrary.need('my-lib')
...      return '<html><head></head><body>Example</body></html>'

>>> grok_component('View3', View3)
True

>>> browser.open('http://localhost/view3')
>>> '/@@/my-lib/included.js' in browser.contents
TrueMaking resource libraries depend on other onesWe can make a resource library depend on another one:>>> class Dependency(megrok.resourcelibrary.ResourceLibrary):
...    megrok.resourcelibrary.directory('tests/example')
...    megrok.resourcelibrary.include('1.js')
>>> grok_component('Dependency', Dependency)
True

>>> class Dependent(megrok.resourcelibrary.ResourceLibrary):
...    megrok.resourcelibrary.directory('tests/example')
...    megrok.resourcelibrary.include('2.css')
...    megrok.resourcelibrary.depend(Dependency)
>>> grok_component('Dependent', Dependent)
TrueLet’s make a view that needsDependent:>>> class DependentView(grok.View):
...   grok.context(Interface)
...   def render(self):
...      Dependent.need()
...      return '<html><head></head><body>Example</body></html>'
>>> grok_component('DependentView', DependentView)
TrueThe included code of both the original and the dependency will now
show up:>>> browser.open('http://localhost/dependentview')
>>> '/@@/dependency/1.js' in browser.contents
True
>>> '/@@/dependent/2.css' in browser.contents
TrueProtecting resourcesIt’s possible to give a resource a permission:>>> class MyPermission(grok.Permission):
...    grok.name("my.permission")
>>> grok_component('MyPermission', MyPermission)
True

>>> class MyLib3(megrok.resourcelibrary.ResourceLibrary):
...    megrok.resourcelibrary.directory('tests/example/my-lib')
...    grok.require(MyPermission)
>>> grok_component('MyLib3', MyLib3)
TrueXXX This doesn’t work yet, as resources don’t do their own security
checks but rely on proxies, which Grok has removed… Need to introduce
new resources/factories to do checks by hand.Changes0.9.2 (2008-08-08)Grokker mistakenly relied on (not imported)GrokImportErrorin failure
case. Corrected this toGrokErrorand added a test for it.Renameusedirective todependand make it take a class
argument instead of a library name.0.9.1 (2008-08-06)Turn off zip-safeness.Actually add a meta.zcml that loads up the grokker!0.9 (2008-08-06)Initial public release.