Skip to content

Instantly share code, notes, and snippets.

@lost-theory
Created August 28, 2012 07:55
Show Gist options
  • Save lost-theory/3495990 to your computer and use it in GitHub Desktop.
Save lost-theory/3495990 to your computer and use it in GitHub Desktop.
coffeescript decorator examples a la raganwald, but in python
#http://news.ycombinator.com/item?id=4439352
def has_permission_to(user, verb, subj):
if user == "steve" and verb == "write":
return True
elif user == "alice" and verb == "read":
return True
return False
def current_user():
import random
return random.choice(["alice", "steve"])
## advice / decorators ########################################################
def with_permission(verb, subj):
def entangle(f):
def inner(*a, **kw):
u = current_user()
if has_permission_to(u, verb, subj):
return f(*a, **kw)
else:
return "error: %r does not have %r access to %r" % (u, verb, subj)
return inner
return entangle
def debug_entry_and_exit(msg):
def entangle(f):
def inner(*a, **kw):
print "[debug]", "entering", msg
ret = f(*a, **kw)
print "[debug]", "leaving", msg
return ret
return inner
return entangle
## widget views using some framework... #######################################
class FrameworkView(object):
def edit(self, page):
return "stub for editing %r" % page
def view(self, page):
return "stub for viewing %r" % page
class WidgetView(FrameworkView):
@debug_entry_and_exit("edit")
@with_permission("write", "widget")
def edit(self, page):
return "you can edit %r" % page
@debug_entry_and_exit("view")
@with_permission("read", "widget")
def view(self, page):
return "you can view %r" % page
class RaganwaldWidgetViewOne(FrameworkView):
'''Same as WidgetView but without python's @decorator syntax.
Somewhat equivalent to the coffeescript version, but instead of decorating the multi-line
anonymous function, we first give that body of the function a name, then decorate that.
'''
def edit(self, page):
def body(self, page):
return "you can edit %r" % page
return (
debug_entry_and_exit("edit")(
with_permission("write", "widget")(
body
)))(self, page)
def view(self, page):
def body(self, page):
return "you can view %r" % page
return (
debug_entry_and_exit("view")(
with_permission("read", "widget")(
body
)))(self, page)
class RaganwaldWidgetViewTwo(FrameworkView):
'''Same as WidgetView but without python's @decorator syntax.
We apply the decorators to the method from the body of the class intead of within the
method itself. This is what people were doing before the @ syntax existed; the @ syntax
isn't really "magic", it's just sugar for this pattern (def f(x)...; f = deco(f)).'''
def edit(self, page):
return "you can edit %r" % page
edit = (
debug_entry_and_exit("edit")(
with_permission("write", "widget")(
edit
)))
def view(self, page):
return "you can view %r" % page
view = (
debug_entry_and_exit("view")(
with_permission("read", "widget")(
view
)))
class RaganwaldWidgetViewThree(FrameworkView):
'''Same as WidgetView, without python's @decorator syntax, and using anonymous functions.'''
edit = (
debug_entry_and_exit("edit")(
with_permission("write", "widget")(
lambda self, page: "you can edit %r" % page #if python had multi-line lambda, this would be equivalent to the coffeescript example
)))
view = (
debug_entry_and_exit("view")(
with_permission("read", "widget")(
lambda self, page: "you can view %r" % page
)))
## main #######################################################################
if __name__ == "__main__":
ws = [
WidgetView(),
RaganwaldWidgetViewOne(),
RaganwaldWidgetViewTwo(),
RaganwaldWidgetViewThree(),
]
for w in ws:
print "\n\n== %s ==\n" % w.__class__.__name__
for name in "red blue".split():
print w.edit(name)
print w.view(name)
print ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment