Skip to main content
Join the official 2019 Python Developers SurveyStart the survey!

Static resource library support for Grok.

Project description

megrok.resourcelibrary: Resources in Grok

Introduction

Grok already comes equipped with a simple way to expose static file resources, the static directory.

megrok.resourcelibrary allows the more flexible inclusion of static file resources in Grok. It uses the zc.resourcelibrary package to do this.

A resource library is essentially like a directory like the static directory 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 is megrok.resourcelibrary more flexible than Grok’s default static directory?

  • 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 the head section of a web page whenever a particular widget needs it.
  • A resource library can also depend on other libraries.

Basic example

Let’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)
True

The resources in this directory are now published, by default under the class name of the library, lower cased (therefore somelibrary):

>>> 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 the grok.name directive:

>>> 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 resources

We now set up a resource library that automatically includes two resources whenever it is used in a web page, namely included.js and included.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)
True

This is how you require the library to be loaded in a particular page template:

<tal:block replace="resource_library:my-lib"/>

test_template_2 makes 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
True

And 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
True

And 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 requirements

Above we’ve demonstrated the use of the resource_library namespace 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
True

This also works for libraries which don’t have an explicit grok.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
True

You 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
True

Making resource libraries depend on other ones

We 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)
True

Let’s make a view that needs Dependent:

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

The 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
True

Protecting resources

It’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)
True

XXX 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.

Changes

0.9.2 (2008-08-08)

  • Grokker mistakenly relied on (not imported) GrokImportError in failure case. Corrected this to GrokError and added a test for it.
  • Rename use directive to depend and 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for megrok.resourcelibrary, version 0.9.2
Filename, size File type Python version Upload date Hashes
Filename, size megrok.resourcelibrary-0.9.2.tar.gz (8.2 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page