SlideShare une entreprise Scribd logo
1  sur  163
“ Using  Grok to Walk Like a Duck” The Zope 3 Component Architecture Brandon Craig Rhodes Plone Conference 2008, Washington, DC
How many methods does a Plone ATFolder have?
Contributors CreationDate Creator Creators DELETE Date Description EffectiveDate ExpirationDate Format HEAD Identifer Identifier LOCK Language MKCOL MKCOL_handler MOVE ModificationDate OPTIONS PROPFIND PROPPATCH PUT PUT_factory ZopeFind Publisher Rights SQLConnectionIDs Schema Schemata SearchableText Subject TRACE Title Type UID UNLOCK Vocabulary ZQueryIds ZopeFind ZopeFindAndApply __url __before_publishing_travers __bobo_traverse__ __browser_default__ __call__ __class_init__ __contains__ __delitem__ __getitem__ __init__ __iter__ __len__ __of__ __repr__ __setitem__ _facade _canCopy _catalogRefs _catalogUID _checkId _ct_defaultAddableTypeIds _ct_defaultConstrainTypesMo _ct_vocabularyPossibleTypes _datify _delOb _delObject _delPropValue _delProperty _delReferenceAnnotations _facade _deleteOwnershipAfterAdd _editMetadata _effective_date _expiration_date _filteredItems _findUniqueId _getCatalogTool _getCopy _getOb getPortalTypeName _getReferenceAnnotations _getURL _getWorkflowTool _get_id _has_user_defined_role _importObjectFromFile _isBeingAccessedAsZClassDef _isBeingUsedAsAMethod _isIDAutoGenerated _isSchemaCurrent _migrateGetValue _migrateSetValue _notifyOfCopyTo _postCopy _processForm _propertyMap _referenceApply _register _renameAfterCreation _setId _setOb _setObject _setPortalTypeName _setPropValue _setProperty _setRoles _setUID _subobject_permissions _uncatalogRefs _uncatalogUID _unregister _updateCatalog _updateProperty _updateSchema _verifyObjectPaste _wrapperCheck absolute_url absolute_url_path ac_inherited_permissions access_debug_info acquiredRolesAreUsedBy addCreator addDTMLDocument addDTMLMethod addReference addSubObjects all_meta_types allowDiscussion allowedContentTypes at_post_create_script at_post_edit_script autoOrderItems bobobase_modification_time canSetConstrainTypes canSetDefaultPage canSetLayout cb_dataItems cb_dataValid cb_isCopyable cb_isMoveable cb_userHasCopyOrMovePermiss changeOwnership checkCreationFlag checkIdAvailable class_manage_path cleanupLayers cmf_edit contentEffective contentExpired contentIds contentItems contentValues copyLayoutFromParent created dav__init dav__simpleifhandler dav__validate decodeFolderFilter defaultIsDiscussable defaultLanguage defaultRights defaultView deleteReference deleteReferences edit editIsDiscussable editMetadata effective encodeFolderFilter exclude_from_nav expires EditLink filtered_manage_options filtered_meta_types folderlistingFolderContents generateNewId get getActionInfo getAttribute getAttributeNode getAttributes getAvailableLayouts getBRefs getBRelationships getBackReferenceImpl getBRefs getCMFObjectsSubsetIds getCatalogs getCharset getChildNodes getConstrainTypesMode getContentType getDefault getDefaultAddableTypes getDefaultLayout getDefaultPage getDefaultSorting getEffectiveDate getElementsByTagName getExcludeFromNav getExpirationDate getField getFilename getFirstChild getFolderWhenPortalFactory getIcon getId getImmediatelyAddableTypes getLastChild getLayout getLocallyAllowedTypes getLocation getMetadataHeaders getNextPreviousEnabled getNextPreviousParentValue getNextSibling getNodeName getNodeType getNodeValue getObjectPosition getOwner getOwnerDocument getOwnerTuple getParentNode getPhysicalPath on.getPhysicalRoot getPortalTypeName getPreviousSibling getPrimaryField getProperty getPropertyType getRawConstrainTypesMode getRawContributors getRawCreation_date getRawCreators getRawDescription getRawEffectiveDate getRawExcludeFromNav getRawExpirationDate getRawId getRawImmediatelyAddableTyp getRawLanguage getRawLocallyAllowedTypes getRawLocation getRawModification_date getRawNextPreviousEnabled getRawRelatedItems getRawRights getRawSubject getRawTitle getReferenceImpl getReferenceMap getReferencePng getRefs getRefs getRelatedItems getRelationships getSiteManager getSortAuto getSortFolderishFirst getSortReverse getSubObject getTagName getTypeInfo getWrappedField getWrappedOwner getContentType get_local_roles get_local_roles_for_userid get_portal_metadata get_request_var_or_attr get_size get_valid_userids hasChildNodes hasObject hasProperty hasRelationshipTo has_local_roles http__etag http__parseMatchList http__processMatchHeaders http__refreshEtag getIcon indexObject initializeArchetype initializeLayers invokeFactory isBinary isDiscussable isTemporary isTransformable items keys languages listContributors listCreators listDAVObjects listFolderContents list_imports locked_in_version manage_CopyContainerAllItem manage_CopyContainerFirstIt manage_DAVget manage_FTPget manage_FTPlist manage_FTPstat manage_access _facade addDTMLDocument addDTMLMethod addDTMLMethod manage_addFile manage_addFolder manage_addImage _facade manage_addOrderedFolder manage_addProperty manage_addSiteRoot manage_addUserFolder manage_addZGadflyConnection manage_addZGadflyConnection manage_afterAdd manage_afterClone manage_afterMKCOL manage_afterPUT manage_beforeDelete _facade _facade manage_changeProperties manage_changePropertyTypes manage_clone manage_copyObjects manage_cutObjects manage_defined_roles _facade manage_delObjects manage_delProperties manage_editMetadata manage_editProperties manage_editRoles manage_editedDialog manage_exportObject manage_fixupOwnershipAfterA manage_getPermissionMapping manage_hasId manage_importObject manage_pasteObjects _facade manage_renameObject manage_renameObjects _facade _facade _facade _facade manage_undo_transactions manage_workflowsTab manage_workspace manage_zmi_logout markCreationFlag modified modified_in_version moveObject moveObjectToPosition moveObjectsByDelta moveObjectsDown moveObjectsToBottom moveObjectsToTop moveObjectsUp notifyModified notifyWorkflowCreated objectIds objectIds_d objectItems objectItems_d objectMap objectMap_d objectValues objectValues_d opaqueIds opaqueItems opaqueValues orderObjects owner_info permission_settings permissionsOfRole possible_permissions post_validate pre_validate processForm propdict propertyDescription propertyIds propertyItems propertyLabel propertyMap propertyValues raise_standardErrorMessage rawIsDiscussable reference_url reindexObject reindexObjectSecurity restrictedTraverse rolesOfPermission setConstrainTypesMode setContentType setContributors setCreationDate setCreators setDefaultPage setDefaultSorting setDefaults setDescription setEffectiveDate setExcludeFromNav setExpirationDate setFilename setFormat setId setImmediatelyAddableTypes setLanguage setLayout setLocallyAllowedTypes setLocation setModificationDate setNextPreviousEnabled setRelatedItems setRights setSiteManager setSortAuto setSortFolderishFirst setSortReverse setSubject setTitle superValues tabs_path_default tabs_path_info this title_and_id title_or_id tpURL tpValues undoable_transactions unindexObject unmarkCreationFlag unrestrictedTraverse update userCanTakeOwnership userdefined_roles users_with_local_role cb_dataValid valid_roles valid_property_id valid_roles validate validate_field validate_preferredTypes validate_roles values virtual_url_path widget wl_clearLocks wl_delLock wl_getLock wl_hasLock wl_isLocked wl_lockItems wl_lockTokens wl_lockValues wl_lockmapping wl_setLock
Contributors CreationDate Creator Creators DELETE Date Description EffectiveDate ExpirationDate Format HEAD Identifer Identifier LOCK Language MKCOL MKCOL_handler MOVE ModificationDate OPTIONS PROPFIND PROPPATCH PUT PUT_factory ZopeFind Publisher Rights SQLConnectionIDs Schema Schemata SearchableText Subject TRACE Title Type UID UNLOCK Vocabulary ZQueryIds ZopeFind ZopeFindAndApply __url __before_publishing_travers __bobo_traverse__ __browser_default__ __call__ __class_init__ __contains__ __delitem__ __getitem__ __init__ __iter__ __len__ __of__ __repr__ __setitem__ _facade _canCopy _catalogRefs _catalogUID _checkId _ct_defaultAddableTypeIds _ct_defaultConstrainTypesMo _ct_vocabularyPossibleTypes _datify _delOb _delObject _delPropValue _delProperty _delReferenceAnnotations _facade _deleteOwnershipAfterAdd _editMetadata _effective_date _expiration_date _filteredItems _findUniqueId _getCatalogTool _getCopy _getOb getPortalTypeName _getReferenceAnnotations _getURL _getWorkflowTool _get_id _has_user_defined_role _importObjectFromFile _isBeingAccessedAsZClassDef _isBeingUsedAsAMethod _isIDAutoGenerated _isSchemaCurrent _migrateGetValue _migrateSetValue _notifyOfCopyTo _postCopy _processForm _propertyMap _referenceApply _register _renameAfterCreation _setId _setOb _setObject _setPortalTypeName _setPropValue _setProperty _setRoles _setUID _subobject_permissions _uncatalogRefs _uncatalogUID _unregister _updateCatalog _updateProperty _updateSchema _verifyObjectPaste _wrapperCheck absolute_url absolute_url_path ac_inherited_permissions access_debug_info acquiredRolesAreUsedBy addCreator addDTMLDocument addDTMLMethod addReference addSubObjects all_meta_types allowDiscussion allowedContentTypes at_post_create_script at_post_edit_script autoOrderItems bobobase_modification_time canSetConstrainTypes canSetDefaultPage canSetLayout cb_dataItems cb_dataValid cb_isCopyable cb_isMoveable cb_userHasCopyOrMovePermiss changeOwnership checkCreationFlag checkIdAvailable class_manage_path cleanupLayers cmf_edit contentEffective contentExpired contentIds contentItems contentValues copyLayoutFromParent created dav__init dav__simpleifhandler dav__validate decodeFolderFilter defaultIsDiscussable defaultLanguage defaultRights defaultView deleteReference deleteReferences edit editIsDiscussable editMetadata effective encodeFolderFilter exclude_from_nav expires EditLink filtered_manage_options filtered_meta_types folderlistingFolderContents generateNewId get getActionInfo getAttribute getAttributeNode getAttributes getAvailableLayouts getBRefs getBRelationships getBackReferenceImpl getBRefs getCMFObjectsSubsetIds getCatalogs getCharset getChildNodes getConstrainTypesMode getContentType getDefault getDefaultAddableTypes getDefaultLayout getDefaultPage getDefaultSorting getEffectiveDate getElementsByTagName getExcludeFromNav getExpirationDate getField getFilename getFirstChild getFolderWhenPortalFactory getIcon getId getImmediatelyAddableTypes getLastChild getLayout getLocallyAllowedTypes getLocation getMetadataHeaders getNextPreviousEnabled getNextPreviousParentValue getNextSibling getNodeName getNodeType getNodeValue getObjectPosition getOwner getOwnerDocument getOwnerTuple getParentNode getPhysicalPath on.getPhysicalRoot getPortalTypeName getPreviousSibling getPrimaryField getProperty getPropertyType getRawConstrainTypesMode getRawContributors getRawCreation_date getRawCreators getRawDescription getRawEffectiveDate getRawExcludeFromNav getRawExpirationDate getRawId getRawImmediatelyAddableTyp getRawLanguage getRawLocallyAllowedTypes getRawLocation getRawModification_date getRawNextPreviousEnabled getRawRelatedItems getRawRights getRawSubject getRawTitle getReferenceImpl getReferenceMap getReferencePng getRefs getRefs getRelatedItems getRelationships getSiteManager getSortAuto getSortFolderishFirst getSortReverse getSubObject getTagName getTypeInfo getWrappedField getWrappedOwner getContentType get_local_roles get_local_roles_for_userid get_portal_metadata get_request_var_or_attr get_size get_valid_userids hasChildNodes hasObject hasProperty hasRelationshipTo has_local_roles http__etag http__parseMatchList http__processMatchHeaders http__refreshEtag getIcon indexObject initializeArchetype initializeLayers invokeFactory isBinary isDiscussable isTemporary isTransformable items keys languages listContributors listCreators listDAVObjects listFolderContents list_imports locked_in_version manage_CopyContainerAllItem manage_CopyContainerFirstIt manage_DAVget manage_FTPget manage_FTPlist manage_FTPstat manage_access _facade addDTMLDocument addDTMLMethod addDTMLMethod manage_addFile manage_addFolder manage_addImage _facade manage_addOrderedFolder manage_addProperty manage_addSiteRoot manage_addUserFolder manage_addZGadflyConnection manage_addZGadflyConnection manage_afterAdd manage_afterClone manage_afterMKCOL manage_afterPUT manage_beforeDelete _facade _facade manage_changeProperties manage_changePropertyTypes manage_clone manage_copyObjects manage_cutObjects manage_defined_roles _facade manage_delObjects manage_delProperties manage_editMetadata manage_editProperties manage_editRoles manage_editedDialog manage_exportObject manage_fixupOwnershipAfterA manage_getPermissionMapping manage_hasId manage_importObject manage_pasteObjects _facade manage_renameObject manage_renameObjects _facade _facade _facade _facade manage_undo_transactions manage_workflowsTab manage_workspace manage_zmi_logout markCreationFlag modified modified_in_version moveObject moveObjectToPosition moveObjectsByDelta moveObjectsDown moveObjectsToBottom moveObjectsToTop moveObjectsUp notifyModified notifyWorkflowCreated objectIds objectIds_d objectItems objectItems_d objectMap objectMap_d objectValues objectValues_d opaqueIds opaqueItems opaqueValues orderObjects owner_info permission_settings permissionsOfRole possible_permissions post_validate pre_validate processForm propdict propertyDescription propertyIds propertyItems propertyLabel propertyMap propertyValues raise_standardErrorMessage rawIsDiscussable reference_url reindexObject reindexObjectSecurity restrictedTraverse rolesOfPermission setConstrainTypesMode setContentType setContributors setCreationDate setCreators setDefaultPage setDefaultSorting setDefaults setDescription setEffectiveDate setExcludeFromNav setExpirationDate setFilename setFormat setId setImmediatelyAddableTypes setLanguage setLayout setLocallyAllowedTypes setLocation setModificationDate setNextPreviousEnabled setRelatedItems setRights setSiteManager setSortAuto setSortFolderishFirst setSortReverse setSubject setTitle superValues tabs_path_default tabs_path_info this title_and_id title_or_id tpURL tpValues undoable_transactions unindexObject unmarkCreationFlag unrestrictedTraverse update userCanTakeOwnership userdefined_roles users_with_local_role cb_dataValid valid_roles valid_property_id valid_roles validate validate_field validate_preferredTypes validate_roles values virtual_url_path widget wl_clearLocks wl_delLock wl_getLock wl_hasLock wl_isLocked wl_lockItems wl_lockTokens wl_lockValues wl_lockmapping wl_setLock 471
Both Zope 2 and Plone solve problems by piling more and more methods on an object
Zope 3 does something different Zope 3 uses Adapters
What are adapters? Let's talk programming.
Many programming languages use  static  typing
float half(int n) { return n / 2.0; }
float  half( int  n) { return n / 2.0; }
Python typing is  dynamic
def half(n): return n / 2.0
You don't worry about whether an object is of the right type
You simply try using it
“ Duck Typing” (Alex Martelli)
“ Duck Typing” Walks like a duck? Quacks like a duck? It's a duck!
def half(n): return n / 2.0
def half(n): return n / 2.0 (Is  n  willing  to be divided by two? Then it's number-ish enough for us!)
Now, imagine...
Imagine a wonderful duck-processing library to which you want to pass an object
But... The object you want to pass  isn't  a duck?
What if it  doesn't already quack?
What if it bears not the least resemblance to a duck!?
Example!
You have a “Message” object from the Python “email” module
>>>  from email import message_from_file >>>  e = message_from_file(open('msg.txt')) >>>  print e <email.message.Message instance at ...> >>>  e.is_multipart() True >>>  for part in e.get_payload(): ...  print part.get_content_type() text/plain text/html
multipart/mixed text/plain multipart/alternative text/plain text/html image/jpeg Messages can be recursive
Imagine that we are writing a Plone email browsing system
And we want to show the parts in a TreeWidget
multipart/mixed
multipart/mixed text/plain multipart/alternative image/jpeg
multipart/mixed text/plain multipart/alternative text/plain text/html image/jpeg
The Tree widget operates on any object with: method   name()  - returns name under which this tree node should be displayed method   children()  - returns list of child nodes in the tree method   __len__()  - returns number of child nodes beneath this one
How can we add these behaviors to our Message?
(How can we make an object which is  not  a duck behave like a duck?)
1. Subclassing
Create a “TreeMessage” class that inherits from the “Message” class...
class  TreeMessage ( Message ): def  name (self): return self.get_content_type() def  children (self): if not self.is_multipart(): return [] return [  TreeMessage (part) for part in self.get_payload() ] def  __len__ (self): return len(self.children())
What will the test suite look like?
Remember: “ Untested code  is broken code” —  Philipp von Weitershausen, Martin Aspeli
Your test suite must instantiate a “TreeMessage” and verify its tree-like behavior...
txt =  “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt,  TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
We were lucky!
Our test can cheaply instantiate Messages.
txt =  “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt,  TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
What if we were subclassing an LDAP connector?! We'd need an LDAP server just to run unit tests!
We were lucky (#2)!
The “message_from_string()” method let us specify an alternate factory!
txt =  “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt,  TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
Final note:  we have just broken the “Message” class's behavior!
Python library manual 7.10.1 defines “Message”: __len__(): Return the total number of headers, including duplicates.
>>> t =  “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” >>>  m = message_from_file(t, Message) >>>  print len(m) 3 >>>  m = message_from_file(t, TreeMessage) >>>   print len(m) 0
So how does subclassing score?
No harm to base class
No harm to base class Cannot test in isolation
No harm to base class Need control of factory Cannot test in isolation
No harm to base class Breaks if names collide Need control of factory Cannot test in isolation
No harm to base class Breaks if names collide Need control of factory Cannot test in isolation Subclassing:  D
2. Using a mixin
Create a “TreeMessage” class that inherits from both “Message” and a “Mixin”...
class  Mixin (object): def  name (self): return self.get_content_type() def  children (self): if not self.is_multipart(): return [] return [ self.__class__(part) for part in self.get_payload() ] def  __len__ (self): return len(self.children()) class  TreeMessage ( Message ,  Mixin ): pass
Your test suite can then inherit from a fake, mocked-up “message”...
class  FakeMessage ( Mixin ): def  get_content_type (self): return 'text/plain' def  is_multipart (self): return False def  get_payload (self): return '' m =  FakeMessage () assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
How does a mixin rate?
No harm to base class
No harm to base class Can test mixin by itself
No harm to base class Need control of factory Can test mixin by itself
No harm to base class Breaks if names collide Need control of factory Can test mixin by itself
No harm to base class Breaks if names collide Need control of factory Can test mixin by itself Mixin:  C
3. Monkey patching
To “monkey patch” a class, you add or change its methods dynamically...
def  name (self): return self.get_content_type() def  children (self): if not self.is_multipart(): return [] return [  Message (part) for part in self.get_payload() ] def  __len__ (self): return len(self.children()) Message . name  =  name Message . children  =  children Message . __len__  =  __len__
Is this desirable?
Don't care about factory
Changes class itself Don't care about factory
Changes class itself Broken by collisions Don't care about factory
Changes class itself Broken by collisions Don't care about factory Patches fight each other
Changes class itself Broken by collisions Don't care about factory Ruby people do this Patches fight each other
Changes class itself Broken by collisions Don't care about factory Ruby people do this Monkey patching:  F Patches fight each other
4. Adapter
Touted in the Gang of Four book (1994)
Idea: provide “Tree” functions through an entirely separate object Message  MessageTreeAdapter get_content_type ()  name () is_multipart ()  call  children () get_payload ()  __len__ ()
class  MessageTreeAdapter (object): def  __init__ (self, message): self. m  = message def  name (self): return self. m .get_content_type() def  children (self): if not self. m .is_multipart(): return [] return [  MessageTreeAdapter (part) for part in self. m .get_payload() ] def  __len__ (self): return len(self.children())
How does wrapping look in your code?
Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(MessageTreeAdapter(msg))
Test suite can try adapting a mock-up object
class  FakeMessage (object): def  get_content_type (self): return 'text/plain' def  is_multipart (self): return True def  get_payload (self): return [] m =  MessageTreeAdapter ( FakeMessage ()) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
How does the Adapter design pattern stack up?
No harm to base class
No harm to base class Can test with mock-up
No harm to base class Don't need factories Can test with mock-up
No harm to base class Don't need factories Can test with mock-up No collision worries
No harm to base class Don't need factories Can test with mock-up Wrapping is annoying No collision worries
No harm to base class Don't need factories Can test with mock-up Wrapping is annoying Adapter:  B No collision worries
Q:  Why call wrapping “ annoying”?
The example makes it look so easy!
Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(TreeMessageAdapter(msg))
A:  The example looks easy because  it only does adaptation  once !
But in a real application, it happens all through your code...
objects objects 3 rd  party Producers Adapters 3 rd  party Consumers Your application C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
This makes you repeat yourself. This  also   locks you in to using that particular adapter, since you use it by name in your code.
How can you avoid repeating yourself, and scattering information about adapters and consumers everywhere?
Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(TreeMessageAdapter(msg))
tw = TreeWidget(TreeMessageAdapter(msg))
The key is seeing that this code conflates  two  issues! tw = TreeWidget(TreeMessageAdapter(msg))
Why does this line work? tw = TreeWidget(TreeMessageAdapter(msg))
It works because a  TreeWidget   needs  what our adapter  provides . tw = TreeWidget(TreeMessageAdapter(msg))
But if  we  call the adapter then the  need   =   want  is   hidden inside of our head! tw = TreeWidget(TreeMessageAdapter(msg))
We need to define  what the  TreeWidget  needs that our adapter provides!
An  interface  is how we specify a set of behaviors
(1988) (1995) An  interface  is how we specify a set of behaviors
 
For the moment, forget Zope-the-web-framework
Instead, look at Zope the Component Framework: zope.interface zope.component
With three simple steps, Zope will put adapters around classes  for you  — and  rid your code of manual adaptation!
1.  Define  an interface 2.  Register  our adapter 3.  Request  adaptation
from zope.interface import Interface class  ITree (Interface): def  name (): “”” Return this tree node's name. ””” def  children (): “”” Return this node's children. ””” def  __len__ (): “”” Return how many children. ””” Define
from zope.component import provideAdapter provideAdapter( MessageTreeAdapter , adapts= Message , provides= ITree ) Register
class  TreeWidget (...): def __init__(self, arg): tree =  ITree (arg) ...  Request
class  TreeWidget (...): def __init__(self, arg): tree =  ITree (arg) ...  Zope will: 1. Recognize need 2. Find the registered adapter 3. Wrap and return the argument Request
class  TreeWidget (...): def __init__(self, arg): tree =  ITree (arg) ...  (Look! Zope is Pythonic!) i = int(32.1) l = list('abc') f = float(1024) Request
And that's it!
And that's it! Define  an interface Register  our adapter Request  adaptation
No harm to base class Don't need factories Can test with mock-up Adapters now dynamic! Registered adapter:  A No collision worries
objects objects 3 rd  party Producers Adapters 3 rd  party Consumers Your application C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
What adapters provide What consumers need C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
DB GUI IMAP email Web Widget Genealogy A B C
The finale Adapting for the Web
dum ... dum ... dum ... DAH DUM!
 
Grok
Web framework built atop Zope 3 component architecture
Grok makes Zope 3 simple to use (and to present!)
Imagine a  Person  class
The  Person  class was written by someone else
The  Person  class is full of business logic, and stores instances in a database
We want to browse  Person  objects on the Web
What might the Web need the object to do?
1. What's at a URL 3. What is its URL 2. HTML document <HTML> <HEAD> <TITLE>Person JOE </TITLE> </HEAD> <BODY> This page presents the basic data we have regarding Joe. ... Person http://host/person_app/Joe http://host/person_app/Joe
1.
What's at this URL?
What's at this URL? # how Zope processes this URL: r = root j = ITraverser(r).traverse('person_app') k = ITraverser(j).traverse('Joe') return k http://host/person_app/Joe
# what we write: class  PersonTraverser (grok. Traverser ): grok.context(PersonApp) def  traverse (self,  name ): if person_exists( name ): return get_person( name ) return None What's at this URL? http://host/person_app/Joe
2.
How does a Person render?
app.py class  PersonIndex (grok. View ): grok.context( Person ) grok.name(' index ') app_templates/personindex.pt < html >< head >< title >All about < tal   tal:replace =”context/name”/> </ title ></ head >... How does a Person render?
3.
What is a person's URL?
class  PersonURL (grok. MultiAdapter ): grok.adapts(Person, IHTTPRequest) grok.implements(IAbsoluteURL) def  __init__ (self, person, req): self.person, self.req = person, req def  __call__ (self): base = grok.url(grok.getSite())  return base + ' / ' + self.person.name What is a person's URL?
6 + 3 + 8 = 17 lines
6 + 3 + 8 = 17 lines And the object has not been harmed!
1. What's at a URL 3. What is its URL 2. HTML Document <HTML> <HEAD> <TITLE>Person JOE </TITLE> </HEAD> <BODY> This page presents the basic data we have regarding Joe. ... Person PersonTraverser PersonURL PersonIndex http://host/person_app/Joe http://host/person_app/Joe
Other Zope adapter uses
Other Zope adapter uses Indexing — Index, Query, Search, ... Data schemas — Schema, Vocabulary, DublinCore ... Form generation — AddForm, EditForm, ... Security — SecurityPolicy, Proxy, Checker, ... Authentication — Login, Logout, Allow, Require, ... Copy and paste — ObjectMover, ObjectCopier, ... I18n — TranslationDomain, Translator, ... Appearance — Skins, macros, viewlets, ... Much, much more!
Other Zope adapter uses And... “Vice”, the Plone RSS/Atom feed engine that Paul Bugni presented on yesterday!
How does Vice give the AT content types RSS superpowers?
The same 3 steps! Define  an interface Register  adapters Request  adaptation
ATDocument ATEvent ATLink ATImage ATFile ATNewsItem IFeedItem IFeedItem IFeedItem IFeedItem IFeedItem IFeedItem Adapter Adapter Adapter Adapter Adapter Adapter
Adapters can be local! Global adapters Local adapters add, override http://host/person_app/Joe http:// person_app Joe
Coming Attraction
five.grok
five.grok Lennart Regebro Martin Aspeli
Thank you! http://zope.org/ Products/Zope3 http://grok.zope.org/ http://rhodesmill.org/brandon/adapters http://regebro.wordpress.com/ [email_address]  mailing list [email_address]  mailing list Web Component Development with Zope 3  by PvW

Contenu connexe

Tendances

Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoMohamed Mosaad
 
Introduction to PHP Lecture 1
Introduction to PHP Lecture 1Introduction to PHP Lecture 1
Introduction to PHP Lecture 1Ajay Khatri
 
Basics of Java Script (JS)
Basics of Java Script (JS)Basics of Java Script (JS)
Basics of Java Script (JS)Ajay Khatri
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the BasicsWO Community
 
Roman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campRoman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campРоман Иовлев
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginningAnis Ahmad
 
Regular expression unit2
Regular expression unit2Regular expression unit2
Regular expression unit2smitha273566
 
W3c markup validator
  W3c markup validator  W3c markup validator
W3c markup validatorHugo Araújo
 
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingError Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingSteve Maraspin
 
Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And AnishOSSCube
 
Introduction to Active Record - Silicon Valley Ruby Conference 2007
Introduction to Active Record - Silicon Valley Ruby Conference 2007Introduction to Active Record - Silicon Valley Ruby Conference 2007
Introduction to Active Record - Silicon Valley Ruby Conference 2007Rabble .
 
Web Front End - (HTML5, CSS3, JavaScript) ++
Web Front End - (HTML5, CSS3, JavaScript) ++Web Front End - (HTML5, CSS3, JavaScript) ++
Web Front End - (HTML5, CSS3, JavaScript) ++ubshreenath
 

Tendances (18)

php string-part 2
php string-part 2php string-part 2
php string-part 2
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 
Introduction to PHP Lecture 1
Introduction to PHP Lecture 1Introduction to PHP Lecture 1
Introduction to PHP Lecture 1
 
KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
 
jQuery
jQueryjQuery
jQuery
 
Basics of Java Script (JS)
Basics of Java Script (JS)Basics of Java Script (JS)
Basics of Java Script (JS)
 
J query lecture 1
J query lecture 1J query lecture 1
J query lecture 1
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the Basics
 
Roman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campRoman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium camp
 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginning
 
Regular expression unit2
Regular expression unit2Regular expression unit2
Regular expression unit2
 
W3c markup validator
  W3c markup validator  W3c markup validator
W3c markup validator
 
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, loggingError Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
 
Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And Anish
 
Introduction to Active Record - Silicon Valley Ruby Conference 2007
Introduction to Active Record - Silicon Valley Ruby Conference 2007Introduction to Active Record - Silicon Valley Ruby Conference 2007
Introduction to Active Record - Silicon Valley Ruby Conference 2007
 
Dollar symbol
Dollar symbolDollar symbol
Dollar symbol
 
jQuery Selectors
jQuery SelectorsjQuery Selectors
jQuery Selectors
 
Web Front End - (HTML5, CSS3, JavaScript) ++
Web Front End - (HTML5, CSS3, JavaScript) ++Web Front End - (HTML5, CSS3, JavaScript) ++
Web Front End - (HTML5, CSS3, JavaScript) ++
 

En vedette

DIY Intranet Wiki
DIY Intranet WikiDIY Intranet Wiki
DIY Intranet Wikiguestea9cfd
 
Plone I18n Tutorial - Hanno Schlichting
Plone I18n Tutorial - Hanno SchlichtingPlone I18n Tutorial - Hanno Schlichting
Plone I18n Tutorial - Hanno SchlichtingJeffrey Clark
 
Zpugdc2007 101105081808-phpapp01
Zpugdc2007 101105081808-phpapp01Zpugdc2007 101105081808-phpapp01
Zpugdc2007 101105081808-phpapp01Jeffrey Clark
 

En vedette (8)

Zenoss: Buildout
Zenoss: BuildoutZenoss: Buildout
Zenoss: Buildout
 
Kss Extjs
Kss ExtjsKss Extjs
Kss Extjs
 
Opensourceweblion
OpensourceweblionOpensourceweblion
Opensourceweblion
 
DIY Intranet Wiki
DIY Intranet WikiDIY Intranet Wiki
DIY Intranet Wiki
 
Top Ten Test
Top Ten TestTop Ten Test
Top Ten Test
 
Plone I18n Tutorial - Hanno Schlichting
Plone I18n Tutorial - Hanno SchlichtingPlone I18n Tutorial - Hanno Schlichting
Plone I18n Tutorial - Hanno Schlichting
 
Simplifying Plone
Simplifying PloneSimplifying Plone
Simplifying Plone
 
Zpugdc2007 101105081808-phpapp01
Zpugdc2007 101105081808-phpapp01Zpugdc2007 101105081808-phpapp01
Zpugdc2007 101105081808-phpapp01
 

Similaire à Using Grok to Walk Like a Duck - Brandon Craig Rhodes

Oracle business intelligence publisher – developer training
Oracle business intelligence publisher – developer trainingOracle business intelligence publisher – developer training
Oracle business intelligence publisher – developer trainingitprofessionals network
 
Learning To Run - XPages for Lotus Notes Client Developers
Learning To Run - XPages for Lotus Notes Client DevelopersLearning To Run - XPages for Lotus Notes Client Developers
Learning To Run - XPages for Lotus Notes Client DevelopersKathy Brown
 
Tame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperTame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperGiordano Scalzo
 
Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Eelco Visser
 
Strategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesStrategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesEelco Visser
 
Swift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSwift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSimonPilkington8
 
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...Baruch Sadogursky
 
Java Online Training Institute in Hyderabad - C-Point
Java Online Training Institute in Hyderabad - C-PointJava Online Training Institute in Hyderabad - C-Point
Java Online Training Institute in Hyderabad - C-Pointcpointss
 
Mongoid in the real world
Mongoid in the real worldMongoid in the real world
Mongoid in the real worldKevin Faustino
 
Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)Wongnai
 
Querydsl fin jug - june 2012
Querydsl   fin jug - june 2012Querydsl   fin jug - june 2012
Querydsl fin jug - june 2012Timo Westkämper
 
Service Functions
Service FunctionsService Functions
Service Functionspineda2
 
Jumpstart Django
Jumpstart DjangoJumpstart Django
Jumpstart Djangoryates
 
Creating GUI Component APIs in Angular and Web Components
Creating GUI Component APIs in Angular and Web ComponentsCreating GUI Component APIs in Angular and Web Components
Creating GUI Component APIs in Angular and Web ComponentsRachael L Moore
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)James Titcumb
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)Oleg Zinchenko
 
CIRCUIT 2015 - Content API's For AEM Sites
CIRCUIT 2015 - Content API's For AEM SitesCIRCUIT 2015 - Content API's For AEM Sites
CIRCUIT 2015 - Content API's For AEM SitesICF CIRCUIT
 

Similaire à Using Grok to Walk Like a Duck - Brandon Craig Rhodes (20)

Oracle business intelligence publisher – developer training
Oracle business intelligence publisher – developer trainingOracle business intelligence publisher – developer training
Oracle business intelligence publisher – developer training
 
Learning To Run - XPages for Lotus Notes Client Developers
Learning To Run - XPages for Lotus Notes Client DevelopersLearning To Run - XPages for Lotus Notes Client Developers
Learning To Run - XPages for Lotus Notes Client Developers
 
Tame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapperTame Accidental Complexity with Ruby and MongoMapper
Tame Accidental Complexity with Ruby and MongoMapper
 
Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...Model-Driven Software Development - Strategies for Design & Implementation of...
Model-Driven Software Development - Strategies for Design & Implementation of...
 
Strategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific LanguagesStrategies for Design & Implementation of Domain-Specific Languages
Strategies for Design & Implementation of Domain-Specific Languages
 
Swift Micro-services and AWS Technologies
Swift Micro-services and AWS TechnologiesSwift Micro-services and AWS Technologies
Swift Micro-services and AWS Technologies
 
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
Persisting Your Objects In The Database World @ AlphaCSP Professional OSS Con...
 
Java Online Training Institute in Hyderabad - C-Point
Java Online Training Institute in Hyderabad - C-PointJava Online Training Institute in Hyderabad - C-Point
Java Online Training Institute in Hyderabad - C-Point
 
Mongoid in the real world
Mongoid in the real worldMongoid in the real world
Mongoid in the real world
 
Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)Solr's Search Relevancy (Understand Solr's query debug)
Solr's Search Relevancy (Understand Solr's query debug)
 
Querydsl fin jug - june 2012
Querydsl   fin jug - june 2012Querydsl   fin jug - june 2012
Querydsl fin jug - june 2012
 
Framework 4
Framework 4Framework 4
Framework 4
 
Service Functions
Service FunctionsService Functions
Service Functions
 
Jumpstart Django
Jumpstart DjangoJumpstart Django
Jumpstart Django
 
Creating GUI Component APIs in Angular and Web Components
Creating GUI Component APIs in Angular and Web ComponentsCreating GUI Component APIs in Angular and Web Components
Creating GUI Component APIs in Angular and Web Components
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
 
Plugins unplugged
Plugins unpluggedPlugins unplugged
Plugins unplugged
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
 
JAVASCRIPT CHEAT SHEET PDF
JAVASCRIPT CHEAT SHEET PDFJAVASCRIPT CHEAT SHEET PDF
JAVASCRIPT CHEAT SHEET PDF
 
CIRCUIT 2015 - Content API's For AEM Sites
CIRCUIT 2015 - Content API's For AEM SitesCIRCUIT 2015 - Content API's For AEM Sites
CIRCUIT 2015 - Content API's For AEM Sites
 

Plus de Jeffrey Clark

Python memory management_v2
Python memory management_v2Python memory management_v2
Python memory management_v2Jeffrey Clark
 
Jwt with flask slide deck - alan swenson
Jwt with flask   slide deck - alan swensonJwt with flask   slide deck - alan swenson
Jwt with flask slide deck - alan swensonJeffrey Clark
 
Genericmeetupslides 110607190400-phpapp02
Genericmeetupslides 110607190400-phpapp02Genericmeetupslides 110607190400-phpapp02
Genericmeetupslides 110607190400-phpapp02Jeffrey Clark
 
Pyramiddcpythonfeb2013 131006105131-phpapp02
Pyramiddcpythonfeb2013 131006105131-phpapp02Pyramiddcpythonfeb2013 131006105131-phpapp02
Pyramiddcpythonfeb2013 131006105131-phpapp02Jeffrey Clark
 
Zpugdc deformpresentation-100709203803-phpapp01
Zpugdc deformpresentation-100709203803-phpapp01Zpugdc deformpresentation-100709203803-phpapp01
Zpugdc deformpresentation-100709203803-phpapp01Jeffrey Clark
 
Zpugdccherry 101105081729-phpapp01
Zpugdccherry 101105081729-phpapp01Zpugdccherry 101105081729-phpapp01
Zpugdccherry 101105081729-phpapp01Jeffrey Clark
 
What Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonWhat Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonJeffrey Clark
 
What Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonWhat Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonJeffrey Clark
 
Real World Intranets - Joel Burton
Real World Intranets - Joel BurtonReal World Intranets - Joel Burton
Real World Intranets - Joel BurtonJeffrey Clark
 
State Of Zope 3 - Stephan Richter
State Of Zope 3 - Stephan RichterState Of Zope 3 - Stephan Richter
State Of Zope 3 - Stephan RichterJeffrey Clark
 
KSS Techniques - Joel Burton
KSS Techniques - Joel BurtonKSS Techniques - Joel Burton
KSS Techniques - Joel BurtonJeffrey Clark
 
Bfg Ploneconf Oct2008
Bfg Ploneconf Oct2008Bfg Ploneconf Oct2008
Bfg Ploneconf Oct2008Jeffrey Clark
 

Plus de Jeffrey Clark (17)

Python memory management_v2
Python memory management_v2Python memory management_v2
Python memory management_v2
 
Python meetup
Python meetupPython meetup
Python meetup
 
Jwt with flask slide deck - alan swenson
Jwt with flask   slide deck - alan swensonJwt with flask   slide deck - alan swenson
Jwt with flask slide deck - alan swenson
 
Genericmeetupslides 110607190400-phpapp02
Genericmeetupslides 110607190400-phpapp02Genericmeetupslides 110607190400-phpapp02
Genericmeetupslides 110607190400-phpapp02
 
Pyramiddcpythonfeb2013 131006105131-phpapp02
Pyramiddcpythonfeb2013 131006105131-phpapp02Pyramiddcpythonfeb2013 131006105131-phpapp02
Pyramiddcpythonfeb2013 131006105131-phpapp02
 
Dc python meetup
Dc python meetupDc python meetup
Dc python meetup
 
Zpugdc deformpresentation-100709203803-phpapp01
Zpugdc deformpresentation-100709203803-phpapp01Zpugdc deformpresentation-100709203803-phpapp01
Zpugdc deformpresentation-100709203803-phpapp01
 
Zpugdccherry 101105081729-phpapp01
Zpugdccherry 101105081729-phpapp01Zpugdccherry 101105081729-phpapp01
Zpugdccherry 101105081729-phpapp01
 
Tornado
TornadoTornado
Tornado
 
Science To Bfg
Science To BfgScience To Bfg
Science To Bfg
 
The PSF and You
The PSF and YouThe PSF and You
The PSF and You
 
What Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonWhat Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike Robinson
 
What Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike RobinsonWhat Makes A Great Dev Team - Mike Robinson
What Makes A Great Dev Team - Mike Robinson
 
Real World Intranets - Joel Burton
Real World Intranets - Joel BurtonReal World Intranets - Joel Burton
Real World Intranets - Joel Burton
 
State Of Zope 3 - Stephan Richter
State Of Zope 3 - Stephan RichterState Of Zope 3 - Stephan Richter
State Of Zope 3 - Stephan Richter
 
KSS Techniques - Joel Burton
KSS Techniques - Joel BurtonKSS Techniques - Joel Burton
KSS Techniques - Joel Burton
 
Bfg Ploneconf Oct2008
Bfg Ploneconf Oct2008Bfg Ploneconf Oct2008
Bfg Ploneconf Oct2008
 

Dernier

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...itnewsafrica
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 

Dernier (20)

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 

Using Grok to Walk Like a Duck - Brandon Craig Rhodes

  • 1. “ Using Grok to Walk Like a Duck” The Zope 3 Component Architecture Brandon Craig Rhodes Plone Conference 2008, Washington, DC
  • 2. How many methods does a Plone ATFolder have?
  • 3. Contributors CreationDate Creator Creators DELETE Date Description EffectiveDate ExpirationDate Format HEAD Identifer Identifier LOCK Language MKCOL MKCOL_handler MOVE ModificationDate OPTIONS PROPFIND PROPPATCH PUT PUT_factory ZopeFind Publisher Rights SQLConnectionIDs Schema Schemata SearchableText Subject TRACE Title Type UID UNLOCK Vocabulary ZQueryIds ZopeFind ZopeFindAndApply __url __before_publishing_travers __bobo_traverse__ __browser_default__ __call__ __class_init__ __contains__ __delitem__ __getitem__ __init__ __iter__ __len__ __of__ __repr__ __setitem__ _facade _canCopy _catalogRefs _catalogUID _checkId _ct_defaultAddableTypeIds _ct_defaultConstrainTypesMo _ct_vocabularyPossibleTypes _datify _delOb _delObject _delPropValue _delProperty _delReferenceAnnotations _facade _deleteOwnershipAfterAdd _editMetadata _effective_date _expiration_date _filteredItems _findUniqueId _getCatalogTool _getCopy _getOb getPortalTypeName _getReferenceAnnotations _getURL _getWorkflowTool _get_id _has_user_defined_role _importObjectFromFile _isBeingAccessedAsZClassDef _isBeingUsedAsAMethod _isIDAutoGenerated _isSchemaCurrent _migrateGetValue _migrateSetValue _notifyOfCopyTo _postCopy _processForm _propertyMap _referenceApply _register _renameAfterCreation _setId _setOb _setObject _setPortalTypeName _setPropValue _setProperty _setRoles _setUID _subobject_permissions _uncatalogRefs _uncatalogUID _unregister _updateCatalog _updateProperty _updateSchema _verifyObjectPaste _wrapperCheck absolute_url absolute_url_path ac_inherited_permissions access_debug_info acquiredRolesAreUsedBy addCreator addDTMLDocument addDTMLMethod addReference addSubObjects all_meta_types allowDiscussion allowedContentTypes at_post_create_script at_post_edit_script autoOrderItems bobobase_modification_time canSetConstrainTypes canSetDefaultPage canSetLayout cb_dataItems cb_dataValid cb_isCopyable cb_isMoveable cb_userHasCopyOrMovePermiss changeOwnership checkCreationFlag checkIdAvailable class_manage_path cleanupLayers cmf_edit contentEffective contentExpired contentIds contentItems contentValues copyLayoutFromParent created dav__init dav__simpleifhandler dav__validate decodeFolderFilter defaultIsDiscussable defaultLanguage defaultRights defaultView deleteReference deleteReferences edit editIsDiscussable editMetadata effective encodeFolderFilter exclude_from_nav expires EditLink filtered_manage_options filtered_meta_types folderlistingFolderContents generateNewId get getActionInfo getAttribute getAttributeNode getAttributes getAvailableLayouts getBRefs getBRelationships getBackReferenceImpl getBRefs getCMFObjectsSubsetIds getCatalogs getCharset getChildNodes getConstrainTypesMode getContentType getDefault getDefaultAddableTypes getDefaultLayout getDefaultPage getDefaultSorting getEffectiveDate getElementsByTagName getExcludeFromNav getExpirationDate getField getFilename getFirstChild getFolderWhenPortalFactory getIcon getId getImmediatelyAddableTypes getLastChild getLayout getLocallyAllowedTypes getLocation getMetadataHeaders getNextPreviousEnabled getNextPreviousParentValue getNextSibling getNodeName getNodeType getNodeValue getObjectPosition getOwner getOwnerDocument getOwnerTuple getParentNode getPhysicalPath on.getPhysicalRoot getPortalTypeName getPreviousSibling getPrimaryField getProperty getPropertyType getRawConstrainTypesMode getRawContributors getRawCreation_date getRawCreators getRawDescription getRawEffectiveDate getRawExcludeFromNav getRawExpirationDate getRawId getRawImmediatelyAddableTyp getRawLanguage getRawLocallyAllowedTypes getRawLocation getRawModification_date getRawNextPreviousEnabled getRawRelatedItems getRawRights getRawSubject getRawTitle getReferenceImpl getReferenceMap getReferencePng getRefs getRefs getRelatedItems getRelationships getSiteManager getSortAuto getSortFolderishFirst getSortReverse getSubObject getTagName getTypeInfo getWrappedField getWrappedOwner getContentType get_local_roles get_local_roles_for_userid get_portal_metadata get_request_var_or_attr get_size get_valid_userids hasChildNodes hasObject hasProperty hasRelationshipTo has_local_roles http__etag http__parseMatchList http__processMatchHeaders http__refreshEtag getIcon indexObject initializeArchetype initializeLayers invokeFactory isBinary isDiscussable isTemporary isTransformable items keys languages listContributors listCreators listDAVObjects listFolderContents list_imports locked_in_version manage_CopyContainerAllItem manage_CopyContainerFirstIt manage_DAVget manage_FTPget manage_FTPlist manage_FTPstat manage_access _facade addDTMLDocument addDTMLMethod addDTMLMethod manage_addFile manage_addFolder manage_addImage _facade manage_addOrderedFolder manage_addProperty manage_addSiteRoot manage_addUserFolder manage_addZGadflyConnection manage_addZGadflyConnection manage_afterAdd manage_afterClone manage_afterMKCOL manage_afterPUT manage_beforeDelete _facade _facade manage_changeProperties manage_changePropertyTypes manage_clone manage_copyObjects manage_cutObjects manage_defined_roles _facade manage_delObjects manage_delProperties manage_editMetadata manage_editProperties manage_editRoles manage_editedDialog manage_exportObject manage_fixupOwnershipAfterA manage_getPermissionMapping manage_hasId manage_importObject manage_pasteObjects _facade manage_renameObject manage_renameObjects _facade _facade _facade _facade manage_undo_transactions manage_workflowsTab manage_workspace manage_zmi_logout markCreationFlag modified modified_in_version moveObject moveObjectToPosition moveObjectsByDelta moveObjectsDown moveObjectsToBottom moveObjectsToTop moveObjectsUp notifyModified notifyWorkflowCreated objectIds objectIds_d objectItems objectItems_d objectMap objectMap_d objectValues objectValues_d opaqueIds opaqueItems opaqueValues orderObjects owner_info permission_settings permissionsOfRole possible_permissions post_validate pre_validate processForm propdict propertyDescription propertyIds propertyItems propertyLabel propertyMap propertyValues raise_standardErrorMessage rawIsDiscussable reference_url reindexObject reindexObjectSecurity restrictedTraverse rolesOfPermission setConstrainTypesMode setContentType setContributors setCreationDate setCreators setDefaultPage setDefaultSorting setDefaults setDescription setEffectiveDate setExcludeFromNav setExpirationDate setFilename setFormat setId setImmediatelyAddableTypes setLanguage setLayout setLocallyAllowedTypes setLocation setModificationDate setNextPreviousEnabled setRelatedItems setRights setSiteManager setSortAuto setSortFolderishFirst setSortReverse setSubject setTitle superValues tabs_path_default tabs_path_info this title_and_id title_or_id tpURL tpValues undoable_transactions unindexObject unmarkCreationFlag unrestrictedTraverse update userCanTakeOwnership userdefined_roles users_with_local_role cb_dataValid valid_roles valid_property_id valid_roles validate validate_field validate_preferredTypes validate_roles values virtual_url_path widget wl_clearLocks wl_delLock wl_getLock wl_hasLock wl_isLocked wl_lockItems wl_lockTokens wl_lockValues wl_lockmapping wl_setLock
  • 4. Contributors CreationDate Creator Creators DELETE Date Description EffectiveDate ExpirationDate Format HEAD Identifer Identifier LOCK Language MKCOL MKCOL_handler MOVE ModificationDate OPTIONS PROPFIND PROPPATCH PUT PUT_factory ZopeFind Publisher Rights SQLConnectionIDs Schema Schemata SearchableText Subject TRACE Title Type UID UNLOCK Vocabulary ZQueryIds ZopeFind ZopeFindAndApply __url __before_publishing_travers __bobo_traverse__ __browser_default__ __call__ __class_init__ __contains__ __delitem__ __getitem__ __init__ __iter__ __len__ __of__ __repr__ __setitem__ _facade _canCopy _catalogRefs _catalogUID _checkId _ct_defaultAddableTypeIds _ct_defaultConstrainTypesMo _ct_vocabularyPossibleTypes _datify _delOb _delObject _delPropValue _delProperty _delReferenceAnnotations _facade _deleteOwnershipAfterAdd _editMetadata _effective_date _expiration_date _filteredItems _findUniqueId _getCatalogTool _getCopy _getOb getPortalTypeName _getReferenceAnnotations _getURL _getWorkflowTool _get_id _has_user_defined_role _importObjectFromFile _isBeingAccessedAsZClassDef _isBeingUsedAsAMethod _isIDAutoGenerated _isSchemaCurrent _migrateGetValue _migrateSetValue _notifyOfCopyTo _postCopy _processForm _propertyMap _referenceApply _register _renameAfterCreation _setId _setOb _setObject _setPortalTypeName _setPropValue _setProperty _setRoles _setUID _subobject_permissions _uncatalogRefs _uncatalogUID _unregister _updateCatalog _updateProperty _updateSchema _verifyObjectPaste _wrapperCheck absolute_url absolute_url_path ac_inherited_permissions access_debug_info acquiredRolesAreUsedBy addCreator addDTMLDocument addDTMLMethod addReference addSubObjects all_meta_types allowDiscussion allowedContentTypes at_post_create_script at_post_edit_script autoOrderItems bobobase_modification_time canSetConstrainTypes canSetDefaultPage canSetLayout cb_dataItems cb_dataValid cb_isCopyable cb_isMoveable cb_userHasCopyOrMovePermiss changeOwnership checkCreationFlag checkIdAvailable class_manage_path cleanupLayers cmf_edit contentEffective contentExpired contentIds contentItems contentValues copyLayoutFromParent created dav__init dav__simpleifhandler dav__validate decodeFolderFilter defaultIsDiscussable defaultLanguage defaultRights defaultView deleteReference deleteReferences edit editIsDiscussable editMetadata effective encodeFolderFilter exclude_from_nav expires EditLink filtered_manage_options filtered_meta_types folderlistingFolderContents generateNewId get getActionInfo getAttribute getAttributeNode getAttributes getAvailableLayouts getBRefs getBRelationships getBackReferenceImpl getBRefs getCMFObjectsSubsetIds getCatalogs getCharset getChildNodes getConstrainTypesMode getContentType getDefault getDefaultAddableTypes getDefaultLayout getDefaultPage getDefaultSorting getEffectiveDate getElementsByTagName getExcludeFromNav getExpirationDate getField getFilename getFirstChild getFolderWhenPortalFactory getIcon getId getImmediatelyAddableTypes getLastChild getLayout getLocallyAllowedTypes getLocation getMetadataHeaders getNextPreviousEnabled getNextPreviousParentValue getNextSibling getNodeName getNodeType getNodeValue getObjectPosition getOwner getOwnerDocument getOwnerTuple getParentNode getPhysicalPath on.getPhysicalRoot getPortalTypeName getPreviousSibling getPrimaryField getProperty getPropertyType getRawConstrainTypesMode getRawContributors getRawCreation_date getRawCreators getRawDescription getRawEffectiveDate getRawExcludeFromNav getRawExpirationDate getRawId getRawImmediatelyAddableTyp getRawLanguage getRawLocallyAllowedTypes getRawLocation getRawModification_date getRawNextPreviousEnabled getRawRelatedItems getRawRights getRawSubject getRawTitle getReferenceImpl getReferenceMap getReferencePng getRefs getRefs getRelatedItems getRelationships getSiteManager getSortAuto getSortFolderishFirst getSortReverse getSubObject getTagName getTypeInfo getWrappedField getWrappedOwner getContentType get_local_roles get_local_roles_for_userid get_portal_metadata get_request_var_or_attr get_size get_valid_userids hasChildNodes hasObject hasProperty hasRelationshipTo has_local_roles http__etag http__parseMatchList http__processMatchHeaders http__refreshEtag getIcon indexObject initializeArchetype initializeLayers invokeFactory isBinary isDiscussable isTemporary isTransformable items keys languages listContributors listCreators listDAVObjects listFolderContents list_imports locked_in_version manage_CopyContainerAllItem manage_CopyContainerFirstIt manage_DAVget manage_FTPget manage_FTPlist manage_FTPstat manage_access _facade addDTMLDocument addDTMLMethod addDTMLMethod manage_addFile manage_addFolder manage_addImage _facade manage_addOrderedFolder manage_addProperty manage_addSiteRoot manage_addUserFolder manage_addZGadflyConnection manage_addZGadflyConnection manage_afterAdd manage_afterClone manage_afterMKCOL manage_afterPUT manage_beforeDelete _facade _facade manage_changeProperties manage_changePropertyTypes manage_clone manage_copyObjects manage_cutObjects manage_defined_roles _facade manage_delObjects manage_delProperties manage_editMetadata manage_editProperties manage_editRoles manage_editedDialog manage_exportObject manage_fixupOwnershipAfterA manage_getPermissionMapping manage_hasId manage_importObject manage_pasteObjects _facade manage_renameObject manage_renameObjects _facade _facade _facade _facade manage_undo_transactions manage_workflowsTab manage_workspace manage_zmi_logout markCreationFlag modified modified_in_version moveObject moveObjectToPosition moveObjectsByDelta moveObjectsDown moveObjectsToBottom moveObjectsToTop moveObjectsUp notifyModified notifyWorkflowCreated objectIds objectIds_d objectItems objectItems_d objectMap objectMap_d objectValues objectValues_d opaqueIds opaqueItems opaqueValues orderObjects owner_info permission_settings permissionsOfRole possible_permissions post_validate pre_validate processForm propdict propertyDescription propertyIds propertyItems propertyLabel propertyMap propertyValues raise_standardErrorMessage rawIsDiscussable reference_url reindexObject reindexObjectSecurity restrictedTraverse rolesOfPermission setConstrainTypesMode setContentType setContributors setCreationDate setCreators setDefaultPage setDefaultSorting setDefaults setDescription setEffectiveDate setExcludeFromNav setExpirationDate setFilename setFormat setId setImmediatelyAddableTypes setLanguage setLayout setLocallyAllowedTypes setLocation setModificationDate setNextPreviousEnabled setRelatedItems setRights setSiteManager setSortAuto setSortFolderishFirst setSortReverse setSubject setTitle superValues tabs_path_default tabs_path_info this title_and_id title_or_id tpURL tpValues undoable_transactions unindexObject unmarkCreationFlag unrestrictedTraverse update userCanTakeOwnership userdefined_roles users_with_local_role cb_dataValid valid_roles valid_property_id valid_roles validate validate_field validate_preferredTypes validate_roles values virtual_url_path widget wl_clearLocks wl_delLock wl_getLock wl_hasLock wl_isLocked wl_lockItems wl_lockTokens wl_lockValues wl_lockmapping wl_setLock 471
  • 5. Both Zope 2 and Plone solve problems by piling more and more methods on an object
  • 6. Zope 3 does something different Zope 3 uses Adapters
  • 7. What are adapters? Let's talk programming.
  • 8. Many programming languages use static typing
  • 9. float half(int n) { return n / 2.0; }
  • 10. float half( int n) { return n / 2.0; }
  • 11. Python typing is dynamic
  • 13. You don't worry about whether an object is of the right type
  • 14. You simply try using it
  • 15. “ Duck Typing” (Alex Martelli)
  • 16. “ Duck Typing” Walks like a duck? Quacks like a duck? It's a duck!
  • 18. def half(n): return n / 2.0 (Is n willing to be divided by two? Then it's number-ish enough for us!)
  • 20. Imagine a wonderful duck-processing library to which you want to pass an object
  • 21. But... The object you want to pass isn't a duck?
  • 22. What if it doesn't already quack?
  • 23. What if it bears not the least resemblance to a duck!?
  • 25. You have a “Message” object from the Python “email” module
  • 26. >>> from email import message_from_file >>> e = message_from_file(open('msg.txt')) >>> print e <email.message.Message instance at ...> >>> e.is_multipart() True >>> for part in e.get_payload(): ... print part.get_content_type() text/plain text/html
  • 27. multipart/mixed text/plain multipart/alternative text/plain text/html image/jpeg Messages can be recursive
  • 28. Imagine that we are writing a Plone email browsing system
  • 29. And we want to show the parts in a TreeWidget
  • 32. multipart/mixed text/plain multipart/alternative text/plain text/html image/jpeg
  • 33. The Tree widget operates on any object with: method name() - returns name under which this tree node should be displayed method children() - returns list of child nodes in the tree method __len__() - returns number of child nodes beneath this one
  • 34. How can we add these behaviors to our Message?
  • 35. (How can we make an object which is not a duck behave like a duck?)
  • 37. Create a “TreeMessage” class that inherits from the “Message” class...
  • 38. class TreeMessage ( Message ): def name (self): return self.get_content_type() def children (self): if not self.is_multipart(): return [] return [ TreeMessage (part) for part in self.get_payload() ] def __len__ (self): return len(self.children())
  • 39. What will the test suite look like?
  • 40. Remember: “ Untested code is broken code” — Philipp von Weitershausen, Martin Aspeli
  • 41. Your test suite must instantiate a “TreeMessage” and verify its tree-like behavior...
  • 42. txt = “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt, TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
  • 44. Our test can cheaply instantiate Messages.
  • 45. txt = “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt, TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
  • 46. What if we were subclassing an LDAP connector?! We'd need an LDAP server just to run unit tests!
  • 47. We were lucky (#2)!
  • 48. The “message_from_string()” method let us specify an alternate factory!
  • 49. txt = “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” m = message_from_string(txt, TreeMessage ) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
  • 50. Final note: we have just broken the “Message” class's behavior!
  • 51. Python library manual 7.10.1 defines “Message”: __len__(): Return the total number of headers, including duplicates.
  • 52. >>> t = “”” From: persephone@gmail.com To: brandon@rhodesmill.org Subject: what an article! Did you read Arts & Letters Daily today? “”” >>> m = message_from_file(t, Message) >>> print len(m) 3 >>> m = message_from_file(t, TreeMessage) >>> print len(m) 0
  • 53. So how does subclassing score?
  • 54. No harm to base class
  • 55. No harm to base class Cannot test in isolation
  • 56. No harm to base class Need control of factory Cannot test in isolation
  • 57. No harm to base class Breaks if names collide Need control of factory Cannot test in isolation
  • 58. No harm to base class Breaks if names collide Need control of factory Cannot test in isolation Subclassing: D
  • 59. 2. Using a mixin
  • 60. Create a “TreeMessage” class that inherits from both “Message” and a “Mixin”...
  • 61. class Mixin (object): def name (self): return self.get_content_type() def children (self): if not self.is_multipart(): return [] return [ self.__class__(part) for part in self.get_payload() ] def __len__ (self): return len(self.children()) class TreeMessage ( Message , Mixin ): pass
  • 62. Your test suite can then inherit from a fake, mocked-up “message”...
  • 63. class FakeMessage ( Mixin ): def get_content_type (self): return 'text/plain' def is_multipart (self): return False def get_payload (self): return '' m = FakeMessage () assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
  • 64. How does a mixin rate?
  • 65. No harm to base class
  • 66. No harm to base class Can test mixin by itself
  • 67. No harm to base class Need control of factory Can test mixin by itself
  • 68. No harm to base class Breaks if names collide Need control of factory Can test mixin by itself
  • 69. No harm to base class Breaks if names collide Need control of factory Can test mixin by itself Mixin: C
  • 71. To “monkey patch” a class, you add or change its methods dynamically...
  • 72. def name (self): return self.get_content_type() def children (self): if not self.is_multipart(): return [] return [ Message (part) for part in self.get_payload() ] def __len__ (self): return len(self.children()) Message . name = name Message . children = children Message . __len__ = __len__
  • 74. Don't care about factory
  • 75. Changes class itself Don't care about factory
  • 76. Changes class itself Broken by collisions Don't care about factory
  • 77. Changes class itself Broken by collisions Don't care about factory Patches fight each other
  • 78. Changes class itself Broken by collisions Don't care about factory Ruby people do this Patches fight each other
  • 79. Changes class itself Broken by collisions Don't care about factory Ruby people do this Monkey patching: F Patches fight each other
  • 81. Touted in the Gang of Four book (1994)
  • 82. Idea: provide “Tree” functions through an entirely separate object Message MessageTreeAdapter get_content_type () name () is_multipart () call children () get_payload () __len__ ()
  • 83. class MessageTreeAdapter (object): def __init__ (self, message): self. m = message def name (self): return self. m .get_content_type() def children (self): if not self. m .is_multipart(): return [] return [ MessageTreeAdapter (part) for part in self. m .get_payload() ] def __len__ (self): return len(self.children())
  • 84. How does wrapping look in your code?
  • 85. Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(MessageTreeAdapter(msg))
  • 86. Test suite can try adapting a mock-up object
  • 87. class FakeMessage (object): def get_content_type (self): return 'text/plain' def is_multipart (self): return True def get_payload (self): return [] m = MessageTreeAdapter ( FakeMessage ()) assert m. name () == 'text/plain' assert m. children () == [] assert m. __len__ () == 0
  • 88. How does the Adapter design pattern stack up?
  • 89. No harm to base class
  • 90. No harm to base class Can test with mock-up
  • 91. No harm to base class Don't need factories Can test with mock-up
  • 92. No harm to base class Don't need factories Can test with mock-up No collision worries
  • 93. No harm to base class Don't need factories Can test with mock-up Wrapping is annoying No collision worries
  • 94. No harm to base class Don't need factories Can test with mock-up Wrapping is annoying Adapter: B No collision worries
  • 95. Q: Why call wrapping “ annoying”?
  • 96. The example makes it look so easy!
  • 97. Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(TreeMessageAdapter(msg))
  • 98. A: The example looks easy because it only does adaptation once !
  • 99. But in a real application, it happens all through your code...
  • 100. objects objects 3 rd party Producers Adapters 3 rd party Consumers Your application C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
  • 101. This makes you repeat yourself. This also locks you in to using that particular adapter, since you use it by name in your code.
  • 102. How can you avoid repeating yourself, and scattering information about adapters and consumers everywhere?
  • 103. Message object Adapted object IMAP library (or whatever) returns a Message “msg” TreeWidget tw = TreeWidget(TreeMessageAdapter(msg))
  • 105. The key is seeing that this code conflates two issues! tw = TreeWidget(TreeMessageAdapter(msg))
  • 106. Why does this line work? tw = TreeWidget(TreeMessageAdapter(msg))
  • 107. It works because a TreeWidget needs what our adapter provides . tw = TreeWidget(TreeMessageAdapter(msg))
  • 108. But if we call the adapter then the need = want is hidden inside of our head! tw = TreeWidget(TreeMessageAdapter(msg))
  • 109. We need to define what the TreeWidget needs that our adapter provides!
  • 110. An interface is how we specify a set of behaviors
  • 111. (1988) (1995) An interface is how we specify a set of behaviors
  • 112.  
  • 113. For the moment, forget Zope-the-web-framework
  • 114. Instead, look at Zope the Component Framework: zope.interface zope.component
  • 115. With three simple steps, Zope will put adapters around classes for you — and rid your code of manual adaptation!
  • 116. 1. Define an interface 2. Register our adapter 3. Request adaptation
  • 117. from zope.interface import Interface class ITree (Interface): def name (): “”” Return this tree node's name. ””” def children (): “”” Return this node's children. ””” def __len__ (): “”” Return how many children. ””” Define
  • 118. from zope.component import provideAdapter provideAdapter( MessageTreeAdapter , adapts= Message , provides= ITree ) Register
  • 119. class TreeWidget (...): def __init__(self, arg): tree = ITree (arg) ... Request
  • 120. class TreeWidget (...): def __init__(self, arg): tree = ITree (arg) ... Zope will: 1. Recognize need 2. Find the registered adapter 3. Wrap and return the argument Request
  • 121. class TreeWidget (...): def __init__(self, arg): tree = ITree (arg) ... (Look! Zope is Pythonic!) i = int(32.1) l = list('abc') f = float(1024) Request
  • 123. And that's it! Define an interface Register our adapter Request adaptation
  • 124. No harm to base class Don't need factories Can test with mock-up Adapters now dynamic! Registered adapter: A No collision worries
  • 125. objects objects 3 rd party Producers Adapters 3 rd party Consumers Your application C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
  • 126. What adapters provide What consumers need C(msg) DB GUI A(famtree) IMAP email msg Web Widget B(msg) Genealogy A B C C(msg)
  • 127. DB GUI IMAP email Web Widget Genealogy A B C
  • 128. The finale Adapting for the Web
  • 129. dum ... dum ... dum ... DAH DUM!
  • 130.  
  • 131. Grok
  • 132. Web framework built atop Zope 3 component architecture
  • 133. Grok makes Zope 3 simple to use (and to present!)
  • 134. Imagine a Person class
  • 135. The Person class was written by someone else
  • 136. The Person class is full of business logic, and stores instances in a database
  • 137. We want to browse Person objects on the Web
  • 138. What might the Web need the object to do?
  • 139. 1. What's at a URL 3. What is its URL 2. HTML document <HTML> <HEAD> <TITLE>Person JOE </TITLE> </HEAD> <BODY> This page presents the basic data we have regarding Joe. ... Person http://host/person_app/Joe http://host/person_app/Joe
  • 140. 1.
  • 141. What's at this URL?
  • 142. What's at this URL? # how Zope processes this URL: r = root j = ITraverser(r).traverse('person_app') k = ITraverser(j).traverse('Joe') return k http://host/person_app/Joe
  • 143. # what we write: class PersonTraverser (grok. Traverser ): grok.context(PersonApp) def traverse (self, name ): if person_exists( name ): return get_person( name ) return None What's at this URL? http://host/person_app/Joe
  • 144. 2.
  • 145. How does a Person render?
  • 146. app.py class PersonIndex (grok. View ): grok.context( Person ) grok.name(' index ') app_templates/personindex.pt < html >< head >< title >All about < tal tal:replace =”context/name”/> </ title ></ head >... How does a Person render?
  • 147. 3.
  • 148. What is a person's URL?
  • 149. class PersonURL (grok. MultiAdapter ): grok.adapts(Person, IHTTPRequest) grok.implements(IAbsoluteURL) def __init__ (self, person, req): self.person, self.req = person, req def __call__ (self): base = grok.url(grok.getSite()) return base + ' / ' + self.person.name What is a person's URL?
  • 150. 6 + 3 + 8 = 17 lines
  • 151. 6 + 3 + 8 = 17 lines And the object has not been harmed!
  • 152. 1. What's at a URL 3. What is its URL 2. HTML Document <HTML> <HEAD> <TITLE>Person JOE </TITLE> </HEAD> <BODY> This page presents the basic data we have regarding Joe. ... Person PersonTraverser PersonURL PersonIndex http://host/person_app/Joe http://host/person_app/Joe
  • 154. Other Zope adapter uses Indexing — Index, Query, Search, ... Data schemas — Schema, Vocabulary, DublinCore ... Form generation — AddForm, EditForm, ... Security — SecurityPolicy, Proxy, Checker, ... Authentication — Login, Logout, Allow, Require, ... Copy and paste — ObjectMover, ObjectCopier, ... I18n — TranslationDomain, Translator, ... Appearance — Skins, macros, viewlets, ... Much, much more!
  • 155. Other Zope adapter uses And... “Vice”, the Plone RSS/Atom feed engine that Paul Bugni presented on yesterday!
  • 156. How does Vice give the AT content types RSS superpowers?
  • 157. The same 3 steps! Define an interface Register adapters Request adaptation
  • 158. ATDocument ATEvent ATLink ATImage ATFile ATNewsItem IFeedItem IFeedItem IFeedItem IFeedItem IFeedItem IFeedItem Adapter Adapter Adapter Adapter Adapter Adapter
  • 159. Adapters can be local! Global adapters Local adapters add, override http://host/person_app/Joe http:// person_app Joe
  • 162. five.grok Lennart Regebro Martin Aspeli
  • 163. Thank you! http://zope.org/ Products/Zope3 http://grok.zope.org/ http://rhodesmill.org/brandon/adapters http://regebro.wordpress.com/ [email_address] mailing list [email_address] mailing list Web Component Development with Zope 3 by PvW