<?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>Brent Fitzgerald &#187; ruby</title>
	<atom:link href="http://blog.brentfitzgerald.com/categories/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.brentfitzgerald.com</link>
	<description>Life &#38; Research Notes</description>
	<lastBuildDate>Wed, 03 Jun 2009 15:54:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sketching in VOIP with Tropo</title>
		<link>http://blog.brentfitzgerald.com/2009/03/sketching-in-voip-with-tropo/</link>
		<comments>http://blog.brentfitzgerald.com/2009/03/sketching-in-voip-with-tropo/#comments</comments>
		<pubDate>Thu, 12 Mar 2009 06:29:02 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[future]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://blog.brentfitzgerald.com/?p=730</guid>
		<description><![CDATA[
At eComm Jeevan and I heard some intriguing stuff about a service called Tropo, a cloud-based scriptable VOIP system designed to let web hackers start working in the voice and telephony world.
The app provides a pretty damn slick interface to quickly set up a real phone number (plus SIP plus Skype, all in one place), [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://tropo.com/"><img class="alignnone size-full wp-image-743" style="width: 100%;" title="Tropo" src="http://blog.brentfitzgerald.com/wp-content/uploads/2009/03/picture-5.png" alt="Tropo" /></a></p>
<p>At <a href="http://ecommconf.com/">eComm</a> Jeevan and I heard some intriguing stuff about a service called <a href="http://tropo.com">Tropo</a>, a cloud-based scriptable VOIP system designed to let web hackers start working in the voice and telephony world.</p>
<p>The app provides a pretty damn slick interface to quickly set up a real phone number (plus SIP plus Skype, all in one place), then assign it to a script written in javascript, groovy, python, ruby, or probably whatever other BSF language they support.</p>
<p>Here&#8217;s one I wrote and deployed in about 20 minutes to read off all the <a href="http://monster.tacolab.com/">Miniature Monster</a> descriptions from the RSS feed (Tropo calls highlighted). You can test it out by calling <strong>(650) 273-5382</strong> (or +99000936 9991428654 on Skype, though I haven&#8217;t tried that):</p>
<pre><code>
require 'net/http'
require 'rexml/document'
<span class="highlighted">
answer
wait(3000)
say "hello, welcome to professor engd's miniature monster hotline. here are your monster updates."
wait(1000)</span>

url = "http://feedproxy.google.com/miniaturemonsters"
xml_data = Net::HTTP.get_response(URI.parse(url)).body
xml_doc = REXML::Document.new(xml_data)

xml_doc.elements.to_a( "//description" ).reverse.each do |desc|
  if (m = (/\&lt;div id=\"description\"&gt;\s*\&lt;em\&gt;(.*?)\&lt;\/em\&gt;\&lt;\/div\&gt;/i).match(desc.text))
    <span class="highlighted">say m[1]</span>
    <span class="highlighted">wait(1000)</span>
  end
end

<span class="highlighted">hangup</span>
</code></pre>
<p>I&#8217;ve worked on some projects recently involving <a href="http://www.asterisk.org/">Asterisk</a>-to-web-to-hardware style hacking, typically using something like <a href="http://gizmoproject.com/">Gizmo</a> to register a regular phone number assigned to a SIP number, then <a href="http://www.voip-info.org/wiki/view/Asterisk+settings+Gizmo">setting up asterisk as the SIP softphone</a> and messing around with a <a href="http://www.voip-info.org/wiki/index.php?page=Asterisk+Dialplan+Introduction">retarded dialplan syntax</a> to get things going. Tropo seems to simplify all that&#8230; substantially.</p>
<p>The documentation is solid if a little thin, but it&#8217;s so new, and the app is so slick and well done, so I&#8217;m sure there&#8217;s more coming. It&#8217;s unclear at this point which Ruby libraries and gems they support, if any. And it all feels a little like a toy, but no more than, say, Google App Engine, and for me it&#8217;s actually more potentially useful. What I can say at this point is that it&#8217;s a solid way to sketch your telelphony ideas quickly and with zero setup time, which is very cool. Are you listening <a href="http://itp.nyu.edu/~sve204/redial/">ITP</a>?</p>
<p>Anyway, happy voip hacking.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2009/03/sketching-in-voip-with-tropo/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gentrify</title>
		<link>http://blog.brentfitzgerald.com/2008/10/gentrify/</link>
		<comments>http://blog.brentfitzgerald.com/2008/10/gentrify/#comments</comments>
		<pubDate>Mon, 20 Oct 2008 00:14:03 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[visual]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.brentfitzgerald.com/?p=524</guid>
		<description><![CDATA[
Tired of stepping over homeless people on your way to bikram? Jonesing for a Yacon Root smoothie? Gentrify helps the elite urban bourgeois find their natural habitats.
Gentrify is currently in alpha lite preview stealth mode edition. Created for Rails Rumble &#8216;08 by 734m: Huned Botee, Brent Fitzgerald, Visnu Pitiyanuvath, and Gerad Suyderhoud.
]]></description>
			<content:encoded><![CDATA[<p><a href="http://gentrifire.com/"><img src="http://blog.brentfitzgerald.com/wp-content/uploads/2008/10/gentrify.png" alt="" title="gentrify" width="500" height="334" class="alignnone size-full wp-image-525" /></a></p>
<p>Tired of stepping over homeless people on your way to bikram? Jonesing for a Yacon Root smoothie? <a href="http://gentrifire.com/">Gentrify</a> helps the elite urban bourgeois find their natural habitats.</p>
<p>Gentrify is currently in alpha lite preview stealth mode edition. Created for <a href="http://railsrumble.com/">Rails Rumble &#8216;08</a> by <a href="http://railsrumble.com/teams/734m">734m</a>: <a href="http://e-huned.com/">Huned Botee</a>, <a href="http://tacolab.com/about/Brent_Fitzgerald">Brent Fitzgerald</a>, <a href="http://me.visnup.com/">Visnu Pitiyanuvath</a>, and <a href="http://attemptry.com/blog/">Gerad Suyderhoud</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2008/10/gentrify/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to write a Promiserver promise</title>
		<link>http://blog.brentfitzgerald.com/2007/04/how-to-write-a-promiserver-promise/</link>
		<comments>http://blog.brentfitzgerald.com/2007/04/how-to-write-a-promiserver-promise/#comments</comments>
		<pubDate>Mon, 23 Apr 2007 19:58:56 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[rails]]></category>
		<category><![CDATA[research]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[thesis]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.brentfitzgerald.com/2007/04/23/how-to-write-a-promiserver-promise/</guid>
		<description><![CDATA[This post is my first attempt to explain how to write Promiserver code. This will eventually also find its way into a Promiserver help section, but I thought I&#8217;d try it out here first. 
Breach and Success
There are two reserved methods: breach and success. Each takes an optional message parameter. Your code defines the conditions [...]]]></description>
			<content:encoded><![CDATA[<p>This post is my first attempt to explain how to write <a href="http://promise.media.mit.edu/">Promiserver</a> code. This will eventually also find its way into a Promiserver help section, but I thought I&#8217;d try it out here first. </p>
<h4>Breach and Success</h4>
<p>There are two reserved methods: <em>breach</em> and <em>success</em>. Each takes an optional message parameter. Your code defines the conditions under which the promise breaches or succeeds.  For example, a really simply promise would be:</p>
<pre>
if condition_x
  success "it happened!"
end
</pre>
<p>The value of the condition_x variable determines whether the promise evaluates to success. When condition_x evaluates to true, the promise will be evaluated as a success, with corresponding message &#8220;it happened!&#8221;. A marginally more sophisticated promise might look like this:</p>
<pre>
if condition_x
  success "x happened!"
elsif condition_y
  breach "sorry, y happened"
end
</pre>
<p>In this one we have possibility of a breach as well, if condition_y evaluates to true.</p>
<h4>Promise State</h4>
<p>Those variables like condition_x and condition_y aren&#8217;t defined anywhere in this code. This means that they are <em>free variables</em>. </p>
<p>All these free variables in your promise code are extracted as you write the promise, and together form the <em>state</em> of the promise. When writing the promise, you can change the values of these variables to the desired initial state. Once published and signed, all participants can also change the values of these variables.</p>
<h4>Time</h4>
<p>Most promises are commitments with respect to some future action or event. So it may make sense to take time into account.</p>
<pre>
if document_received
  success "thanks, nice work"
elsif  Time.now > document_deadline
  breach "missed the deadline
end
</pre>
<p>Again, document_deadline and document_received become promise state variables, meaning they can be changed by the participants. If we wanted to fix the deadline and remove it from the state, we could simply add in a line.</p>
<pre>
<strong>document_deadline = Time.parse("5/11/2007 6:00pm")</strong>
if document_received
  success "thanks, nice work"
elsif  Time.now > document_deadline
  breach "missed the deadline
end
</pre>
<p>Keep in mind that Time.now evaluates differently each time the promise is evaluated. Future versions of Promiserver will have a timeline or calendar view, to try out the code for different times in the future.</p>
<h4>Ruby Niceness</h4>
<p>Since we&#8217;re using Ruby with some special <a href="http://as.rubyonrails.com/">activesupport</a> magic, we can use some cool shortcuts. For example, say we want to allow for an extension:</p>
<pre>
...
if Time.now > (final_date = deadline + extension.days)
  breach "missed the extended deadline #{final_date}"
end
...
</pre>
<p>This is just a starting point. I have a few people using the system now, and in particular <a href="http://www.burak-arikan.com/">Burak</a> has been a great tester, <a href="http://promise.media.mit.edu/users/arikan/authored">authoring some promises</a> that have pushed Promiserver a little our of its comfort zone. So we&#8217;ll see how this contract-as-code idea continues to develop.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2007/04/how-to-write-a-promiserver-promise/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Promiserver ultra-alpha omega supreme</title>
		<link>http://blog.brentfitzgerald.com/2007/04/promiserver-ultra-alpha-omega-supreme/</link>
		<comments>http://blog.brentfitzgerald.com/2007/04/promiserver-ultra-alpha-omega-supreme/#comments</comments>
		<pubDate>Sun, 15 Apr 2007 07:39:32 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[future]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[research]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[thesis]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.brentfitzgerald.com/2007/04/15/promiserver-ultra-alpha-omega-supreme/</guid>
		<description><![CDATA[
Check it out: promise.media.mit.edu. Borrowing the slogan from OpenCode, This is so alpha, you won&#8217;t even want to use it™
Well, it&#8217;s been a while coming, and now I have a super alpha version of Promiserver live and ready for you to make all your programmed commitments with that same desperate, wanton abandon we saw in [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://promise.media.mit.edu/"><img src='http://blog.brentfitzgerald.com/wp-content/uploads/2007/04/promiserver_alpha_sm.jpg' alt='Promiserver' /></a></p>
<p>Check it out: <a href="http://promise.media.mit.edu">promise.media.mit.edu</a>. Borrowing the slogan from <a href="http://opencode.media.mit.edu/">OpenCode</a>, <em>This is so alpha, you won&#8217;t even want to use it™</em></p>
<p>Well, it&#8217;s been a while coming, and now I have a super alpha version of Promiserver live and ready for you to make all your programmed commitments with that same desperate, wanton abandon we saw in the early field tests. It&#8217;s got bugs aplenty, as well as interface problems, but I can fix em as we find em. Tags coming soon, plus REST API for creating promises programmatically, which is where I think a lot of the applications will be. A lot of other updates too, providing I have enough time given this whole writing ordeal I&#8217;m still in the middle of (sigh).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2007/04/promiserver-ultra-alpha-omega-supreme/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Tiny Drawing</title>
		<link>http://blog.brentfitzgerald.com/2006/08/tiny-drawing/</link>
		<comments>http://blog.brentfitzgerald.com/2006/08/tiny-drawing/#comments</comments>
		<pubDate>Tue, 29 Aug 2006 21:20:19 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[research]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/08/29/tiny-drawing/</guid>
		<description><![CDATA[Inspired by the flurry of 13&#215;13 icon creation, Luis and I have been at work the past day on a new, super low resolution icon creation system called Tiny. I&#8217;ve written a javascript version with a Rails backend that uses RMagick to produce the PNGs. Meanwhile Luis has thrown together a nice little applet, which [...]]]></description>
			<content:encoded><![CDATA[<p>Inspired by the flurry of 13&#215;13 icon creation, Luis and I have been at work the past day on a new, super low resolution icon creation system called <a href="http://tiny.media.mit.edu/">Tiny</a>. I&#8217;ve written a javascript version with a Rails backend that uses RMagick to produce the PNGs. Meanwhile Luis has thrown together a nice little applet, which I have to admit is a tad more sophisticated than my version. We&#8217;ll integrate them in the next few days. It&#8217;ll be pretty easy, since creating a new icon is as easy as sending an HTTP POST with a data parameter of 169 0&#8217;s or 1&#8217;s. Title and parent parameters are taken optionally.</p>
<p>Forever alpha at <a href="http://tiny.media.mit.edu/">http://tiny.media.mit.edu/</a></p>
<p><a href="http://tiny.media.mit.edu/"><img id="image95" src="/wp-content/uploads/2006/08/tiny_screen.png" alt="Tiny" /></a></p>
<p>The excitement will really never end. There are 2^169 possible images! Thanks to <a href="http://www.media.mit.edu/~amber/">Amber</a> for the original inspiration with her Mini app for <a href="http://openstudio.media.mit.edu/">OS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/08/tiny-drawing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Friendly Ruby (Quiz Solution)</title>
		<link>http://blog.brentfitzgerald.com/2006/08/friendly-ruby-quiz-solution/</link>
		<comments>http://blog.brentfitzgerald.com/2006/08/friendly-ruby-quiz-solution/#comments</comments>
		<pubDate>Sun, 20 Aug 2006 18:53:17 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/08/20/friendly-ruby-quiz-solution/</guid>
		<description><![CDATA[My solution to the recent Ruby Quiz #91 is friendly.rb, a module that allows a user to interactively add method definitions at runtime.

module Friendly

  def method_missing name
    @_new_methods &#124;&#124;= Hash.new
    unless @_new_methods.has_key? name
      prompt_for_definition name
    end
    eval [...]]]></description>
			<content:encoded><![CDATA[<p>My solution to the recent <a href="http://www.rubyquiz.com/quiz91.html">Ruby Quiz #91</a> is friendly.rb, a module that allows a user to interactively add method definitions at runtime.</p>
<pre>
module Friendly

  def method_missing name
    @_new_methods ||= Hash.new
    unless @_new_methods.has_key? name
      prompt_for_definition name
    end
    eval @_new_methods[name]
  end

  def prompt_for_definition name
    puts "It appears that #{name} is undefined."
    puts "Please define what I should do (end with a blankline):"
    @_new_methods[name] = ""
    while $stdin.gets !~ /^\s*$/
      @_new_methods[name] << $_
    end
  end

  def added_methods
    @_new_methods.keys
  end

  def added_method_definitions
    @_new_methods.map {|k,v|
      s = "def #{k}\n  "
      v.rstrip!
      s << v.gsub("\n", "\n  ")
      s << "\nend"
    }
  end

end
</pre>
<p>Example usage, in this case just using Friendly to extend the top level object:</p>
<pre>
irb(main):001:0> include Friendly
=> Object
irb(main):002:0> foo = bar * z
It appears that bar is undefined.
Please define what I should do (end with a blankline):
12

It appears that z is undefined.
Please define what I should do (end with a blankline):
4

=> 48
irb(main):003:0> foo
=> 48
irb(main):004:0> bar
=> 12
irb(main):005:0> z
=> 4
irb(main):006:0> added_methods
=> [:z, :bar]
irb(main):007:0> puts added_method_definitions.join("\n\n")
def z
  4
end

def bar
  12
end
=> nil
irb(main):008:0>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/08/friendly-ruby-quiz-solution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Acts As Permalinkable</title>
		<link>http://blog.brentfitzgerald.com/2006/08/acts-as-permalinkable/</link>
		<comments>http://blog.brentfitzgerald.com/2006/08/acts-as-permalinkable/#comments</comments>
		<pubDate>Tue, 08 Aug 2006 02:11:10 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/08/07/acts-as-permalinkable/</guid>
		<description><![CDATA[I&#8217;ve released the polymorphic acts_as_permalinkable plugin that I developed for use with PLWire. To install:

./script/plugin discover \
   http://plw.media.mit.edu:9090/repository/public/rails/plugins
./script/plugin install -x acts_as_permalinkable
./script/generate permalinkable_migration
rake migrate

Then just add the acts_as_permalinkable snippet to your models:

class Article < ActiveRecord::Base
  acts_as_permalinkable
  ...
end

class Photo < ActiveRecord::Base
  acts_as_permalinkable
  ...
end

When you save your model the permalink will automatically [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve released the polymorphic <a href="http://plw.media.mit.edu:9090/repository/public/rails/plugins/acts_as_permalinkable">acts_as_permalinkable</a> plugin that I developed for use with <a href="http://plwire.media.mit.edu/">PLWire</a>. To install:</p>
<pre>
./script/plugin discover \
   http://plw.media.mit.edu:9090/repository/public/rails/plugins
./script/plugin install -x acts_as_permalinkable
./script/generate permalinkable_migration
rake migrate
</pre>
<p>Then just add the <code>acts_as_permalinkable</code> snippet to your models:</p>
<pre>
class Article < ActiveRecord::Base
  acts_as_permalinkable
  ...
end

class Photo < ActiveRecord::Base
  acts_as_permalinkable
  ...
end
</pre>
<p>When you save your model the permalink will automatically update as well. By default it uses a <code>title</code> attribute to create the slug and the <code>created_on</code> attribute for the date, but this is easily customized. For example to use it with the name attribute and the updated_at attribute:</p>
<pre>
  acts_as_permalinkable \:on => :name,
                         :use_date => :updated_at
</pre>
<p>You can also provide a Proc that filters the permalinkable title field before it is turned into a slug. For example maybe you want to strip the tags and only take the first 20 characters:</p>
<pre>
  acts_as_permalinkable \:on => :content,
      :slug_modifier => lambda { |x|
             x.gsub(/\<.+?\>/, "").strip[0..20]
          }
</pre>
<p>Within your views you can link to the permalinks with a few url helper methods, <code>url_for_permalink</code> and <code>link_to_permalink</code>:</p>
<pre>
&lt;%= url_for_permalink @article,
    {:action => "permalink"},
    {:class => "permalink",
     :title => "Permalink for '#{@article.title}'"}
%&gt;

&lt;%= link_to_permalink "permalink", @article,
    {:action => "permalink"},
    {:class => "permalink",
     :title => "Permalink for '#{@article.title}'"}
%&gt;
</pre>
<p>And within your controller just use the <code>find_permalinked</code> method:</p>
<pre>
find_permalinked :slug => "this-is-a-slug",
    :year => 2006,
    :month => 8,
    :day => 7
</pre>
<p>Underspecifying these parameters will return a collection for all matching records. Or if your parameters already have these values it is pretty easy:</p>
<pre>
find_permalinked params
</pre>
<p>You can add permalinks to existing records with the <code>create_all_slugs</code> singleton method. I use the console. For example, with an Article model:</p>
<pre>
Article.create_all_slugs
</pre>
<p>Hope it works out to be helpful for at least a few people out there.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/08/acts-as-permalinkable/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Rails Layered Dispatching Hints</title>
		<link>http://blog.brentfitzgerald.com/2006/07/rails-layered-dispatching-hints/</link>
		<comments>http://blog.brentfitzgerald.com/2006/07/rails-layered-dispatching-hints/#comments</comments>
		<pubDate>Thu, 06 Jul 2006 00:44:55 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/07/05/rails-layered-dispatching-hints/</guid>
		<description><![CDATA[For my current Rails project I&#8217;m setting up my web services with layered dispatch, which nicely organizes all the methods while keeping them at the same endpoint URI. There&#8217;s some good documentation already out there in the Agile Web Development with Rails book as well as the ActionWebServices manual, but I have a few extra [...]]]></description>
			<content:encoded><![CDATA[<p>For my current Rails project I&#8217;m setting up my web services with layered dispatch, which nicely organizes all the methods while keeping them at the same endpoint URI. There&#8217;s some good documentation already out there in the <span style="font-style: italic">Agile Web Development with Rails</span> book as well as the <a title="Rails docs on ActionWebService Layered Dispatching" href="http://manuals.rubyonrails.com/read/chapter/69#page192">ActionWebServices</a> manual, but I have a few extra tips that could be helpful.</p>
<p>If we&#8217;re using a before_invocation interceptor, like say for authentication, we can clean things up by creating a subclass of ActionWebService::Base that includes the authentication method:</p>
<p class="code_title">app/apis/authenticated_web_service.rb</p>
<pre>
class AuthenticatedWebService < ActionWebService::Base
  def authenticate name, args
    @authenticated_user = User.find_by_login args[0]
    unless @authenticated_user.authenticated?(args[1])
      raise "Not authenticated"
    end
  end
end</pre>
<p>Because we are actually using an instance variable here, @authenticated_user, we have to set up our layered web service controller to use instances of the services rather than the classes.</p>
<p class="code_title">app/controllers/services_controller.rb</p>
<pre>class ServicesController < ApplicationController
  web_service_dispatching_mode :layered
  wsdl_service_name 'contract_services'
  web_service_scaffold :invoke

  # Here we use instances...
  web_service(:contract) {ContractService.new}
  web_service(:account) {AccountService.new}

  # rather than classes...
  # web_service :contract, ContractService
  # web_service :account, AccountService
end</pre>
<p>Then your various services can inherit from this "abstract" AuthenticatedWebService. Each can make use of the authenticate method and the @authenticated_user variable.</p>
<p class="code_title">app/apis/contract_service.rb</p>
<pre>class ContractApi < ActionWebService::API::Base

  api_method :all,
             :returns => [[Contract]]
  api_method :new,
             :expects => [{:login => :string},
                          {:password => :string},
                          {:description => :string}],
             :returns => [Contract]
end

class ContractService < AuthenticatedWebService
  web_service_api ContractApi

  def all
    Contract.find :all
  end

  def find contract_id
    c = Contract.find(contract_id)
    raise "Contract not found." if c.nil?
    c
  end

  ## Authenticated API Methods
  before_invocation :authenticate, \:only => [:new]

  def new l, p, description
    c = Contract.new :creator => @authenticated_user,
                     :description => description
    c.save!
    c
  end
end</pre>
<p>Once your service is put together, keep in mind that XML-RPC requests will use a method of the form <em>service</em>.<em>method</em>. So for example, my contract service's find method is <code>contract.find</code>. I have to admit that this really threw me off for a little while when I was testing out the API in <a href="http://www.ditchnet.org/xmlrpc/">XML-RPC Client</a> and I kept getting back a "no such web service 'api'" error message. The manual does point this out, but I missed it the first time, and only on a close reread did I figure this out, at which point I realized how much good sense this approach makes. Note that for SOAP requests the service API is encoded in the header.</p>
<p>One more final note is that Rails logger object is not available in the layered services. This could be a deal breaker in certain cases.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/07/rails-layered-dispatching-hints/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Tempting Abstractions</title>
		<link>http://blog.brentfitzgerald.com/2006/07/the-tempting-abstractions/</link>
		<comments>http://blog.brentfitzgerald.com/2006/07/the-tempting-abstractions/#comments</comments>
		<pubDate>Tue, 04 Jul 2006 15:41:40 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[research]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/07/04/the-tempting-abstractions/</guid>
		<description><![CDATA[I&#8217;ve been meaning to figure out OSX development for a few years now. I&#8217;ve halfheartedly gone through the currency converter tutorial a few times, fooled around in XCode with various sample projects,  worked through some of the NeHe OpenGL lessons that were ported to Mac, and even bought and went through the first edition [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to figure out OSX development for a few years now. I&#8217;ve halfheartedly gone through the currency converter tutorial a few times, fooled around in XCode with various sample projects,  worked through some of the NeHe OpenGL lessons that were ported to Mac, and even bought and went through the first edition of Aaron Hillgass&#8217;s book 3 or 4 years ago. What got me going again recently was an interest in combining native accelerated graphics with functional language extensibility. I was in part inspired by the ideas of the scheme-based <a title="A graphics environment for scheme." href="http://www.pawfal.org/Software/fluxus/">fluxus</a>.  I reread the docs for <a title="Python Objective-C Bridge" href="http://pyobjc.sourceforge.net/">PyObjC</a> and <a title="Ruby Cocoa Bridge" href="http://rubycocoa.sourceforge.net/">RubyCocoa</a>, and both seem like a lead. Then a few days ago I found Will Thimbleby&#8217;s concise tutorial and example project for using <a title="Javascript with Cocoa views" href="http://will.thimbleby.net/script/">Javascript to script a Cocoa view</a>. This is nice because the Javascipt engine is exactly the one used in Safari, based on KDE&#8217;s <acronym title="KDE's Javascript JavaScript">KJS</acronym> engine. Even nicer is that his code is short and straightforward. In the end I will probably go back to figuring out Ruby and RubyCocoa, but  this tutorial got me moving in this world again.</p>
<p>The biggest stumbling block in my Cocoa experience has been Interface Builder. I know it is supposed to be easy and elegant. But I&#8217;ve been suspicious, and consequently hesitant to really get into it. Along with other Apple systems like <a title="Apple's WebObjects Web Application Environment" href="http://www.apple.com/webobjects/">WebObjects</a> and <a title="Apple's tool for combining programmatic and visual dynamic composition." href="http://developer.apple.com/graphicsimaging/quartz/quartzcomposer.html">Quartz Composer</a>, it requires aquisition of knowledge that is essentially non-transferable. Learning how to visually connect these specific little icons, widgets and outlets just isn&#8217;t going to help me in any other system. It is abstracted to the point of simulation, and learning the rules of the system involves little knowledge of the inner workings. It reminds me of the tension Sherry Turkle noted in the introduction to the new edition of <a title="Sherry Turkle's The Second Self at MIT Press" href="http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&#038;tid=10515"><em>The Second Self</em></a>:</p>
<blockquote><p>The aesthetic of transparency (common to the Logo movement and the early generations of personal computer hobbyists) carried with it a political aesthetic that was tied both to authorship and to knowing how things worked on a level of considerable detail. There is a kind of understanding that is not communicated by playing off-the-shelf simulations (p13).</p></blockquote>
<p>Turkle is concerned that the increasing opacity in modern software and systems is leading to a new type of illiteracy within the emerging generation:</p>
<blockquote><p>&#8230;as I meet professional in all of these fields who move easily within their computational systems and yet feel constrained by them, trapped by their systems&#8217; unseen and unknown assumptions, I feel continued concern. Are the new generation of simulation consumers reminiscent of people who can pronounce the words in a book but don&#8217;t understand what they mean? (p14).</p></blockquote>
<p>Yet I&#8217;m giving in. After investing only a few days I&#8217;m realizing how Interface Builder takes care of many parts of the application that I don&#8217;t ever want to handle myself. The abstraction is easier, simpler, and it saves me time, leaving room in my brain for other problems and puzzles. Turkle&#8217;s concerns are understandable, and to some extend I share them, yet I wonder whether it is in part nostalgia for an aethetic that is only interesting now that it is so obviously impossible (in a recent talk my colleague and friend <a title="Jeevan Kalanithi, also a Media Lab student" href="http://web.media.mit.edu/~jeevan/">Jeevan</a> elaborated on the connection between simplicity and nostalgia for a simple past).</p>
<p>Maybe it is this tension between opaque abstraction versus transparent details that makes for good design. Which details do we choose to hide by assuming defaults? Which details do we conflate versus keep separate? Which details to we expose? As the abstraction increases, the gap between the two increases as well. Finding the balance is harder, yet also much more important.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/07/the-tempting-abstractions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pascal&#8217;s Triangle in Ruby</title>
		<link>http://blog.brentfitzgerald.com/2006/06/pascals-triangle-in-ruby/</link>
		<comments>http://blog.brentfitzgerald.com/2006/06/pascals-triangle-in-ruby/#comments</comments>
		<pubDate>Tue, 27 Jun 2006 14:03:17 +0000</pubDate>
		<dc:creator>brent</dc:creator>
				<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.brentfitzgerald.com/2006/06/27/pascals-triangle-in-ruby/</guid>
		<description><![CDATA[My solution to the Pascal&#8217;s Triangle quiz this week:
#!/usr/bin/env ruby

def center_str s, len
  n = (len - s.length) / 2.0
  ' '*(n.floor) + s + ' '*(n.ceil)
end

n = ARGV[0].to_i
rows = [[1]]
for i in 1..(n-1)
  k = -1; r = rows[i-1] + [0]
  rows ]]></description>
			<content:encoded><![CDATA[<p>My solution to the <a href="http://www.rubyquiz.com/quiz84.html" title="Ruby Quiz #84">Pascal&#8217;s Triangle quiz</a> this week:</p>
<pre>#!/usr/bin/env ruby

def center_str s, len
  n = (len - s.length) / 2.0
  ' '*(n.floor) + s + ' '*(n.ceil)
end

n = ARGV[0].to_i
rows = [[1]]
for i in 1..(n-1)
  k = -1; r = rows[i-1] + [0]
  rows << r.map{ |x| j = k; k+=1; x + r[j] }
end
m = rows.last[n/2].to_s.length * 2
n = n * m
rows.each do |r|
  puts center_str(r.collect{|x| center_str(x.to_s, m)}.join, n)
end</pre>
<p>Sample output:</p>
<pre>
                             1
                          1     1
                       1     2     1
                    1     3     3     1
                 1     4     6     4     1
              1     5     10    10    5     1
           1     6     15    20    15    6     1
        1     7     21    35    35    21    7     1
     1     8     28    56    70    56    28    8     1
  1     9     36    84   126   126    84    36    9     1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.brentfitzgerald.com/2006/06/pascals-triangle-in-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
