<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Graceful Exits &#187; hacking</title>
	<atom:link href="http://www.jpstacey.info/blog/category/hacking/www.jpstacey.info/blog/category/hacking/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jpstacey.info/blog</link>
	<description>Garbage collection, in a very real sense</description>
	<pubDate>Thu, 14 Aug 2008 09:05:55 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>The Mashup Song</title>
		<link>http://www.jpstacey.info/blog/2008/07/09/the-mashup-song/</link>
		<comments>http://www.jpstacey.info/blog/2008/07/09/the-mashup-song/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 11:45:26 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[law]]></category>

		<category><![CDATA[network]]></category>

		<category><![CDATA[non-programming]]></category>

		<category><![CDATA[quickies]]></category>

		<category><![CDATA[bonny]]></category>

		<category><![CDATA[filk]]></category>

		<category><![CDATA[legal]]></category>

		<category><![CDATA[mashup]]></category>

		<category><![CDATA[song]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/?p=181</guid>
		<description><![CDATA[I am Richard Stallman for the Web 2.0 Generation. Fear me. I mean, pity me.]]></description>
			<content:encoded><![CDATA[<p>Inspired by the title of <a href="http://yro.slashdot.org/yro/08/07/08/1245204.shtml" >the relevant Slashdot article</a>, to the tune of <cite>My Bonny</cite>:</p>
<blockquote><p>
Your mashup is probably legal.<br />
Your mashup is probably sound.<br />
Your mashup is probably legal,<br />
So pass all that data around!</p>
<p>Stuff here<br />
Stuff there<br />
And something mashed up in between (be-tween!)<br />
Stuff here<br />
Stuff there<br />
And something mashed up in between</p>
<p>Your mashup is probably legal;<br />
You could monetize it as well!<br />
But though I contend it&#8217;s all legal,<br />
Remember I-A-N-A-L!</p>
<p>[<i>Repeat chorus</i>]
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/07/09/the-mashup-song/feed/</wfw:commentRss>
		</item>
		<item>
		<title>User loading and saving in Drupal 5.x</title>
		<link>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/</link>
		<comments>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 15:48:48 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[information]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[5.x]]></category>

		<category><![CDATA[api]]></category>

		<category><![CDATA[core]]></category>

		<category><![CDATA[drupal]]></category>

		<category><![CDATA[hook]]></category>

		<category><![CDATA[id]]></category>

		<category><![CDATA[profile]]></category>

		<category><![CDATA[user]]></category>

		<category><![CDATA[user_load]]></category>

		<category><![CDATA[user_save]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/</guid>
		<description><![CDATA[Workflows of Drupal's user load and save functionality: spot the hooks and win a programmatical prize.]]></description>
			<content:encoded><![CDATA[<p>Recently at <a href="http://torchbox.com/" >Torchbox</a> we&#8217;ve been looking into how to build extra functionality on top of Drupal users. The standard Drupal user object is a combination of the contents from the users table, plus any properties provided by the core <code>profile</code> module. This means that the Drupal user is a combination of rows (and admittedly deserialized, structured data) from a couple of tables in a relational database. </p>
<div style="float: right;"><a title="flowcharts of user_load and user_save" href="#user-flowcharts"><img src="/blog/files/drupal/core/drupal_user_teaser.gif" alt="flowcharts of user_load and user_save" width="145" height="184" /></a></div>
<p>That works just fine for most purposes, but we may have to bring in content from not just outside the core Drupal tables but outside the core database, and even on a remote server through webservices. To this end we&#8217;ve decomposed the core <code>user</code> module&#8217;s <code>user_load()</code> and <code>user_save()</code> functions. This helps us understand better both the workflow and at what points in it our own code can motor into life, query all those extra resources (or set those queries in motion), assemble the rest of the user++ object, and then hand control back over to Drupal.</p>
<p>For those who don&#8217;t know much about Drupal, its core has a <em>hook-based</em> API structure. At certain points in its workflow, it checks all the modules for functions following certain naming conventions (typically the module name followed by the hook name e.g. <code>mymodule_init</code> on response startup, or <code>mymodule_block</code> to return details about the module&#8217;s support for Drupal page furniture). Any matching hook functions are called in the order defined by module weightings, and then page processing will generally continue: you can crowbar a grind-to-a-halt <code>exit()</code> in your hook, but it&#8217;d be unwise, as you can never be sure what tidying up Drupal might need to do after your hook. Outside these hooks, your code has little control over Drupal&#8217;s core functioning, unless you stub out entirely the bits of core you need yourself, and get your request to use those bits instead.z</p>
<p>Because of the way they let your code tag along with Drupal&#8217;s powerful core, hooks are essential to developing modules in the most <em>Drupalish</em> way. With that in mind, <a name="user-flowcharts"></a>here are flow diagrams of the three basic aspects of user functionality&#8212;create new, load, save existing&#8212;lifted straight from examination of the code:</p>
<ul>
<li><a href="/blog/files/drupal/core/drupal_user_load.gif">Loading an existing user with user_load</a></li>
<li><a href="/blog/files/drupal/core/drupal_user_create.gif">Creating a user: saving a new user with user_save</a></li>
<li><a href="/blog/files/drupal/core/drupal_user_update.gif">Updating a user: saving an existing user with user_save</a></li>
</ul>
<p>Although you have to save a user before you can load them, I&#8217;ve put this functionality first in the above (admittedly unordered) list. There are two main reasons for this:</p>
<ol>
<li><code>user_save</code> actually calls <code>user_load</code> a number of times, once or twice, to &#8220;refresh&#8221; the user object</li>
<li><code>user_load</code> is a more primitive function and so bears examination first</li>
</ol>
<p>Stripped down, <code>user_load</code> consists of: querying the database for a core user record matching the search criteria; returning this and the extended profile data; unserializing a free-data field and inserting it into the user object; discovering user roles; <strong>triggering <code>hook_user('load')</code></strong> and returning the object (or boolean false, if no user found).</p>
<p>What this reveals (which I didn&#8217;t realise before) is that <em>the anonymous user is in the Drupal users table</em>, with ID=0. Otherwise, searching for this user would return no records, and the anonymous user object could not be instantiated. You could therefore attach rich data to the anonymous user, if you were in a hacky mood.</p>
<p>The two <code>user_save</code> workflows are fairly similar. Creating a user means obtaining an ID from the database: because some MySQL providers have poorer feature sets than others, referential integrity is ensured at the application level rather than the database level. In place of obtaining an ID, user update <strong>calls <code>hook_user('update')</code> to pre-process</strong> the user. Both workflows then set aside special fields, such as the user&#8217;s password, user roles and any profile fields managed by that module (determined from <code>user_fields()</code>). Then they save this data into the database in slightly different orders, with user creation <code>calling </code><code>hook_user('insert')</code> early on, and the update procedure <code>calling </code><code>hook_user('after_update')</code> much later in the process, just before determining the external authentication mappings (e.g. OpenID) and returning the user object.</p>
<p>What does this mean for us? Well, we&#8217;ll want varying amounts of data to piggyback on the core user object, so we have somewhere to cache it. Ideally this data won&#8217;t be summoned&#8212;brought out of the distributed data &#8216;cloud&#8217;&#8212;on every request/response cycle, so we&#8217;ll need to do some local cacheing, but not so much that we&#8217;ll get out of synch with the cloud (or that we&#8217;ll duplicate sensitive data). We think that, given the pair of hooks in <code>user_save</code> for existing users, we&#8217;ll have just enough leverage to do this: the first hook will effectively &#8220;tear down&#8221; our extra data, so we can do what we want with it, and store it somewhere temporarily; the second hook will &#8220;set up&#8221; the user for the rest of the request, by putting all that data back in. The existence of <code>user_load</code> within <code>user_save</code> complicates things somewhat, but at the same time it gives us some more wiggle room, because each call to that function fires another hook.</p>
<p>A Drupal hook is worth a thousand lines of module code, but they&#8217;re still a bit few and far between for some workflows. Hopefully the accompanying images will help anyone reading to find them, and ditch those thousand lines before they&#8217;re even written.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/06/09/user-loading-and-saving-in-drupal-5x/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Django&#8217;s ViewDoesNotExist Heisenbug</title>
		<link>http://www.jpstacey.info/blog/2008/06/08/djangos-viewdoesnotexist-heisenbug/</link>
		<comments>http://www.jpstacey.info/blog/2008/06/08/djangos-viewdoesnotexist-heisenbug/#comments</comments>
		<pubDate>Sun, 08 Jun 2008 17:21:55 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[information]]></category>

		<category><![CDATA[reporting]]></category>

		<category><![CDATA[control]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[error]]></category>

		<category><![CDATA[fusebox]]></category>

		<category><![CDATA[layer]]></category>

		<category><![CDATA[method]]></category>

		<category><![CDATA[pattern]]></category>

		<category><![CDATA[tag]]></category>

		<category><![CDATA[template]]></category>

		<category><![CDATA[url]]></category>

		<category><![CDATA[view]]></category>

		<category><![CDATA[viewdoesnotexist]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/06/08/djangos-viewdoesnotexist-heisenbug/</guid>
		<description><![CDATA[Django's fusebox sometimes blows one, if you start poking around in it with a template-tag screwdriver.]]></description>
			<content:encoded><![CDATA[<p>To the untrained eye, you might think that you can put any old string in as the second element of one of your <a href="http://www.djangoproject.com/documentation/url_dispatch/" >Django URL dispatcher patterns</a> in <code>urls.py</code>:</p>
<blockquote class="code"><p>
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,<br />
&nbsp;&nbsp;&nbsp;&nbsp;(r&#8217;^$&#8217;, &#8216;myapp.views.webroot&#8217;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;(r&#8217;^a_page/$&#8217;, &#8216;myapp.views.another_page&#8217;),<br />
&nbsp;&nbsp;&nbsp;&nbsp;(r&#8217;^nothing_here_dude/$&#8217;, &#8216;myapp.views.this_view_does_not_exist&#8217;),<br />
)
</p>
</blockquote>
<p>You have a fairly basic Django page which works; you add a new tuple to the URL patterns and refresh the page: it works OK, so if everything runs through the URL dispatcher fusebox, then it must be all right, yeah?</p>
<p>Unfortunately, nonexistent view methods seem to break pages that do a reverse lookup in the URL layer using the <code>{% url %}</code> template tag. You might not use this, but the standard Django admin interface does, several times, on its first page after login e.g:</p>
<blockquote class="code"><p>
&lt;a href=&#8221;{% url django.contrib.admin.views.doc.doc_index %}&#8221;>{% trans &#8216;Documentation&#8217; %}&lt;/a>
</p>
</blockquote>
<p>The above code generates a URL by comparing the view method to the evaluated second arguments of each URL pattern, and evaluation fails at the nonexistent method, giving the error:</p>
<blockquote class="code"><p>
<strong>ViewDoesNotExist at /admin/</strong><br />
Tried options in module myapp.views. Error was: &#8216;module&#8217; object has no attribute &#8216;this_view_does_not_exist&#8217;
</p>
</blockquote>
<p>Sometimes this error isn&#8217;t thrown, so perhaps the underlying code searches a dict of URL patterns in no particular order: that would mean that every now and again it returns the matching view without ever getting to the nonexistent method.</p>
<p>The fix is to comment out the URL. But what if you&#8217;ve got a big codebase, and there are several people working on it, and sometimes nonexistent view methods just get committed? <a href="http://www.djangoproject.com/documentation/testing/" >Testing</a> can help here, specifically interface testing using the fake <code>Client</code> &#8220;browser&#8221;. That&#8217;s not easy when it comes to the out-of-box admin interface, though, because its login procedure seems to require both cookies and a hidden, hashed field to prevent automated logins.</p>
<p>This sounded like it was going somewhere when I started writing it; now, though, I think it&#8217;s just handy to publish it and let it have the Googlejuice, as I couldn&#8217;t find any references online to other people spotting this solution to a reasonably common problem that just&#8212;possibly because another view somewhere else was finally fixed&#8212;suddenly vanishes.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/06/08/djangos-viewdoesnotexist-heisenbug/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Variable assignment in Django templates, sort of</title>
		<link>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/</link>
		<comments>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/#comments</comments>
		<pubDate>Thu, 29 May 2008 13:08:33 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[assignment]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[equals]]></category>

		<category><![CDATA[hack]]></category>

		<category><![CDATA[include]]></category>

		<category><![CDATA[template]]></category>

		<category><![CDATA[variable]]></category>

		<category><![CDATA[with]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/</guid>
		<description><![CDATA[Use and abuse of the "with" programmatic statement to make your Django template code less mad.]]></description>
			<content:encoded><![CDATA[<p>Django&#8217;s templating language is intentionally quite restrictive. The idea is that you have to do all your data munging in the control-ish sublayer of the view layer, in the method registered as handling the view in <code>urls.py</code>. In principle this simplifies templates, but in practice it can make life for the developer more difficult: you have to really think ahead, and assemble your variables properly, so that the templating language can use simple iterative loops to prepare your HTML.</p>
<p>What if you want the same output for several different data structures? Let&#8217;s say we have three people, and we&#8217;d like to run the following <a href="http://www.djangoproject.com/documentation/templates/#include" >include</a>, saved as <code>name.html</code>, on all three:</p>
<blockquote class="code"><p>&lt;p>{{ person.firstname }} {{ person.surname }}&lt;/p></p>
</blockquote>
<p>Ideally you&#8217;d have the three people in a structure called <code>people</code>, and be able to run:</p>
<blockquote class="code"><p>{% for person in people %}{% include &#8220;name.html&#8221; %}{% endfor %}</p>
</blockquote>
<p>But what if the order matters? What if you need <code>account_director</code> to do different things in the template from <code>project_manager</code>? You&#8217;d want to send them through as separate data structures, and this:</p>
<blockquote class="code"><p>{% include &#8220;name.html&#8221; %}<br />
{% include &#8220;name.html&#8221; %}<br />
{% include &#8220;name.html&#8221; %}</p>
</blockquote>
<p>would just do nothing, because it references <code>person</code> and not <code>account_director</code>. An alternative is to turn <code>name.html</code> into a custom tag, taking arguments; but if the content of <code>name.html</code> were any more HTML-heavy then you might want to abstract it into the include nonetheless, and then you&#8217;d just be running a custom tag method, to pass variables to a template fragment, to render the fragment, to pass it back up to the template. It&#8217;d be nicer if we could do this with core functionality instead.</p>
<p>Using the <a href="http://www.djangoproject.com/download/" >latest development version of Django</a>, we can implement basic variable assignment&#8212;getting <code>person</code> to reference whatever we want in the template layer&#8212;using the <a href="http://www.djangoproject.com/documentation/templates/#with" ><code>with</code> template tag</a>. This means that we can wrap each <code>include</code> tag to produce the required output:</p>
<blockquote class="code"><p>{% with account_director as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}<br />
{% with project_manager as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}<br />
{% with lead_developer as person %}<br />
&nbsp;&nbsp;{% include &#8220;name.html&#8221; %}<br />
{% endwith %}</p>
</blockquote>
<p>It seems like overkill for our <code>name.html</code> example, but there are plenty of situations&#8212;I just found one, hence this post&#8212;where it makes sense to factor out code into an include: being able to fiddle with the template context before including it is a lightweight alternative to template tags and a tidy alternative to dumping the HTML right there in the primary template.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/05/29/variable-assignment-in-django-templates-sort-of/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Django laziness at all levels</title>
		<link>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/</link>
		<comments>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/#comments</comments>
		<pubDate>Mon, 12 May 2008 19:03:55 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[chaining]]></category>

		<category><![CDATA[django]]></category>

		<category><![CDATA[evaluation]]></category>

		<category><![CDATA[filter]]></category>

		<category><![CDATA[forms]]></category>

		<category><![CDATA[lazy]]></category>

		<category><![CDATA[modelform]]></category>

		<category><![CDATA[newforms]]></category>

		<category><![CDATA[orm]]></category>

		<category><![CDATA[queryset]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/</guid>
		<description><![CDATA[Lazy evaluation in Django means you can wait till the last possible moment before modifying what you want from the database.]]></description>
			<content:encoded><![CDATA[<p>Following on from Simon Willison&#8217;s <a href="http://simonwillison.net/2008/May/1/orm/">recent post about Django&#8217;s ORM</a>, I&#8217;ve found both the lazy evaluation and chaining properties of Django&#8217;s querysets to be really useful quite deep within Django&#8217;s own view-layer framework.</p>
<p>Django has its own library for building forms, currently called <code>newforms</code> (to distinguish it from the old library, deprecated but left around for compatibility reasons). The <code>ModelForm</code> class in this library interrogates a particular class from the model layer and builds an HTML form&#8212;complete with post-submit validation, field widgets, the lot. The beauty of this is that you can run:</p>
<blockquote class="code"><p>
import django.newforms as forms<br />
from myproject.models import MyObject</p>
<p>class MyForm(forms.ModelForm):<br />
&nbsp;&nbsp;&nbsp;&nbsp;class Meta:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model = MyObject
</p>
</blockquote>
<p>and <em>that&#8217;s it</em>: you can then use an instance of MyForm anywhere in your view layer to add or edit MyObject instances in the database.</p>
<p>Problems arise, of course, when the automatically generated form doesn&#8217;t provide exactly what you want. It might, for example produce select dropdowns for you with thousands of items, whereas with better knowledge of the page your user is on then you might be able to whittle that list down to a handful of items. </p>
<p>Let&#8217;s imagine your objects can belong to Django users i.e. in your <code>models.py</code> you have:</p>
<blockquote class="code"><p>
class MyObject(models.Model):<br />
&nbsp;&nbsp;&nbsp;&nbsp;owner = models.ForeignKey(User)
</p>
</blockquote>
<p>This means that when you try to create an object, the HTML from <code>newforms</code> will give you a select dropdown of all the users in the database. But what if you have loads of inactive users, cluttering up the dropdown? How do you get rid of them with the minimal amount of coding i.e. without having to build your own form if possible?</p>
<p>Luckily, <code>newforms</code> sticks the queryset it creates somewhere that you can fiddle with it. With lazy evaluation, you get a chance to change the queryset before it hits the database; with chaining, you don&#8217;t have to worry about rebuilding the queryset yourself, but can just add to it instead. </p>
<p>In the <code>MyForm</code> class, you can override the inherited <code>__init__</code> method as follows:</p>
<blockquote class="code"><p>
def __init__(self, *a, **kw):<br />
&nbsp;&nbsp;&nbsp;&nbsp;forms.ModelForm.__init__(self, *a, **kw)<br />
&nbsp;&nbsp;&nbsp;&nbsp;self.fields['owner'].queryset = self.fields['owner'].queryset.filter(is_active=True)
</p>
</blockquote>
<p>This calls the existing superclass constructor first, passing along any values. Then, after the queryset has been created for the select dropdown <em>but before it&#8217;s been evaluated</em>, the queryset is modified to whittle down the resultant set of users to only those where the &#8220;is_active&#8221; flag is set to True.</p>
<p>Laziness and chaining make Django&#8217;s ORM layer very effective; <code>forms</code> and <code>newforms</code> help to greatly reduce the amount of coding required by the view and control layers; together they can really simplify a codebase.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/05/12/django-laziness-at-all-levels/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Inconsistent syntax in SQL Server&#8217;s sp_rename</title>
		<link>http://www.jpstacey.info/blog/2008/04/03/inconsistent-syntax-in-sql-servers-sp_rename/</link>
		<comments>http://www.jpstacey.info/blog/2008/04/03/inconsistent-syntax-in-sql-servers-sp_rename/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 16:47:28 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[enterprise]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[subtleties]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/04/03/inconsistent-syntax-in-sql-servers-sp_rename/</guid>
		<description><![CDATA[To rename columns in a SQL Server database, you can use sp_rename. The syntax of the command, in Transact-SQL-ese, is:

sp_rename
&#160;&#160;[ @objname = ] &#8216;object_name&#8217; ,
&#160;&#160;[ @newname = ] &#8216;new_name&#8217;
&#160;&#160;[ , [ @objtype = ] &#8216;object_type&#8217; ]

So say you have a table called t_est, with a column in it called est_client. You want to rename these [...]]]></description>
			<content:encoded><![CDATA[<p>To rename columns in a SQL Server database, you can use sp_rename. The syntax of the command, in Transact-SQL-ese, is:</p>
<blockquote class="code"><p>
sp_rename<br />
&nbsp;&nbsp;[ @objname = ] &#8216;object_name&#8217; ,<br />
&nbsp;&nbsp;[ @newname = ] &#8216;new_name&#8217;<br />
&nbsp;&nbsp;[ , [ @objtype = ] &#8216;object_type&#8217; ]
</p></blockquote>
<p>So say you have a table called <code>t_est</code>, with a column in it called <code>est_client</code>. You want to rename these to <code>t_job</code> and <code>job_client</code> respectively. Firstly, with some trepidation, you rename the table:</p>
<blockquote class="code"><p>sp_rename &#8216;t_est&#8217;, &#8216;t_job&#8217;</p></blockquote>
<p>You find, miracle of miracles, that it works! SQL Server warns you about stored procedures breaking, but looking at other dependent tables you find that foreign key constraints have all been updated so you still have referential integrity.</p>
<p>At this point, you might try renaming a column called, say, <code>est_client</code> to <code>job_client</code> as follows:</p>
<blockquote class="code"><p>sp_rename &#8216;est_client&#8217;, &#8216;job_client&#8217;</p></blockquote>
<p>That&#8217;s wrong, of course, as you soon find out: the <code>object_name</code> needs to be qualified to distinguish it from . So you might try:</p>
<blockquote class="code"><p>sp_rename &#8216;t_job.est_client&#8217;, &#8216;t_job.job_client&#8217;</p></blockquote>
<p>Well, that was successful, but: oh! You now have a column called <code>t_job.job_client</code>, in the <code>t_job</code> table. It looks like <code>new_name</code> shouldn&#8217;t have been qualified after all: you should have assumed inconsistency where consistency was implied by the spec. Well, dealing with Microsoft&#8217;s tech documentation is certainly a learning experience at the best of times, so chalk this one up to experience. But if you now try to learn from your mistakes and revert the column name, you find you can&#8217;t, because:</p>
<blockquote class="code"><p>sp_rename &#8216;t_job.t_job.job_client&#8217;, &#8216;job_client&#8217;</p></blockquote>
<p>tries to rename the column <code>job_client</code>, owned by <em>user</em> <code>t_job</code>, in table <code>t_job</code>&#8230; to <code>job_client</code>. After much headscratching, you finally realise that you can employ <em>double quotes</em> to qualify the column name and make SQL Server treat the dot as a literal dot and not a separator:</p>
<blockquote class="code"><p>sp_rename &#8216;t_job.&#8221;t_job.job_client&#8221;&#8216;, &#8216;job_client&#8217;</p></blockquote>
<p>You sit back, grudgingly satisfied. More time passes. Spring arrives. The owls are not what they seem.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/04/03/inconsistent-syntax-in-sql-servers-sp_rename/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Cheaper rail journeys with Matthew and Spliticket</title>
		<link>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/</link>
		<comments>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/#comments</comments>
		<pubDate>Thu, 13 Mar 2008 21:39:28 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[formats]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[layers]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[useability]]></category>

		<category><![CDATA[accessibility]]></category>

		<category><![CDATA[mashup]]></category>

		<category><![CDATA[matthew]]></category>

		<category><![CDATA[rail]]></category>

		<category><![CDATA[somerville]]></category>

		<category><![CDATA[split]]></category>

		<category><![CDATA[spliticket]]></category>

		<category><![CDATA[tickets]]></category>

		<category><![CDATA[train]]></category>

		<category><![CDATA[traintimes]]></category>

		<category><![CDATA[wiki]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/</guid>
		<description><![CDATA[I&#8217;ve built something, just in time for me to crowbar it awkwardly into conversations at OKCon.
Matthew Somerville is well known for his accessible takes on rubbish websites: most useful is Traintimes, a layer on top of one of the equally poor commercial British rail sites; most notorious is Accessible Odeon, a fixing of the Odeon [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve built something, just in time for me to crowbar it awkwardly into conversations at OKCon.</p>
<p>Matthew Somerville is well known for his accessible takes on rubbish websites: most useful is <a href="http://traintimes.org.uk/">Traintimes</a>, a layer on top of one of the equally poor commercial British rail sites; most notorious is <a href="http://www.dracos.co.uk/odeon/" >Accessible Odeon</a>, a fixing of the Odeon Cinema&#8217;s website that put their own substandard development to shame so much that in 2004 they had Matthew&#8217;s version taken down with legal threats. Remember: just because you&#8217;re successful doesn&#8217;t mean you&#8217;re not stupid.</p>
<p>Recently, Matthew gave an <a href="http://oxford.geeknights.net/" ><abbr title="Oxford Geek Nights">OGN</abbr></a> <a href="http://oxford.geeknights.net/2007/july-25th/talks/MatthewSomerville.mp4" title="'Train in Vain' by Matthew Somerville (mp4 video)">talk on split tickets</a>. These are train journeys which one cross-country train company sells at exhorbitant rates, whereas the components of the journey can be bought separately from the local companies for considerably less. This is what we infer; the rail websites try to keep it all quiet, in the hope that you might lose interest and stump up. The whole headshakeworthy situation is either a stinging indictment of the stupidity of privatizing a rail network and making passengers jump through ridiculous hoops to glean even the tiniest advantage, or a perfect demonstration of how the choice-enriched consumer can leverage capitalism in action: take your pick. </p>
<p>To come to the point: Matthew has set up a wiki where people have been adding the <a href="http://www.dracos.co.uk/wiki/Trains/SplitTickets" >split tickets they&#8217;ve worked out</a> in an <i>ad-hoc</i> fashion. Last Sunday I added K&#8217;s astonishing 47% saving for Oxford&#8211;Cardiff to the end of it, and there&#8217;s been little activity since. The page hasn&#8217;t got fantastic Google juice&#8212;&#8221;split tickets&#8221; means too many other things&#8212;and is just non-dynamic HTML, editable through the wiki but otherwise searchable only by eye.</p>
<p>At the moment, of course, there&#8217;s no reason for Matthew to expend any more effort on such a small and barely popular data set. But last Sunday I had a sudden instinctive jolt, to the effect that: more people would be likely to take advantage of split tickets if there was an easier way of looking up other people&#8217;s discoveries (my colleagues were recently trying to find split tickets and the wiki page was harder to use than Traintimes, for that very purpose).</p>
<p>With this in mind, here&#8217;s my take on accessificating the wiki page: <a href="http://www.jpstacey.info/applications/spliticket/">Spliticket</a>. It accesses a cached version of the page, and then using Python&#8217;s HTMLParser to hack away at the HTML it returns either a HTML or XML representation of any journey it finds. The idea is that it&#8217;s a bit easier to use on your mobile device, and lets you pin down journeys better. I&#8217;ve also included an option for searching strictly for the same journey: I&#8217;m not sure if split tickets&#8212;even returns&#8212;always work when the journey is reversed.</p>
<p>Spliticket also supports friendly URLs (inspired by Traintimes itself), so York to Edinburgh in HTML becomes &lt;<a href="http://www.jpstacey.info/applications/spliticket/html/york/edinburgh/" >http://www.jpstacey.info/applications/spliticket/html/york/edinburgh/</a>&gt; and the aforementioned Oxford to Cardiff route in XML becomes: &lt;<a href="http://www.jpstacey.info/applications/spliticket/xml/oxford/cardiff/">http://www.jpstacey.info/applications/spliticket/xml/oxford/cardiff/</a>&gt; .</p>
<p>Mostly this was just something to fill idle hours, and also to convince myself of some ideas I&#8217;ve had recently about loose coupling, data reuse and open data. Hopefully at the same time (a) Matthew won&#8217;t take it as a dig, (b) others might find some casual use for it see it, and (c) a select few might see it as a testament to the ease of freeing information from solid if unsemantic markup. And maybe in six months&#8217; time we&#8217;ll all be booking split tickets as a matter of course; by then, of course, Spliticket will probably be gratefully obsolete, replaced by the fully-fledged application that poor, embittered rail passengers deserve. I&#8217;m sure Matthew will build it if so.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/03/13/cheaper-rail-journeys-with-matthew-and-spliticket/feed/</wfw:commentRss>
<enclosure url="http://oxford.geeknights.net/2007/july-25th/talks/MatthewSomerville.mp4" length="15044283" type="video/mp4" />
		</item>
		<item>
		<title>How to see Last.fm from the other side of the room with LastJS</title>
		<link>http://www.jpstacey.info/blog/2008/03/02/how-to-see-lastfm-from-the-other-side-of-the-room-with-lastjs/</link>
		<comments>http://www.jpstacey.info/blog/2008/03/02/how-to-see-lastfm-from-the-other-side-of-the-room-with-lastjs/#comments</comments>
		<pubDate>Sun, 02 Mar 2008 14:16:00 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[hacking]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[quickies]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[accessibility]]></category>

		<category><![CDATA[bookmarklet]]></category>

		<category><![CDATA[interface]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[jquery]]></category>

		<category><![CDATA[lastfm]]></category>

		<category><![CDATA[lastjs]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/03/02/how-to-see-lastfm-from-the-other-side-of-the-room-with-lastjs/</guid>
		<description><![CDATA[Back from a rather physical near-week of team building with work, I&#8217;ve been listening to Last.fm today to recuperate and nurse my tired muscles. But with the music playing on our crusty, trusty old purple iMac in one corner, and me in the other reading, drinking tea or otherwise recuperating, how can I tell at [...]]]></description>
			<content:encoded><![CDATA[<p>Back from a rather physical near-week of team building with work, I&#8217;ve been listening to Last.fm today to recuperate and nurse my tired muscles. But with the music playing on our crusty, trusty old purple iMac in one corner, and me in the other reading, drinking tea or otherwise recuperating, how can I tell at a glance what the current artist is?</p>
<p>Last.fm&#8217;s web interface isn&#8217;t optimized for the sort of &#8220;media station&#8221; use we put it to, and their downloadable widget won&#8217;t work on the antiquated version of OSX that I&#8217;ve just about managed to squeeze onto dear old Purpurea. So today I&#8217;ve spent some time writing a bookmarklet to allow me (and you, dear reader) to hook into Last.fm and its Flash player&#8217;s behaviour, to update a larger-view popup window with the necessary information.</p>
<p>Here&#8217;s the bookmarklet&#8212;which with attention to catchy names I&#8217;ve called LastJS&#8212;with spaces added for legibility:</p>
<blockquote class="code"><p>
javascript:void(function(){<br />
&nbsp;&nbsp;var&nbsp;s1=document.createElement(&#8217;script&#8217;);<br />
&nbsp;&nbsp;var&nbsp;s2=document.createElement(&#8217;script&#8217;);<br />
&nbsp;&nbsp;s1.src=&#8217;http://www.jpstacey.info/applications/lastjs/jquery.js&#8217;;<br />
&nbsp;&nbsp;s2.src=&#8217;http://www.jpstacey.info/applications/lastjs/last.js&#8217;;</p>
<p>&nbsp;&nbsp;var&nbsp;h=document.getElementsByTagName(&#8217;head&#8217;)[0];<br />
&nbsp;&nbsp;h.appendChild(s1);<br />
&nbsp;&nbsp;h.appendChild(s2);<br />
}())
</p>
</blockquote>
<p>(As the above suggests, the bulk of the code is at <a href="http://www.jpstacey.info/applications/lastjs/last.js">http://www.jpstacey.info/applications/lastjs/last.js</a>.)</p>
<p>And here&#8217;s what you need to do to use it:</p>
<ol>
<li>Add this link to your browser favourites (IE7) or bookmarks (everyone else): <a href="//www.jpstacey.info/applications/lastjs/last.js';var%20h=document.getElementsByTagName('head')[0];h.appendChild(s1);h.appendChild(s2);}())">LastJS bookmarklet</a>.</li>
<li>While on a Last.FM &#8220;now playing&#8221; page e.g. <a href="http://www.last.fm/listen/artist/Hold%2520Steady/similarartists">for The Hold Steady</a>, click the bookmarklet.</li>
<li>This will pull an instance of jQuery and LastJS off my own server, and add a &#8220;click for big&#8221; link under the title.</li>
<li>Click on the link. A new window will open, containing the artist information (track information is a bit obfuscated until the Flash player loads the next track).</li>
<li>Wait. As the track changes, the new window will update with the new track information.</li>
<li>The text is purposefully large yet not too large. If you&#8217;ve got a big monitor you can make it even bigger by increasing the base font size in your browser. To do this in Firefox press CTRL-+ (or Apple-+); I think it&#8217;s something similar in IE7.</li>
</ol>
<p>Feel free to poke around at the code, and distribute it (under GPL, for what it&#8217;s worth: I tried looking into precisely which variant I wanted but my knees started to ache). Here are some of the problems it has to solve:</p>
<ol>
<li>Last.fm uses Prototype, and so needs jQuery to restore the <code>$</code> variable using <code>jQuery.noConflict()</code>.</li>
<li>Events in the Flash player trigger functions in the <code>window</code> scope: by putting a new method in for a given event handler you can hook into Flash events. Care has to be taken, though, not to wrap and re-wrap too often&#8212;the bookmarklet might after all be re-clicked&#8212;or you might provoke a recursion warning.</li>
<li>Popup blockers mean that you can&#8217;t always guarantee the window will exist, and the code has to check accordingly.</li>
<li>Firefox seems to blank the contents of the popup window shortly after it&#8217;s opened, so any writing of text to it has to be delayed, lest it be lost by this clear-out.</li>
</ol>
<p>All probably needs work, but feel free to have a play. It doesn&#8217;t circumvent any DRM or anything, of course, but I&#8217;ve no idea whether it invalidates terms of use, so <i>caveat fructor</i>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/03/02/how-to-see-lastfm-from-the-other-side-of-the-room-with-lastjs/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Subversion log messages need not be set in stone</title>
		<link>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 12:17:23 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[quickies]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[change]]></category>

		<category><![CDATA[commit]]></category>

		<category><![CDATA[log]]></category>

		<category><![CDATA[message]]></category>

		<category><![CDATA[subversion]]></category>

		<category><![CDATA[svn]]></category>

		<category><![CDATA[undo]]></category>

		<category><![CDATA[version]]></category>

		<category><![CDATA[versioning]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/</guid>
		<description><![CDATA[Simon Willison mentioned a while back a link to help on how to undo a svn commit in subversion (more a kind of internal branching than an actual undo, of course: but that&#8217;s subversion). That&#8217;s all very well, but how about undoing the log message for a particular commit?
Say you have a codebase that only [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://simonwillison.net/">Simon Willison</a> mentioned a while back a link to help on <a href="http://noehr.org/2007/12/undo_commit_in_subversion_svn_1.html">how to undo a svn commit</a> in subversion (more a kind of internal branching than an actual undo, of course: but that&#8217;s subversion). That&#8217;s all very well, but how about undoing the log message for a particular commit?</p>
<p>Say you have a codebase that only you&#8217;ve worked on, and the log messages are (to say the least) idiosyncratic. Worse, they might contain swear words like &#8220;p*mh*le,&#8221; &#8220;cl*ff-pr*nker&#8221; or &#8220;Gr**nsp*n.&#8221; How can you, for example, get rid of a bit of bitching between programmers like:</p>
<blockquote class="code"><p>
$ svn log -r 200<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
r200 | jps | 2007-05-30 14:50:56 +0100 (Wed, 30 May 2007) | 2 lines</p>
<p>oh for heaven&#8217;s sake - cacheing at view layer broke CSS!<br />
Which buffoon wrote l51-78, ***Malcolm***?<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;
</p>
</blockquote>
<p>The <code>svn propset</code> command in principle <a href="http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.propset.html" title="svn propset and logs">lets you change log messages</a>. However, most archives are set up to prevent this by default with &#8220;hooks.&#8221; You <em>can</em> alter the configuration of the archive to permit this, if you&#8217;ve got administrator&#8217;s access to the physical files of the archive. But if you&#8217;ve got that, then you can <a href="http://svnbook.red-bean.com/en/1.4/svn.reposadmin.maint.html#svn.reposadmin.maint.setlog" title="svnadmin setlog and logs">change the log message directly</a> with the <code>svnadmin setlog</code> command and the <code>-<!-- -->-bypass-hooks</code> option:</p>
<blockquote class="code"><p>
% echo &#8220;Fixed&#8221; &gt; /tmp/newlog.txt<br />
% svnadmin setlog -<!-- -->-bypass-hooks /home/svn/repositories/bluefish /tmp/newlog.txt -r 200
</p>
</blockquote>
<p>The advantage of this is that all hooks remain in place afterwards, so you don&#8217;t have to worry about re-securing the archive. As the link to the Redbean book up there states, though, be warned that <code>-<!-- -->-bypass-hooks</code> bypasses <em>all</em> hooks: if you have email alerts set up to report each submission, then they too will fail to fire. Another reason not to do it permanently, I suppose.</p>
<p>(And I don&#8217;t work with anyone called Malcolm.)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/14/subversion-log-messages-need-not-be-set-in-stone/feed/</wfw:commentRss>
		</item>
		<item>
		<title>&#8220;You have to have something bad happen to you&#8221;</title>
		<link>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</link>
		<comments>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/#comments</comments>
		<pubDate>Mon, 07 Jan 2008 12:05:11 +0000</pubDate>
		<dc:creator>jps</dc:creator>
		
		<category><![CDATA[diagnostics]]></category>

		<category><![CDATA[efficiency]]></category>

		<category><![CDATA[hacking]]></category>

		<category><![CDATA[paradigms]]></category>

		<category><![CDATA[projects]]></category>

		<category><![CDATA[software]]></category>

		<category><![CDATA[bloat]]></category>

		<category><![CDATA[code]]></category>

		<category><![CDATA[copy]]></category>

		<category><![CDATA[debug]]></category>

		<category><![CDATA[ide]]></category>

		<category><![CDATA[paste]]></category>

		<category><![CDATA[rants]]></category>

		<category><![CDATA[reuse]]></category>

		<category><![CDATA[steve]]></category>

		<category><![CDATA[yegge]]></category>

		<guid isPermaLink="false">http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/</guid>
		<description><![CDATA[Steve Yegge on code&#8217;s worst enemy:
&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://steve-yegge.blogspot.com/">Steve Yegge</a> on <a href="http://steve-yegge.blogspot.com/2007/12/codes-worst-enemy.html">code&#8217;s worst enemy</a>:</p>
<blockquote><p>&#8230; This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn&#8217;t take very long for programmers to learn this lesson the hard way. It&#8217;s not so much a rule you have to memorize as a scar you&#8217;re going to get whether you like it or not. Computers make copy-and-paste really easy, so every programmer falls into the trap once in a while. The lesson you eventually learn is that code always changes, always always always, and as soon as you have to change the same thing in N places, where N is more than 1, you&#8217;ll have earned your scar&#8230;.</p>
</blockquote>
<p>Code reuse is great, although some languages punish you for it: Coldfusion takes a performance hit on behalf of debug logging whenever it crosses a component boundary, even if debugging is turned off. And a lot of includes scattered across the place can make it difficult to track what&#8217;s going on (unless you use those very IDEs that Steve suggests treat code like heaps of dirt to be rearranged). I suppose ultimately it&#8217;s about developing an instinct for balancing short-term performance, ongoing maintainability and long-term scalability, and you only learn that by dint of many, many scars.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jpstacey.info/blog/2008/01/07/you-have-to-have-something-bad-happen-to-you/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
