<?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>Scholars&#039; Lab &#187; Wayne Graham</title>
	<atom:link href="http://www.scholarslab.org/author/wsg4w/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.scholarslab.org</link>
	<description>Works in Progress</description>
	<lastBuildDate>Fri, 03 Feb 2012 15:03:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Last week in Open Source</title>
		<link>http://www.scholarslab.org/slab-code/last-week-in-open-source/</link>
		<comments>http://www.scholarslab.org/slab-code/last-week-in-open-source/#comments</comments>
		<pubDate>Mon, 15 Aug 2011 13:42:51 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1909</guid>
		<description><![CDATA[Another busy week in the Scholars&#8217; Lab R&#38;D offices. If you have anything to contribute, remember, pull requests are welcome! Rails 3.1 Template Eric Rochester (erochest) spent some time building a template for Rails 3.1 projects which include HTML 5 Boilerplate and 960gs for erb template layouts, along with rspec-rails, annotate, faker, webrat, spork, and&#8230;. <a href="http://www.scholarslab.org/slab-code/last-week-in-open-source/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>Another busy week in the Scholars&#8217; Lab R&amp;D offices. If you have anything to contribute, remember, pull requests are welcome!</p>
<h2>Rails 3.1 Template</h2>
<p>Eric Rochester (<a href="https://github.com/erochest">erochest</a>) spent some time building a <a href="https://github.com/scholarslab/rails31-template">template for Rails 3.1</a> projects which include <a href="http://html5boilerplate.com/">HTML 5 Boilerplate</a> and <a href="http://960.gs/">960gs</a> for erb template layouts, along with <a href="https://rubygems.org/gems/rspec-rails">rspec-rails</a>, <a href="https://rubygems.org/gems/annotate">annotate</a>, <a href="https://rubygems.org/gems/faker">faker</a>, <a href="https://rubygems.org/gems/webrat">webrat</a>, <a href="https://rubygems.org/gems/spork">spork</a>, and <a href="https://rubygems.org/gems/factory_girl_rails">factory_girl_rails</a> gems to help speed spinning up a new rails project. He wrote a nice <a href="http://www.scholarslab.org/slab-code/web-development-template-rails-3-1-html-5-boilerplate-960-gs/">post on using this technique</a>, then we refactored it a bit, using the rails <a href="http://guides.rubyonrails.org/generators.html#application-templates">application templating system</a>, as well modifying the inclusion of styles and javascripts as we read more of the sprockets 2.0 source to see how it actually handles combining CSS and Javascript.</p>
<p>The entire group has been working with Rails a bit more the past couple of weeks (we have lots of experience in the group with Python and PHP), and there were some humorous responses when I asked their thoughts on rails and the new asset pipeline:</p>
<p>&#8220;I like it a lot more than I used too&#8230;&#8221; &#8211; Jeremy Boggs</p>
<p>&#8220;The asset pipeline is easy enough to override&#8230;&#8221; &#8211; Eric Rochester</p>
<p>&#8220;Meh&#8230;&#8221; &#8211; David McClure</p>
<h2>Octopress</h2>
<p>Eric Rochester <a href="http://www.ericrochester.com/">reworked his blog</a> in <a href="http://octopress.org/">Octopress</a>, a <a href="http://github.com/mojombo/jekyll">Jekyll</a> framework for blogging (<a href="https://github.com/erochest/erochest.github.com">0b331a9</a>). No more database overhead, just straight up HTML goodness! If you feel WordPress is overkill for your needs, and love markdown (or other minimalist markups), you should definitely check this technique out.</p>
<h2>Chef</h2>
<p>Eric Rochester found a <a href="http://tickets.opscode.com/browse/COOK-665">bug in the Chef when using httpd on CentOS 6</a> (<a href="https://github.com/opscode/cookbooks/pull/178">pull request</a>). This update changes the default <a href="http://en.wikipedia.org/wiki/Process_identifier">pid</a> file for the httpd daemon and updates the Apache configuration to appropriately assign the pid as expected. There is really nothing worse than a stale pid file that stalls a daemon.</p>
<h2>NeatlineMaps</h2>
<p>David McClure is getting closer to finishing a major refactor of the <a href="https://github.com/scholarslab/NeatlineMaps">Neatline Maps plugin</a> for Omeka, which makes is possible to display .tiff files hosted in <a href="http://geoserver.org/display/GEOS/Welcome">GeoServer</a> with a &#8220;slippy&#8221; map courtesy of <a href="http://www.openlayers.org">OpenLayers</a>. The current <a href="https://github.com/scholarslab/NeatlineMaps/tree/maps">maps branch</a> of the plugin has quite a number of UX improvements that ease the building of composite maps from of a number of files and associate them with Omeka items.</p>
<h2>The Mind is a Metaphor</h2>
<p>Wayne Graham has started the work of migrating a Rails 2 application to Rails 3 using upgrade plugins and rake tasks. Not only is this application upgrading frameworks, but also is being upgraded to run on Ruby 1.9. As support for Ruby 1.8.7 will reach its <a href="http://redmine.ruby-lang.org/issues/4996">EOL</a>, with normal maintenance until June 2012 and security fixes until June 2013. After spending some time grinding on this, enough has changed that I&#8217;m going to try a new tack and merge models and controllers into a blank project because of the difference in how rails sets itself up depending on if 1.9 or 1.8 is used to initialize the project.</p>
<h2>Git Flow</h2>
<p>We are attempting to standardize our git workflow to make a bit more sense and be &#8220;safer.&#8221; After reading the great piece by Vincent Driessen (&#8220;<a href="http://nvie.com/posts/a-successful-git-branching-model/">A successful Git branching model</a>&#8221; <a href="http://github.com/downloads/nvie/gitflow/Git-branching-model.pdf">pdf</a>), we&#8217;ve begun utilizing <a href="https://github.com/nvie/gitflow">gitflow</a>.  Essentially it  breaks down to a master branch (the release), a develop branch (your next version), release versions (archive of past releases). You then create local &#8220;feature&#8221; branches that you merge in to the develop branch, merging up the tree as needed. I personally am digging the fact that to merge my local branches I no longer have to type:</p>
<pre class="brush: bash; title: ; notranslate">
git co develop
git merge --no-ff mybranch
git branch -d mybranch
git push origin develop
</pre>
<p>There are only two lines now:</p>
<pre class="brush: bash; title: ; notranslate">
git flow feature finish mybranch
git push origin develop
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/last-week-in-open-source/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>This week in Open Source</title>
		<link>http://www.scholarslab.org/slab-code/this-week-in-open-source/</link>
		<comments>http://www.scholarslab.org/slab-code/this-week-in-open-source/#comments</comments>
		<pubDate>Thu, 04 Aug 2011 10:30:00 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[neatline]]></category>
		<category><![CDATA[omeka]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[timeline]]></category>
		<category><![CDATA[vagrant]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1816</guid>
		<description><![CDATA[After reading a post on one of my favorite blogs, Giant Robots Smashing Into Other Giant Robots, I was inspired to start this series chronicling highlights in our Open Source development efforts. It was a busy week for the Scholars&#8217; Lab R&#38;D team, with updates to the FedoraConnector, NeatlineMaps, and Timeline plugins for Omeka, as&#8230;. <a href="http://www.scholarslab.org/slab-code/this-week-in-open-source/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>After reading a post on one of my favorite blogs, <a href="http://robots.thoughtbot.com/post/8221237451/this-week-in-open-source">Giant Robots Smashing Into Other Giant Robots</a>, I was inspired to start this series chronicling highlights in our Open Source development efforts.</p>
<p>It was a busy week for the Scholars&#8217; Lab R&amp;D team, with updates to the <a href="https://github.com/scholarslab/FedoraConnector">FedoraConnector</a>, <a href="https://github.com/scholarslab/NeatlineMaps">NeatlineMaps</a>, and <a href="https://github.com/scholarslab/Timeline">Timeline</a> plugins for <a href="https://github.com/omeka/Omeka">Omeka</a>, as well as updates to our Vagrant <a href="https://github.com/scholarslab/cookbooks">cookbooks</a> (and an <a href="https://github.com/scholarslab/FalmouthDevEnv">Omeka dev example</a>), and <a href="https://github.com/scholarslab/BagItPHP">BagItPHP</a> library.</p>
<h2>FedoraConnector</h2>
<p>David McClure (<a href="https://github.com/davidmcclure">davidmcclure</a>) greatly improved the workflow for updating metadata from FedoraCommons objects in to an Omeka instance (<a href="http://">04b8ee8</a>). Users can now set not only system-wide defaults for polling updates to metadata records from a Fedora server, but also on a per-field basis within individual records, giving users greater control over their metadata pulls.</p>
<h2>NeatlineMaps</h2>
<p>David McClure (<a href="https://github.com/davidmcclure">davidmcclure</a>) also has begun work on a major refactor of the NeatlineMaps plugin on the refactor branch of the project. There is now much smarter support for dynamically determining a map&#8217;s bounding box (<a href="https://github.com/scholarslab/NeatlineMaps/commit/c4090fe1c37cb7547dfe11b309d50290d357b9a2">c4090fe</a>). Just a note if you are checking out this branch: this commit (<a href="https://github.com/scholarslab/NeatlineMaps/commit/032adf36eb72ec5d6cd9ece34a5ad625168c1f23">032adf3</a>) adds the map in the item view, but is default code and displays the map incorrectly due to a bug in the projection. Next up is a major revamp of the administration interface, which will provide a facade for GeoServer inside of Omeka, making it easy to manage collections of maps and assign them to servers and namespaces.</p>
<h2>Timeline</h2>
<p>Jeremy Boggs (<a href="https://github.com/clioweb">clioweb</a>) has re-implemented the Timeline plugin to use the <a href="http://timeglider.com/jquery/">jQuery Timeglider plugin</a>. This update (<a href="https://github.com/scholarslab/Timeline/commit/b078df8169cc30ce2706d3c564161bef44ea3330">b078df8</a>) replaces the plugin&#8217;s use of the SIMILE Timeline and begins to add support for a custom JSON output (<a href="https://github.com/scholarslab/Timeline/commit/51eb12a1c8cdcc37d9d96f72223e7cbee99aa09b">51eb12a</a>) for Omeka records for use in Timeglider timelines.</p>
<h2>Vagrant</h2>
<p>Eric Rochester (<a href="https://github.com/erochest">erochest</a>) has been working on standardizing our development, testing, and deployment environments using virtual servers with <a href="http://vagrantup.com/">Vagrant</a>. He has set up a repository of <a href="https://github.com/scholarslab/cookbooks">cookbooks</a> which automate the setup of development environments for various projects. For a cool example, check out the <a href="https://github.com/scholarslab/FalmouthDevEnv">dev environment</a> for our project with Louis Nelson, chronicling the architectural development of <a href="http://falmouth.lib.virginia.edu/">Falmouth Jamaica</a>.</p>
<h2>BagitPHP</h2>
<p>We spent some time this week moving our Omeka plugins (and other libraries) to a new Jenkins server. In getting the PEAR/Pecl packages properly set up, Wayne Graham (<a href="https://github.com/waynegraham">waynegraham</a>) updated the ant script for the various testing and code reports that we run on our software  (<a href="https://github.com/scholarslab/BagItPHP/commit/465fa89cf2c9cdc763018acde72c82be0f21e6bb">465fa89</a>).</p>
<h2>Jenkins</h2>
<p>To better automate our testing environment, David McClure (<a href="https://github.com/davidmcclure">davidmcclure</a>) worked out the final issues with automating the testing of our plugins with multiple versions of Omeka. We are currently targeting the <a href="https://github.com/omeka/Omeka/tree/stable-1.4">current stable tag of Omeka</a>, and the <a href="https://github.com/omeka/Omeka">master branch</a>. We are working on turning everything green, but the major work of integrating the plugins in to the test environment is complete. It took a bit of tinkering to get the plugins to build correctly when they&#8217;re not sitting inside of an Omeka installation tree (as they would in a standard configuration). Watch this space for a more detailed post about how to replicate this set up.</p>
<p><a rel="attachment wp-att-1821" href="http://www.scholarslab.org/slab-code/this-week-in-open-source/attachment/omeka-jenkins/"><img class="alignleft size-medium wp-image-1821" title="omeka-jenkins" src="http://www.scholarslab.org/wp-content/uploads/2011/08/omeka-jenkins-300x175.png" alt="" width="300" height="175" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/this-week-in-open-source/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Welcoming David McClure!</title>
		<link>http://www.scholarslab.org/announcements/welcoming-david-mcclure/</link>
		<comments>http://www.scholarslab.org/announcements/welcoming-david-mcclure/#comments</comments>
		<pubDate>Mon, 02 May 2011 15:42:01 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[staffing]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1538</guid>
		<description><![CDATA[We&#8217;re delighted to welcome our new Web Applications Specialist, David McClure, to the Scholars&#8217; Lab R&#38;D team. David graduated from Yale University with a degree in Humanities in 2009, and has been working as an independent web developer in San Francisco, New York, and Madison, Wisconsin for the last few years. David is the creator&#8230;. <a href="http://www.scholarslab.org/announcements/welcoming-david-mcclure/">More.</a>]]></description>
			<content:encoded><![CDATA[<p><a rel="attachment wp-att-1567" href="http://www.scholarslab.org/announcements/welcoming-david-mcclure/attachment/pic/"><img class="alignleft size-full wp-image-1567" title="David McClure" src="http://www.scholarslab.org/wp-content/uploads/2011/05/pic.jpg" alt="" width="200" height="211" /></a>We&#8217;re delighted to welcome our new Web Applications Specialist, <a href="http://twitter.com/#!/clured">David McClure</a>, to the Scholars&#8217; Lab R&amp;D team.</p>
<p>David graduated from Yale University with a degree in Humanities in 2009, and has been working as an independent web developer in San Francisco, New York, and Madison, Wisconsin for the last few years. David is the creator of <a href="http://publicpoetics.org/">Public Poetics</a>, an elegant PHP interface for collaborative, web-based commentary on poetry.  He characterizes this project as a design experiment in addressing &#8220;a problem of content &#8216;over-accumulation&#8217; that tends to plague many existing systems of textual annotation and commenting.&#8221;  Not only does David have a strong aesthetic sense and background in web application development, he also has experience in computer graphics, having worked with graphics libraries while developing software for the Cognitive Science department at Yale.</p>
<p>David is also an avid outdoorsman.  His essay &#8220;<a href="http://www.backpackinglight.com/cgi-bin/backpackinglight/pyrenean.html">Mountain Magic on the Pyrenean High Route</a>&#8221; was published in <em>Backpacking Light</em> online.</p>
<p>David McClure will start with us in late May, and we&#8217;re excited to bring him on as a collaborator!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/announcements/welcoming-david-mcclure/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DH Dev Links for 2/14</title>
		<link>http://www.scholarslab.org/dh-developer/dh-dev-links-for-214/</link>
		<comments>http://www.scholarslab.org/dh-developer/dh-dev-links-for-214/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 14:41:15 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[DH Developer]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1298</guid>
		<description><![CDATA[There seem to be quite a few links this week loosely grouped around interface design, with some other geeky goodness mixed in. Isotope jQuery Plugin: Seriously one of the coolest jQuery plugins I&#8217;ve seen in a while. When I get some time, I plan to spend some time with this plugin and Solr results for&#8230;. <a href="http://www.scholarslab.org/dh-developer/dh-dev-links-for-214/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>There seem to be quite a few links this week loosely grouped around interface design, with some other geeky goodness mixed in.</p>
<ul>
<li> <a href="http://isotope.metafizzy.co/">Isotope jQuery Plugin</a>: Seriously one of the coolest jQuery plugins I&#8217;ve seen in a while. When I get some time, I plan to spend some time with this plugin and Solr results for a couple of projects&#8230;</li>
<li><a href="http://andrewcbrown.com/2011/02/07/duke-exeter-and-how-i-wish-computer-science-was-taught/">Duke, Exeter, and Howe I Wish Computer Science was Taught</a>: Good post on some of the shortcomings of the current state of computer science education.</li>
<li><a href="http://web2.uwindsor.ca/math/hlynka/qonline.html">Queuing Theory Books Online</a>: Eventually you&#8217;ll find a problem that could use some queuing. This is a great list of books that give a great theoretical handling of the subject.</li>
<li><a href="http://www.edukatr.com/here-is-the-biggest-mistake-you-will-make-on-amazon-ec2/">Here is the Biggest Mistake You Will Make on Amazon EC2</a>: With the popularity of cloud computing, there are some things you need to remember when deploying to platforms like EC2. Take away from the article&#8230;be careful rebooting server instances!</li>
<li><a href="http://www.quora.com/Twitter-Inc-company/What-is-the-on-boarding-process-for-new-employees-at-Twitter">What is the On-Boarding Process for new Employees at Twitter</a>: While most DH centers have pretty small teams, I&#8217;m always interested in how bigger companies bring new developers in and cultivate their cultural beliefs. This is a nice piece on how Twitter brings new people in.</li>
<li><a href="http://blog.revenueloan.com/2011/02/07/howto-use-dropbox-to-organize-your-startups-documents/">How to Use Dropbox to Organize Your <span style="text-decoration: line-through;">Startup&#8217;s</span> DH Project&#8217;s Documents</a>: Just replace &#8220;startup&#8221; in this article with &#8220;your project&#8221; and this has some good tips for keeping your project documents organized.</li>
<li><a href="https://github.com/blog/785-pull-request-diff-comments">Pull Request Diff Comments</a>: Github now allows you to comment on individual lines on pull requests! Very useful for code reviews.</li>
<li><a href="http://visualwebsiteoptimizer.com/split-testing-blog/landing-page-best-practices/">Landing Page Best Practices</a>: Remember Flash splash pages? This post has some great tips on designing landing pages to engage users in the content of your site.</li>
<li><a href="http://windows.microsoft.com/ie9">IE 9 Beta</a>: Let&#8217;s face it, a lot of people don&#8217;t have access to other browsers for various reasons (can&#8217;t install software on work computer). Even though IE is painful, Microsoft swears IE 9 will be better&#8230;</li>
<li><a href="http://robots.thoughtbot.com/post/3217276323/better-grids-lessons-learned-from-design-for">Better grids: Lessons learned from Design for Developers</a>: Thoughtbot is putting on a series of training sessions to teach design principals to developers. Take away on this&#8230;3 and 4 column grid systems provide a solid foundation that introduces clarity to your web layouts.</li>
<li><a href="http://warpspire.com/talks/documentation/">Documentation is Freaking Awesome</a>: Enough said.</li>
<li><a href="http://ontwik.com/html5-2/paul-irish-on-html5-boilerplate/">Paul Irish on HTML 5 Boilerplate</a>: Anyone who&#8217;s looked at any HTML I&#8217;ve done in the last 6 months will notice that it starts with HTML 5 Boilerplate (usually with some 960gs). This is a nice presentation by Paul on its development and use.</li>
<li><a href="http://www.engineyard.com/blog/2011/reuse-your-javascript-as-jquery-plugins/">Reuse your JavaScript as jQuery Plugins</a>: Nice post on converting JS scripts in to jQuery plugins using a couple of different patterns. Definitely worth a look if you are writing any Javascript.</li>
<li><a href="http://www.intermediaware.com/blog/1085">How to use Dropbox as a git server</a>: Can&#8217;t/Don&#8217;t want to use github as your SCM? This tutorial shows how you might use Dropbox to replicate your git repo (you&#8217;ll need to adjust the paths if you&#8217;re a Windows user).</li>
<li><a href="http://developmentseed.org/blog/2011/feb/16/announcing-tilemill-modern-map-design-studio-powered-open-source">Announcing TileMill: A Modern Map Design Studio Powered by Open Source</a>: The folks at DevelopmentSeed are doing some amazing work. If you have need to create some maps, TileMill looks like a nice piece of software to get you running without needing to install a large server infrastructure!</li>
<li><a href="http://vodpod.com/watch/799407-hacked-floppy-disk-plays-star-wars-music-as-awesome-as-it-">Hacked Floppy Disk Plays Starwars Music</a>: Just for fun</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/dh-developer/dh-dev-links-for-214/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DH Dev Picks</title>
		<link>http://www.scholarslab.org/dh-developer/dh-dev-picks/</link>
		<comments>http://www.scholarslab.org/dh-developer/dh-dev-picks/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 21:30:07 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[DH Developer]]></category>
		<category><![CDATA[algorithms]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[web fonts]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1287</guid>
		<description><![CDATA[Part of mission here at the Scholars&#8217; Lab is provide guidance for folks working on digital projects. As such, I do my best to keep up with trends in software development. For a while I&#8217;ve just been adding these to my delicious account to make it a bit easier to find references later. However, recent&#8230;. <a href="http://www.scholarslab.org/dh-developer/dh-dev-picks/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>Part of mission here at the Scholars&#8217; Lab is provide guidance for folks working on digital projects. As such, I do my best to keep up with trends in software development. For a while I&#8217;ve just been adding these to my <a href="http://www.delicious.com/wsgrah">delicious account</a> to make it a bit easier to find references later. However, recent trends in the way Yahoo! is handling its properties (specifically with delicious), made the think a bit harder about this approach and I thought I might try something else. The idea here is to have a regular series of posts with links that I find interesting and I think are are of some utility to other DH developers.</p>
<ul>
<li><a href="http://awesome-fontstacks.com/">Awesome Fontstacks</a>: If you&#8217;re a developer who does design, or a designer who codes, browser support for beautiful fonts opens a lot of doors for creating compelling presentations of your work.</li>
<li><a href="http://toroid.org/ams/git-website-howto">Using Git to manage a web site</a>: Web workflows vary widely, but wouldn&#8217;t it be nice to use your SCM for deploying your web application? This post describes a method of using git to deploy web pages.</li>
<li><a href="http://jcsalterego.github.com/2011/02/04/getting-comfortable-with-ssh.html">Getting Comfortable With SSH</a>: I use keys, aliases, and remote tunneling as part of my workflow, and this post provides a nice introduction to all of these. I would be remiss, however, if I didn&#8217;t point out something they highlight on the post: this method is pretty insecure. After you get your feet wet, be sure to check out a much more secure method over on <a href="http://help.github.com/working-with-key-passphrases/">Github</a></li>
<li><a href="http://resume.github.com/">My Github Resume</a>: Use github? This site does a nice job creating a resume/cv of your code commits</li>
<li><a href="http://www.designyourway.net/blog/resources/31-css-code-snippets-to-make-you-a-better-coder/">31 CSS Code Snippets To Make You A Better Coder</a>: If you&#8217;re like me, I can&#8217;t keep browser-specific differences in the implementation of the CSS spec straight in my head. These code snippets help. Add them to a program like <a href="http://code.google.com/p/snippely/">Snippely</a>, <a href="http://www.vim.org/scripts/script.php?script_id=2540">SnipMate</a>,<br />
or your favorite IDE, you can throw them in your code as needed.</li>
<li><a href="http://jeromeetienne.github.com/jquery-mobile-960/">960 Grid on jQuery-Mobile</a>: I&#8217;m a fan of 960 grid and jQuery. While these techniques for use on mobile devices has a way to go, this technique does show some promise.</li>
<li><a href="http://weblog.jamisbuck.org/">Maze Algorithms</a>: Great set of posts on solving tough problems algorithmically. These are also nice if you&#8217;re not familiar with the pseudo-code commonly used to express discrete algorithmic logic. Very clear explanation of the problem and the approach used to solve the issues.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/dh-developer/dh-dev-picks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Are you our new Web Applications Specialist?</title>
		<link>http://www.scholarslab.org/announcements/web-applications-specialist/</link>
		<comments>http://www.scholarslab.org/announcements/web-applications-specialist/#comments</comments>
		<pubDate>Fri, 04 Feb 2011 20:51:07 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[career opportunities]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1254</guid>
		<description><![CDATA[Are you an enthusiastic Web developer with an interest in the humanities or cultural heritage? UVa Library seeks a Web Applications Specialist to help develop software in our internationally-recognized Scholars&#8217; Lab. The ideal candidate is detail-oriented, eager to work collaboratively, and stays involved with the latest Web and digital humanities technologies. We&#8217;re seeking someone passionate&#8230;. <a href="http://www.scholarslab.org/announcements/web-applications-specialist/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>Are you an enthusiastic Web developer with an interest in the humanities or cultural heritage? UVa Library seeks a Web Applications Specialist to help develop software in our internationally-recognized <a href="http://lib.virginia.edu/scholarslab">Scholars&#8217; Lab</a>. The ideal candidate is detail-oriented, eager to work collaboratively, and stays involved with the latest Web and digital humanities technologies.</p>
<p>We&#8217;re seeking someone passionate about tackling technical problems in the digital humanities – preferably a person with both a technical and liberal arts background, prepared to build next-generation DH interfaces and tools. Our new Web Application Specialist will also be able to take advantage of the “20% time” that all Department of Digital Research &amp; Scholarship faculty and staff are granted to pursue professional development and their own (often collaborative) R&amp;D projects. This is a full-time, permanent position at UVa.</p>
<h3>Web Applications Specialist</h3>
<p>As a Web Applications Specialist reporting to the Head of R&amp;D for the Scholars&#8217; Lab, you will be responsible for building, testing, and debugging code, developing documentation, and assisting at troubleshooting. You should possess an attention to detail and a high level of accountability and responsibility. We&#8217;re looking for someone who enjoys technical challenges, likes to figure out how things work, and stays involved in the latest Web and digital humanities technologies. You will need to be able to fit in to a creative and collaborative environment. Want to join us as we create great scholarly interfaces?</p>
<ul>
<li>2-3 years of experience developing web applications with tech skills demonstrated via one or more of the following:
<ul>
<li>your open source work</li>
<li>your github repository</li>
<li>your awesome blog</li>
<li>your code samples from side projects</li>
<li>or your production web site (handling real traffic)</li>
</ul>
</li>
<li>knowlege of SQL, git, svn, HTML, CSS, Javascript</li>
<li>ability to work with technical and non-technical collaborators thanks to your great communications skills</li>
<li>experience with software development (maybe even including Agile methodologies)</li>
</ul>
<h3>Duties and Responsibilities:</h3>
<div id="_mcePaste">
<ul>
<li>Build, test, and debug code</li>
<li>Write test cases</li>
<li>Estimate coding projects</li>
<li>Provide consultation on collaborative projects</li>
<li>Develop documentation</li>
<li>Assist in the debugging and system troubleshooting for existing software written in a variety of languages and platform</li>
</ul>
</div>
<h3>Qualifications:</h3>
<ul>
<li>1+ years full-time experience with web development (Rails and PHP preferred)</li>
<li>2+ years experience of standards compliant HTML, CSS, and Javascript</li>
<li>Javascript skills (AJAX, JQuery or similar JS framework)</li>
<li>Experience with Test Driven Development (Shoulda, RSpec, PHPUnit)</li>
<li>Experience with relational database management systems (MySQL, Postgresql)</li>
<li>Familiarity with version control systems</li>
<li>Understanding of software life cycle</li>
<li>Strong foundation in OO programming and practices</li>
<li>Experience with <a href="http://omeka.org">Omeka</a> a plus</li>
</ul>
<h3>If this sounds like you&#8230;</h3>
<p>We encourage you to <a href="http://jobs.virginia.edu/applicants/Central?quickFind=63332 ">APPLY FOR THIS JOB</a>. Salary is commensurate with experience, and expected to range between approximately $43,500 and $75,500 per annum. We’re looking to fill this position quickly, so please don’t delay!</p>
<p>Consideration of applications will begin immediately and continue until the position is filled.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/announcements/web-applications-specialist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Are you our new Senior Developer?</title>
		<link>http://www.scholarslab.org/announcements/senior-developer-position/</link>
		<comments>http://www.scholarslab.org/announcements/senior-developer-position/#comments</comments>
		<pubDate>Tue, 09 Nov 2010 14:19:17 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[career opportunities]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=1082</guid>
		<description><![CDATA[Still fairly fresh on the scene, but drawing on a long history in digital humanities and spatial and data-driven work at the University of Virginia, the UVa Library&#8217;s Scholars&#8217; Lab has developed great projects and hosted amazing events over the past three years. We now have an opportunity to add new collaborators to round out&#8230;. <a href="http://www.scholarslab.org/announcements/senior-developer-position/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>Still fairly fresh on the scene, but drawing on a long history in digital humanities and spatial and data-driven work at the University of Virginia, the UVa Library&#8217;s <a href="http://lib.virginia.edu/scholarslab">Scholars&#8217; Lab</a> has developed <a href="http://www.scholarslab.org/">great projects</a> and hosted <a href="http://www2.lib.virginia.edu/scholarslab/about/events.html">amazing events</a> over the past three years. We now have an opportunity to add new collaborators to round out our team! (So stay tuned for future postings later this semester.)</p>
<p>Today, <a href="http://jobs.virginia.edu/applicants/Central?quickFind=62652">we&#8217;re looking for a Senior Developer</a> who can build, test, and debug code and who loves to get &#8216;under the hood&#8217; to figure out how things work.</p>
<h3>Senior Developer, Scholars&#8217; Lab</h3>
<p>As a senior web and software developer reporting to the Head of R&amp;D for the <a href="http://www.scholarslab.org/">Scholars&#8217; Lab</a>, you will be responsible for enhancing, maintaining, and optimizing projects related to digital research and scholarship. Not only should you enjoy writing well organized, highly tested code, but you should enjoy working with a great group of teammates and scholarly stake holders to solve hard problems in both software engineering and the digital humanities. You will need to fit into a fast-paced, interdisciplinary environment where technology enables creative vision &#8212; and where you can take good advantage of the &#8220;20% time&#8221; that all Scholars&#8217; Lab and <a href="http://lib.virginia.edu/scholarslab">Department of Digital Research &amp; Scholarship</a> faculty and staff are granted to pursue professional development and their own (often collaborative) R&amp;D projects.</p>
<p><strong>Responsibilities:</strong></p>
<ul>
<li>Write scalable, well-factored, well-tested application code</li>
<li>Lead development projects</li>
<li>Work with support teams to find and fix application bugs</li>
<li>Work with cross-functional teams to develop design solutions</li>
</ul>
<p><strong>Specialized Knowledge and Skills:</strong></p>
<ul>
<li>In-depth knowledge of multiple programming languages including PHP, Perl, Ruby, and Java</li>
<li>Full-time experience with PHP and Ruby frameworks (e.g. Zend and Rails)</li>
<li>Proven ability to quickly learn new systems and environments</li>
<li>Experience working on open source projects</li>
<li>Efficient problem solving techniques</li>
<li>Excellent verbal and written communication skills</li>
<li>Knowledge of multiple RDBMSes (PostgreSQL, Oracle, MySQL)</li>
<li>Javascript skills (AJAX, DHTML, jQuery and similar JS frameworks)</li>
<li>Familiarity with version control systems (Subversion and Git)</li>
<li>Experience Test-Driven development (PHPUnit, SimpleTest, RSpec, Shoulda, etc.)</li>
<li>Linux experience a plus (RHEL, Fedora Core)</li>
</ul>
<h3>If this sounds like you&#8230;</h3>
<p>we invite you to <a href="http://jobs.virginia.edu/applicants/Central?quickFind=62652   ">APPLY FOR THE JOB</a>.</p>
<p>Salary is commensurate with experience, and expected to range between approximately $58,000 and $106,000 per annum. We&#8217;re looking to fill this position quickly, so please don&#8217;t delay!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/announcements/senior-developer-position/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Synchronizing Development Databases</title>
		<link>http://www.scholarslab.org/slab-code/synchronizing-development-databases/</link>
		<comments>http://www.scholarslab.org/slab-code/synchronizing-development-databases/#comments</comments>
		<pubDate>Fri, 24 Sep 2010 18:27:06 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[databases]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=949</guid>
		<description><![CDATA[As a developer, I routinely work on multiple machines during the course of a project. One of the biggest pains is working on a database-driven project is that I often need to move the data on machine X to machine Y, make changes, then move the updated data from machine Y back to machine X.&#8230;. <a href="http://www.scholarslab.org/slab-code/synchronizing-development-databases/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>As a developer, I routinely work on multiple machines during the course of a project. One of the biggest pains is working on a database-driven project is that I often need to move the data on machine X to machine Y, make changes, then move the updated data from machine Y back to machine X.</p>
<p>Back in the day (ok, so like last week), I would typically write a mysqldump/pgdump script that would dump the data to a tarball, then scp the data around as needed. If it were really important, I might take the time to set up rsync, or even a master/slave configuration for the data. What I found, however, is that I could &#8220;break&#8221; my development databases and I did this often, wasting time recovering from this foolishness. There had to be a better way. <span id="more-949"></span></p>
<p>Turns out there is. If you&#8217;ve ever deployed anything to <a href="http://www.heroku.com">heroku</a>, you&#8217;ll find they have a really neat way to allow you to synchronize your databases. From the command line, you can pull the database running on the server to your local database (and it actually doesn&#8217;t matter if you&#8217;re running sqlite, mysql, or postgresql locally, it just works) with:</p>
<pre class="brush: bash; title: ; notranslate">
heroku db:pull mysql://user:pass@localhost/mydb
heroku db:pull sqlite://path/to/my.db
</pre>
<p>Need to push changes to the server?</p>
<pre class="brush: bash; title: ; notranslate">
heroku db:push
</pre>
<p>Behind the scenes, heroku is using the <a href="http://rubygems.org/gems/taps">taps</a> gem, so you can actually use this same technique for your local setups.</p>
<p>The following will walk through a &#8220;typical&#8221; (e.g. the way I have my dev system set up) use case for integrating taps in to your workflow. I use a Mac, so if you&#8217;re on Linux or worse (Windows), you&#8217;ll need to slightly adjust some of these directions.</p>
<p>The first thing you need to do is make sure that your gems are up-to-date. From a terminal, issue this command:</p>
<pre class="brush: bash; title: ; notranslate">
sudo gem update --system
</pre>
<p>Now, we need the taps gem:</p>
<pre class="brush: bash; title: ; notranslate">
sudo gem install taps
</pre>
<p>This will take a while as the library dependencies are calculated, and the documentation is generated, but you will some something along these lines:</p>
<pre class="brush: bash; title: ; notranslate">
devbox:~ user$ gem install taps
Building native extensions.  This could take a while...
Successfully installed json_pure-1.4.6
Successfully installed rack-1.2.1
Successfully installed sinatra-1.0
Successfully installed mime-types-1.16
Successfully installed rest-client-1.4.2
Successfully installed sequel-3.15.0
Successfully installed sqlite3-ruby-1.3.1
Successfully installed taps-0.3.12
8 gems installed
Installing ri documentation for json_pure-1.4.6...
Installing ri documentation for rack-1.2.1...
Installing ri documentation for sinatra-1.0...
Installing ri documentation for mime-types-1.16...
Installing ri documentation for rest-client-1.4.2...
Installing ri documentation for sequel-3.15.0...
Installing ri documentation for sqlite3-ruby-1.3.1...
Installing ri documentation for taps-0.3.12...
Installing RDoc documentation for json_pure-1.4.6...
Installing RDoc documentation for rack-1.2.1...
Installing RDoc documentation for sinatra-1.0...
Installing RDoc documentation for mime-types-1.16...
Installing RDoc documentation for rest-client-1.4.2...
Installing RDoc documentation for sequel-3.15.0...
Installing RDoc documentation for sqlite3-ruby-1.3.1...
Installing RDoc documentation for taps-0.3.12...
</pre>
<p>You will need to have this installed on each of the boxes you want to be able to push/pull to/from.</p>
<p>Ok, assuming you&#8217;ve got the taps gem installed on all the computers you want to use, you need to fire up the taps server on each box that actually responds to the push/pull requests. This is a simple <a href="http://www.sinatrarb.com/">Sinatra</a> application that runs and listens for push/pull requests. To fire this up, issue the command:</p>
<pre class="brush: bash; title: ; notranslate">
taps server mysql://user@localhost:port/database tapsusername tapspassword
</pre>
<p>Let&#8217;s unpack this a little. The taps server needs to know what database to connect to, and a secret user/password to use. Let&#8217;s say you&#8217;re running MAMP with the default mysql server and accounts running, and you want to be able to sync your Omeka database. Your connection string would look like this:</p>
<pre class="brush: bash; title: ; notranslate">
taps server mysql://root@localhost:8889/omeka tapuser IeEf643
 </pre>
<p>Now we can test that the server is running by pointing your browser at <a href="http://localhost:5000">http://localhost:5000</a>. You should see something along these lines after using the username and password you set with the server:</p>
<p><a rel="attachment wp-att-954" href="http://www.scholarslab.org/slab-code/synchronizing-development-databases/attachment/taps_server/"><img class="alignnone size-medium wp-image-954" title="taps_server" src="http://www.scholarslab.org/wp-content/uploads/2010/09/taps_server-300x149.jpg" alt="" width="300" height="149" /></a></p>
<p>Now this doesn&#8217;t actually do anything, just ensures that you have the server up-and-running. Now to get the data loaded on another box&#8230;</p>
<p>Assuming you&#8217;re on another computer now (and that you&#8217;re not blocking port 5000 on the host machine), you issue a pull command (assuming you&#8217;ve already created the omeka database in the MAMP phpMyAdmin):</p>
<pre class="brush: bash; title: ; notranslate">

taps pull mysql://root@localhost:3306/omeka http://tapuser:IeEf643@remoteip:5000
</pre>
<p>Again, assuming you don&#8217;t have a firewall port blocking issues, you should see the tables getting propagated on your system:</p>
<pre class="brush: bash; title: ; notranslate">
Receiving schema
Schema:        100% |==========================================| Time: 00:00:22
Receiving data
25 tables, 228 records
omeka_item_ty: 100% |==========================================| Time: 00:00:00
omeka_tags:    100% |==========================================| Time: 00:00:00
omeka_entity_: 100% |==========================================| Time: 00:00:00
omeka_items:   100% |==========================================| Time: 00:00:00
omeka_section: 100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_record_: 100% |==========================================| Time: 00:00:00
omeka_tagging: 100% |==========================================| Time: 00:00:00
omeka_users_a: 100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_entitie: 100% |==========================================| Time: 00:00:00
omeka_data_ty: 100% |==========================================| Time: 00:00:00
omeka_item_ty: 100% |==========================================| Time: 00:00:00
omeka_options: 100% |==========================================| Time: 00:00:00
omeka_entitie: 100% |==========================================| Time: 00:00:00
omeka_mime_el: 100% |==========================================| Time: 00:00:00
omeka_section: 100% |==========================================| Time: 00:00:00
omeka_items_s: 100% |==========================================| Time: 00:00:00
omeka_process: 100% |==========================================| Time: 00:00:00
omeka_collect: 100% |==========================================| Time: 00:00:00
omeka_exhibit: 100% |==========================================| Time: 00:00:00
omeka_files:   100% |==========================================| Time: 00:00:00
omeka_plugins: 100% |==========================================| Time: 00:00:00
omeka_users:   100% |==========================================| Time: 00:00:00
Receiving indexes
Resetting sequences
</pre>
<p>You should now have a functional copy of all your data from the server machine. Now all you have to do is make your changes, then push those changes back to the server.</p>
<pre class="brush: bash; title: ; notranslate">

$ taps push mysql://root@localhost:8889/omeka http://tapuser:IeEf643@localhost:5000
Sending schema
Schema:        100% |==========================================| Time: 00:00:20
Sending data
25 tables, 0 records
omeka_item_ty: 100% |==========================================| Time: 00:00:00
omeka_tags:    100% |==========================================| Time: 00:00:00
omeka_section: 100% |==========================================| Time: 00:00:00
omeka_entity_: 100% |==========================================| Time: 00:00:00
omeka_items:   100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_tagging: 100% |==========================================| Time: 00:00:00
omeka_users_a: 100% |==========================================| Time: 00:00:00
omeka_record_: 100% |==========================================| Time: 00:00:00
omeka_entitie: 100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_element: 100% |==========================================| Time: 00:00:00
omeka_item_ty: 100% |==========================================| Time: 00:00:00
omeka_options: 100% |==========================================| Time: 00:00:00
omeka_data_ty: 100% |==========================================| Time: 00:00:00
omeka_entitie: 100% |==========================================| Time: 00:00:00
omeka_section: 100% |==========================================| Time: 00:00:00
omeka_mime_el: 100% |==========================================| Time: 00:00:00
omeka_process: 100% |==========================================| Time: 00:00:00
omeka_items_s: 100% |==========================================| Time: 00:00:00
omeka_collect: 100% |==========================================| Time: 00:00:00
omeka_plugins: 100% |==========================================| Time: 00:00:00
omeka_files:   100% |==========================================| Time: 00:00:00
omeka_exhibit: 100% |==========================================| Time: 00:00:00
omeka_users:   100% |==========================================| Time: 00:00:00
Sending indexes
Resetting sequences
</pre>
<h2>So what can go wrong?</h2>
<p>This is a young project, so there are a few things you should know. As of the time of writing this (taps v 3.12.0), there are a few issues being worked on:</p>
<ul>
<li>Foreign Keys get lost in the schema transfer</li>
<li>Tables without primary keys will be incredibly slow to transfer. This is due to it being inefficient having large offset values in queries.</li>
<li>Multiple schemas are currently not supported</li>
</ul>
<p><strong>I strongly suggest only using this in a development setting for non-Rails projects</strong>. Rails-based projects have a special object for table relations which help manage keys. If you&#8217;re doing heavy database development, use the tools your database provides (mysqldump/pgdump) to create snapshots of your data! Script it, crontab it, download it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/synchronizing-development-databases/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Code Reviews and the Digital Humanities</title>
		<link>http://www.scholarslab.org/digital-humanities/code-reviews-and-the-digital-humanities/</link>
		<comments>http://www.scholarslab.org/digital-humanities/code-reviews-and-the-digital-humanities/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 12:47:57 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[Digital Humanities]]></category>
		<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[code review]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=890</guid>
		<description><![CDATA[The following was a response I made in an email exchange with Tom Elliot of the Pleiades Project  and Bethany Nowviskie. Our conversation was prompted by Tom's inquiry on planning, budgeting for, and conducting a code review as part of a grant-funded project. What follows is a slightly modified (and expanded) version of that email conversation.

Testing and code review is something that has been on my mind a lot lately as our shop has been shifting its focus from boutique, one-off projects, to building upon frameworks maintained by other organizations. As these code bases continue to grow, we need to ensure that subtle changes to the core functionality of the underlying systems do not propagate into bugs in our code. We also need a way to handle this situation quickly and efficiently when this does arise. This was especially reinforced by two recent projects our group undertook to migrate nearly decade-old software on to new servers.]]></description>
			<content:encoded><![CDATA[<p>The following was a response I made in an email exchange with Tom Elliot of the <a href="http://pleiades.stoa.org/">Pleiades Project</a> and Bethany Nowviskie. Our conversation was prompted by Tom&#8217;s inquiry on planning, budgeting for, and conducting a code review as part of a grant-funded project. What follows is a slightly modified (and expanded) version of that email conversation.</p>
<p>Testing and code review is something that has been on my mind a lot lately as our shop has been shifting its focus from boutique, one-off projects, to building upon frameworks maintained by other organizations. As these code bases continue to grow, we need to ensure that subtle changes to the core functionality of the underlying systems do not propagate into bugs in our code. We also need a way to handle this situation quickly and efficiently when this does arise. This was especially reinforced by two recent projects our group undertook to migrate nearly decade-old software on to new servers.</p>
<p>If you ask anyone in the office, they will most likely roll their eyes when I start beating the testing drum. <span id="more-890"></span> These are great tools for not only generating pretty green and red bar charts, but also documenting the intention of the programmer in writing the code, and zeroing in on bugs where they occur without weeks of hunting. However, this is only one of the tools in the chest for writing solid code, sans bugs. In fact, there are a lot of sophisticated, freely available, automated tools that help programmers of all skill levels not only write more consistent code, but also zero in on potential performance issues and just plain smelly code (that they obviously wrote just to get running and fully intended to go back and fix later).</p>
<p>Over the years, tools that measure code complexity (like <a href="http://pmd.sourceforge.net/">PMD</a>, <a href="http://phpmd.org/about.html">PHPMD</a>, and <a href="http://ruby.sadi.st/Flog.html">flog</a>), code dependency analyzers (<a href="http://www.clarkware.com/software/JDepend.html">JDepend</a>, <a href="http://pdepend.org/news.html">PHPDepend</a>, and <a href="http://eigenclass.org/hiki.rb?rcov">rcov</a>), copy/paste detection (in PMD, <a href="http://ruby.sadi.st/Flay.html">flay</a>, and <a href="http://github.com/sebastianbergmann/phpcpd">phpcpd</a>), and enforcing coding standards (a la PHPCode Sniffer and rails_best_practices), along with not only unit and integration tests (in whatever style you choose), but a code coverage analysis reports that provides feedback on which lines were executed, go a long way in reducing the number of bugs in code. These tools are really pre-emptive step in writing stronger, more elegant, and ultimately more sustainable code, all before once gets to the point of performing a human code review.</p>
<p>While I don&#8217;t need to be building software per-se, I have started experimenting with the Hudson continuous integration server as a dashboard to get a quick snapshot of how these different metric tests all play together in the code that our team writes. It is no longer good enough to simply have code functioning, we need the code to pass certain thresholds of quality and sustainability before we can release. Where we find issues in the code, like test coverage, high cyclomatic complexity, lots of copy-n-pasted code, or high volatility in dependency scans, we can sit down and perform a rather focused mini code review (resembling the pair-programming idiom) on that section of code to refactor a better solution or approach To this end, we&#8217;re currently working on a set of baseline testing and reporting tools for our projects. Currently, we have Ant scripts for our PHP and Java projects, and a gem bundle for Rails and Sinatra projects.</p>
<p>While we take this approach in the Scholars&#8217; Lab, we were wondering if there were others out there that had opinions or experiences to share about code review during development? If you do, leave a comment, write a post, or tweet at us (@scholarslab, @nowviskie, @wayne_graham) &#8212; and at @paregorios, who started the conversation in the first place. We&#8217;d love to hear about your best practices (and even horror stories) and philosophy on what constitutes good software and useful code reviewing, including whether you think current trends in open source development constitute a good-enough review for DH projects.</p>
<h2>Further Resources</h2>
<p>Java</p>
<ul>
<li><a href="http://pmd.sourceforge.net/">PMD</a></li>
<li><a href="http://www.clarkware.com/software/JDepend.html">JDedend</a></li>
<li><a href="http://www.junit.org/">junit</a></li>
<li><a href="http://www.atlassian.com/software/clover/">Clover</a></li>
<li><a href="http://www.oracle.com/technetwork/java/javase/documentation/index-jsp-135444.html">Javadoc</a></li>
<li><a href="http://checkstyle.sourceforge.net/">Checkstyle</a></li>
</ul>
<p>PHP</p>
<ul>
<li><a href="http://pdepend.org/news.html">PHP Depend</a></li>
<li><a href="http://phpmd.org/about.html">PHPMD</a></li>
<li><a href="http://github.com/sebastianbergmann/phpcpd">phpcpd</a></li>
<li><a href="http://pear.php.net/package/PHP_CodeSniffer/redirected">PHP Codesniffer</a></li>
<li><a href="http://www.phpdoc.org/">phpDocumentor</a></li>
</ul>
<p>Ruby</p>
<ul>
<li><a href="http://ruby.sadi.st/Flog.html">Flog</a></li>
<li><a href="http://ruby.sadi.st/Flay.html">Flay</a></li>
<li><a href="http://metric-fu.rubyforge.org/">metric_fu</a></li>
<li><a href="http://rdoc.sourceforge.net/">rdoc</a></li>
</ul>
<p>Javascript</p>
<ul>
<li><a href="http://docs.jquery.com/QUnit">QUnit</a></li>
<li><a href="http://siliconforks.com/jscoverage/">JSCoverage</a></li>
</ul>
<p>Continuous Integration</p>
<ul>
<li><a href="http://hudson-ci.org/">Hudson</a></li>
<li><a href="http://phing.info/trac/">Phing</a></li>
<li><a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a></li>
</ul>
<p>Issue Tracking</p>
<ul>
<li><a href="https://code.google.com/hosting/">Google Code</a></li>
<li><a href="http://github.com/">GitHub</a></li>
<li><a href="http://kenai.com/">Project Kenai</a></li>
<li><a href="http://www.atlassian.com/software/jira/">Jira</a></li>
<li><a href="http://www.redmine.org/">Redmine</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/digital-humanities/code-reviews-and-the-digital-humanities/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why Ruby?</title>
		<link>http://www.scholarslab.org/slab-code/why-ruby/</link>
		<comments>http://www.scholarslab.org/slab-code/why-ruby/#comments</comments>
		<pubDate>Tue, 11 May 2010 19:27:02 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=741</guid>
		<description><![CDATA[Stemming from a Twitter conversation last month, I thought it would be a good idea to describe &#8212; in more than the 140 character bursts that Twitter allows &#8212; why we at the Scholars&#8217; Lab often promote Ruby, opposed to one of the other 4 or 5 languages we develop with. This isn&#8217;t an attempt&#8230;. <a href="http://www.scholarslab.org/slab-code/why-ruby/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>Stemming from <a href="http://twitter.com/dougreside/status/12881732120">a Twitter conversation</a> last month, I thought it would be a good idea to describe &#8212; in more than the 140 character bursts that Twitter allows &#8212; why we at the <a href="http://lib.virginia.edu/scholarslab/">Scholars&#8217; Lab</a> often promote Ruby, opposed to one of the other 4 or 5 languages we develop with. This isn&#8217;t an attempt to declare one language &#8220;the best,&#8221; but is meant to lay out some of the fundamental reasons why we use Ruby in the context of our digital humanities work and why we think it&#8217;s a nice language to suggest to folks just starting to program.<span id="more-741"></span></p>
<h2>Qualification</h2>
<p>People often think of the Scholars&#8217; Lab as a <a href="http://www.ruby-lang.org/en/">Ruby</a> (and <a href="http://rubyonrails.org/">Rails</a>) shop, which isn&#8217;t quite the case. We code in many different languages.  In the past several moths, we have written <a href="http://metaphors.lib.virginia.edu">The Mind is a Metaphor</a> in Ruby (with Rails). <a href="http://prosody.lib.virginia.edu/">For Better For Verse</a> uses <a href="http://wordpress.org/">WordPress</a> with <a href="http://www.tei-c.org/index.xml">TEI</a> and <a href="http://java.sun.com/products/jsp/">JSP</a>, and some more recent work on a William Faulkner audio archive employs <a href="http://cocoon.apache.org/2.1/">Cocoon</a> with <a href="http://lucene.apache.org/solr/">Solr</a>. In addition to those collaborations with UVa faculty, we&#8217;ve been writing plugins for <a href="http://omeka.org/">Omeka</a> (and dusting off our PHP skills) and have created a <a href="http://gis.lib.virginia.edu/">discovery interface</a> for our GIS infrastructure in Ruby (with <a href="http://www.sinatrarb.com/">Sinatra</a>). If you analyze the technologies we currently deploy, it turns out we use <a href="http://cocoon.apache.org/">Cocoon</a> + <a href="http://lucene.apache.org/solr/">Solr</a> more than anything else, though we&#8217;re starting to move away from that particular stack as our approach for tool development.</p>
<p>The Scholars&#8217; Lab has a lot of experience with all types of languages, and depending on the circumstances, we choose different tools to accomplish any given task. However, after quite a bit of time helping people get started on a programming path, I&#8217;ve come to appreciate some of the features Ruby provides in getting new programmers up to speed.</p>
<h2>Learning Curve</h2>
<p>Every language has a learning curve. However, once you get the hang of some of the basics of computer languages (flow control, data structures, objects, etc.), the biggest differences come from syntax. All web languages make certain programming exercises easy, and once you buy in to the way in which that language handles programming constructs, moving between languages for experienced programmers becomes a simpler exercise in exploring syntax and built-in functionality.</p>
<p>As one of my computer science professors posited, generally the first language you learn governs the way you code until something significantly better comes along. For a lot of folks getting in to programming for the first time, this usually means either taking a class or finding someone to show you the basics. If you&#8217;re in higher education, this has typically meant the tool of choice is PHP. However, having seen the look of bewilderment on the faces of enough graduate students and faculty members as I attempt to explain the difference between sprintf and printf (printf returns the length of the formatted String and sprintf returns the formatted String), I&#8217;ve come to believe that the syntax of a programming language (and it&#8217;s readability) is an exceptionally important part of a language, especially when teaching basics of software construction.</p>
<h3>Method Chaining</h3>
<p>Without getting into how the PHP and Ruby <a href="http://en.wikipedia.org/wiki/Duck_typing">duck-type</a><a href="http://en.wikipedia.org/wiki/Primitive_data_type"> primitive data types</a> and <a href="http://en.wikipedia.org/wiki/Data_structure">data structures</a>, one big difference in syntax between the two is how one combines multiple method calls together. Ruby uses method chaining for objects whereas PHP uses &#8220;bolted-on&#8221; functions (think of these as order-of-operations from your high school Algebra class). Let&#8217;s look at this brief example of addressing and sorting an associative array in PHP and its equivalent in Ruby:</p>
<pre class="brush: php; title: ; notranslate">
$projects = array(&quot;solr&quot; =&gt; 4, &quot;php&quot; =&gt; 1, &quot;rails&quot; =&gt; 2, &quot;jsp&quot; =&gt; 3);
$keys = array_keys($projects);
sort($keys);
$sorted = array_slice($keys, 0, 3);
</pre>
<p>If you&#8217;re a little more advanced, you might refactor (rewrite) the code to look more like this (methods anonymously &#8220;bolted-on&#8221; to one another):</p>
<pre class="brush: php; title: ; notranslate">
$projects = array(&quot;solr&quot; =&gt; 4, &quot;php&quot; =&gt;  1, &quot;rails&quot; =&gt; 2, &quot;jsp&quot; =&gt; 3);
$sorted = array_slice(sort(array_keys($projects)), 0, 3);
</pre>
<p>Now, the same examples in Ruby syntax:</p>
<pre class="brush: ruby; title: ; notranslate">
projects = {&quot;solr&quot; =&gt; 4, &quot;php&quot; =&gt;  1, &quot;rails&quot; =&gt; 2, &quot;jsp&quot; =&gt; 3}
sorted = projects.keys.sort.slice(0,3)
</pre>
<p>Or, even more concisely:</p>
<pre class="brush: ruby; title: ; notranslate">
projects = {&quot;solr&quot; =&gt; 4, &quot;php&quot; =&gt;  1, &quot;rails&quot; =&gt; 2, &quot;jsp&quot; =&gt; 3}
sorted = projects.keys.sort[0..3]
</pre>
<p>I&#8217;ve found that Ruby&#8217;s method chaining syntax makes more sense to new programmers than the more mathematical &#8220;bolted-on&#8221; syntax.</p>
<h3>Blocks</h3>
<p>Ruby has a neat construct that you use all over the place to create anonymous functions (a technical term for creating specific functionality without defining a new function to define the action). Let&#8217;s take a function to sort an array of projects. First, in PHP:</p>
<pre class="brush: php; title: ; notranslate">

function sort_projects_by_count($a, $b)
{
    if($a -&gt; counts == $b -&gt; counts)
    {
        return 0;
    }
    return($a -&gt; counts &gt; $b -&gt; counts) ? +1 : -1;
}

usort($projects, &quot;sort_projects_by_count&quot;);
</pre>
<p>And the same thing in Ruby:</p>
<pre class="brush: ruby; title: ; notranslate">
projects.sort do |a, b|
    a.counts &lt;=&gt; b.counts
end
</pre>
<p>Ok, so this is a bit of an unfair comparison, but here is an analogous version of the Ruby code in PHP:</p>
<pre class="brush: php; title: ; notranslate">
usort($projects, create_function($a, $b, 'if($a-&gt;counts == $b-&gt;counts){
    return 0;}return ($a-&gt;counts &gt; $b-&gt;counts ? +1 : -1));
</pre>
<p>No matter how you slice it, Ruby syntax just feels more human. Even if you don&#8217;t know exactly what&#8217;s going on, looking up one operator in the Ruby syntax as opposed to following the logic flow and determining what &#8220;? +1 : -1&#8243; means (it&#8217;s shorthand for an if-then statement) makes the act of reading code much easier.</p>
<h2>Monkeypatching</h2>
<p>If you&#8217;re not familiar with the term, &#8220;monkeypatching&#8221; is what programmers call changing or extending a base class (like an array or string object) to add functionality or change the way it works. Let&#8217;s say you really need to be able to test a string to see if it looks like an integer, you could create a monkeypatch along these lines:</p>
<pre class="brush: ruby; title: ; notranslate">
class String
    def is_int?
        self =~ /^[-+]?[0-9]*$/
    end
end
</pre>
<p>This code snip extends the String class and uses a <a href="http://en.wikipedia.org/wiki/Regular_expression">Regular Expression</a> (regex) to test if a given String is an integer (number) by simply calling &#8220;is_int?&#8221; (notice the question mark at the end of the definition; this is used for methods that return a Boolean value). That&#8217;s a little advanced, but it does show off a very useful piece of functionality of the language that allows you to do a better job dealing with a <a href="http://en.wikipedia.org/wiki/Duck_typing">duck-typed language</a>.</p>
<h2>Frameworks</h2>
<p>Many people when talking about Ruby associate its use in web development with the Rails <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC framework</a>. Just as PHP has <a href="http://framework.zend.com/">Zend</a>, <a href="http://codeigniter.com/">CodeIgniter</a>, <a href="http://cakephp.org/">CakePHP</a>, <a href="http://www.symfony-project.org/">symfony</a>, etc., Ruby has <a href="http://rubyonrails.org/">Rails</a>, <a href="http://www.merbivore.com/">Merb</a>, <a href="http://www.sinatrarb.com/">Sinatra</a>, <a href="http://camping.rubyforge.org/">Camping</a>, and many more. Rails is the 900-pound gorilla of Ruby frameworks, and has a lot of nice features to get new applications off the ground quickly and some really great online guides to setting things up (I frequent <a href="http://guides.rubyonrails.org/">RailsGuides</a>). Since we often suggest Rails to our collaborators I&#8217;ll focus on this framework, but there are several other frameworks out there to choose from.</p>
<p>Think of Ruby (or PHP for that matter) as a pile of building materials: you can to build anything you want if you know how to put everything together. Rails, on the other hand, is like a prefab house where workers pour a foundation, set the house up, and then leave you to add the drywall, siding, windows, and roof. If you need a new component for your prefab house, a sales representative is standing by to help immediately ship you what you need.</p>
<h3>Generators</h3>
<p>To extend the previous metaphor, generators are like sales representatives that allow you to place orders for new aspects of your site.  To create all the erb templates (the default templeting language for Rails), controller methods, model, database migrations, routes, and tests for a new project with a single line, you might run something like the following:</p>
<pre class="brush: ruby; title: ; notranslate">
script/generate scaffold topic title:string description:text
</pre>
<p>I moved away from using scaffolding pretty quickly, but it does provide a nice starting point for new programmers to build interactions with data models.</p>
<h3>Templates</h3>
<p>The default templating engine in Rails is <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/">erb</a> which provides a convenient method for generating views of  your models. One of erb&#8217;s most important features is the use of &#8220;partials,&#8221; pieces of code that are used in multiple views by calling the render method. I often replicated this behavior in PHP by calling an include somewhere in a view.</p>
<h3>ActiveRecord</h3>
<p>The key to database interactions in Rails is ActiveRecord. As an SQL expert, I have to admit this part of the Rails framework drove me a bit batty at first, but then again I&#8217;ve been writing SQL for over 10 years (my colleagues often roll their eyes when I start writing it with relational algebra nomenclature), so allowing a framework to abstract this particular piece took some getting used to. If you&#8217;re new to programming, though, this means you don&#8217;t have to learn SQL but instead can use Ruby-style syntax to interact with your database without necessarily needing to care what your <a href="http://en.wikipedia.org/wiki/Relational_database_management_system">RDBMS</a> back-end happens to be.</p>
<p>Take this example of looking up a book review where you have both a &#8220;book&#8221; and &#8220;review&#8221; table. In PHP you would do something like this (this snip will only work with a MySQL connection but has some sub-selection stuff going on):</p>
<pre class="brush: php; title: ; notranslate">
function query($sql)
{
    global $conn;
    return mysql_query($sql, $conn);
}

function recent_reviews($count)
{
    $query = query(sprintf('SELECT b.book_title, r.review_id, r.created_at, r.id, review_counter.review_total
        FROM reviews r, books b,
            (SELECT count(*) AS review_total FROM reviews) AS review_counter
        WHERE r.book_id = b.book_id
        ORDER BY created_at DESC
        LIMIT %d', $count);

    return $query
}

print_r(recent_reviews(5));
</pre>
<p>Now, for the ActiveRecord equivalent:</p>
<pre class="brush: ruby; title: ; notranslate">
reviews = Review.find(:limit =&gt; 5, <img src='http://www.scholarslab.org/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> rder =&gt; &quot;created_at DESC&quot;);
puts reviews.inspect
</pre>
<p>Because of the way in which ActiveRecord sets up its model associations, you&#8217;ll have access to the different name scopes to print out the same information, just in far less code. However, if you really want to, you can pass your SQL to get more granular control over the syntax:</p>
<pre class="brush: ruby; title: ; notranslate">
reviews = Review.find_by_sql(&quot;SELECT b.book_title, r.review_id, r.created_at, r.id, review_counter.review_total
        FROM reviews r, books b,
            (SELECT count(*) AS review_total FROM reviews) AS review_counter
        WHERE r.book_id = b.book_id
        ORDER BY created_at DESC
        LIMIT ?&quot;, count);
</pre>
<p>One of the real beauties of the ActiveRecord methods is that as long as you&#8217;re using the generic ActiveRecord syntax, your data persistence layer can be pretty much any RDBMS and be changed with a couple lines in the configuration file. The trade-off however, is that you lose a few things and can make slightly more work for yourself than you might anticipate. One important caveat is that ActiveRecord doesn&#8217;t create foreign keys when you set up reference fields. This is actually by design as it&#8217;s using an object-oriented idiom (an object should validate the presence of another, without the underlying persistence layer enforcing any type of constraint), but I find myself adding these in to ensure that the RDBMS takes advantage of the pre-calculated indexes to improve overall performance.</p>
<p>I should also mention that I think the ActiveRecord model has some real limitations. As you develop your models, you will most like be tweaking its fields, which in turn requires new migrations, and you may forget which fields are actually in your models. There are plugins that help with this, but you do need to take additional steps to have this information placed somewhere convenient (I use a pre-commit git hook that calls the <a href="http://github.com/ctran/annotate_models">annotate gem</a> to dynamically annotate my model schemas).</p>
<h3>Security</h3>
<p>You&#8217;ll notice in the last examples I was doing some funny stuff in both the PHP and Ruby examples to protect against <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection attacks</a>. If you&#8217;re using the ActiveRecord methods of addressing objects, Rails will take care of this for you. If you&#8217;re using PHP, you&#8217;ll either need to do this yourself (sprintf is commonly used) or rely on a framework to parametrize your statements (you don&#8217;t want someone deleting everything in your database).</p>
<p>You also need to protect yourself from <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site Scripting Attacks</a> (XSS) by escaping HTML from fields with dynamic content. erb has a helper function html_escape (h is the shorthand) which escapes this data. In Rails 3, this will change slightly and erb will automatically html_escape model output unless you explicitly tell it not to escape the field. One less thing to remember!</p>
<h3>Testing</h3>
<p>Testing is important, and I try to preach its virtues every chance I get. After finishing a project, the typical programmer won&#8217;t touch the code again until the application breaks. Good testing will save you (or the person that inherits the code) a lot of time discovering exactly what broke the application.</p>
<p>Let&#8217;s face it: testing is a pain in PHP, and I rarely see it done well. What I&#8217;ve really enjoyed about Ruby development is the fact that no matter how you code there is an appropriate testing framework available (I use <a href="http://rspec.info/">rspec</a>). There&#8217;s a strong emphasis on not only unit testing, but also integration and acceptance testing. There are also libraries that give you an idea of how well your <a href="http://github.com/relevance/rcov">code is tested</a>, something I sorely missed from my Java coding endeavors. One other huge plus is that every gem on the <a href="http://www.rubygems.org">rubygems.org</a> site includes test-coverage metrics to give you an idea of how well the code you want to install is tested.</p>
<p>PHP also has testing frameworks with <a href="http://www.phpunit.de/">PHPUnit</a> and <a href="http://code.google.com/p/phpspec/">PHPSpec</a> being rather popular. I won&#8217;t say too much about the PHP testing frameworks other than to say that there are analogous frameworks for writing and running tests in PHP and Ruby. However, I&#8217;ve noticed a slightly more concerted effort to think through the inclusion of the tools in Ruby and their integration into the coding workflow than I&#8217;ve experienced with PHP. With the latter language, I&#8217;ve often fell in to the trap of writing the code, getting it to where I want it, and then, really as an afterthought, writing basic unit tests to get rather skimpy code coverage.</p>
<p>As a case in point, a mantra in Rails development is <a href="http://rubyhoedown2008.confreaks.com/05-bryan-liles-lightning-talk-tatft-test-all-the-f-in-time.html">TATFT</a>.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="400" height="302" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=1534976&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /><embed type="application/x-shockwave-flash" width="400" height="302" src="http://vimeo.com/moogaloop.swf?clip_id=1534976&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><a href="http://vimeo.com/1534976">BryanL on TATFT</a> from <a href="http://vimeo.com/bryanl">Bryan Liles</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<h2>Deployment</h2>
<p>Two typical objections raised when contemplating Ruby development are that &#8220;Ruby doesn&#8217;t scale&#8221; and that server setup is a real pain. These are valid concerns, but as with many open source projects with a large number of fanatical supporters, the Ruby community has steadily made improvements in these areas. Actually, for the vast majority of our readership, these issues can be filed away in the solved category.</p>
<h3>Scaling</h3>
<p>I&#8217;ve always found objections to scaling a bit troubling. Scaling is one of those over-used terms that means different things to different people, but most of the &#8220;Rails doesn&#8217;t scale&#8221; comes from Twitter&#8217;s experience with the framework. They found, as they scaled horizontally (adding more servers) to handle loads of 11,000+ requests per second, that a bottleneck existed at the data persistence level as Rails doesn&#8217;t, by default, provide a mechanism to to address multiple databases. Twitter has since moved parts of their code base to <a href="http://www.scala-lang.org/">Scala</a> but has retained the majority of their code in Rails and has developed some rather ingenious messaging capabilities to talk to the appropriate abstraction layers that one needs in very large enterprise applications.</p>
<p>While Twitter shows that Rails is capable of scaling (with lots of work), quite honestly the likelihood of any of our applications needing this level of engineering is slim. I will say, however, that there are relatively simple methods of scaling with your infrastructure should you start running into performance issues. We have, for example, an application written in pure Ruby on Rails deployed as a Tomcat application (the details of which are completely outside the scope of this article, but the application gets all the benefits of an Enterprise class Java environment with the ease of Rails development).</p>
<h2>Server Support</h2>
<p>The Ruby language is included in most (if not all) modern Linux package systems and makes installation a snap. The other &#8220;major&#8221; piece of software you&#8217;ll need is RubyGems (a package manager for Ruby libraries), which is also generally available as a managed package.</p>
<blockquote><p><strong>Note</strong>: There is a major change occurring with the development of Rails 3. Rails is moving from a system of system-wide gems to application-level gems with the introduction of <a href="http://gembundler.com/">GemBundler</a>. This approach is a more stable method of deploying application requirements which not only allows you to ensure that application libraries are properly resolved, but also provide better granular control over which libraries are deployed in specific contexts.</p></blockquote>
<p>There was a time where deploying Rails applications was a real bear. Then along came <a href="http://www.modrails.com/">Phusion Passenger</a> (aka mod_rails). This allows you to run Rails (actually any Rack-based application) through Apache and Nginx without any other port management, service process monitoring, file cleanup, etc. As long as Apache is running, so is your Rails app!</p>
<h2>Community of Support</h2>
<p>The Rails community is pretty great in getting folks off the ground. As with any technology there are a fair number of curmudgeons, but leaders in the community as quick to remind people to be nice (see Yahuda Katz&#8217;s <a href="http://yehudakatz.com/2010/02/09/the-blind-men-and-the-elephant-a-story-of-noobs/">The Blind Men and the Elephant: A Story of Noobs</a>). There are several corporations backing Rails development (<a href="http://www.engineyard.com">EngineYard</a> is a big one) and when the Google Summer of Code for Rails program wasn&#8217;t continued, the Rails community was able to raise $100,000 in three days to support a <a href="http://rubysoc.org/">Ruby Summer of Code</a>.</p>
<p>There are a number of really good podcasts (<a href="http://ruby5.envylabs.com/">Ruby5</a> and <a href="http://5by5.tv/rubyshow">The Ruby Show</a> are good), vodcasts (<a href="http://railscasts.com/">Railscasts</a>), tutorial sites (<a href="http://asciicasts.com/">ACSIIcasts</a>), blogs (<a href="http://www.railsdispatch.com/">RailsDispatch</a>, <a href="http://thoughtbot.com/">ThoughtBot</a>, <a href="http://www.engineyard.com/blog/">EngineYard</a>), open source projects (lots on <a href="http://www.github.com">github</a>), open source books (<a href="http://www.railstutorial.org/book">Rails Tutorials</a>), and some really good reference books from <a href="http://pragprog.com/">The Pragmatic Programmers</a>. There&#8217;s even some humor&#8230;</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="480" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/p5EIrSM8dCA&amp;hl=en_US&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="480" height="385" src="http://www.youtube.com/v/p5EIrSM8dCA&amp;hl=en_US&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<h2>Summary</h2>
<p>As much as it drives language purists crazy when I say it, there&#8217;s nothing that you can do in Ruby that you can&#8217;t replicate in PHP (and vice-versa). In my experience, getting people set up with a functioning web application is far easier with Ruby than it is with PHP (and less prone to <a href="http://en.wikipedia.org/wiki/Spaghetti_code">spaghetti code</a>), and the deployment options make Ruby (plus a framework) a great starting point for new programmers to get their feet wet with web application development (check out <a href="http://www.heroku.com">Heroku</a>). If you&#8217;re an experienced developer, does it make sense to drop PHP and rewrite your code base? Absolutely not. However, at some point, you will be faced with the prospect of needing to migrate a legacy application where Ruby may make a lot of sense. As someone who has spent quite a bit of time de-tangling spaghetti code from Perl CGI and mixed HTML and PHP pages, I&#8217;m hoping that the people that will eventually be migrating my Ruby code will not need to perform the level of coding archaeology we&#8217;ve needed to perform.</p>
<p>Like most things in life, choosing the correct tool for the job needs some careful consideration and planning. Ruby makes a lot of sense for getting applications off the ground quickly and reinforcing good practices like testing, code separation, and readability that I find important in forming new digital humanities programmers. Web development over the last decade has become exceptionally complex (AJAX, web services, web standards, multiple browsers, etc.) and the real hope is that by using Ruby and Rails as an approach, people will be inspired to continue down a development path to both enrich their own scholarship and impact the larger digital humanities community without becoming frustrated by syntax. This is a bit of an experiment which we and other digital humanities shops are undertaking, and in which we&#8217;re inviting everyone to participate.  No matter the language, we should all be engaged in teaching best practices in project design and management, in software development techniques, in the construction of usable and elegant interfaces, and in the application of these things to humanities scholarship, through which everyone wins!</p>
<h2>Other Resources</h2>
<ul>
<li><a href="http://railsforphp.com/">Rails for PHP Developers</a></li>
<li><a href="http://www.oreillynet.com/ruby/blog/2007/09/7_reasons_i_switched_back_to_p_1.html">7 Reason I switched back to PHP after 2 years on Rails</a></li>
<li><a href="http://guides.rubyonrails.org/">RubyGuides</a></li>
<li><a href="http://www.jruby.org/">JRuby</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/why-ruby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automating Omeka Deployment with Capistrano</title>
		<link>http://www.scholarslab.org/slab-code/automating-omeka-deployment-with-capistrano/</link>
		<comments>http://www.scholarslab.org/slab-code/automating-omeka-deployment-with-capistrano/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 23:53:25 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[omeka]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=660</guid>
		<description><![CDATA[If you&#8217;ve done much web development, you&#8217;ll know that deploying applications can be a real pain. Typically you get some code (like Omeka), FTP it to your server, run the install, then go grab some plugins and themes and FTP them to your server. If you&#8217;re a bit more sophisticated, you may have put this&#8230;. <a href="http://www.scholarslab.org/slab-code/automating-omeka-deployment-with-capistrano/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;ve done much web development, you&#8217;ll know that deploying applications can be a real pain. Typically you get some code (like Omeka), FTP it to your server, run the install, then go grab some plugins and themes and FTP them to your server. If you&#8217;re a bit more sophisticated, you may have put this in to an source code management (SCM) system like <a href="http://git-scm.com/">git</a>, <a href="http://mercurial.selenic.com/">mercurial</a>, or <a href="http://subversion.apache.org/">subversion</a>, which then changes your workflow to editing on your local machine, committing the changes to your SCM, logging on to the command line interface for your server, running an update on the code, praying nothing breaks; if it does, you then try to roll back to a working version (you remembered to run svn info on the code before updating so you know what number to go back to). Even if everything goes swimmingly, that&#8217;s a lot of steps and way more applications than I like to fool with, and since it&#8217;s essentially doing the same thing over and over again, wouldn&#8217;t it be nice to automate this process?   <span id="more-660"></span></p>
<p>Enter <a href="http://www.capify.org/index.php/Capistrano">Capistrano</a>&#8230;If you&#8217;ve not used this before, essentially this automates the deployment of web applications to your server environment.  It&#8217;s written in Ruby, but allows you to deploy ANY type of web application (we use it for Cocoon, Rails, Java, and PHP applications in the Scholars&#8217; Lab). If you&#8217;ve got a larger shop, you may also take a look at a web interface called <a href="http://labs.peritor.com/webistrano">Webistrano</a> which allows non-programmer types to deploy software through a web interface.</p>
<p>To show off the power of this software, I thought I&#8217;d write up how we use capistrano to deploy Omeka in various environments. The setup can be a little complex, but there are some good tutorials for getting started (see <a href="http://net.tutsplus.com/tutorials/ruby/setting-up-a-rails-server-and-deploying-with-capistrano-on-fedora-from-scratch/">Setting up a Rails Server and Deploying with Capistrano on Fedora from Scratch</a> and the <a href="http://www.capify.org/index.php/Getting_Started">Capistrano Getting Started</a>). The following code snips assume you have successfully installed capistrano and use Subversion as your SCM (if you need SVN hosting, you can start a new project on <a href="http://code.google.com/hosting/createProject">Google Code</a>; you can also use <a href="https://github.com/">Github</a> if you declare the git scm in the code).</p>
<p>The first step in getting your Omeka project automated for capistrano is ensuring both the capistrano and railsless-deploy gems are installed (if you&#8217;re not a ruby-ist, <a href="http://docs.rubygems.org/read/book/1">gem</a> is a package manager for Ruby applications and libraries):</p>
<pre class="brush: bash; title: ; notranslate">
sudo gem install capistrano railsless-deploy
</pre>
<p>Capistrano installs a new command on your system called &#8220;capify&#8221; which sets up the boilerplate for capistrano. Just execute the capify script in your project directory:</p>
<pre class="brush: bash; title: ; notranslate">
cd /path/to/project/trunk
capify .
</pre>
<p>This will create two files, Capfile in your root directory and a config/deploy.rb. You&#8217;ll need to edit the Capfile ever so slightly to add the requirement for the railsless-deploy gem. It should read as follows:</p>
<pre class="brush: ruby; title: ; notranslate">
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
# Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }

require 'rubygems'
require 'railsless-deploy'
load    'config/deploy'
</pre>
<p>Now we just need to do some setup in the config/deploy.rb file to tell capistrano about Omeka. This is where you need to know a little about how your server is set up and you may need to slightly change your server set up in order to use capistrano. The way capistrano works is that it creates a releases directory on your path that holds &#8220;deployments&#8221; of you project. The latest version of the project is then symlinked the project directory into the releases. This allows you to very quickly undo a deployment that goes awry.</p>
<p>As an example, we deploy projects to /usr/local/projects, so our omeka project would get deployed to /usr/local/projects/omeka. Capistano will create a few directories in /usr/local/projects/omeka:</p>
<ul>
<li><strong>releases</strong> (timestamped directories of your application)</li>
<li><strong>shared</strong> (for log files, SCM cache, files you don&#8217;t want to be overwritten)</li>
<li><strong>current</strong> (symlink to latest directory in the releases directory)</li>
</ul>
<p>If you&#8217;re setting up Omeka, you will need to redirect the base Directory to the &#8220;current&#8221; symlink. Here&#8217;s the vhost entry we use for Omeka as an example (this is an Ubuntu server; you may need to change the log file path if you are deploying to another operating system).</p>
<pre class="brush: bash; title: ; notranslate">
&lt;VirtualHost *:80&gt;
ServerName your.server.org
DocumentRoot /usr/local/projects/omeka/current/
&lt;Directory &quot;/usr/local/projects/omeka/current&quot;&gt;
Options FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
&lt;/Directory&gt;

ErrorLog /var/log/apache2/omeka_error.log
TransferLog /var/log/apache2/omeka_access.log
&lt;/VirtualHost&gt;
</pre>
<p>Now, to edit the config/deploy.rb file to set things up for automated deployments.</p>
<pre class="brush: ruby; title: ; notranslate">
# You must always specify the application and repository for every recipe. The
# repository must be the URL of the repository you want this recipe to
# correspond to. The deploy_to path must be the path on each machine that will
# form the root of the application path.

set :application, 'omeka'
set :repository, 'http://your.svn.path/repo/trunk'

set :deploy_to, &quot;/usr/local/projects/#{application}&quot;
set :deploy_via, :remote_cache
set :user, 'deployer'
set :runner, user
set :run_method, :run

default_run_options[:pty] = true

ssh_options[:username] = user
ssh_options[:host_key] = 'ssh-dss'
ssh_options[:paranoid] = false

role :app, 'www.coolomekaapp.org'
role :web, 'www.coolomekaapp.org'
role :db, 'www.coolomekaapp.org'

# ===============
# Custom Tasks
# ===============
namespace :deploy do
desc 'Make sure the archives directory has the proper permissions'
task :chmod_archive_dir, :except=&gt;{:no_release =&gt; true} do

run &quot;chmod g+rw #{current_path}/archives&quot;
end
desc 'Sets up the intitial db.ini config'
task :upload_database_config, :except=&gt;{:no_release =&gt; true} do
db_config = &lt;&lt;-INI
[database]
host     = &quot;your.db.host&quot;
username = &quot;db_user&quot;
password = &quot;db_password&quot;
name     = &quot;db_name&quot;
prefix   = &quot;omeka_&quot;
;port     = &quot;&quot;
INI

put db_config, &quot;#{current_path}/db.ini&quot;

end

desc 'Move archives directory so it doesn\'t get overwritten during deployments'
 task :move_archive_dir, :except=&gt;{:no_release =&gt; true} do
 run &quot;mv #{current_path}/archives #{shared_path}&quot;
 end

 desc 'Just svn up the directory'
 task :svn_up, :except =&gt; {:no_release =&gt; true} do
 run &quot;svn up #{current_path}&quot;
 end

 desc 'Link archives folder to shared directory'
 task :link_archives_dir, :except=&gt;{:no_release =&gt; true} do
 run &quot;cd #{current_path} &amp;&amp; ln -snf #{shared_path}/archives archives&quot;
 end

end

# ======================
# Task Event Hooks
# ======================

after 'deploy:symlink', 'deploy:upload_database_config', 'deploy:link_archives_dir'
after 'deploy:cold', 'deploy:chmod_archives_dir', 'deploy:move_archives_dir'
after 'deploy', 'deploy:cleanup'
</pre>
<p>Ok, there&#8217;s a lot going on here. I&#8217;ll briefly explain what&#8217;s going on, but there should be enough here for you to start hacking. But let&#8217;s see what tasks capistrano know about and you can call. If you are still in your project directory, just type cap -T to list all the capistrano tasks. Your output should look similar to this:</p>
<pre class="brush: bash; title: ; notranslate">
cap deploy                        # Deploys your project.
cap deploy:check                  # Test deployment dependencies.
cap deploy:chmod_archive_dir      # Make sure the archives directory has the ...
cap deploy:cleanup                # Clean up old releases.
cap deploy:cold                   # Deploys and starts a `cold' application.
cap deploy:migrate                # Run the migrate rake task.
cap deploy:migrations             # Deploy and run pending migrations.
cap deploy:pending                # Displays the commits since your last deploy.
cap deploy:pending:diff           # Displays the `diff' since your last deploy.
cap deploy:restart                # Restarts your application.
cap deploy:rollback               # Rolls back to a previous version and rest...
cap deploy:rollback:code          # Rolls back to the previously deployed ver...
cap deploy:setup                  # Prepares one or more servers for deployment.
cap deploy:start                  # Start the application servers.
cap deploy:stop                   # Stop the application servers.
cap deploy:symlink                # Updates the symlink to the most recently ...
cap deploy:update                 # Copies your project and updates the symlink.
cap deploy:update_code            # Copies your project to the remote servers.
cap deploy:upload                 # Copy files to the currently deployed vers...
cap deploy:upload_database_config # Sets up the intitial db.ini config
cap deploy:web:disable            # Present a maintenance page to visitors.
cap deploy:web:enable             # Makes the application web-accessible again.
cap invoke                        # Invoke a single command on the remote ser...
cap log:tail_log                  # Tail the rails log file
cap shell                         # Begin an interactive Capistrano session.

Some tasks were not listed, either because they have no description,
or because they are only used internally by other tasks. To see all
tasks, type `cap -vT'.

Extended help may be available for these tasks.
Type `cap -e taskname' to view it.
</pre>
<p>To use a specific capistrano task, you just type the command listed. But let&#8217;s get back to the actual script and go over that briefly. Part of the installation process of Omeka requires you to reset the permissions of the archives directory. This is handled by the chmod_archive_dir. However, because of the way that capistrano deploys applications, the archives folder would get overwritten in every deployment. To get around this, we move the archives directory to the shared folder, then create a symlink from the current directory to the shared/archives directory.</p>
<p>There&#8217;s a task to upload_database_config that you can have in your cap script (we deploy out of private repos), but if you&#8217;re deploying out of a public repo, you may want to just put the db.ini file on the server in the shared directory and symlink it into the current_path. Lastly, there are times where you just need to do an &#8220;svn up&#8221; (or git pull) to update something small and not need to do a full deployment. This is where the cap deploy:svn_up helps out&#8230;.guess what it does <img src='http://www.scholarslab.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Capistrano also provides task even hooks to execute specific tasks after specific events. In this script, when you do a cold deployment (when you are setting things up for the first time), the script will change the permissions on the archives directory, then move the archives directory to the shared directory. When you do a normal deploy (after the directory has gotten a proper symlink), the script will upload the database config, then symlink the archives directory and run a cleanup (keep the last 5 versions you deployed).</p>
<p>While there&#8217;s still a bit of up-front set up to do on your server, capistrano significantly speeds up your ability to to consistently deploy software, quickly roll-back if (that changes to &#8220;when&#8221;, if you write code long enough) problems occur, and reinforces a development process that involves SCM!</p>
<h2>Resources</h2>
<ul>
<li><a href="http://www.capify.org/index.php/Capistrano">Capistrano</a></li>
<li><a href="http://www.jonmaddox.com/2006/08/16/automated-php-deployment-with-capistrano/">Automated PHP Deployment with Capistrano</a></li>
<li><a href="http://github.com/leehambley/railsless-deploy">Railsless-deploy</a></li>
<li><a href="http://www.capify.org/index.php/Tutorials">Capistrano Tutorials</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/automating-omeka-deployment-with-capistrano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Omeka Timeline Plugin</title>
		<link>http://www.scholarslab.org/slab-code/omeka-timeline-plugin/</link>
		<comments>http://www.scholarslab.org/slab-code/omeka-timeline-plugin/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 19:19:44 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[omeka]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[timeline]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=605</guid>
		<description><![CDATA[As part of our ongoing efforts on our Neatline grant, we needed to include a way of displaying temporal information and interacting with other data stored in Omeka. Just about the time we were starting to write this code, CHNM announced their Plugin Rush which pays an honorarium to give folks some incentive to pitch in and develop a plugin or two. Since we were going to develop the plugin anyway, we're donating this back to the Omeka project, but we thought this might be a good opportunity to talk a little more about the development cycle for Omeka plugins, and hopefully inspire others to get involved.]]></description>
			<content:encoded><![CDATA[<p>As part of our ongoing efforts on our <a href="http://www.neatline.org">Neatline</a> grant, we needed to include a way of displaying temporal information and interacting with other data stored in Omeka. Just about the time we were starting to write this code, CHNM announced their <a href="http://omeka.org/blog/2010/02/18/plugin-rush-2010/">Plugin Rush</a> which pays an honorarium to give folks some incentive to pitch in and develop a plugin or two. Since we were going to develop the plugin anyway, we&#8217;re donating this back to the Omeka project, but we thought this might be a good opportunity to talk a little more about the development cycle for Omeka plugins, and hopefully inspire others to get involved.  <span id="more-605"></span></p>
<p>The specifications for the <a href="http://omeka.org/c/index.php/Plugin_Rush_2010#Timeline_.281.1-1.0.29">Timeline plugin</a> are wonderfully documented and explained on the Omeka wiki. This actually illustrates a great practice that is all too often ignored&#8230;explicitly stating what some software should do. Taking the time to think through the &#8220;what&#8221; a piece of software should do will save  you time in the long run as it forces you to think about how everything fits together, alleviating ambiguity and allowing you to focus on the task at hand.</p>
<p>For this specification, there were two requirements:</p>
<ul>
<li>The plugin should create a helper function for creating a <a href="http://www.simile-widgets.org/timeline/">SIMILE  Timeline</a> widget from an array of items.  The helper function should allow you to  specify which metadata elements the time data should come from, as well  as the element that specifies the caption (by default, the Dublin Core  Title element).</li>
<li> The timeline should allow for time intervals (start and end dates) and points in  time (singe date).</li>
</ul>
<p>While there are two requirements, it&#8217;s a good idea to break this us a little more into individual (atomic) tasks. First, we need to take a look at the <a href="http://code.google.com/p/simile-widgets/wiki/Timeline">SIMILE Timeline Widget documentation</a>. Taking a quick look at their <a href="http://code.google.com/p/simile-widgets/wiki/Timeline_GettingStarted">Getting Started</a> guide, this seems pretty straight forward</p>
<ol>
<li> <a href="http://code.google.com/p/simile-widgets/wiki/Timeline_GettingStarted#Step_1._Link_to_the_API">Include the Timeline javascript</a></li>
<li>Create a div container in the HTML view (e.g. &lt;div id=&#8221;timeline&#8221;&gt;&lt;/div&gt;</li>
<li>Format the items from Omeka as <a href="http://code.google.com/p/simile-widgets/wiki/Timeline_GettingStarted#Step_5._Add_Events">Timeline Events</a></li>
<li>Add the Timeline.create() call to the Omeka HTML view</li>
</ol>
<p>The specification states that this needs to be a helper function. If you&#8217;re not familiar with this term, a helper function is a block of code that does some of the computation for another piece of code. In many frameworks, helper functions aren&#8217;t actual objects, but pieces of procedural code that can be accessed from across the application that help add functionality that isn&#8217;t exactly proper to place in a model or controller; essentially these are statically accessible functions (in coding terms) that can be called from properly instantiated objects (in this case a view).</p>
<p>Now that we have good idea of what the code should do, let&#8217;s turn to some actual code. Omeka uses the <a href="http://framework.zend.com/">Zend Framework</a> to keep from doing a lot of repetitive programming, so most of the syntax of what we need to do is driven by how Zend handles PHP. On top of the Zend Framework, Omeka implements its own plugin infrastructure, so there are a few things we need to take in to account in our design.</p>
<p>The Zend Framework is a <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">model-view-controller (MVC) framework</a> designed to organize code for maintainability and DRY-ness (<a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself">Don&#8217;t Repeat Yourself</a>). One the the hallmarks of most MVC applications is its physical separation of files and functionalities. In the case of Omeka plugins, the hierarchy is generally split into model, view, controller, and tests directory. For the Timeline plugin, since we are developing a helper function, we use a slightly modified directory structure:</p>
<pre class="brush: bash; title: ; notranslate">
Timeline
|__helpers
|__tests
|__views
</pre>
<p>We also need some mechanism to tell Omeka about a plugin. This metadata is currently provided in a file called plugin.ini. This file is pretty straight forward, but  let&#8217;s go over it briefly:</p>
<pre class="brush: php; title: ; notranslate">

[info]
name=&quot;Timeline&quot;
author=&quot;Scholars' Lab&quot;
description=&quot;SIMILE Timeline for Omeka&quot;
link=&quot;http://omeka.org/codex/Plugins/Timeline&quot;
omeka_minimum_version=&quot;1.0&quot;
omeka_tested_up_to=&quot;1.2&quot;
version=&quot;1.1&quot;
tags=&quot;Timeline, simile, chronology, time, temporal&quot;
</pre>
<p>This file is what the Omeka admin interface uses to display information about your plugin. Two things that may not be initially obvious are the<strong> omeka_minimimum_version</strong> and <strong>omeka_tested_up_to</strong> lines. One fact you&#8217;ll learn about software development, especially with API development, is as projects mature, the needs of the API grow along with them. You want to be able to mitigate potential issues should the plugin API change by explicitly setting the minimum revision number that your plugin is tested against (you can get older revisions from the SVN tags repo at <a href="https://omeka.org/svn/tags/">https://omeka.org/svn/tags/</a>).</p>
<blockquote><p><strong>Note:</strong> you can run multiple versions of Omeka on your machine for testing by checking out separate versions of the software in you web tree. For instance, you can have <strong>localhost/omeka1.0</strong>, <strong>localhost/omeka1.1</strong>, <strong>localhost/omeka_trunk</strong>. Setting this up is beyond the scope of this post (be sure to set up separate databases), but if you have questions, leave a comment.</p></blockquote>
<p>The next thing we need to do is tell Omeka what to do with our plugin. The top-level plugin.php file contains instructions (<a href="http://omeka.org/codex/Plugin_API/Hooks">hooks</a>) to tell the Admin interface what to do when a user installs or uninstalls the plugin. This is where we let Omeka know that items tagged with &#8220;Timeline&#8221; should use the Timeline Plugin, to set up some logging to help us debug when something goes wrong, and some default <a href="http://omeka.org/codex/Plugin_API/Hook/define_routes">routes</a> to help make &#8220;pretty&#8221; URLs.</p>
<p>Now, with all the preliminary setup taken care of, now we can start developing the helper function. First, let&#8217;s examine the Controller which tells Omeka what to do when an action is requested by the framework. This is actually a fairly straight forward:</p>
<pre class="brush: php; title: ; notranslate">

&lt;?php
class Timeline_TimelinesController extends Omeka_Controller_Action

{
	private $logger;

	public function init()
	{
		$this-&gt;_modelClass = 'Item';
		$writer = new Zend_Log_Writer_Stream(LOGS_DIR . DIRECTORY_SEPARATOR . &quot;timeline.log&quot;);
		$this-&gt;logger = new Zend_Log($writer);
	}

	public function showAction()
	{
		$this-&gt;view-&gt;item = $this-&gt;findById();
	}

}
</pre>
<p>Let&#8217;s go over briefly what&#8217;s going on here. There are some semantics in the way in which these Controller objects are named which are inherited from the way in which Zend handles Controllers. The <strong>Timeline_TimelinesController</strong> follows the convention of the &#8220;package&#8221; (the plugin) name, underscore, plural controller name (to handle multiple controllers), and finally &#8220;Controller&#8221; (which explicitly tells a programmer what function the Object performs). Because this is a Framework, we also want to be able to inherit a lot of behaviors without needing to code them ourselves, which is handled by the &#8220;extends Omeka_Controller_Action&#8221; (this is the base <a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> class for Omeka which overrides and extends the <a href="http://framework.zend.com/manual/en/zend.controller.action.html">Zend_Controller_Action</a> object). The &#8220;important&#8221; part of the Controller code is really the showAction function which sets a variable named &#8220;item&#8221; in the view which contains a reference to the ID of an Omeka object. The rest just sets up a logger to keep track of what&#8217;s going on.</p>
<blockquote><p><strong>Note</strong>: If you run in to problems with this plugin, it is most likely related to logging. For more on this, see the documentation on <a href="http://omeka.org/codex/Retrieving_error_messages">Retrieving Error Messages</a>.</p></blockquote>
<p>Now we can get into the guts of the actual helper function. When you boil down the code, most of this is JavaScript with some strategically placed PHP. What we did is create a helper function named &#8220;createTimeline&#8221; which actually does the work for us. This takes two required items, a div reference to associate the Timeline on your page, and an array of Omeka Items with which to populate the Timeline.</p>
<pre class="brush: php; title: ; notranslate">
function createTimeline($div, $items = array(), $captionElementSet = &quot;Dublin Core&quot;, $captionElement =  &quot;Title&quot;, $dateElementSet = &quot;Dublin Core&quot;, $dateElement =  &quot;Date&quot; ) {
		echo js(&quot;prototype&quot;);
		global $mets;
		$mets = array($captionElementSet, $captionElement, $dateElementSet, $dateElement);
		?&gt;
		&lt;!--  we have to load the script in this funny way because we need to get the tag into the head of the doc
			because of the the funky way Simile Timeline loads its sub-scripts  --&gt;
		&lt;script type=&quot;text/javascript&quot;&gt;
			scripttag = document.createElement(&quot;script&quot;);
			scripttag.src = &quot;http://static.simile.mit.edu/timeline/api-2.3.0/timeline-api.js?bundle=false&quot;;
			scripttag.type = &quot;text/javascript&quot;;
			$$(&quot;head&quot;)[0].insert(scripttag);

			if (typeof(Omeka) == &quot;undefined&quot;) {
				Omeka = new Object();
			}

			if (!Omeka.Timeline) {
				Omeka.Timeline = new Object();
			}

		&lt;/script&gt;

		&lt;script type=&quot;text/javascript&quot; defer=&quot;defer&quot;&gt;
			Omeka.Timeline.timelinediv = $(&quot;&lt;?php echo $div;?&gt;&quot;);

			Omeka.Timeline.events = [
			&lt;?php
				function event_to_json($item) {
					global $mets;
					return &quot;{ 'title' : '&quot; . getMet($item, $mets[0], $mets[1]) . &quot;',
					'start' : '&quot; . getMet($item, $mets[2], $mets[3]) . &quot;',
					'description' : '&quot; . getMet($item, &quot;Dublin Core&quot;, &quot;Description&quot;) . &quot;',
					'durationEvent':false }&quot;;
				}
				echo implode(',',array_map('event_to_json', $items));
				?&gt;
				];

		&lt;/script&gt;
		&lt;?php
	     echo js(&quot;createTimeline&quot;);
		?&gt;
		&lt;script type=&quot;text/javascript&quot;&gt;
			Event.observe(window, 'load', onLoad);
			Event.observe(document.body, 'resize', onResize);
		&lt;/script&gt;

		&lt;?php
}
</pre>
<p>There&#8217;s a lot going on here, and there is a mix of PHP in the JavaScript. The first thing is making sure the prototype.js library is included, then declaring a variable named &#8220;mets&#8221; in the <a href="http://php.net/manual/en/language.variables.scope.php">global scope</a> (to make it available to other variable scopes). After we&#8217;ve declared $mets, get in to the JavaScript to include on the page and introducing a new JavaScript <a href="http://en.wikipedia.org/wiki/Namespace_%28computer_science%29">Namespace</a> (Omeka.Timeline) which allows you to extend this code in other views.</p>
<p>The second script block actually formats Omeka items that you&#8217;ve called as Timeline Events in the <a href="http://www.json.org/">JSON</a> format calling a helper method we also include in the code:</p>
<pre class="brush: php; title: ; notranslate">
function getMet($item, $elementSet, $element) {
	 $tmp = $item-&gt;getElementTextsByElementNameAndSetName($element, $elementSet);
	 return addslashes( $tmp[0]-&gt;text ) ;
}
</pre>
<p>This function returns the metadata for an Omeka item, which is then used the createTimeline&#8217;s sub-method of event_to_json to properly construct an event for Timeline. After all the JSON strings are created, we &#8220;glue&#8221; all the array elements with a comma with the <a href="http://php.net/manual/en/function.implode.php">implode</a> function.</p>
<p>As you can see, not a lot of code actually needs to be written to add functionality to Omeka. With a little research, and some pointers on syntax, extending Omeka can be done quite quickly and doesn&#8217;t require a degree in computer science. If you&#8217;re interested in getting started on a plugin, I highly recommend the <a href="http://groups.google.com/group/omeka-dev">Omeka dev list</a>; the community is growing and questions are answered quickly (usually by folks on the Omeka development team) and is a great way to learn about the technical issues surrounding developing software using the Omeka platform.</p>
<h2>Resources</h2>
<ul>
<li><a href="http://omeka.org/codex/Plugin_API">Omeka Plugin API</a></li>
<li><a href="http://groups.google.com/group/omeka-dev">Omeka Developer List</a></li>
<li><a href="https://addons.omeka.org/svn/plugins/Timeline/trunk/">Timeline Source Code</a></li>
<li><a href="http://omeka.org/codex/Plugins/Timeline">Timeline Documentation</a></li>
<li><a href="http://framework.zend.com/">Zend Framework</a></li>
<li><a href="http://framework.zend.com/manual/en/">Zend Framework Documentation</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/omeka-timeline-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Large Files and Omeka</title>
		<link>http://www.scholarslab.org/slab-code/large-files-and-omeka/</link>
		<comments>http://www.scholarslab.org/slab-code/large-files-and-omeka/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 19:40:05 +0000</pubDate>
		<dc:creator>Wayne Graham</dc:creator>
				<category><![CDATA[SLab Code]]></category>

		<guid isPermaLink="false">http://www.scholarslab.org/?p=376</guid>
		<description><![CDATA[This issue came up for a friend of the Scholars&#8217; Lab today on Twitter, but it&#8217;s hard to answer in 140 characters. It&#8217;s a question about allowing for larger file sizes in Omeka and there are a few ways to handle this. (Because we want our new blog to be a combination of thoughtful essays&#8230;. <a href="http://www.scholarslab.org/slab-code/large-files-and-omeka/">More.</a>]]></description>
			<content:encoded><![CDATA[<p>This issue came up for a friend of the Scholars&#8217; Lab today on Twitter, but it&#8217;s hard to answer in 140 characters. It&#8217;s a question about allowing for larger file sizes in Omeka and there are a few ways to handle this.  (Because we want our new blog to be a combination of thoughtful essays on digital scholarship and quick answers to real-world technical problems, I thought I&#8217;d post here.)</p>
<p>Since Omeka runs on PHP, this is actually a PHP configuration issue and not something you can currently tweak in Omeka. Basically, you just need to tell PHP to allow larger files sizes that are larger than the default. A very easy way to do this is to edit the .htaccess file that Omeka ships with along the following lines:</p>
<pre class="brush: bash; title: ; notranslate">
php_value upload_max_filesize 20971520
php_value post_max_size 20971520
</pre>
<p>I&#8217;ll note here that doing things this way only affects your Omeka project. Another way to go about this is to add the above to the Apache configuration that defines from where Omeka should be served. For example:</p>
<pre class="brush: bash; title: ; notranslate">

&lt;VirtualHost *:80&gt;

ServerName www.coolomeka.org
DocumentRoot /var/www/omeka

&lt;Directory &quot;/var/www/omeka&quot;&gt;
    Options FollwSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
&lt;/Directory&gt;

    ErrorLog logs/omeka_error_log
    TransferLog logs/omeka_transfer_log

    php_value upload_max_filesize 20M
    php_value post_max_size 20M
&lt;/VirtualHost&gt;
</pre>
<p>Lastly, you can edit the php.ini file (usually in /etc/php.ini or /etc/php5/apache2/php.ini). Just do a search in the file and change the following settings:</p>
<pre class="brush: bash; title: ; notranslate">
  memory_limit = 32M
  post_max_size = 20M
  upload_max_size = 20M
</pre>
<p>You typically don&#8217;t need to reload Apache (as long as you did not edit the Apache configuration file) to get these settings to work.</p>
<p>For more info on this, check out these resources</p>
<ul>
<li><a href="http://php.net/manual/en/ini.core.php">Description of core php.ini directives</a></li>
<li><a href="http://www.radinks.com/upload/config.php">PHP Upload Configuration</a></li>
<li><a href="http://www.developershome.com/wap/wapUpload/wap_upload.asp?page=php2">PHP Directives Related to (Large) File Upload</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.scholarslab.org/slab-code/large-files-and-omeka/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

