<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Giv Parvaneh</title>
	<atom:link href="http://www.givp.org/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.givp.org/blog</link>
	<description>::::..::..:::::::...:::::....::......:::::::::....::::......::::::::::::::::</description>
	<lastBuildDate>Wed, 11 Aug 2010 18:32:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<meta xmlns="http://www.w3.org/1999/xhtml" name="robots" content="noindex,follow" />
		<item>
		<title>Test-Driven Development &#8211; How Do I Start?</title>
		<link>http://www.givp.org/blog/2010/07/22/test-driven-development-how-do-i-start/</link>
		<comments>http://www.givp.org/blog/2010/07/22/test-driven-development-how-do-i-start/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 21:42:12 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[p]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=188</guid>
		<description><![CDATA[There seem to be a lot of developers who like the idea of Test-Driven Development (TDD) and can clearly see the benefit of having tests written for their code but can&#8217;t seem to get their head around the process. How do you start writing unit tests before writing the actual code? Let&#8217;s start with an [...]]]></description>
			<content:encoded><![CDATA[<p>There seem to be a lot of developers who like the idea of <a href="http://en.wikipedia.org/wiki/Test-driven_development" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Test-driven_development?referer=');">Test-Driven Development</a> (TDD) and can clearly see the benefit of having tests written for their code but can&#8217;t seem to get their head around the process. How do you start writing unit tests <em>before</em> writing the actual code?</p>
<p>Let&#8217;s start with an example. You want to write a method that takes a URL as an argument and have it tell you through a boolean return if it&#8217;s the correct domain or not. It seems simple enough. Just write your method, pass the URL through some regular expression and you&#8217;re done.</p>
<p>But you yourself already know which domains are allowed and which are not so before writing the actual code you can run some tests in your head. E.g. I only want www.bbc.co.uk and its sub-domains on http and https. Nothing else should be allowed. So https://beta.bbc.co.uk/iplayer should return TRUE and http://www.bbcbb.com should return FALSE etc.</p>
<blockquote><p>The process behind TDD is that you first write a failing test. Then you write the actual code and adjust until the test passes.</p></blockquote>
<p>So let&#8217;s write some tests for our domain checker. I&#8217;m using Python and Unittest here:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">unittest</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># this is what we're going to be testing</span>
<span style="color: #ff7700;font-weight:bold;">class</span> Utils<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> is_bbc<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, val<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">pass</span> <span style="color: #808080; font-style: italic;">#placeholder</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># this is the actual test</span>
<span style="color: #ff7700;font-weight:bold;">class</span> TestUtils<span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestCase</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> setUp<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">u</span> = Utils<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_is_bbc<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk/iplayer'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk/food'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'https://www.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://beta.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.com'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
suite = <span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestLoader</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">loadTestsFromTestCase</span><span style="color: black;">&#40;</span>TestUtils<span style="color: black;">&#41;</span>
<span style="color: #dc143c;">unittest</span>.<span style="color: black;">TextTestRunner</span><span style="color: black;">&#40;</span>verbosity=<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>.<span style="color: black;">run</span><span style="color: black;">&#40;</span>suite<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>I&#8217;ve created a an empty method where our domain checker is going to live but as you can see it doesn&#8217;t do anything. The tests should immediately make sense. We pass a bunch of domain variations and we know which ones should pass or fail. Naturally, running the test right now will fail:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python sample.py 
test_is_bbc <span style="color: #7a0874; font-weight: bold;">&#40;</span>__main__.TestUtils<span style="color: #7a0874; font-weight: bold;">&#41;</span> ... FAIL
&nbsp;
======================================================================
FAIL: test_is_bbc <span style="color: #7a0874; font-weight: bold;">&#40;</span>__main__.TestUtils<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #660033;">----------------------------------------------------------------------</span>
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
  File <span style="color: #ff0000;">&quot;sample.py&quot;</span>, line <span style="color: #000000;">14</span>, <span style="color: #000000; font-weight: bold;">in</span> test_is_bbc
    self.assertTrue<span style="color: #7a0874; font-weight: bold;">&#40;</span>self.u.is_bbc<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'http://www.bbc.co.uk/iplayer'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
AssertionError
&nbsp;
<span style="color: #660033;">----------------------------------------------------------------------</span>
Ran <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #000000; font-weight: bold;">in</span> 0.000s
&nbsp;
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">failures</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>Now you can start writing the actual code and keep running the same tests until it passes:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">unittest</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># this is what we're going to be testing</span>
<span style="color: #ff7700;font-weight:bold;">class</span> Utils<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> is_bbc<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, val<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #dc143c;">re</span>.<span style="color: black;">match</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'^https?://([^/]+)?<span style="color: #000099; font-weight: bold;">\.</span>bbc<span style="color: #000099; font-weight: bold;">\.</span>co<span style="color: #000099; font-weight: bold;">\.</span>uk'</span>, val<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># this is the actual test</span>
<span style="color: #ff7700;font-weight:bold;">class</span> TestUtils<span style="color: black;">&#40;</span><span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestCase</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> setUp<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">u</span> = Utils<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> test_is_bbc<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk/iplayer'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk/food'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'https://www.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertTrue</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://beta.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbc.com'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://www.bbbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">assertFalse</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">u</span>.<span style="color: black;">is_bbc</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'http://.bbc.co.uk'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;">#this should fail</span>
&nbsp;
suite = <span style="color: #dc143c;">unittest</span>.<span style="color: black;">TestLoader</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">loadTestsFromTestCase</span><span style="color: black;">&#40;</span>TestUtils<span style="color: black;">&#41;</span>
<span style="color: #dc143c;">unittest</span>.<span style="color: black;">TextTestRunner</span><span style="color: black;">&#40;</span>verbosity=<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>.<span style="color: black;">run</span><span style="color: black;">&#40;</span>suite<span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>The regex may look like it&#8217;s correct but running the test will fail again:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ python sample.py
test_is_bbc <span style="color: #7a0874; font-weight: bold;">&#40;</span>__main__.TestUtils<span style="color: #7a0874; font-weight: bold;">&#41;</span> ... FAIL
&nbsp;
======================================================================
FAIL: test_is_bbc <span style="color: #7a0874; font-weight: bold;">&#40;</span>__main__.TestUtils<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #660033;">----------------------------------------------------------------------</span>
Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
  File <span style="color: #ff0000;">&quot;sample.py&quot;</span>, line <span style="color: #000000;">22</span>, <span style="color: #000000; font-weight: bold;">in</span> test_is_bbc
    self.assertFalse<span style="color: #7a0874; font-weight: bold;">&#40;</span>self.u.is_bbc<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'http://.bbc.co.uk'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
AssertionError
&nbsp;
<span style="color: #660033;">----------------------------------------------------------------------</span>
Ran <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #000000; font-weight: bold;">in</span> 0.001s
&nbsp;
FAILED <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">failures</span>=<span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

<p>It has failed on the final assert because our code will also allow http://.bbc.co.uk and we obviously don&#8217;t want that. But as you can see we&#8217;ve caught this edge case before deploying our app so we can promptly fix our code.</p>
<p>Hopefully this example demonstrates why it&#8217;s a good idea to start with tests. This is obviously a simple example but on bigger projects predicting the outcome of your system can save you a lot of debugging time in the future.</p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Test-Driven%20Development%20-%20How%20Do%20I%20Start%3F%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F22%2Ftest-driven-development-how-do-i-start%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Test-Driven_20Development_20-_20How_20Do_20I_20Start_3F_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F22_2Ftest-driven-development-how-do-i-start_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F22%2Ftest-driven-development-how-do-i-start%2F&amp;t=Test-Driven%20Development%20-%20How%20Do%20I%20Start%3F" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F22_2Ftest-driven-development-how-do-i-start_2F_amp_t=Test-Driven_20Development_20-_20How_20Do_20I_20Start_3F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F22%2Ftest-driven-development-how-do-i-start%2F&amp;title=Test-Driven%20Development%20-%20How%20Do%20I%20Start%3F&amp;bodytext=There%20seem%20to%20be%20a%20lot%20of%20developers%20who%20like%20the%20idea%20of%20Test-Driven%20Development%20%28TDD%29%20and%20can%20clearly%20see%20the%20benefit%20of%20having%20tests%20written%20for%20their%20code%20but%20can%27t%20seem%20to%20get%20their%20head%20around%20the%20process.%20How%20do%20you%20start%20writing%20unit%20tests%20be" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F22_2Ftest-driven-development-how-do-i-start_2F_amp_title=Test-Driven_20Development_20-_20How_20Do_20I_20Start_3F_amp_bodytext=There_20seem_20to_20be_20a_20lot_20of_20developers_20who_20like_20the_20idea_20of_20Test-Driven_20Development_20_28TDD_29_20and_20can_20clearly_20see_20the_20benefit_20of_20having_20tests_20written_20for_20their_20code_20but_20can_27t_20seem_20to_20get_20their_20head_20around_20the_20process._20How_20do_20you_20start_20writing_20unit_20tests_20be&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F22%2Ftest-driven-development-how-do-i-start%2F&amp;title=Test-Driven%20Development%20-%20How%20Do%20I%20Start%3F&amp;notes=There%20seem%20to%20be%20a%20lot%20of%20developers%20who%20like%20the%20idea%20of%20Test-Driven%20Development%20%28TDD%29%20and%20can%20clearly%20see%20the%20benefit%20of%20having%20tests%20written%20for%20their%20code%20but%20can%27t%20seem%20to%20get%20their%20head%20around%20the%20process.%20How%20do%20you%20start%20writing%20unit%20tests%20be" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F22_2Ftest-driven-development-how-do-i-start_2F_amp_title=Test-Driven_20Development_20-_20How_20Do_20I_20Start_3F_amp_notes=There_20seem_20to_20be_20a_20lot_20of_20developers_20who_20like_20the_20idea_20of_20Test-Driven_20Development_20_28TDD_29_20and_20can_20clearly_20see_20the_20benefit_20of_20having_20tests_20written_20for_20their_20code_20but_20can_27t_20seem_20to_20get_20their_20head_20around_20the_20process._20How_20do_20you_20start_20writing_20unit_20tests_20be&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F22%2Ftest-driven-development-how-do-i-start%2F&amp;title=Test-Driven%20Development%20-%20How%20Do%20I%20Start%3F&amp;annotation=There%20seem%20to%20be%20a%20lot%20of%20developers%20who%20like%20the%20idea%20of%20Test-Driven%20Development%20%28TDD%29%20and%20can%20clearly%20see%20the%20benefit%20of%20having%20tests%20written%20for%20their%20code%20but%20can%27t%20seem%20to%20get%20their%20head%20around%20the%20process.%20How%20do%20you%20start%20writing%20unit%20tests%20be" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F22_2Ftest-driven-development-how-do-i-start_2F_amp_title=Test-Driven_20Development_20-_20How_20Do_20I_20Start_3F_amp_annotation=There_20seem_20to_20be_20a_20lot_20of_20developers_20who_20like_20the_20idea_20of_20Test-Driven_20Development_20_28TDD_29_20and_20can_20clearly_20see_20the_20benefit_20of_20having_20tests_20written_20for_20their_20code_20but_20can_27t_20seem_20to_20get_20their_20head_20around_20the_20process._20How_20do_20you_20start_20writing_20unit_20tests_20be&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/07/22/test-driven-development-how-do-i-start/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Saving data with Titanium mobile</title>
		<link>http://www.givp.org/blog/2010/07/15/saving-data-with-titanium-mobile/</link>
		<comments>http://www.givp.org/blog/2010/07/15/saving-data-with-titanium-mobile/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 20:15:29 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[appcelerator]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[titanium]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=181</guid>
		<description><![CDATA[In my previous post I talked about getting a simple table view up and running quickly using Titanium. A few people have asked me to continue the tutorial and explain how to save individual items and then display saved items in a separate window. Saving data is quite simple. You first need to create the [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.givp.org/blog/2010/07/13/building-mobile-app-with-titanium/">my previous post</a> I talked about getting a simple table view up and running quickly using Titanium. A few people have asked me to continue the tutorial and explain how to save individual items and then display saved items in a separate window.</p>
<p>Saving data is quite simple. You first need to create the database and schema. You obviously only need to do this the first time the user opens your app. So in your app.js file you can do something like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> db <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">Database</span>.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'mydb'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
db.<span style="color: #660066;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'CREATE TABLE IF NOT EXISTS SAVEDITEMS  (NAME TEXT)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>This should look very familiar to you if you&#8217;re used to SQL. It first instantiates a database object then checks to see if the &#8220;SAVEDITEMS&#8221; table exists. If not, it will simply create it. If it does exist, it will just ignore that command. This will create a table with a single text field for storing the name of a selected item.</p>
<p>Now that we have our table set up, we can read and write to it whenever we like. If you wanted to save an item, you would do this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">db.<span style="color: #660066;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;INSERT INTO SAVEDITEMS ( NAME ) VALUES ('my cool item')&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>To get a list of all items in the database:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> rows <span style="color: #339933;">=</span> db.<span style="color: #660066;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;SELECT * FROM SAVEDITEMS&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
rows.<span style="color: #000066;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>The last line is very important. You must close your query results to avoid memory leakage.</p>
<p>You can now loop through the saved items and stick them in a table view:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// create blank table view</span>
<span style="color: #003366; font-weight: bold;">var</span> tableview <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createTableView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">currentWindow</span>.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span>tableview<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create an empty array</span>
<span style="color: #003366; font-weight: bold;">var</span> data <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// get a list of all saved items</span>
<span style="color: #003366; font-weight: bold;">var</span> rows <span style="color: #339933;">=</span> db.<span style="color: #660066;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'SELECT * FROM SAVEDITEMS'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// loop through all items</span>
<span style="color: #000066; font-weight: bold;">while</span> <span style="color: #009900;">&#40;</span>rows.<span style="color: #660066;">isValidRow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
   <span style="color: #006600; font-style: italic;">// add each item to the data array and set the table row title    	</span>
   data.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>title<span style="color: #339933;">:</span>rows.<span style="color: #660066;">field</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>hasChild<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   rows.<span style="color: #660066;">next</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>  
&nbsp;
<span style="color: #006600; font-style: italic;">// load db data into the table view </span>
tableview.<span style="color: #660066;">setData</span><span style="color: #009900;">&#40;</span>data<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
rows.<span style="color: #000066;">close</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>That should help you get started. You can look at how to use events to save items and also check to see which items have already been saved so you don&#8217;t show the save button etc. Take a look at the <a href="http://github.com/givp/Titanium-Mobile-Reference-Directory-App" onclick="pageTracker._trackPageview('/outgoing/github.com/givp/Titanium-Mobile-Reference-Directory-App?referer=');">demo app</a> I&#8217;ve created to see how I handled the saving logic. Specifically the <a href="http://github.com/givp/Titanium-Mobile-Reference-Directory-App/blob/master/details.js" onclick="pageTracker._trackPageview('/outgoing/github.com/givp/Titanium-Mobile-Reference-Directory-App/blob/master/details.js?referer=');">details.js</a> file.</p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Saving%20data%20with%20Titanium%20mobile%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F15%2Fsaving-data-with-titanium-mobile%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Saving_20data_20with_20Titanium_20mobile_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F15_2Fsaving-data-with-titanium-mobile_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F15%2Fsaving-data-with-titanium-mobile%2F&amp;t=Saving%20data%20with%20Titanium%20mobile" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F15_2Fsaving-data-with-titanium-mobile_2F_amp_t=Saving_20data_20with_20Titanium_20mobile&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F15%2Fsaving-data-with-titanium-mobile%2F&amp;title=Saving%20data%20with%20Titanium%20mobile&amp;bodytext=In%20my%20previous%20post%20I%20talked%20about%20getting%20a%20simple%20table%20view%20up%20and%20running%20quickly%20using%20Titanium.%20A%20few%20people%20have%20asked%20me%20to%20continue%20the%20tutorial%20and%20explain%20how%20to%20save%20individual%20items%20and%20then%20display%20saved%20items%20in%20a%20separate%20window.%0D%0A%0D%0AS" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F15_2Fsaving-data-with-titanium-mobile_2F_amp_title=Saving_20data_20with_20Titanium_20mobile_amp_bodytext=In_20my_20previous_20post_20I_20talked_20about_20getting_20a_20simple_20table_20view_20up_20and_20running_20quickly_20using_20Titanium._20A_20few_20people_20have_20asked_20me_20to_20continue_20the_20tutorial_20and_20explain_20how_20to_20save_20individual_20items_20and_20then_20display_20saved_20items_20in_20a_20separate_20window._0D_0A_0D_0AS&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F15%2Fsaving-data-with-titanium-mobile%2F&amp;title=Saving%20data%20with%20Titanium%20mobile&amp;notes=In%20my%20previous%20post%20I%20talked%20about%20getting%20a%20simple%20table%20view%20up%20and%20running%20quickly%20using%20Titanium.%20A%20few%20people%20have%20asked%20me%20to%20continue%20the%20tutorial%20and%20explain%20how%20to%20save%20individual%20items%20and%20then%20display%20saved%20items%20in%20a%20separate%20window.%0D%0A%0D%0AS" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F15_2Fsaving-data-with-titanium-mobile_2F_amp_title=Saving_20data_20with_20Titanium_20mobile_amp_notes=In_20my_20previous_20post_20I_20talked_20about_20getting_20a_20simple_20table_20view_20up_20and_20running_20quickly_20using_20Titanium._20A_20few_20people_20have_20asked_20me_20to_20continue_20the_20tutorial_20and_20explain_20how_20to_20save_20individual_20items_20and_20then_20display_20saved_20items_20in_20a_20separate_20window._0D_0A_0D_0AS&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F15%2Fsaving-data-with-titanium-mobile%2F&amp;title=Saving%20data%20with%20Titanium%20mobile&amp;annotation=In%20my%20previous%20post%20I%20talked%20about%20getting%20a%20simple%20table%20view%20up%20and%20running%20quickly%20using%20Titanium.%20A%20few%20people%20have%20asked%20me%20to%20continue%20the%20tutorial%20and%20explain%20how%20to%20save%20individual%20items%20and%20then%20display%20saved%20items%20in%20a%20separate%20window.%0D%0A%0D%0AS" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F15_2Fsaving-data-with-titanium-mobile_2F_amp_title=Saving_20data_20with_20Titanium_20mobile_amp_annotation=In_20my_20previous_20post_20I_20talked_20about_20getting_20a_20simple_20table_20view_20up_20and_20running_20quickly_20using_20Titanium._20A_20few_20people_20have_20asked_20me_20to_20continue_20the_20tutorial_20and_20explain_20how_20to_20save_20individual_20items_20and_20then_20display_20saved_20items_20in_20a_20separate_20window._0D_0A_0D_0AS&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/07/15/saving-data-with-titanium-mobile/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a native mobile app with Titanium in less than an hour</title>
		<link>http://www.givp.org/blog/2010/07/13/building-mobile-app-with-titanium/</link>
		<comments>http://www.givp.org/blog/2010/07/13/building-mobile-app-with-titanium/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 12:03:46 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[appcelerator]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[Objective-c]]></category>
		<category><![CDATA[titanium]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=164</guid>
		<description><![CDATA[When I wrote my last blog entry, I favoured objective-c over Appcelerator&#8217;s Titanium framework thinking it just wasn&#8217;t good enough. Almost 6 months later and I would like to take back that comment. Titanium is no longer an embedded web browser inside an app. It uses Javascript to compile an entire iPhone/Xcode project with objective-c, [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.givp.org/blog/wp-content/uploads/2010/07/animalApp.jpg" alt="" title="animalApp" width="595" height="376" class="alignleft size-full wp-image-166" /><br />
<br />
When I wrote my last blog entry, I favoured objective-c over <a href="http://www.appcelerator.com/" onclick="pageTracker._trackPageview('/outgoing/www.appcelerator.com/?referer=');">Appcelerator&#8217;s Titanium framework</a> thinking it just wasn&#8217;t good enough. Almost 6 months later and I would like to take back that comment. Titanium is no longer an embedded web browser inside an app. It uses Javascript to compile an entire iPhone/Xcode project with objective-c, so it uses native UI elements using clever APIs. This is also true for Android apps, iPad and now Blackberry.</p>
<p>This is not to say there&#8217;s no need to use Xcode ever again. But if you&#8217;re planning to build a general navigation-based app with loads of menus, windows and the ability to pull/push data from the web, it can be done much faster with Titanium. Plus you&#8217;ll be able to create the same app for multiple platforms without re-writing the code.</p>
<p>So I wanted to put together a relatively simple app that lets me browse and search through a list of items, in this example, animals; and be able to group them alphabetically like the iPhone&#8217;s contacts directory. Then I want to click on an item to see more details and be able to save my favourite items for easy access later.</p>
<p>I&#8217;ve created a sample app that you can <a href="http://github.com/givp/Titanium-Mobile-Reference-Directory-App" onclick="pageTracker._trackPageview('/outgoing/github.com/givp/Titanium-Mobile-Reference-Directory-App?referer=');">download</a> and use right now. All you have to do is add your own data and you&#8217;re done. </p>
<p>I&#8217;m going to quickly run you through how to set up the tabs, the list, alphabetical grouping, search and detail view for each item. I won&#8217;t explain the saving feature here but once you do the main part below you should be able to easily follow the rest by looking at <a href="http://github.com/givp/Titanium-Mobile-Reference-Directory-App" onclick="pageTracker._trackPageview('/outgoing/github.com/givp/Titanium-Mobile-Reference-Directory-App?referer=');">the code</a>. </p>
<p>Here&#8217;s how it works. See the sample app to work out where to place individual files.</p>
<p>1. Create a tab group. One for the main list and one tab for saved items:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// create tab group</span>
<span style="color: #003366; font-weight: bold;">var</span> tabGroup <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createTabGroup</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create base UI tab and root window</span>
<span style="color: #003366; font-weight: bold;">var</span> mainList <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createWindow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>  
    title<span style="color: #339933;">:</span><span style="color: #3366CC;">'Animals'</span><span style="color: #339933;">,</span>
    backgroundColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#ffffff'</span><span style="color: #339933;">,</span>
    barColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#333'</span><span style="color: #339933;">,</span>
    url<span style="color: #339933;">:</span><span style="color: #3366CC;">'mainList.js'</span><span style="color: #339933;">,</span>
    tabBarHidden<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> tabMainList <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createTab</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>  
    icon<span style="color: #339933;">:</span><span style="color: #3366CC;">'book.png'</span><span style="color: #339933;">,</span>
    title<span style="color: #339933;">:</span><span style="color: #3366CC;">'Animals'</span><span style="color: #339933;">,</span>
    window<span style="color: #339933;">:</span>mainList
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create saved items tab</span>
<span style="color: #003366; font-weight: bold;">var</span> faves <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createWindow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>  
    title<span style="color: #339933;">:</span><span style="color: #3366CC;">'Saved Items'</span><span style="color: #339933;">,</span>
    backgroundColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#ffffff'</span><span style="color: #339933;">,</span>
    barColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#333'</span><span style="color: #339933;">,</span>
    url<span style="color: #339933;">:</span><span style="color: #3366CC;">'faves.js'</span><span style="color: #339933;">,</span>
    tabBarHidden<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> tabFaves <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createTab</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>  
    icon<span style="color: #339933;">:</span><span style="color: #3366CC;">'star.png'</span><span style="color: #339933;">,</span>
    title<span style="color: #339933;">:</span><span style="color: #3366CC;">'Saved Items'</span><span style="color: #339933;">,</span>
    window<span style="color: #339933;">:</span>faves
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">//  add tabs</span>
tabGroup.<span style="color: #660066;">addTab</span><span style="color: #009900;">&#40;</span>tabMainList<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
tabGroup.<span style="color: #660066;">addTab</span><span style="color: #009900;">&#40;</span>tabFaves<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  
tabGroup.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span>tabMainList<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">currentWindow</span>.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span>tabGroup<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>That&#8217;s it. We have now created two tabs. mainList.js will take care of the content for the first tab and faves.js for the saved items tab.</p>
<p>2. Create a JSON doc (data.js) containing your data for the list:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> myData <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>
    <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Armadillo&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;description&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Armadillos eat ants but they are not Anteaters&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Bear&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;description&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Bears are awesome and they like honey&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Dog&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;description&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Dogs are the best and they woof&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Deer&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;description&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;D'oh! a deer...&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;title&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Zebra&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;description&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;Zebras are stripey and cool&quot;</span><span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>3. Set up your directory list in the first tab (mainList.js)</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// include the data</span>
Titanium.<span style="color: #660066;">include</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'data.js'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> data <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> firstLetter<span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> oldFirstLetter<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// loop through data and add to list</span>
<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> myData.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">// get first letter of each item for grouping</span>
	firstLetter <span style="color: #339933;">=</span> myData<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">title</span>.<span style="color: #660066;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">==</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	    oldFirstLetter <span style="color: #339933;">=</span> firstLetter<span style="color: #339933;">;</span>
	    Ti.<span style="color: #660066;">API</span>.<span style="color: #660066;">info</span><span style="color: #009900;">&#40;</span>oldFirstLetter<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>	
	    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>firstLetter <span style="color: #339933;">==</span> oldFirstLetter<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    	        oldFirstLetter <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    	    <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
    	        oldFirstLetter <span style="color: #339933;">=</span> firstLetter<span style="color: #339933;">;</span>
    	    <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        data.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>title<span style="color: #339933;">:</span>myData<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">title</span><span style="color: #339933;">,</span>hasChild<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>header<span style="color: #339933;">:</span>oldFirstLetter<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>	
        oldFirstLetter <span style="color: #339933;">=</span> firstLetter<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// add search bar</span>
<span style="color: #003366; font-weight: bold;">var</span> search <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createSearchBar</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
	showCancel<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create table view</span>
<span style="color: #003366; font-weight: bold;">var</span> tableview <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createTableView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    data<span style="color: #339933;">:</span>data<span style="color: #339933;">,</span>
    search<span style="color: #339933;">:</span>search<span style="color: #339933;">,</span>
    filterAttribute<span style="color: #339933;">:</span><span style="color: #3366CC;">'title'</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">currentWindow</span>.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span>tableview<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create table view event listener</span>
tableview.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'click'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> win <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createWindow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
		url<span style="color: #339933;">:</span><span style="color: #3366CC;">'details.js'</span><span style="color: #339933;">,</span>
		backgroundColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#ffffff'</span><span style="color: #339933;">,</span>
                barColor<span style="color: #339933;">:</span><span style="color: #3366CC;">'#333333'</span><span style="color: #339933;">,</span>
		title<span style="color: #339933;">:</span>e.<span style="color: #660066;">rowData</span>.<span style="color: #660066;">title</span>
	<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #006600; font-style: italic;">// send selected item's title to detail page</span>
	win.<span style="color: #660066;">currentItem</span> <span style="color: #339933;">=</span> e.<span style="color: #660066;">rowData</span>.<span style="color: #660066;">title</span><span style="color: #339933;">;</span>
&nbsp;
	Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">currentTab</span>.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span>win<span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span>animated<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>Notice in the tableview event listener we are telling it to just open a new window on click and pass the item&#8217;s title.</p>
<p>4. Display the selected item&#8217;s data in details.js</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// include the data</span>
Titanium.<span style="color: #660066;">include</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'data.js'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
win <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">currentWindow</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> desc <span style="color: #339933;">=</span> <span style="color: #3366CC;">''</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create scroll view for the content</span>
<span style="color: #003366; font-weight: bold;">var</span> scrollView <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createScrollView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
	contentWidth<span style="color: #339933;">:</span><span style="color: #3366CC;">'auto'</span><span style="color: #339933;">,</span>
	contentHeight<span style="color: #339933;">:</span><span style="color: #3366CC;">'auto'</span><span style="color: #339933;">,</span>
	top<span style="color: #339933;">:</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span>
	showVerticalScrollIndicator<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span>
	showHorizontalScrollIndicator<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
<span style="color: #006600; font-style: italic;">// loop through data and get correct item by title (this is easier than using Id's incase you add new items later)</span>
<span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> myData.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>myData<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">title</span> <span style="color: #339933;">==</span> win.<span style="color: #660066;">currentItem</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
        desc <span style="color: #339933;">=</span> myData<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #660066;">description</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #006600; font-style: italic;">// create description label</span>
<span style="color: #003366; font-weight: bold;">var</span> label <span style="color: #339933;">=</span> Titanium.<span style="color: #660066;">UI</span>.<span style="color: #660066;">createLabel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
	text<span style="color: #339933;">:</span>desc<span style="color: #339933;">,</span>
	height<span style="color: #339933;">:</span><span style="color: #3366CC;">'auto'</span><span style="color: #339933;">,</span>
	width<span style="color: #339933;">:</span><span style="color: #CC0000;">300</span><span style="color: #339933;">,</span>
	top<span style="color: #339933;">:</span><span style="color: #CC0000;">10</span><span style="color: #339933;">,</span>
	font<span style="color: #339933;">:</span><span style="color: #009900;">&#123;</span>fontSize<span style="color: #339933;">:</span><span style="color: #CC0000;">16</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>
	color<span style="color: #339933;">:</span><span style="color: #3366CC;">'#333333'</span><span style="color: #339933;">,</span>
	textAlign<span style="color: #339933;">:</span><span style="color: #3366CC;">'left'</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>That&#8217;s it. I said an hour to develop this but in reality it will probably take you much less once you get used to the APIs. Of course for the data source you can use XHR to get data from the web but if you want your app to be usable without an internet connection, you would have to store the data locally like this.</p>
<p>I hope this was helpful. Let me know if you have any questions.</p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Building%20a%20native%20mobile%20app%20with%20Titanium%20in%20less%20than%20an%20hour%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F13%2Fbuilding-mobile-app-with-titanium%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Building_20a_20native_20mobile_20app_20with_20Titanium_20in_20less_20than_20an_20hour_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F13_2Fbuilding-mobile-app-with-titanium_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F13%2Fbuilding-mobile-app-with-titanium%2F&amp;t=Building%20a%20native%20mobile%20app%20with%20Titanium%20in%20less%20than%20an%20hour" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F13_2Fbuilding-mobile-app-with-titanium_2F_amp_t=Building_20a_20native_20mobile_20app_20with_20Titanium_20in_20less_20than_20an_20hour&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F13%2Fbuilding-mobile-app-with-titanium%2F&amp;title=Building%20a%20native%20mobile%20app%20with%20Titanium%20in%20less%20than%20an%20hour&amp;bodytext=%0D%0A%0D%0AWhen%20I%20wrote%20my%20last%20blog%20entry%2C%20I%20favoured%20objective-c%20over%20Appcelerator%27s%20Titanium%20framework%20thinking%20it%20just%20wasn%27t%20good%20enough.%20Almost%206%20months%20later%20and%20I%20would%20like%20to%20take%20back%20that%20comment.%20Titanium%20is%20no%20longer%20an%20embedded%20web%20browser%20in" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F13_2Fbuilding-mobile-app-with-titanium_2F_amp_title=Building_20a_20native_20mobile_20app_20with_20Titanium_20in_20less_20than_20an_20hour_amp_bodytext=_0D_0A_0D_0AWhen_20I_20wrote_20my_20last_20blog_20entry_2C_20I_20favoured_20objective-c_20over_20Appcelerator_27s_20Titanium_20framework_20thinking_20it_20just_20wasn_27t_20good_20enough._20Almost_206_20months_20later_20and_20I_20would_20like_20to_20take_20back_20that_20comment._20Titanium_20is_20no_20longer_20an_20embedded_20web_20browser_20in&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F13%2Fbuilding-mobile-app-with-titanium%2F&amp;title=Building%20a%20native%20mobile%20app%20with%20Titanium%20in%20less%20than%20an%20hour&amp;notes=%0D%0A%0D%0AWhen%20I%20wrote%20my%20last%20blog%20entry%2C%20I%20favoured%20objective-c%20over%20Appcelerator%27s%20Titanium%20framework%20thinking%20it%20just%20wasn%27t%20good%20enough.%20Almost%206%20months%20later%20and%20I%20would%20like%20to%20take%20back%20that%20comment.%20Titanium%20is%20no%20longer%20an%20embedded%20web%20browser%20in" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F13_2Fbuilding-mobile-app-with-titanium_2F_amp_title=Building_20a_20native_20mobile_20app_20with_20Titanium_20in_20less_20than_20an_20hour_amp_notes=_0D_0A_0D_0AWhen_20I_20wrote_20my_20last_20blog_20entry_2C_20I_20favoured_20objective-c_20over_20Appcelerator_27s_20Titanium_20framework_20thinking_20it_20just_20wasn_27t_20good_20enough._20Almost_206_20months_20later_20and_20I_20would_20like_20to_20take_20back_20that_20comment._20Titanium_20is_20no_20longer_20an_20embedded_20web_20browser_20in&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F07%2F13%2Fbuilding-mobile-app-with-titanium%2F&amp;title=Building%20a%20native%20mobile%20app%20with%20Titanium%20in%20less%20than%20an%20hour&amp;annotation=%0D%0A%0D%0AWhen%20I%20wrote%20my%20last%20blog%20entry%2C%20I%20favoured%20objective-c%20over%20Appcelerator%27s%20Titanium%20framework%20thinking%20it%20just%20wasn%27t%20good%20enough.%20Almost%206%20months%20later%20and%20I%20would%20like%20to%20take%20back%20that%20comment.%20Titanium%20is%20no%20longer%20an%20embedded%20web%20browser%20in" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F07_2F13_2Fbuilding-mobile-app-with-titanium_2F_amp_title=Building_20a_20native_20mobile_20app_20with_20Titanium_20in_20less_20than_20an_20hour_amp_annotation=_0D_0A_0D_0AWhen_20I_20wrote_20my_20last_20blog_20entry_2C_20I_20favoured_20objective-c_20over_20Appcelerator_27s_20Titanium_20framework_20thinking_20it_20just_20wasn_27t_20good_20enough._20Almost_206_20months_20later_20and_20I_20would_20like_20to_20take_20back_20that_20comment._20Titanium_20is_20no_20longer_20an_20embedded_20web_20browser_20in&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/07/13/building-mobile-app-with-titanium/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>iPhone App Development with Google App Engine</title>
		<link>http://www.givp.org/blog/2010/02/14/iphone-app-dev-google-app-engine/</link>
		<comments>http://www.givp.org/blog/2010/02/14/iphone-app-dev-google-app-engine/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 12:11:04 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[Objective-c]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[appengine]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[memcached]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=138</guid>
		<description><![CDATA[After almost a year of messing around with various iPhone development alternatives such as Phonegap and Titanium, I finally decided to learn Objective-C and do it all properly. I actually think those other frameworks are brilliant as they allow you to use familiar languages like Javascript to quickly create nice apps for both iPhone and [...]]]></description>
			<content:encoded><![CDATA[<p>After almost a year of messing around with various iPhone development alternatives such as <a href="http://phonegap.com/" onclick="pageTracker._trackPageview('/outgoing/phonegap.com/?referer=');">Phonegap</a> and <a href="http://www.appcelerator.com/" onclick="pageTracker._trackPageview('/outgoing/www.appcelerator.com/?referer=');">Titanium</a>, I finally decided to learn Objective-C and do it all properly. I actually think those other frameworks are brilliant as they allow you to use familiar languages like Javascript to quickly create nice apps for both iPhone and Android. But since they rely heavily on the web view element for loading HTML, creating sophisticated apps like Skype would be impossible.</p>
<p>So I set out to create an app for the iPhone with Objective-C. My app is pretty simple. It basically pulls in RSS news, audio podcast and video podcast feeds into a <a href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html" onclick="pageTracker._trackPageview('/outgoing/developer.apple.com/iphone/library/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html?referer=');">UITableView</a> list, allowing the user to read, listen and watch news stories from the <a href="http://www.democracynow.org/" onclick="pageTracker._trackPageview('/outgoing/www.democracynow.org/?referer=');">Democracy Now!</a> website.</p>
<p><img class="alignright" title="Democracy Now! app" src="http://www.givp.org/democracyapp/img/democphone.png" alt="" width="164" height="305" /><br />
I managed to put together the app pretty quickly but I ran into a lot of issues when I tried to parse and massage the XML data. For starters, cocoa does not have native support for regular expressions (but there are several external libraries). I wanted to clean up the content I was getting back before displaying it to the user but I soon realised something that would normally take me a few minutes in Python/PHP/Javascript would take a lot longer in Objective-C. Parsing XML using <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html" onclick="pageTracker._trackPageview('/outgoing/developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html?referer=');">NSXMLParser</a> was an absolute nightmare and extremely slow. I rarely work with XML these days and find JSON a much easier protocol to deal with. I even tested the app with some sample JSON data using the excellent <a href="http://code.google.com/p/json-framework/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/p/json-framework/?referer=');">json-framework</a> libarary and it was much easier and faster. Alas, I only had RSS feeds to work with. </p>
<p>The other problem I ran into was slow HTTP requests. It would sometimes take up to 20 seconds just to load the first screen. This was due to a combination of slow connection speeds, long response times from the data provider and a slow XML parser.</p>
<p>The solution I came up with was to do as little as possible in the phone app as far as the data was concerned. I decided to use Google App Engine to fetch the data from the source, parse, rejig, massage and beautify in Python, then serialise and return the results in JSON to the phone app to use.</p>
<p>It may sound like this would increase response times even more since the phone would have to first call GAE, then GAE would need to call the data source and then all the way back to the phone. This is true, however, once the data is with GAE we have the luxury of using <a href="http://code.google.com/appengine/docs/python/memcache/usingmemcache.html" onclick="pageTracker._trackPageview('/outgoing/code.google.com/appengine/docs/python/memcache/usingmemcache.html?referer=');">memcache</a> and <a href="http://code.google.com/appengine/docs/python/datastore/" onclick="pageTracker._trackPageview('/outgoing/code.google.com/appengine/docs/python/datastore/?referer=');">datastore</a>. The RSS and podcast feeds are updated once a day so there&#8217;s no reason to request the data from the source every time the user loads the app. Because each time we have to make the HTTP call, parse the data and load it up. This is extremely slow and unnecessary. We can just make one request a day, then parse, cleanup and cache the results for the next user that requests it.</p>
<p>So the app only talks to GAE. GAE first checks memcache to see if we have a cached version. If we don&#8217;t, it will make the HTTP call, fetch the data, parse, serialise, cache and return results. If we do have a cached version, there&#8217;s nothing else to do but to return the data. A cron job will also run every 24 hours to make sure memcache is up to date.</p>
<p><img src="http://www.givp.org/blog/wp-content/uploads/2010/02/bloggae.gif" alt="" /></p>
<p>If you really want a solid and reliable app, you need to think about all the edge cases also. What happens if the cache expires and the data provider&#8217;s website is down? At that exact moment a user loads the app only to get an error message saying there&#8217;s nothing to show. An unlikely scenario but not impossible. So the way I got around this issue was to store the serialised JSON output in GAE&#8217;s datastore as well. We always use the data from memcache but should memcache be empty and the data source down, we can switch over to the datastore and load yesterday&#8217;s content instead. Not ideal but better than having a broken app.</p>
<p>This is a bit of an overkill for such a simple app but it&#8217;s super fast and efficient and will work well for almost any app that relies on 3rd-party APIs. To be fair, it was my lack of experience with Objective-C that led me to using GAE. I feel much more comfortable in Python than Objective-C and I&#8217;m sure an experienced cocoa developer would have no problems parsing and massaging data in the app itself.</p>
<p>Of course there is one other edge case &#8211; Google App Engine could go down or worst, the interwebz could break. In which case, a simple error message will suffice.</p>
<p>You can download <a href="http://itunes.apple.com/app/democracy-now-war-peace-report/id353540657" onclick="pageTracker._trackPageview('/outgoing/itunes.apple.com/app/democracy-now-war-peace-report/id353540657?referer=');">Democracy Now! app on iTunes</a></p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=iPhone%20App%20Development%20with%20Google%20App%20Engine%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F14%2Fiphone-app-dev-google-app-engine%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=iPhone_20App_20Development_20with_20Google_20App_20Engine_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F14_2Fiphone-app-dev-google-app-engine_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F14%2Fiphone-app-dev-google-app-engine%2F&amp;t=iPhone%20App%20Development%20with%20Google%20App%20Engine" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F14_2Fiphone-app-dev-google-app-engine_2F_amp_t=iPhone_20App_20Development_20with_20Google_20App_20Engine&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F14%2Fiphone-app-dev-google-app-engine%2F&amp;title=iPhone%20App%20Development%20with%20Google%20App%20Engine&amp;bodytext=After%20almost%20a%20year%20of%20messing%20around%20with%20various%20iPhone%20development%20alternatives%20such%20as%20Phonegap%20and%20Titanium%2C%20I%20finally%20decided%20to%20learn%20Objective-C%20and%20do%20it%20all%20properly.%20I%20actually%20think%20those%20other%20frameworks%20are%20brilliant%20as%20they%20allow%20you%20t" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F14_2Fiphone-app-dev-google-app-engine_2F_amp_title=iPhone_20App_20Development_20with_20Google_20App_20Engine_amp_bodytext=After_20almost_20a_20year_20of_20messing_20around_20with_20various_20iPhone_20development_20alternatives_20such_20as_20Phonegap_20and_20Titanium_2C_20I_20finally_20decided_20to_20learn_20Objective-C_20and_20do_20it_20all_20properly._20I_20actually_20think_20those_20other_20frameworks_20are_20brilliant_20as_20they_20allow_20you_20t&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F14%2Fiphone-app-dev-google-app-engine%2F&amp;title=iPhone%20App%20Development%20with%20Google%20App%20Engine&amp;notes=After%20almost%20a%20year%20of%20messing%20around%20with%20various%20iPhone%20development%20alternatives%20such%20as%20Phonegap%20and%20Titanium%2C%20I%20finally%20decided%20to%20learn%20Objective-C%20and%20do%20it%20all%20properly.%20I%20actually%20think%20those%20other%20frameworks%20are%20brilliant%20as%20they%20allow%20you%20t" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F14_2Fiphone-app-dev-google-app-engine_2F_amp_title=iPhone_20App_20Development_20with_20Google_20App_20Engine_amp_notes=After_20almost_20a_20year_20of_20messing_20around_20with_20various_20iPhone_20development_20alternatives_20such_20as_20Phonegap_20and_20Titanium_2C_20I_20finally_20decided_20to_20learn_20Objective-C_20and_20do_20it_20all_20properly._20I_20actually_20think_20those_20other_20frameworks_20are_20brilliant_20as_20they_20allow_20you_20t&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F14%2Fiphone-app-dev-google-app-engine%2F&amp;title=iPhone%20App%20Development%20with%20Google%20App%20Engine&amp;annotation=After%20almost%20a%20year%20of%20messing%20around%20with%20various%20iPhone%20development%20alternatives%20such%20as%20Phonegap%20and%20Titanium%2C%20I%20finally%20decided%20to%20learn%20Objective-C%20and%20do%20it%20all%20properly.%20I%20actually%20think%20those%20other%20frameworks%20are%20brilliant%20as%20they%20allow%20you%20t" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F14_2Fiphone-app-dev-google-app-engine_2F_amp_title=iPhone_20App_20Development_20with_20Google_20App_20Engine_amp_annotation=After_20almost_20a_20year_20of_20messing_20around_20with_20various_20iPhone_20development_20alternatives_20such_20as_20Phonegap_20and_20Titanium_2C_20I_20finally_20decided_20to_20learn_20Objective-C_20and_20do_20it_20all_20properly._20I_20actually_20think_20those_20other_20frameworks_20are_20brilliant_20as_20they_20allow_20you_20t&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/02/14/iphone-app-dev-google-app-engine/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>KALX 90.7 FM iPhone App</title>
		<link>http://www.givp.org/blog/2010/02/09/kalx-90-7-fm-iphone-app/</link>
		<comments>http://www.givp.org/blog/2010/02/09/kalx-90-7-fm-iphone-app/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 12:30:37 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Objective-c]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=142</guid>
		<description><![CDATA[My first iPhone/iPod Touch app is out! I&#8217;m waiting for the approval of a second app. When that&#8217;s done, I&#8217;ll do a proper post about all things Objective-C and iPhone SDK. KALX app on iTunes Share]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" title="KALX app" src="http://www.givp.org/kalxapp/img/kalxphone.png" alt="" width="164" height="305" />My first iPhone/iPod Touch app is out! I&#8217;m waiting for the approval of a second app. When that&#8217;s done, I&#8217;ll do a proper post about all things Objective-C and iPhone SDK.</p>
<p><a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=354549285&amp;mt=8" onclick="pageTracker._trackPageview('/outgoing/itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=354549285_amp_mt=8&amp;referer=');">KALX app on iTunes</a></p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=KALX%2090.7%20FM%20iPhone%20App%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F09%2Fkalx-90-7-fm-iphone-app%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=KALX_2090.7_20FM_20iPhone_20App_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F09_2Fkalx-90-7-fm-iphone-app_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F09%2Fkalx-90-7-fm-iphone-app%2F&amp;t=KALX%2090.7%20FM%20iPhone%20App" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F09_2Fkalx-90-7-fm-iphone-app_2F_amp_t=KALX_2090.7_20FM_20iPhone_20App&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F09%2Fkalx-90-7-fm-iphone-app%2F&amp;title=KALX%2090.7%20FM%20iPhone%20App&amp;bodytext=My%20first%20iPhone%2FiPod%20Touch%20app%20is%20out%21%20I%27m%20waiting%20for%20the%20approval%20of%20a%20second%20app.%20When%20that%27s%20done%2C%20I%27ll%20do%20a%20proper%20post%20about%20all%20things%20Objective-C%20and%20iPhone%20SDK.%0D%0A%0D%0AKALX%20app%20on%20iTunes" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F09_2Fkalx-90-7-fm-iphone-app_2F_amp_title=KALX_2090.7_20FM_20iPhone_20App_amp_bodytext=My_20first_20iPhone_2FiPod_20Touch_20app_20is_20out_21_20I_27m_20waiting_20for_20the_20approval_20of_20a_20second_20app._20When_20that_27s_20done_2C_20I_27ll_20do_20a_20proper_20post_20about_20all_20things_20Objective-C_20and_20iPhone_20SDK._0D_0A_0D_0AKALX_20app_20on_20iTunes&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F09%2Fkalx-90-7-fm-iphone-app%2F&amp;title=KALX%2090.7%20FM%20iPhone%20App&amp;notes=My%20first%20iPhone%2FiPod%20Touch%20app%20is%20out%21%20I%27m%20waiting%20for%20the%20approval%20of%20a%20second%20app.%20When%20that%27s%20done%2C%20I%27ll%20do%20a%20proper%20post%20about%20all%20things%20Objective-C%20and%20iPhone%20SDK.%0D%0A%0D%0AKALX%20app%20on%20iTunes" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F09_2Fkalx-90-7-fm-iphone-app_2F_amp_title=KALX_2090.7_20FM_20iPhone_20App_amp_notes=My_20first_20iPhone_2FiPod_20Touch_20app_20is_20out_21_20I_27m_20waiting_20for_20the_20approval_20of_20a_20second_20app._20When_20that_27s_20done_2C_20I_27ll_20do_20a_20proper_20post_20about_20all_20things_20Objective-C_20and_20iPhone_20SDK._0D_0A_0D_0AKALX_20app_20on_20iTunes&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F02%2F09%2Fkalx-90-7-fm-iphone-app%2F&amp;title=KALX%2090.7%20FM%20iPhone%20App&amp;annotation=My%20first%20iPhone%2FiPod%20Touch%20app%20is%20out%21%20I%27m%20waiting%20for%20the%20approval%20of%20a%20second%20app.%20When%20that%27s%20done%2C%20I%27ll%20do%20a%20proper%20post%20about%20all%20things%20Objective-C%20and%20iPhone%20SDK.%0D%0A%0D%0AKALX%20app%20on%20iTunes" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F02_2F09_2Fkalx-90-7-fm-iphone-app_2F_amp_title=KALX_2090.7_20FM_20iPhone_20App_amp_annotation=My_20first_20iPhone_2FiPod_20Touch_20app_20is_20out_21_20I_27m_20waiting_20for_20the_20approval_20of_20a_20second_20app._20When_20that_27s_20done_2C_20I_27ll_20do_20a_20proper_20post_20about_20all_20things_20Objective-C_20and_20iPhone_20SDK._0D_0A_0D_0AKALX_20app_20on_20iTunes&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/02/09/kalx-90-7-fm-iphone-app/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Soup</title>
		<link>http://www.givp.org/blog/2010/01/10/soup/</link>
		<comments>http://www.givp.org/blog/2010/01/10/soup/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 13:34:11 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Videos]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=130</guid>
		<description><![CDATA[I&#8217;ve been meaning to get back into video editing for a while so I spent the weekend putting this together: Soup from Giv Parvaneh on Vimeo. Share]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to get back into video editing for a while so I spent the weekend putting this together:</p>
<p><object width="551" height="413"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=8638520&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=8638520&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="551" height="413"></embed></object>
<p><a href="http://vimeo.com/8638520" onclick="pageTracker._trackPageview('/outgoing/vimeo.com/8638520?referer=');">Soup</a> from <a href="http://vimeo.com/user2940453" onclick="pageTracker._trackPageview('/outgoing/vimeo.com/user2940453?referer=');">Giv Parvaneh</a> on <a href="http://vimeo.com" onclick="pageTracker._trackPageview('/outgoing/vimeo.com?referer=');">Vimeo</a>.</p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Soup%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F01%2F10%2Fsoup%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Soup_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F01_2F10_2Fsoup_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F01%2F10%2Fsoup%2F&amp;t=Soup" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F01_2F10_2Fsoup_2F_amp_t=Soup&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F01%2F10%2Fsoup%2F&amp;title=Soup&amp;bodytext=I%27ve%20been%20meaning%20to%20get%20back%20into%20video%20editing%20for%20a%20while%20so%20I%20spent%20the%20weekend%20putting%20this%20together%3A%0D%0A%0D%0ASoup%20from%20Giv%20Parvaneh%20on%20Vimeo." title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F01_2F10_2Fsoup_2F_amp_title=Soup_amp_bodytext=I_27ve_20been_20meaning_20to_20get_20back_20into_20video_20editing_20for_20a_20while_20so_20I_20spent_20the_20weekend_20putting_20this_20together_3A_0D_0A_0D_0ASoup_20from_20Giv_20Parvaneh_20on_20Vimeo.&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F01%2F10%2Fsoup%2F&amp;title=Soup&amp;notes=I%27ve%20been%20meaning%20to%20get%20back%20into%20video%20editing%20for%20a%20while%20so%20I%20spent%20the%20weekend%20putting%20this%20together%3A%0D%0A%0D%0ASoup%20from%20Giv%20Parvaneh%20on%20Vimeo." title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F01_2F10_2Fsoup_2F_amp_title=Soup_amp_notes=I_27ve_20been_20meaning_20to_20get_20back_20into_20video_20editing_20for_20a_20while_20so_20I_20spent_20the_20weekend_20putting_20this_20together_3A_0D_0A_0D_0ASoup_20from_20Giv_20Parvaneh_20on_20Vimeo.&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2010%2F01%2F10%2Fsoup%2F&amp;title=Soup&amp;annotation=I%27ve%20been%20meaning%20to%20get%20back%20into%20video%20editing%20for%20a%20while%20so%20I%20spent%20the%20weekend%20putting%20this%20together%3A%0D%0A%0D%0ASoup%20from%20Giv%20Parvaneh%20on%20Vimeo." title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2010_2F01_2F10_2Fsoup_2F_amp_title=Soup_amp_annotation=I_27ve_20been_20meaning_20to_20get_20back_20into_20video_20editing_20for_20a_20while_20so_20I_20spent_20the_20weekend_20putting_20this_20together_3A_0D_0A_0D_0ASoup_20from_20Giv_20Parvaneh_20on_20Vimeo.&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2010/01/10/soup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Django Gravatar filter</title>
		<link>http://www.givp.org/blog/2009/12/13/django-gravatar-filter/</link>
		<comments>http://www.givp.org/blog/2009/12/13/django-gravatar-filter/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 22:04:37 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=120</guid>
		<description><![CDATA[If you want to add user avatars to your Django app, you can certainly use the excellent django-avatar app. This will let your users upload/edit their own avatars or use Gravatar. But for my app I only wanted to use Gravatar so I was looking for a simpler solution that let me just pass the [...]]]></description>
			<content:encoded><![CDATA[<p>If you want to add user avatars to your Django app, you can certainly use the excellent <a href="http://github.com/ericflo/django-avatar" onclick="pageTracker._trackPageview('/outgoing/github.com/ericflo/django-avatar?referer=');">django-avatar</a> app. This will let your users upload/edit their own avatars or use <a href="http://www.gravatar.com/" onclick="pageTracker._trackPageview('/outgoing/www.gravatar.com/?referer=');">Gravatar</a>.</p>
<p>But for my app I <u>only</u> wanted to use Gravatar so I was looking for a simpler solution that let me just pass the user object and an optional size in a template filter and have Gravatar take care of the rest.</p>
<p>The solution is <a href="http://docs.djangoproject.com/en/dev/howto/custom-template-tags/" onclick="pageTracker._trackPageview('/outgoing/docs.djangoproject.com/en/dev/howto/custom-template-tags/?referer=');">custom template tags</a>. If you&#8217;re already used to using the built-in template filters, you&#8217;ll know how useful and easy they are. I wanted my Gravatar filter to be as simple as possible. Something like this:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: black;">&#123;</span><span style="color: black;">&#123;</span> <span style="color: #dc143c;">user</span>|gravatar:<span style="color: #ff4500;">20</span> <span style="color: black;">&#125;</span><span style="color: black;">&#125;</span></pre></td></tr></table></div>

<p>Where 20 is the optional width/height of the avatar. This would then create an img tag with the full Gravatar URL.</p>
<p>First create your &#8216;templatetags&#8217; directory and associated files as instructed in the <a href="http://docs.djangoproject.com/en/dev/howto/custom-template-tags/" onclick="pageTracker._trackPageview('/outgoing/docs.djangoproject.com/en/dev/howto/custom-template-tags/?referer=');">docs</a>. Then create a function that takes in the user object and uses the email address to construct the Gravatar URL:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> django <span style="color: #ff7700;font-weight:bold;">import</span> template
<span style="color: #ff7700;font-weight:bold;">import</span> hashlib
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">utils</span>.<span style="color: black;">safestring</span> <span style="color: #ff7700;font-weight:bold;">import</span> mark_safe
register = template.<span style="color: black;">Library</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
@register.<span style="color: #008000;">filter</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> gravatar<span style="color: black;">&#40;</span><span style="color: #dc143c;">user</span>, size=<span style="color: #ff4500;">50</span><span style="color: black;">&#41;</span>:
    gravatar_url = <span style="color: #483d8b;">&quot;http://www.gravatar.com/avatar&quot;</span>
    emailHash = hashlib.<span style="color: #dc143c;">md5</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">user</span>.<span style="color: #dc143c;">email</span>.<span style="color: black;">lower</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">hexdigest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> mark_safe<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&lt;img src='%s/%s.jpg?d=identicon&amp;s=%s' alt='' /&gt;&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>gravatar_url, emailHash, size<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>




Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Django%20Gravatar%20filter%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F12%2F13%2Fdjango-gravatar-filter%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Django_20Gravatar_20filter_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F12_2F13_2Fdjango-gravatar-filter_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F12%2F13%2Fdjango-gravatar-filter%2F&amp;t=Django%20Gravatar%20filter" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F12_2F13_2Fdjango-gravatar-filter_2F_amp_t=Django_20Gravatar_20filter&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F12%2F13%2Fdjango-gravatar-filter%2F&amp;title=Django%20Gravatar%20filter&amp;bodytext=If%20you%20want%20to%20add%20user%20avatars%20to%20your%20Django%20app%2C%20you%20can%20certainly%20use%20the%20excellent%20django-avatar%20app.%20This%20will%20let%20your%20users%20upload%2Fedit%20their%20own%20avatars%20or%20use%20Gravatar.%0D%0A%0D%0ABut%20for%20my%20app%20I%20only%20wanted%20to%20use%20Gravatar%20so%20I%20was%20looking%20for%20a%20" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F12_2F13_2Fdjango-gravatar-filter_2F_amp_title=Django_20Gravatar_20filter_amp_bodytext=If_20you_20want_20to_20add_20user_20avatars_20to_20your_20Django_20app_2C_20you_20can_20certainly_20use_20the_20excellent_20django-avatar_20app._20This_20will_20let_20your_20users_20upload_2Fedit_20their_20own_20avatars_20or_20use_20Gravatar._0D_0A_0D_0ABut_20for_20my_20app_20I_20only_20wanted_20to_20use_20Gravatar_20so_20I_20was_20looking_20for_20a_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F12%2F13%2Fdjango-gravatar-filter%2F&amp;title=Django%20Gravatar%20filter&amp;notes=If%20you%20want%20to%20add%20user%20avatars%20to%20your%20Django%20app%2C%20you%20can%20certainly%20use%20the%20excellent%20django-avatar%20app.%20This%20will%20let%20your%20users%20upload%2Fedit%20their%20own%20avatars%20or%20use%20Gravatar.%0D%0A%0D%0ABut%20for%20my%20app%20I%20only%20wanted%20to%20use%20Gravatar%20so%20I%20was%20looking%20for%20a%20" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F12_2F13_2Fdjango-gravatar-filter_2F_amp_title=Django_20Gravatar_20filter_amp_notes=If_20you_20want_20to_20add_20user_20avatars_20to_20your_20Django_20app_2C_20you_20can_20certainly_20use_20the_20excellent_20django-avatar_20app._20This_20will_20let_20your_20users_20upload_2Fedit_20their_20own_20avatars_20or_20use_20Gravatar._0D_0A_0D_0ABut_20for_20my_20app_20I_20only_20wanted_20to_20use_20Gravatar_20so_20I_20was_20looking_20for_20a_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F12%2F13%2Fdjango-gravatar-filter%2F&amp;title=Django%20Gravatar%20filter&amp;annotation=If%20you%20want%20to%20add%20user%20avatars%20to%20your%20Django%20app%2C%20you%20can%20certainly%20use%20the%20excellent%20django-avatar%20app.%20This%20will%20let%20your%20users%20upload%2Fedit%20their%20own%20avatars%20or%20use%20Gravatar.%0D%0A%0D%0ABut%20for%20my%20app%20I%20only%20wanted%20to%20use%20Gravatar%20so%20I%20was%20looking%20for%20a%20" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F12_2F13_2Fdjango-gravatar-filter_2F_amp_title=Django_20Gravatar_20filter_amp_annotation=If_20you_20want_20to_20add_20user_20avatars_20to_20your_20Django_20app_2C_20you_20can_20certainly_20use_20the_20excellent_20django-avatar_20app._20This_20will_20let_20your_20users_20upload_2Fedit_20their_20own_20avatars_20or_20use_20Gravatar._0D_0A_0D_0ABut_20for_20my_20app_20I_20only_20wanted_20to_20use_20Gravatar_20so_20I_20was_20looking_20for_20a_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2009/12/13/django-gravatar-filter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Test-driven Development in Agile Projects</title>
		<link>http://www.givp.org/blog/2009/11/21/test-driven-development-in-agile/</link>
		<comments>http://www.givp.org/blog/2009/11/21/test-driven-development-in-agile/#comments</comments>
		<pubDate>Sat, 21 Nov 2009 14:29:06 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Experiments]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=113</guid>
		<description><![CDATA[I recently posted this on the BBC Web Developer Blog: http://www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml Developers at the BBC tend to use Agile methodologies as a way to quickly release iterations of products. But where does rigorous code testing fit in with the short development and release cycles? How can we maintain the quality of our code when things [...]]]></description>
			<content:encoded><![CDATA[<p>I recently posted this on the BBC Web Developer Blog:</p>
<p><a href="http://www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml" onclick="pageTracker._trackPageview('/outgoing/www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml?referer=');">http://www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml</a></p>
<blockquote><p>
Developers at the BBC tend to use Agile methodologies as a way to quickly release iterations of products. But where does rigorous code testing fit in with the short development and release cycles? How can we maintain the quality of our code when things need to change so fast?
</p></blockquote>
<p><a href="http://www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml" onclick="pageTracker._trackPageview('/outgoing/www.bbc.co.uk/blogs/webdeveloper/2009/11/testdriven-development-in-agil.shtml?referer=');">More</a></p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Test-driven%20Development%20in%20Agile%20Projects%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F11%2F21%2Ftest-driven-development-in-agile%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Test-driven_20Development_20in_20Agile_20Projects_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F11_2F21_2Ftest-driven-development-in-agile_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F11%2F21%2Ftest-driven-development-in-agile%2F&amp;t=Test-driven%20Development%20in%20Agile%20Projects" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F11_2F21_2Ftest-driven-development-in-agile_2F_amp_t=Test-driven_20Development_20in_20Agile_20Projects&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F11%2F21%2Ftest-driven-development-in-agile%2F&amp;title=Test-driven%20Development%20in%20Agile%20Projects&amp;bodytext=I%20recently%20posted%20this%20on%20the%20BBC%20Web%20Developer%20Blog%3A%0D%0A%0D%0Ahttp%3A%2F%2Fwww.bbc.co.uk%2Fblogs%2Fwebdeveloper%2F2009%2F11%2Ftestdriven-development-in-agil.shtml%0D%0A%0D%0A%0D%0ADevelopers%20at%20the%20BBC%20tend%20to%20use%20Agile%20methodologies%20as%20a%20way%20to%20quickly%20release%20iterations%20of%20product" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F11_2F21_2Ftest-driven-development-in-agile_2F_amp_title=Test-driven_20Development_20in_20Agile_20Projects_amp_bodytext=I_20recently_20posted_20this_20on_20the_20BBC_20Web_20Developer_20Blog_3A_0D_0A_0D_0Ahttp_3A_2F_2Fwww.bbc.co.uk_2Fblogs_2Fwebdeveloper_2F2009_2F11_2Ftestdriven-development-in-agil.shtml_0D_0A_0D_0A_0D_0ADevelopers_20at_20the_20BBC_20tend_20to_20use_20Agile_20methodologies_20as_20a_20way_20to_20quickly_20release_20iterations_20of_20product&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F11%2F21%2Ftest-driven-development-in-agile%2F&amp;title=Test-driven%20Development%20in%20Agile%20Projects&amp;notes=I%20recently%20posted%20this%20on%20the%20BBC%20Web%20Developer%20Blog%3A%0D%0A%0D%0Ahttp%3A%2F%2Fwww.bbc.co.uk%2Fblogs%2Fwebdeveloper%2F2009%2F11%2Ftestdriven-development-in-agil.shtml%0D%0A%0D%0A%0D%0ADevelopers%20at%20the%20BBC%20tend%20to%20use%20Agile%20methodologies%20as%20a%20way%20to%20quickly%20release%20iterations%20of%20product" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F11_2F21_2Ftest-driven-development-in-agile_2F_amp_title=Test-driven_20Development_20in_20Agile_20Projects_amp_notes=I_20recently_20posted_20this_20on_20the_20BBC_20Web_20Developer_20Blog_3A_0D_0A_0D_0Ahttp_3A_2F_2Fwww.bbc.co.uk_2Fblogs_2Fwebdeveloper_2F2009_2F11_2Ftestdriven-development-in-agil.shtml_0D_0A_0D_0A_0D_0ADevelopers_20at_20the_20BBC_20tend_20to_20use_20Agile_20methodologies_20as_20a_20way_20to_20quickly_20release_20iterations_20of_20product&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F11%2F21%2Ftest-driven-development-in-agile%2F&amp;title=Test-driven%20Development%20in%20Agile%20Projects&amp;annotation=I%20recently%20posted%20this%20on%20the%20BBC%20Web%20Developer%20Blog%3A%0D%0A%0D%0Ahttp%3A%2F%2Fwww.bbc.co.uk%2Fblogs%2Fwebdeveloper%2F2009%2F11%2Ftestdriven-development-in-agil.shtml%0D%0A%0D%0A%0D%0ADevelopers%20at%20the%20BBC%20tend%20to%20use%20Agile%20methodologies%20as%20a%20way%20to%20quickly%20release%20iterations%20of%20product" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F11_2F21_2Ftest-driven-development-in-agile_2F_amp_title=Test-driven_20Development_20in_20Agile_20Projects_amp_annotation=I_20recently_20posted_20this_20on_20the_20BBC_20Web_20Developer_20Blog_3A_0D_0A_0D_0Ahttp_3A_2F_2Fwww.bbc.co.uk_2Fblogs_2Fwebdeveloper_2F2009_2F11_2Ftestdriven-development-in-agil.shtml_0D_0A_0D_0A_0D_0ADevelopers_20at_20the_20BBC_20tend_20to_20use_20Agile_20methodologies_20as_20a_20way_20to_20quickly_20release_20iterations_20of_20product&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2009/11/21/test-driven-development-in-agile/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django Geolocation</title>
		<link>http://www.givp.org/blog/2009/10/31/django-geolocation/</link>
		<comments>http://www.givp.org/blog/2009/10/31/django-geolocation/#comments</comments>
		<pubDate>Sat, 31 Oct 2009 16:35:37 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[model]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=87</guid>
		<description><![CDATA[One thing I love about Django models is the ability to subclass its methods to add extra functionality without having to write any extra code in admin or view layers. I have an application where a user can enter an address in the admin section. I want to plot this location on Google Maps later [...]]]></description>
			<content:encoded><![CDATA[<p>One thing I love about Django models is the ability to subclass its methods to add extra functionality without having to write any extra code in admin or view layers.</p>
<p>I have an application where a user can enter an address in the admin section. I want to plot this location on Google Maps later but I don&#8217;t want to have to parse the address and do a reverse geolocation lookup in the view layer every time that page is viewed. The best thing to do is to store the lat/long values in the database.</p>
<p>I could do this by messing around with the Django admin templates but I&#8217;d rather not even let the user know the geolocation lookup is happening. Besides, what if I want to interact with the DB from the interpreter? The geolocation bit should happen no matter where the database is being used.</p>
<p>This is my model</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Entry<span style="color: black;">&#40;</span>models.<span style="color: black;">Model</span><span style="color: black;">&#41;</span>:
    title = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">200</span><span style="color: black;">&#41;</span>
    description = models.<span style="color: black;">TextField</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'description'</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    address = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">200</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    postcode = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">200</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    city = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">200</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    country = models.<span style="color: black;">CharField</span><span style="color: black;">&#40;</span>max_length=<span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
    geo_lat = models.<span style="color: black;">DecimalField</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'latitude'</span>, max_digits=<span style="color: #ff4500;">13</span>, decimal_places=<span style="color: #ff4500;">10</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    geo_long = models.<span style="color: black;">DecimalField</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'longitude'</span>, max_digits=<span style="color: #ff4500;">13</span>, decimal_places=<span style="color: #ff4500;">10</span>, blank=<span style="color: #008000;">True</span>, null=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>In Django admin I don&#8217;t show &#8216;geo_lat&#8217; and &#8216;geo_lat&#8217;. We just ask the user to enter the address, then before saving, we do the lookup, set the lat/long values and then save the model.</p>
<p>Creating a new entry would still be done the same way from either admin, view or interpreter:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">e = Entry<span style="color: black;">&#40;</span>title=<span style="color: #483d8b;">'a new entry'</span>, address=<span style="color: #483d8b;">'123 Smith Road'</span>, city=<span style="color: #483d8b;">'London'</span>, country=<span style="color: #483d8b;">'UK'</span><span style="color: black;">&#41;</span>
e.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>But we are going to hijack the save() method to do some extra work before saving to the database. Let&#8217;s create a method that does the geolocation lookup first:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span>
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">utils</span> <span style="color: #ff7700;font-weight:bold;">import</span> simplejson <span style="color: #ff7700;font-weight:bold;">as</span> json
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> get_geo<span style="color: black;">&#40;</span>address<span style="color: black;">&#41;</span>:
    address = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">quote</span><span style="color: black;">&#40;</span>address<span style="color: black;">&#41;</span>
    url = <span style="color: #483d8b;">&quot;http://maps.google.com/maps/geo?q=%s&amp;output=json&amp;oe=utf8&amp;sensor=true_or_false&amp;key=12345&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>address<span style="color: black;">&#41;</span>
    data = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>
    obj = json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span> data.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> obj<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Status'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'code'</span><span style="color: black;">&#93;</span> == <span style="color: #ff4500;">200</span>:
        data = obj<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Placemark'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Point'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'coordinates'</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">Exception</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Invalid address'</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> data</pre></td></tr></table></div>

<p>We pass the address to Google and if we get a 200 status code, we grab the lat/long values and return them.</p>
<p>Now let&#8217;s call this method in our save() subclass (inside the Entry model):</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">def</span> save<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
    add = <span style="color: #483d8b;">&quot;%s, %s, %s, %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">address</span>, <span style="color: #008000;">self</span>.<span style="color: black;">postcode</span>, <span style="color: #008000;">self</span>.<span style="color: black;">city</span>, <span style="color: #008000;">self</span>.<span style="color: black;">country</span><span style="color: black;">&#41;</span>
    geo_data = utils.<span style="color: black;">get_geo</span><span style="color: black;">&#40;</span>add<span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">geo_long</span> = <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>geo_data<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">self</span>.<span style="color: black;">geo_lat</span> = <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>geo_data<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>Listing, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> <span style="color: #808080; font-style: italic;"># Call the &quot;real&quot; save() method</span></pre></td></tr></table></div>

<p>This could be improved so instead of throwing and exception for bad addresses we handle it more gracefully by informing the user or at least save the address and ignore the geolocation lookup. But either way, the model is now responsible for doing the extra work before saving the new/updated data.</p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=Django%20Geolocation%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F31%2Fdjango-geolocation%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=Django_20Geolocation_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F31_2Fdjango-geolocation_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F31%2Fdjango-geolocation%2F&amp;t=Django%20Geolocation" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F31_2Fdjango-geolocation_2F_amp_t=Django_20Geolocation&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F31%2Fdjango-geolocation%2F&amp;title=Django%20Geolocation&amp;bodytext=One%20thing%20I%20love%20about%20Django%20models%20is%20the%20ability%20to%20subclass%20its%20methods%20to%20add%20extra%20functionality%20without%20having%20to%20write%20any%20extra%20code%20in%20admin%20or%20view%20layers.%0D%0A%0D%0AI%20have%20an%20application%20where%20a%20user%20can%20enter%20an%20address%20in%20the%20admin%20section.%20I%20" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F31_2Fdjango-geolocation_2F_amp_title=Django_20Geolocation_amp_bodytext=One_20thing_20I_20love_20about_20Django_20models_20is_20the_20ability_20to_20subclass_20its_20methods_20to_20add_20extra_20functionality_20without_20having_20to_20write_20any_20extra_20code_20in_20admin_20or_20view_20layers._0D_0A_0D_0AI_20have_20an_20application_20where_20a_20user_20can_20enter_20an_20address_20in_20the_20admin_20section._20I_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F31%2Fdjango-geolocation%2F&amp;title=Django%20Geolocation&amp;notes=One%20thing%20I%20love%20about%20Django%20models%20is%20the%20ability%20to%20subclass%20its%20methods%20to%20add%20extra%20functionality%20without%20having%20to%20write%20any%20extra%20code%20in%20admin%20or%20view%20layers.%0D%0A%0D%0AI%20have%20an%20application%20where%20a%20user%20can%20enter%20an%20address%20in%20the%20admin%20section.%20I%20" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F31_2Fdjango-geolocation_2F_amp_title=Django_20Geolocation_amp_notes=One_20thing_20I_20love_20about_20Django_20models_20is_20the_20ability_20to_20subclass_20its_20methods_20to_20add_20extra_20functionality_20without_20having_20to_20write_20any_20extra_20code_20in_20admin_20or_20view_20layers._0D_0A_0D_0AI_20have_20an_20application_20where_20a_20user_20can_20enter_20an_20address_20in_20the_20admin_20section._20I_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F31%2Fdjango-geolocation%2F&amp;title=Django%20Geolocation&amp;annotation=One%20thing%20I%20love%20about%20Django%20models%20is%20the%20ability%20to%20subclass%20its%20methods%20to%20add%20extra%20functionality%20without%20having%20to%20write%20any%20extra%20code%20in%20admin%20or%20view%20layers.%0D%0A%0D%0AI%20have%20an%20application%20where%20a%20user%20can%20enter%20an%20address%20in%20the%20admin%20section.%20I%20" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F31_2Fdjango-geolocation_2F_amp_title=Django_20Geolocation_amp_annotation=One_20thing_20I_20love_20about_20Django_20models_20is_20the_20ability_20to_20subclass_20its_20methods_20to_20add_20extra_20functionality_20without_20having_20to_20write_20any_20extra_20code_20in_20admin_20or_20view_20layers._0D_0A_0D_0AI_20have_20an_20application_20where_20a_20user_20can_20enter_20an_20address_20in_20the_20admin_20section._20I_20&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2009/10/31/django-geolocation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>HTML Scraping &#8211; Python vs PHP (re-post)</title>
		<link>http://www.givp.org/blog/2009/10/26/html-scraping-python-vs-php/</link>
		<comments>http://www.givp.org/blog/2009/10/26/html-scraping-python-vs-php/#comments</comments>
		<pubDate>Mon, 26 Oct 2009 21:11:19 +0000</pubDate>
		<dc:creator>Giv</dc:creator>
				<category><![CDATA[Experiments]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.givp.org/blog/?p=81</guid>
		<description><![CDATA[I posted this last year on my old blog. The subject came up again today so I dug it up from the archives: I usually hate these &#8220;X vs Y&#8221; discussions but this week I was working on a harvesting project and was trying to figure out whether I should go down the Python or [...]]]></description>
			<content:encoded><![CDATA[<p>I posted this last year on my old blog. The subject came up again today so I dug it up from the archives:</p>
<p>I usually hate these &#8220;X vs Y&#8221; discussions but this week I was working on a harvesting project and was trying to figure out whether I should go down the Python or PHP route. I have been using PHP for many years now so PHP was the obvious choice but recently I have been using Python a fair bit and the more I use it, the more I realise what a sloppy language PHP is.</p>
<p>So I set out to do some tests to see which would get my task done quicker.</p>
<p>For Python I used the <a href="http://www.crummy.com/software/BeautifulSoup/" onclick="pageTracker._trackPageview('/outgoing/www.crummy.com/software/BeautifulSoup/?referer=');">Beautiful Soup</a> module and for PHP I used <a href="http://simplehtmldom.sourceforge.net/" onclick="pageTracker._trackPageview('/outgoing/simplehtmldom.sourceforge.net/?referer=');">PHP Simple HTML DOM Parser</a> class.</p>
<p><strong>The test:</strong><br />
<em>Go to http://news.bbc.co.uk, look for the third &lt;p&gt; tag and return the text for the first link within that paragraph.</em></p>
<p>Both classes make this very easy to do so coding was not a concern:</p>
<p><strong>in Python:</strong></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code"><pre class="python" style="font-family:monospace;">page = <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://news.bbc.co.uk&quot;</span><span style="color: black;">&#41;</span>
soup = BeautifulSoup<span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">print</span> soup.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'p'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span>.<span style="color: black;">findAll</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'a'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: #dc143c;">string</span></pre></td></tr></table></div>

<p><strong>in PHP:</strong></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> file_get_html<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'http://news.bbc.co.uk'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$html</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'p'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'a'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">innertext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>I ran each 5 times to measure the execution time.</p>
<p><strong>Python:</strong><br />
0.622022151947 seconds<br />
0.577415943146 seconds<br />
0.518396139145 seconds<br />
0.503247022629 seconds<br />
0.482849121094 seconds</p>
<p><strong>PHP:</strong><br />
0.430239915848 seconds<br />
0.415632009506 seconds<br />
0.408473014832 seconds<br />
0.413187026978 seconds<br />
0.411664962769 seconds</p>
<p>Pretty damn close but PHP is on average a bit faster it seems.</p>
<p>To be fair, this really isn&#8217;t a very good way to measure the performance of the two. The real test, in my opinion, would be to see how scalable each method is and how they handle memory management once I start scraping say the entire Wikipedia collection. I could be wrong here but from what I&#8217;ve read so far, Python is the tool of choice for such heavy processing tasks.</p>
<p>Either way, I think I&#8217;ll go with Python <img src='http://www.givp.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>



Share


	<a rel="nofollow"  href="http://twitter.com/home?status=HTML%20Scraping%20-%20Python%20vs%20PHP%20%28re-post%29%20-%20http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F26%2Fhtml-scraping-python-vs-php%2F" title="Twitter" onclick="pageTracker._trackPageview('/outgoing/twitter.com/home?status=HTML_20Scraping_20-_20Python_20vs_20PHP_20_28re-post_29_20-_20http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F26_2Fhtml-scraping-python-vs-php_2F&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/twitter.png" title="Twitter" alt="Twitter" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.facebook.com/share.php?u=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F26%2Fhtml-scraping-python-vs-php%2F&amp;t=HTML%20Scraping%20-%20Python%20vs%20PHP%20%28re-post%29" title="Facebook" onclick="pageTracker._trackPageview('/outgoing/www.facebook.com/share.php?u=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F26_2Fhtml-scraping-python-vs-php_2F_amp_t=HTML_20Scraping_20-_20Python_20vs_20PHP_20_28re-post_29&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/facebook.png" title="Facebook" alt="Facebook" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F26%2Fhtml-scraping-python-vs-php%2F&amp;title=HTML%20Scraping%20-%20Python%20vs%20PHP%20%28re-post%29&amp;bodytext=I%20posted%20this%20last%20year%20on%20my%20old%20blog.%20The%20subject%20came%20up%20again%20today%20so%20I%20dug%20it%20up%20from%20the%20archives%3A%0D%0A%0D%0AI%20usually%20hate%20these%20%22X%20vs%20Y%22%20discussions%20but%20this%20week%20I%20was%20working%20on%20a%20harvesting%20project%20and%20was%20trying%20to%20figure%20out%20whether%20I%20should%20g" title="Digg" onclick="pageTracker._trackPageview('/outgoing/digg.com/submit?phase=2_amp_url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F26_2Fhtml-scraping-python-vs-php_2F_amp_title=HTML_20Scraping_20-_20Python_20vs_20PHP_20_28re-post_29_amp_bodytext=I_20posted_20this_20last_20year_20on_20my_20old_20blog._20The_20subject_20came_20up_20again_20today_20so_20I_20dug_20it_20up_20from_20the_20archives_3A_0D_0A_0D_0AI_20usually_20hate_20these_20_22X_20vs_20Y_22_20discussions_20but_20this_20week_20I_20was_20working_20on_20a_20harvesting_20project_20and_20was_20trying_20to_20figure_20out_20whether_20I_20should_20g&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/digg.png" title="Digg" alt="Digg" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://delicious.com/post?url=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F26%2Fhtml-scraping-python-vs-php%2F&amp;title=HTML%20Scraping%20-%20Python%20vs%20PHP%20%28re-post%29&amp;notes=I%20posted%20this%20last%20year%20on%20my%20old%20blog.%20The%20subject%20came%20up%20again%20today%20so%20I%20dug%20it%20up%20from%20the%20archives%3A%0D%0A%0D%0AI%20usually%20hate%20these%20%22X%20vs%20Y%22%20discussions%20but%20this%20week%20I%20was%20working%20on%20a%20harvesting%20project%20and%20was%20trying%20to%20figure%20out%20whether%20I%20should%20g" title="del.icio.us" onclick="pageTracker._trackPageview('/outgoing/delicious.com/post?url=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F26_2Fhtml-scraping-python-vs-php_2F_amp_title=HTML_20Scraping_20-_20Python_20vs_20PHP_20_28re-post_29_amp_notes=I_20posted_20this_20last_20year_20on_20my_20old_20blog._20The_20subject_20came_20up_20again_20today_20so_20I_20dug_20it_20up_20from_20the_20archives_3A_0D_0A_0D_0AI_20usually_20hate_20these_20_22X_20vs_20Y_22_20discussions_20but_20this_20week_20I_20was_20working_20on_20a_20harvesting_20project_20and_20was_20trying_20to_20figure_20out_20whether_20I_20should_20g&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/delicious.png" title="del.icio.us" alt="del.icio.us" class="sociable-hovers" /></a>
	<a rel="nofollow"  href="http://www.google.com/bookmarks/mark?op=edit&amp;bkmk=http%3A%2F%2Fwww.givp.org%2Fblog%2F2009%2F10%2F26%2Fhtml-scraping-python-vs-php%2F&amp;title=HTML%20Scraping%20-%20Python%20vs%20PHP%20%28re-post%29&amp;annotation=I%20posted%20this%20last%20year%20on%20my%20old%20blog.%20The%20subject%20came%20up%20again%20today%20so%20I%20dug%20it%20up%20from%20the%20archives%3A%0D%0A%0D%0AI%20usually%20hate%20these%20%22X%20vs%20Y%22%20discussions%20but%20this%20week%20I%20was%20working%20on%20a%20harvesting%20project%20and%20was%20trying%20to%20figure%20out%20whether%20I%20should%20g" title="Google Bookmarks" onclick="pageTracker._trackPageview('/outgoing/www.google.com/bookmarks/mark?op=edit_amp_bkmk=http_3A_2F_2Fwww.givp.org_2Fblog_2F2009_2F10_2F26_2Fhtml-scraping-python-vs-php_2F_amp_title=HTML_20Scraping_20-_20Python_20vs_20PHP_20_28re-post_29_amp_annotation=I_20posted_20this_20last_20year_20on_20my_20old_20blog._20The_20subject_20came_20up_20again_20today_20so_20I_20dug_20it_20up_20from_20the_20archives_3A_0D_0A_0D_0AI_20usually_20hate_20these_20_22X_20vs_20Y_22_20discussions_20but_20this_20week_20I_20was_20working_20on_20a_20harvesting_20project_20and_20was_20trying_20to_20figure_20out_20whether_20I_20should_20g&amp;referer=');"><img src="http://www.givp.org/blog/wp-content/plugins/sociable/images/googlebookmark.png" title="Google Bookmarks" alt="Google Bookmarks" class="sociable-hovers" /></a>


<br/><br/>]]></content:encoded>
			<wfw:commentRss>http://www.givp.org/blog/2009/10/26/html-scraping-python-vs-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
