Created
August 28, 2012 07:55
-
-
Save lost-theory/3495990 to your computer and use it in GitHub Desktop.
coffeescript decorator examples a la raganwald, but in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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