# -*- coding: utf-8 -*- #-------------------------------- #$Date$ #$Author$ #$Revision$ #-------------------------------- #Copyright (C) 2007 Alexander Koshelev (daevaorn@gmail.com) from django.utils.functional import curry from django.utils.encoding import smart_unicode,smart_str from django.utils.safestring import SafeString SIMPLE_ATTRS = [ "fn", "nickname", "sort-string", "url", "tz", "photo", "logo", "sound", "bday", "title", "role", "category", "note", "class", "key", "mailer", "uid", "rev" ] COMPLEX_ATTRS = { "n" : ( "family-name", "given-name", "additional-name", "honorific-prefix", "honorific-suffix" ), "email" : ( "type", "value" ), "tel" : ( "type", "value" ), "geo" : ( "latitude", "longitude" ), "org" : ( "organization-name", "organization-unit" ), "adr" : ( "post-office-box", "extended-address", "street-address", "locality", "region", "postal-code", "country-name", "type", "value") } ATTRS_TYPES = { "adr" : ( 'work', 'home', 'pref', 'postal', 'dom', 'intl' ), } def simple_format( value, name ): return SafeString( smart_str( '%s' % ( name, value ) ) ) def _hcard_simple_field( self,instance,name,getter ): value = getter( self, instance ) formatter = getattr( self, "format_%s" % name, curry( simple_format, name = name ) ) return SafeString( smart_str( formatter( value ) ) ) def _hcard_complex_render( name, values ): res = '' % name for key in COMPLEX_ATTRS[ name ]: res += '%s' % ( key, values.get( key ) ) res += '' return SafeString( res ) def format_complex( value, name ): if isinstance( value, ( list, tuple ) ): res = [] for v in value: res.append( _hcard_complex_render( name, v ) ) return "".join( res ) elif isinstance( value, dict ): return _hcard_complex_render( name, value ) else: raise AttributeError, "hCard attribute with name %s must be dict or list/tuple of dicts" % name def _hcard_complex_field( self, instance, name, getter ): value = getter( self, instance ) formatter = getattr( self, "format_%s" % name, curry( format_complex, name = name ) ) return SafeString( smart_str( formatter( value ) ) ) make_name = lambda key: key #"hcard_%s" % def value_getter( instance, name ): attr = getattr( instance, name ) if callable( attr ): return attr() return attr def value_getter_with_instance( obj, instance, name ): attr = getattr( obj, name ) if callable( attr ): return attr( instance = instance ) return attr def resolve_value( format, instance, name ): bits = name.split( '.' ) attr = instance try: for bit in bits: attr = value_getter( attr, bit ) return attr except AttributeError, e: pass attr = format try: for bit in bits: attr = value_getter_with_instance( attr, instance, bit ) return attr except AttributeError: raise def make_methods( hcard, keys, func ): attrs = {} for key in keys: attr_name = make_name( key ) if key in hcard: field_name = hcard.pop( key ) attrs[ attr_name ] = curry( func, name = key, getter = curry( resolve_value, name = field_name ) ) else: attrs[ attr_name ] = lambda obj: "" return attrs class HcardMetaclass( type ): def __new__( cls, name, bases, attrs ): attrs.update( make_methods( attrs, SIMPLE_ATTRS, _hcard_simple_field ) ) attrs.update( make_methods( attrs, COMPLEX_ATTRS.keys(), _hcard_complex_field ) ) return type.__new__( cls, name, bases, attrs ) class FormatProxy( object ): def __init__(self, format, instance ): self.format = format self.instance = instance def __getattr__( self, name ): return getattr( self.format, name )( self.instance ) class HcardFormat( object ): __metaclass__ = HcardMetaclass def __get__(self, instance, instance_type = None ): return FormatProxy( self, instance ) def __set__(self, instance, value ): pass def format_email( self, value ): return """ %(type)s %(value)s """ % value def format_bday( self, value ): title = value.strftime( "%Y-%m-%d" ) text = value.strftime( "%B %d, %Y" ) return """%s""" % ( title, text )