I recently found myself in need of a command-line URL shortening tool, primarily for use from inside Vim, and a quick search on Freshmeat didn't turn up any likely candidates. In particular I was looking for something that worked with bit.ly, since they provide a variety of tracking tools.
The bit.ly API looked pretty simple, so I spent a little time wrapping it in a simple Python module. The result is available on GitHub for general consumption.
The heart of the module is clever use of Python's __getattr__ call. From the Python 2.6 documentation:
object.__getattr__(self, name) Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should return the (computed) attribute value or raise an AttributeError exception.
The design of the bit.ly REST API makes it very easy to use __getattr__ to generate method accessors. A bit.ly API call is generally a GET request to a URL like this:
http://api.bit.ly/shorten
Arguments to the call are provided as URL parameters, e.g:
http://api.bit.ly/shorten?version=2.0.1&longUrl=http://cnn.com
Since (a) the method calls are all approximately identical and (b) they all take named arguments, this maps nicely to a Python method call using the **kwargs syntax. The general framework of the __getattr__ function looks like this:
def __getattr__ (self, func_name):
def _ (**kwargs):
url = '/'.join([self.api_url, func_name])
query_string = self._build_query_string(kwargs)
fd = urllib.urlopen(url, query_string)
res = json.loads(fd.read())
return res['results']
return _
That is, when client code attempts to access a method attribute, like bitly.shorten(...), we generate an anonymous function that appends the method name to a base url, then appends all the query paramters, and lastly returns the results (decoded from JSON into Python data structures).
The actual code is only slightly more involved (I've tried to provide some reasonable exceptions, for example).
0 comments:
Post a Comment