Very cute. Reminds me of a cross between Ruby's Sinatra (http://sintrarb.com/) and Ramaze (http://ramaze.net/) without obviously being inspired by those :)
The idea of routing annotations is used extensively in the Recess PHP Framework, except that in Recess the annotation also takes the HTTP verb (GET, PUT, POST, etc.) to make beautiful, RESTful URLs even easier to work with.
Really? That's your contribution to the discussion?
I have a lot of negative things to say about a lot of different languages, but I think what Kris has done with annotations in PHP is pretty cool, even if it is ultimately a hack.
PS. Juno looks nice though I'm not a huge fan of frameworks that return rendered html from controllers. But I do like it's Sinatra-esque simplicity.
While I respect the cleverness of his hack, it's the kind of thing that sets off alarm bells in my head. Much like fancy template metaprogramming tricks in C++ did, only worse since it actually breaks the semantic contract that the language imposes for comment blocks.
I'm not so sure there is a "semantic contract" for comment blocks since they're made available via reflection. Comments are metadata after all.
And this is more akin to annotations/attributes ala python, java, C#. C++ doesn't have any feature that is approximate by virtue that annotations are aspects of reflection and C++ doesn't have reflection.
I dont know if I would call a comment(part of language that has meaning only to the programmers) equivalent to a language defined thing like annotations/attributes which has specific meaning to the compiler/interpreter. But I do aggree it CAN be metadata in the same regard a file name or path can be (which many frameworks use).
They're not used as executable code. They're used as meta data. Not much different than an XML file sitting beside of a script, except that
1) it's more DRY because for external files to say something about a construct in code there is repeated information, i.e. <route><to><class>Foo</class><method>bar</method></to><from><method>GET</method><url>some/url/here</url></to></route>,
2) because you're using the PHP language to specify metadata about a PHP construct refactoring is easier, i.e. change the name of a function and you don't have to go update your routing somewhere else,
3) having the metadata inline with code turns out to be mentally lightweight once you get over the initial shock of seeing metadata in a comment.
It's little known that doccomments are a PHP language construct that can be reflected over just as Python's doc strings can be introspected with __doc__.
Thus !Route GET, a/good/$programmer is just as much a language construct in a PHP program as @route('a/good/:programmer') is in a Python program. The key difference is Python defines at the language level how that particular bit of script is expanded as a decorator. Recess does its expansion of annotations at the framework level.
Python is a much better and more thoughtfully designed programming language than PHP, for sure. PHP has loop holes, doccomments is one of them. PHP does not do anything, by default, with a doccomment, but it does give an opportunity to introduce meta-data on classes, methods, and properties and easily reflect over that meta-data and then it's up to the programmer to define a 'DSL'.
In this sense PHP offers something powerful and dangerous. Recess choose a simple data format, such that parsing can be expressed in a regexp that is then processed by essentially 'Constructing a class of type [FirstWord] and call init method with array of [Following words as a PHP array] - finally make these annotations available through reflection'. Not too much different than annotations in Java/C#. Simple enough that the danger is mostly negated and the utility makes the 'hack' justifiable.
I don't understand why almost every (except for Django) framework author insists on hiding regular expressions in his routing scheme and instead forcing developers to use his homegrown language with slashes hardcoded. It's not like the developers are afraid of regular expressions, are they? This is so painful, i have to undo the work of those routers sometimes to get the results i want.
Luckily this is Python so it's possible to monkeypatch the implementation.
Regular expressions are overkill in most cases, and clutter the code. Do you really always know you need a 6 character long integer in a URL? what you really want is an ID, which may be a 6 character integer. Simple keyword-based routing is fine for 99% of cases.
Here is a simple example which pops up too often: i need a "flatpages" controller which will display a page based on its url. Or, as another example, a category tree. With regexes, this is a piece of cake. With routers that try to hide regexes, i have to undo the work done by the router.
What I don't get is why web frameworks put routing into the code at all. Most of them don't do anything interesting with it (Rails is the most prominent exception), and if you're just gonna map a few things with regexes, well... what's so difficult about mod_rewrite?
Portability between servers and reusable apps are the first examples that came to my mind. A reusable app would need an extra installation step and need to duplicate its routes in more than one syntax for different webservers.
I really like Juno. It's very small, and quite elegant, and it mostly feels like Python (rather than a DSL-ish framework). My only issues are that the URLs are tightly coupled to the controllers--from a stylistic point of view I prefer to manage the URLs in a single place (since they're both related but different).
dict holding list holding tuple holding dict :) no biggy to throw a wrapper over it though. Is it possible to place all the routes in one place you think with this? I am worried with a larger project I will forget which module contains what url... Unless there is some convention for url path->module name (if there isnt I would suggest establishing one). A suggestion I would have is standardize on some templating so if people end up using this there wont be a person using a different available one. (http://wiki.python.org/moin/Templating) I noticed http://karrigell.sourceforge.net/en/pythoninsidehtml.htm was not on that page though... albeit its more like php.
Juno looks to be simple and the developer has chosen a good set of libraries to build it on. It is a demonstration of the inherent simplicity in using well written, WSGI aware python libraries.
IMO, web.py qualifies to be called "really lightweight"
take for instance the hello world code:
import web
urls = (
'/(.*)', 'hello'
)
app = web.application(urls, globals())
class hello:
def GET(self, name):
if not name:
name = 'world'
return 'Hello, ' + name + '!'
if __name__ == "__main__":
app.run()
This has two advantages over the Juno code..
1. more `REST`y (GET/POST)
2. `app` object is a wsgi callable..
More importantly, web.py does not need have any external library dependencies unless you choose to use mysql/postgresql when you have to install the db interface libraries. I had problem running the hello world Juno code because I did not have pysqlite2 installed.. huh? why do I need pysqlite2 to return a string?
While some may object saying that web.py has a case of NIH, the code of web.py itself does not reflect any such attitude. The whole library is just a directory of aptly named modules. You can plop it anywhere in the python path and start coding ..
25 comments
[ 0.23 ms ] story [ 62.4 ms ] threadhttp://news.ycombinator.com/item?id=506352
http://www.recessframework.org/page/routing-in-recess-screen...
I have a lot of negative things to say about a lot of different languages, but I think what Kris has done with annotations in PHP is pretty cool, even if it is ultimately a hack.
PS. Juno looks nice though I'm not a huge fan of frameworks that return rendered html from controllers. But I do like it's Sinatra-esque simplicity.
I'm not so sure there is a "semantic contract" for comment blocks since they're made available via reflection. Comments are metadata after all.
And this is more akin to annotations/attributes ala python, java, C#. C++ doesn't have any feature that is approximate by virtue that annotations are aspects of reflection and C++ doesn't have reflection.
1) it's more DRY because for external files to say something about a construct in code there is repeated information, i.e. <route><to><class>Foo</class><method>bar</method></to><from><method>GET</method><url>some/url/here</url></to></route>,
2) because you're using the PHP language to specify metadata about a PHP construct refactoring is easier, i.e. change the name of a function and you don't have to go update your routing somewhere else,
3) having the metadata inline with code turns out to be mentally lightweight once you get over the initial shock of seeing metadata in a comment.
It's little known that doccomments are a PHP language construct that can be reflected over just as Python's doc strings can be introspected with __doc__.
http://us3.php.net/manual/en/language.oop5.reflection.php#la...
Thus !Route GET, a/good/$programmer is just as much a language construct in a PHP program as @route('a/good/:programmer') is in a Python program. The key difference is Python defines at the language level how that particular bit of script is expanded as a decorator. Recess does its expansion of annotations at the framework level.
Python is a much better and more thoughtfully designed programming language than PHP, for sure. PHP has loop holes, doccomments is one of them. PHP does not do anything, by default, with a doccomment, but it does give an opportunity to introduce meta-data on classes, methods, and properties and easily reflect over that meta-data and then it's up to the programmer to define a 'DSL'.
In this sense PHP offers something powerful and dangerous. Recess choose a simple data format, such that parsing can be expressed in a regexp that is then processed by essentially 'Constructing a class of type [FirstWord] and call init method with array of [Following words as a PHP array] - finally make these annotations available through reflection'. Not too much different than annotations in Java/C#. Simple enough that the danger is mostly negated and the utility makes the 'hack' justifiable.
For a better-written justification of why this design decision was made for Recess: http://www.recessframework.org/page/on-hiding-our-dick-tracy...
(Aside: This is why I'm a huge fan of Scala - extending a language with the language is awesome.)
The equivalent in Python would be:
def my_controller(request): """route: /thing/:var/""" pass
or similar.
Luckily this is Python so it's possible to monkeypatch the implementation.
dict holding list holding tuple holding dict :) no biggy to throw a wrapper over it though. Is it possible to place all the routes in one place you think with this? I am worried with a larger project I will forget which module contains what url... Unless there is some convention for url path->module name (if there isnt I would suggest establishing one). A suggestion I would have is standardize on some templating so if people end up using this there wont be a person using a different available one. (http://wiki.python.org/moin/Templating) I noticed http://karrigell.sourceforge.net/en/pythoninsidehtml.htm was not on that page though... albeit its more like php.
Umm... can somebody compare Juno to Pylons please - I'm kind of confused here
IMO, web.py qualifies to be called "really lightweight"
take for instance the hello world code:
This has two advantages over the Juno code..1. more `REST`y (GET/POST)
2. `app` object is a wsgi callable..
More importantly, web.py does not need have any external library dependencies unless you choose to use mysql/postgresql when you have to install the db interface libraries. I had problem running the hello world Juno code because I did not have pysqlite2 installed.. huh? why do I need pysqlite2 to return a string?
While some may object saying that web.py has a case of NIH, the code of web.py itself does not reflect any such attitude. The whole library is just a directory of aptly named modules. You can plop it anywhere in the python path and start coding ..