<?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>Innovation On The Run &#187; ruby</title>
	<atom:link href="http://www.innovationontherun.com/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.innovationontherun.com</link>
	<description>Ruminations about innovation and software by Rob Di Marco</description>
	<lastBuildDate>Sun, 25 Oct 2009 14:44:46 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Philly JUG Presentation on Using JRuby</title>
		<link>http://www.innovationontherun.com/philly-jug-presentation-on-using-jruby/</link>
		<comments>http://www.innovationontherun.com/philly-jug-presentation-on-using-jruby/#comments</comments>
		<pubDate>Wed, 24 Oct 2007 10:43:45 +0000</pubDate>
		<dc:creator>Rob Di Marco</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.innovationontherun.com/philly-jug-presentation-on-using-jruby/</guid>
		<description><![CDATA[Last night I presented an Introduction to JRuby at the Philadelphia Java Users Group.&#160; My goal was to introduce Java programmers to Ruby and&#160;get them to how features of the language allowed for functionality and code structure that is not possible in Java alone.&#160; While I did talk about Rails at the end, my point [...]]]></description>
			<content:encoded><![CDATA[<p>Last night I presented an Introduction to JRuby at the <a href="http://phillyjug.jsync.com">Philadelphia Java Users Group</a>.&nbsp; My goal was to introduce Java programmers to Ruby and&nbsp;get them to how features of the language allowed for functionality and code structure that is not possible in Java alone.&nbsp; While I did talk about Rails at the end, my point was to get the developers to understand that the meta-programming functionality in Ruby allows for both plugin develeropers and users of Rails to extend and improve the base platform in many interesting ways.
<p>Probably my favorite example was an expansion on a previous blog post about using <a href="/scraping-dynamic-websites-using-jruby-and-htmlunit/">JRuby and HtmlUnit</a>.&nbsp; In the presentation, I created a simple Domain Specific Language on top of the great HtmlUnit library to allow for simple parsing of pages with content in JavaScript.&nbsp; This was a great example of how JRuby can be used to take advantage of both Java and Ruby
<p>The presentation is available at <a href="http://www.innovationontherun.com/presentation-files/Introduction%20to%20JRuby-10-23-2007.pdf">http://www.innovationontherun.com/presentation-files/Introduction%20to%20JRuby-10-23-2007.pdf</a>&nbsp;and the associated source code can be found at <a href="http://www.innovationontherun.com/presentation-files/JRuby-JUG.zip">http://www.innovationontherun.com/presentation-files/JRuby-JUG.zip</a>.&nbsp; If you are looking at the source code, start with the file ABOUT.txt.&nbsp; It describes the prerequisites needed to get the code to run and the order of the listed files follows the order that they were used in the presentation.
<p>If you have questions or comments, feel free to <a href="http://www.innovationontherun.com/contact/">send me an email</a>.</p>
<img src="http://www.innovationontherun.com/?ak_action=api_record_view&id=42&type=feed" alt="" /><!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d42').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Bookmark to:</em></strong></a>
<br />
<div class="d42" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=Philly+JUG+Presentation+on+Using+JRuby&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.squidoo.com/lensmaster/bookmark?http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F" rel="nofollow" title="Add to&nbsp;Squidoo"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/squidoo.png" title="Add to&nbsp;Squidoo" alt="Add to&nbsp;Squidoo" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.spurl.net/spurl.php?url=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F&amp;title=Philly+JUG+Presentation+on+Using+JRuby" rel="nofollow" title="Add to&nbsp;Spurl"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/spurl.png" title="Add to&nbsp;Spurl" alt="Add to&nbsp;Spurl" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.innovationontherun.com%2Fphilly-jug-presentation-on-using-jruby%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d42').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d42').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>]]></content:encoded>
			<wfw:commentRss>http://www.innovationontherun.com/philly-jug-presentation-on-using-jruby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why Ruby&#8217;s Mixins Gives Rails an Advantage over Java Frameworks</title>
		<link>http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/</link>
		<comments>http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/#comments</comments>
		<pubDate>Wed, 19 Sep 2007 23:57:42 +0000</pubDate>
		<dc:creator>Rob Di Marco</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/</guid>
		<description><![CDATA[Much has been made over Paul Graham&#8217;s&#160;famous&#160;posting about how Lisp&#160;gave his startup Viaweb an advantage over the competition.&#160; Graham&#8217;s thesis is that there are features in the Lisp language that could be leveraged to make his programming team more productive and better able to respond to customer needs. The idea that a programming language will [...]]]></description>
			<content:encoded><![CDATA[<p>Much has been made over <a href="http://www.paulgraham.com">Paul Graham&#8217;s</a>&nbsp;famous&nbsp;posting about how <a href="http://en.wikipedia.org/wiki/Lisp_programming_language">Lisp</a>&nbsp;<a href="http://www.paulgraham.com/avg.html">gave his startup Viaweb an advantage</a> over the competition.&nbsp; Graham&#8217;s thesis is that there are features in the Lisp language that could be leveraged to make his programming team more productive and better able to respond to customer needs.</p>
<p>The idea that a programming language will make your team more productive is the Holy Grail of software development.&nbsp; Many languages have been promoted as a cure all for productivity (C++ in the 80s, Java in the 90s, Ruby now, Lisp perpetually), and each turns out to have their benefits and weaknesses.&nbsp; But there is no doubt that certain features in languages can lead to leaps in improvements in productivity.&nbsp; For example, having built in garbage collection&nbsp;is a <em>sine qua non </em>for modern development languages.&nbsp; No one can argue (at least no one can argue well) that garbage collection does not improve developer productivity for 99.9% of development efforts.</p>
<h2>What is Mixin?</h2>
<p>Since many readers may not be aware of what a mixin is, I will try to describe it briefly.&nbsp; Ruby is an object-oriented language.&nbsp; With all object-oriented languages, the designers had to decide whether or not to support <a href="http://en.wikipedia.org/wiki/Multiple_inheritance#Debate">multiple inheritance</a>.&nbsp; Perl and C++&nbsp;designers allow for multiple inheritance, Java does not allow for multiple inheritance but does allow for polymorphism through the use of interfaces.&nbsp; Ruby&#8217;s designers&nbsp;opted to not allow multiple inheritance, but to allow for code from one module to be able to be included in another class.</p>
<p>So consider the following code:</p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>module BarModule
  def hello_world
    puts "Hello World"
  end
end

class BaseClass
  def class_method
    puts "In class method"
  end
end

class Foo &lt; BaseClass
  include BarModule
end

f = Foo.new
f.class_method
f.hello_world
</pre>
</div>
<p>&nbsp;In this example, we are creating a module named <em>BarModule</em>&nbsp;with a <em>hello_world</em> method, a class named <em>BaseClass</em>, and then another class <em>Foo</em> that extends <em>BaseClass</em> and includes <em>BarModule</em>. The class <em>Foo</em> will then have both the methods from <em>BarModule</em> and <em>BaseClass</em>, but it will only <em>BE</em> an instance of <em>BaseClass</em> as that is its only parent. Somewhat different than what a Java developer would do, but it makes sense. Running this file will result in the following output:</p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>$ ruby foo.rb
In class method
Hello World
$
</pre>
</div>
<p>So that is a basic example of what a mixin is.</p>
<h2>Adding send() into the equation</h2>
<p>Another interesting and powerful thing about Ruby is that all method calls are actually message passing calls.&nbsp; So for example, we could rewrite:</p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>f = Foo.new
f.class_method
f.hello_world
</pre>
</div>
<p>to</p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>f = Foo.send(:new)
f.send(:class_method)
f.send(:hello_world)
</pre>
</div>
<p>and the results would be exactly the same! Again a little weird if new to Ruby, but it this language feature can lead to some very interesting and powerful results.</p>
<h2>Combining include and send</h2>
<p>Now let&#8217;s combine these two methods.&nbsp; What if I wanted to take my <em>BarModule</em> and apply it to a class that is not sign, say the ruby base class <em>String</em>.</p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>String.send(:include, BarModule)
s = "Arbitrary String"
s.hello_world
</pre>
</div>
<p>Running the above code would produce: </p>
<div style="border-right: 1px dotted; border-top: 1px dotted; padding-left: 1em; border-left: 1px dotted; border-bottom: 1px dotted">
<pre>$ ruby include-bar-module-on-string.rb
Hello World
$
</pre>
</div>
<p>That&#8217;s right, at runtime, I was able to add an arbitrary method onto the base <em>String</em> class. That method is now available to any <em>String</em>s that I instantiate within my application. </p>
<h2>The Implication of this Feature on Rails</h2>
<p>Because of this mixin feature, a developer can add arbitrary methods and modify behavior of core classes at runtime.&nbsp; This is amazingly powerful if you are trying to write plugins and extensions to the framework.&nbsp; Because you can add functionality to existing objects, users can install your plugin and start taking advantage of new functionality without having to make changes to the objects that they are instantiating in their application.&nbsp; In frameworks written in other languages, such as Java, plugging in new functionality means that you need to change how your objects are instantiated.&nbsp; This will require code changes and/or potentially configuration changes (if you are using a dependency injection framework like Spring).&nbsp; Hard to develop, hard&nbsp;to maintain, and a pain for plugin developers to support.&nbsp; But because of the mixin feature, Rails plugin developers can customize the base objects and the users of the plugins do not have to change any of their code or configuration logic.&nbsp; A good example of this can be seen in the <a href="http://www.redhillonrails.org/#row_version_migrations">Row Version</a>&nbsp;Rails plugin.&nbsp; This particular plugin puts a <strong>created_at, UPDATED_AT</strong>&nbsp;and a&nbsp;<strong>row_version</strong> on every row inserted into the database.&nbsp; It requires ZERO code change to make this happen.&nbsp; You just install the plugin and go.&nbsp; It works by adding hooks into the <em>ActiveRecord::Base</em> (the base persistence class in Rails) so that when records are saved, the correct information is put in to those fields.&nbsp; A very easy and powerful plugin to install and use.</p>
<h2>Conclusions</h2>
<p>The point to take away from this is not that Ruby on Rails rocks and Java sucks.&nbsp; Far from it.&nbsp; But choosing a framework with lots of extensions that can take care of many of the mundane tasks allows your developers to spend more of their time focused on the problems of the user and not on common problems.&nbsp; The mixin feature of Ruby allows for the development of easy to use but powerful plugins that will be hard for any non-Ruby based framework to compete with.</p>
<img src="http://www.innovationontherun.com/?ak_action=api_record_view&id=41&type=feed" alt="" /><!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d41').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Bookmark to:</em></strong></a>
<br />
<div class="d41" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.squidoo.com/lensmaster/bookmark?http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F" rel="nofollow" title="Add to&nbsp;Squidoo"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/squidoo.png" title="Add to&nbsp;Squidoo" alt="Add to&nbsp;Squidoo" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.spurl.net/spurl.php?url=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F&amp;title=Why+Ruby%26%238217%3Bs+Mixins+Gives+Rails+an+Advantage+over+Java+Frameworks" rel="nofollow" title="Add to&nbsp;Spurl"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/spurl.png" title="Add to&nbsp;Spurl" alt="Add to&nbsp;Spurl" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.innovationontherun.com%2Fwhy-rubys-mixins-gives-rails-an-advantage-over-java-frameworks%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d41').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d41').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>]]></content:encoded>
			<wfw:commentRss>http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Scraping Dynamic Websites Using JRuby and HtmlUnit</title>
		<link>http://www.innovationontherun.com/scraping-dynamic-websites-using-jruby-and-htmlunit/</link>
		<comments>http://www.innovationontherun.com/scraping-dynamic-websites-using-jruby-and-htmlunit/#comments</comments>
		<pubDate>Wed, 05 Sep 2007 21:58:21 +0000</pubDate>
		<dc:creator>Rob Di Marco</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.innovationontherun.com/scraping-dynamic-websites-using-jruby-and-htmlunit/</guid>
		<description><![CDATA[Scraping static web sites to verify functionality or to access data has been around as long as there has been a web (example of scraping of a static web&#160;page with Ruby).&#160; But with the advent of AJAX and other techniques that use JavaScript to dynamically insert HTML into a web page, scraping has gotten more [...]]]></description>
			<content:encoded><![CDATA[<p>Scraping static web sites to verify functionality or to access data has been around as long as there has been a web (example of <a href="http://muharem.wordpress.com/2007/09/04/scrape-the-web-with-ruby/">scraping of a static web&nbsp;page with Ruby</a>).&nbsp; But with the advent of AJAX and other techniques that use JavaScript to dynamically insert HTML into a web page, scraping has gotten more challenging.&nbsp; Most scraping technology does fine when downloading a single HTML page, but cannot easily handle the dynamic content.</p>
<p>With the 1.12 release of <a href="http://htmlunit.sourceforge.net">HtmlUnit</a>, this&nbsp;headless web browser can now support parsing and executing JavaScript.&nbsp; This allows a scraper to access this dynamic content as simply as the scraper accesses static content, and without having to fire up a heavy execution engine like Gecko.</p>
<p><a href="http://jruby.codehaus.org">JRuby</a> is a great technology for easily construct a script that calls into the HtmlUnit functionality without having to deal with all the syntactic sugar that Java requires.</p>
</p>
<h1>Step 0: About The Example Code</h1>
<p>The tar ball, <a href="http://www.innovationontherun.com/jruby-scraper/scraper.tgz">scraper.tgz</a>, contains:</p>
<ul>
<li><a href="http://www.innovationontherun.com/jruby-scraper/scraper.rb ">scraper.rb</a> &#8211; the JRuby script we will be executing.&nbsp; All code discussed in this example comes from there
<li>lib/*.jar &#8211; all of the JAR files needed to run the example
<li>run.sh &#8211; a simple shell script that&nbsp;points JRuby at the lib directory and silences some warning messages</li>
</ul>
<h1>Step 1: Enabling JRuby to Use the Java JAR files</h1>
<table cellspacing="0" cellpadding="0" width="451" border="0" unselectable="on">
<tbody>
<tr>
<td valign="top" width="449">
<pre class="code"># Require Java so we can use the Java libraries
require 'java';

# Get HTML Unit and all of its required libraries
require 'htmlunit-1.13.jar';
require 'commons-httpclient-3.1.jar';
require 'commons-io-1.3.1.jar';
require 'commons-logging-1.1.jar';
require 'commons-lang-2.3.jar'
require 'commons-codec-1.3.jar'
require 'xercesImpl-2.6.2.jar'
require 'xmlParserAPIs-2.6.2.jar'
require 'jaxen-1.1.1.jar'
require 'commons-collections-3.2.jar'
require 'js-1.6R7'
require 'nekohtml-0.9.5.jar'

# Include the Web Client class
include_class 'com.gargoylesoftware.htmlunit.WebClient';</pre>
</td>
</tr>
</tbody>
</table>
<p>In this block, we first use the are telling JRuby to use the JAR files required by HtmlUnit.&nbsp; Some notes:</p>
<ul>
<li>You have to specify every JAR file that HtmlUnit depends upon, even if you are not calling the method directly
<li>All JAR files must be in the LOAD_PATH for JRuby.&nbsp; This is done by -I&lt;DIR_NAME&gt; arguments passed in to JRuby from the command line.
<li>The <em>include_class</em><strong> </strong>is similar to an import statement in Java and puts the WebClient object in scope.</li>
</ul>
<p>At this point, we can now instantiate and use the WebClient class</p>
<h1>Step 2: Parsing a Basic HTML Page</h1>
<p>Before we get into parsing a dynamic page, let&#8217;s take a look at how to parse a simple page.&nbsp; In this example, I am going to parse out information from the Maven 2 Archive for HtmlUnit found at <a title="http://repo1.maven.org/maven2/htmlunit/htmlunit" href="http://repo1.maven.org/maven2/htmlunit/htmlunit">http://repo1.maven.org/maven2/htmlunit/htmlunit</a>.</p>
<table cellspacing="0" cellpadding="0" width="400" border="0" unselectable="on">
<tbody>
<tr>
<td valign="top" width="400">
<pre class="code"># Function for getting a list of all directories
def get_htmlunit_maven_pages
  wc = WebClient.new;

  page = wc.getPage("http://repo1.maven.org/maven2/htmlunit/htmlunit");

  # List the directories...
  page.getByXPath('//img[@alt="[DIR]"]').each do |img|
    a = img.getNextSibling.getNextSibling
    puts 'DIR: ' + a.getHrefAttribute
  end

  # List the files...
  page.getByXPath('//img[@alt="[TXT]"]').each do |img|
    a = img.getNextSibling.getNextSibling
    puts 'FILE: ' + a.getHrefAttribute
  end
end</pre>
</td>
</tr>
</tbody>
</table>
<p>The first step in the method is instantiating a new instance by calling <em>WebClient.new </em>and then download the page using <em>wc.getPage.</em></p>
<p>When requesting a page with a content type of text/html, the getPage call will return an instance of <a href="http://htmlunit.sourceforge.net/apidocs/com/gargoylesoftware/htmlunit/html/HtmlPage.html">HtmlPage</a>, and we can now use XPath expressions and DOM calls to get the URLs for the directories and for files.&nbsp; Very simple to get at the appropriate data.&nbsp; HtmlUnit has a bunch of other methods that you can use to navigate the page, check out the <a href="http://htmlunit.sourceforge.net/apidocs/com/gargoylesoftware/htmlunit/html/HtmlPage.html">source documentation for the HtmlPage</a> object.</p>
<h1>Step 3: Parsing Data Written By JavaScript Functions</h1>
<p>The code behind parsing a HTML page that uses JavaScript to dynamically create content is actually no harder than the previous example.&nbsp; HtmlUnit will detect the script tags in the page you are downloading and execute the appropriate script in line.&nbsp; For an example, I will use my <a href="http://www.innovationontherun.com">blog home page</a> and its inclusion of a JavaScript widget from <a href="http://www.mybloglog.com">MyBlogLog</a>.&nbsp; This script makes a call to MyBlogLog and finds out who the most recent registered users to visit my site have been.&nbsp; In our example, we will parse out these users name and URLs.</p>
<table cellspacing="0" cellpadding="0" width="400" border="0" unselectable="on">
<tbody>
<tr>
<td valign="top" width="400">
<pre class="code"># Function for seeing who the most recent my blog log users were

def search_iotr
  wc = WebClient.new;

  page = wc.getPage("http://www.innovationontherun.com");
  my_blog_log_info = page.getHtmlElementById("MBL_COMM")
  my_blog_log_info.getByXPath('//td[@class="mbl_mem"]').each do |td|
    td.getByXPath('//a').each do |a|
      puts a.asText + ":" + a.getHrefAttribute
    end
  end
end
</pre>
</td>
</tr>
</tbody>
</table>
<p>If you look at the source for this page, you will see a script tag that downloads a JavaScript file from MyBlogLog.com.&nbsp; The downloaded JavaScript will make calls to <em>document.write</em> that will insert an HTML table into the page.&nbsp; The id of the table is MBL_COMM, so our first step is to find that HTML element.&nbsp; Once we have the element, it is a couple of simple XPath expressions to find the anchor tag that contains the recent visitors name and URL.&nbsp; All of the implementation of downloading the data and putting into the HTML page is hidden from us by HtmlUnit so we can easily use DOM to get at the information we are interested in.</p>
<h1>Other Situations Where HtmlUnit Rocks!</h1>
<p>Anytime JavaScript is being used to either enable navigation or modify the HTML document, HtmlUnit can be a great asset in your parsing.&nbsp; This includes:</p>
<ul>
<li>Content from AJAX requests</li>
<li>Situations where JavaScript events are being used to impact behavior.&nbsp; An example would be a page using an onChange handler on a select list to modify form values and/or submit the form.&nbsp; HtmlUnit is very handy for simplifying this interaction.</li>
</ul>
<p>A word of caution, the JavaScript implementation is not fully featured in HtmlUnit, so some sites still may not work.&nbsp; However, the HtmlUnit team is validating the browser against a fair number of popular libraries, so hopefully in future HtmlUnit releases, this will be less of an issue.</p>
<h1>Appendix</h1>
<h2>Prerequisite Information To Run the Example</h2>
<p>Make sure that you have Java installed.&nbsp; I am using Java 1.6, but HtmlUnit and JRuby should support older versions.</p>
<p>Download JRuby from <a title="http://dist.codehaus.org/jruby/jruby-bin-1.0.1.tar.gz" href="http://dist.codehaus.org/jruby/">http://dist.codehaus.org/jruby/</a>&nbsp;and put the jruby executable (found in the bin directory of the downloaded file) in your path.</p>
<p>To verify that Java and jruby are set up correctly, just run jruby from the command line and ask for the version:</p>
<p>
<pre class="code">  &gt; jruby -version
ruby 1.8.5 (2007-08-23 rev 4201) [x86-jruby1.0.1]</pre>
<h2>My Environment Details</h2>
<ul>
<li>JRuby version 1.0.1
<li>HtmlUnit 1.13
<li>Java version 1.6.0_02-b05
<li>Ubuntu 7.0.4</li>
</ul>
<h1>Reference</h1>
<ul>
<li><a href="http://jruby.codehaus.org/">JRuby Home Page</a>
<li><a href="http://htmlunit.sourceforge.net">HtmlUnit Home Page</a>
<li><a href="http://htmlunit.sourceforge.net/apidocs/index.html">HtmlUnit Java Doc</a>
<li><a title="http://www.innovationontherun.com/jruby-scraper/scraper.tgz" href="http://www.innovationontherun.com/jruby-scraper/scraper.tgz">http://www.innovationontherun.com/jruby-scraper/scraper.tgz</a>&nbsp;- The source code for this example</li>
</ul>
<img src="http://www.innovationontherun.com/?ak_action=api_record_view&id=38&type=feed" alt="" /><!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d38').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Bookmark to:</em></strong></a>
<br />
<div class="d38" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.squidoo.com/lensmaster/bookmark?http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F" rel="nofollow" title="Add to&nbsp;Squidoo"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/squidoo.png" title="Add to&nbsp;Squidoo" alt="Add to&nbsp;Squidoo" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.spurl.net/spurl.php?url=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F&amp;title=Scraping+Dynamic+Websites+Using+JRuby+and+HtmlUnit" rel="nofollow" title="Add to&nbsp;Spurl"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/spurl.png" title="Add to&nbsp;Spurl" alt="Add to&nbsp;Spurl" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.innovationontherun.com%2Fscraping-dynamic-websites-using-jruby-and-htmlunit%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d38').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d38').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>]]></content:encoded>
			<wfw:commentRss>http://www.innovationontherun.com/scraping-dynamic-websites-using-jruby-and-htmlunit/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Using Ruby, SOAP, and Apache to implement SSO for SalesForce.com</title>
		<link>http://www.innovationontherun.com/using-ruby-soap-and-apache-to-implement-sso-for-salesforcecom/</link>
		<comments>http://www.innovationontherun.com/using-ruby-soap-and-apache-to-implement-sso-for-salesforcecom/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 02:02:31 +0000</pubDate>
		<dc:creator>Rob Di Marco</dc:creator>
				<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.innovationontherun.com/using-ruby-soap-and-apache-to-implement-sso-for-salesforcecom/</guid>
		<description><![CDATA[Since I have been talking about Java vs. Ruby, I figured I would give a recent example of where Ruby really solved my problems simply and easily. &#160;My company uses SalesForce.com for their CRM solution.&#160; Our sales, finance,&#160;and fulfillment&#160;teams have logins that are maintained and managed through the website.&#160; This is a pain for both [...]]]></description>
			<content:encoded><![CDATA[<p>Since I have been talking about <a href="http://www.redmonk.com/cote/2007/07/25/javas-fear-of-commitment/">Java vs. Ruby</a>, I figured I would give a recent example of where Ruby really solved my problems simply and easily. &nbsp;My company uses <a href="http://www.salesforce.com">SalesForce.com</a> for their <a href="http://en.wikipedia.org/wiki/Customer_relationship_management">CRM</a> solution.&nbsp; Our sales, finance,&nbsp;and fulfillment&nbsp;teams have logins that are maintained and managed through the website.&nbsp; This is a pain for both the users and our IT team&nbsp;as people now have to remember their SalesForce username and password as well as their internal user name and password.</p>
<p>To combat this problem, SalesForce has created a method that allows <a href="http://wiki.apexdevnet.com/index.php/How_to_Implement_Single_Sign-On_with_Salesforce.com">authentication of users via a SOAP request</a>.&nbsp; Very cool, solves the problem, so I signed up to implement it.&nbsp; SalesForce supplies a WSDL documenting the services that need to be supported and&nbsp;you supply the URL that implements the defined services.&nbsp; Should be simple to connect to our ActiveDirectory server using LDAP to perform the validation of users.</p>
<h1>The Initial Attempt: Using Java Web Services&#8230;</h1>
<p>Our standard development environment is Java 5,&nbsp;Maven 2 for builds,&nbsp;Apache 2 for HTTP(S), and JBoss 4.0.5 as an application server.&nbsp; I thought it would be a simple exercise to use <a href="https://jax-ws.dev.java.net/">JAX-WS</a>&nbsp;combined with <a href="https://jax-ws-commons.dev.java.net/jaxws-maven-plugin/">JAX-WS Maven Plugin</a>&nbsp;for auto-generation of my stubs and the&nbsp;<a href="http://labs.jboss.com/jbossws/">JBoss WS</a>&nbsp;to simply deploy.&nbsp; First problem was getting the Maven plugin working correctly.&nbsp; After some trial and error, I got my POM setup correctly and was deploying the EAR.&nbsp; Unfortunately, I realized that JBoss was assuming that Tomcat was running on port 8080, causing a problem in the WSDL that was being referenced.&nbsp; So I had to find the JBoss property to tweak to fix that.&nbsp; Next problem wound up being that the default org.jboss.ws.soap.SOAPMessageImpl did not implement the setProperty method causing an <em>UnsupportedOperationException</em>.&nbsp; Awesome.&nbsp; To try to fix that issue, I wound up trying the following (in different combinations):</p>
<ul>
<li>Upgrading JBoss to 4.2.1.
<li>Upgrading JBoss WS to 2.0 with JBoss 4.2.1
<li>Trying Java 6 as JAX-WS is in the standard JDK with both JBoss 4.0.5 and JBoss 4.2.1</li>
</ul>
<p>With all of these combinations, I kept running into class loading issues and little help on the web.&nbsp; After much frustration, I said to hell with this, how can I do it in ruby&#8230;.</p>
<h1>SOAP4R to the rescue</h1>
<p><a href="http://dev.ctor.org/soap4r">SOAP4R</a>&nbsp;is the best know SOAP library for ruby and the gem is easily installed</p>
<blockquote><p>&gt; gem install soap4r &#8211;source <a href="http://dev.ctor.org/download/">http://dev.ctor.org/download/</a></p>
</blockquote>
<p>Now I could auto-generate my stubs from the WSDL and put in my business logic.</p>
<h2>Generating Stubs from the WSDL</h2>
<p>In general, the <a href="http://www.ruby-doc.org/stdlib/libdoc/soap/rdoc/index.html">documentation</a> for soap4r is non-helpful, but by looking at the source code and googling around a bit, I was able to get the gist.&nbsp; From the supplied SalesForce WSDL, I was able to quickly generate my stubs:</p>
<blockquote><p>require &#8216;rubygems&#8217;<br />gem &#8216;soap4r&#8217;<br />require &#8216;wsdl/soap/wsdl2ruby&#8217;<br />DIR = File.dirname(&#8220;.&#8221;)<br />gen = WSDL::SOAP::WSDL2Ruby.new<br />gen.basedir=File.dirname(DIR)<br />gen.location=File.join(DIR,&#8221;AuthenticationService.wsdl&#8221;)<br />gen.logger.level=Logger::DEBUG<br />gen.opt['classdef'] = &#8220;SforceAuth&#8221;<br />gen.opt['client_skelton'] = nil<br />gen.opt['servant_skelton'] = nil<br />gen.opt['cgi_stub'] = nil<br />gen.opt['standalone_server_stub'] = nil<br />gen.opt['mapping_registry'] = nil<br />gen.opt['driver'] = nil<br />gen.opt['force'] = true<br />gen.run</p>
</blockquote>
<p>&nbsp;Running this produces seven files:</p>
<table cellspacing="0" cellpadding="1" width="600" border="1" unselectable="on">
<tbody>
<tr>
<td valign="top" width="239"><strong>File Name</strong></td>
<td valign="top" width="356"><strong>Purpose</strong></td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthServant.rb</td>
<td valign="top" width="356">Stub class that is used for the implementation.&nbsp; The server side implementation code will need to go in here.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthenticationService.rb</td>
<td valign="top" width="356">If you would like to run a standalone server, this will be the file that you run.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthenticationService.cgi</td>
<td valign="top" width="356">If you would like to use a web server (e.g. Apache) and CGI, this will be the file that you use.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthenticationServiceClient.rb</td>
<td valign="top" width="356">If you would like to have a client to test your code, this will be the file that you run.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuth.rb</td>
<td valign="top" width="356">Class definitions for the request object and the response object.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthMappingRegistry.rb</td>
<td valign="top" width="356">Class used to map SOAP requests and responses to ruby objects.</td>
</tr>
<tr>
<td valign="top" width="239">SforceAuthDriver.rb</td>
<td valign="top" width="356">Driver class used by the client to call into the server.</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h2>Customizing the Generated Ruby Files to Get A Working System</h2>
<p>Of the seven files created, I needed three of them (the client, the standalone server, and the CGI script) needed to be executable.&nbsp; To get them to run, I needed to set the executable flag:</p>
<blockquote><p>&gt; chmod +x SforceAuthenticationService.rb SforceAuthenticationService.cgi SforceAuthenticationServiceClient.rb</p>
</blockquote>
<p>In addition, because I am using Ruby Gems to manage my dependencies, I needed to add the following two lines to the top of each of these three files:</p>
<blockquote><p>require &#8216;rubygems&#8217;<br />gem &#8216;soap4r</p>
</blockquote>
<p>To test the implementation, I started up the standalone authentication server (which listens on&nbsp;port 10080&nbsp;by default) and called it from the client.<br />
<blockquote>
<p>&gt; SforceAuthenticationService.rb &amp;
<p>&gt; SforceAuthenticationServiceClient.rb <a href="http://localhost:10080">http://localhost:10080</a></p>
</blockquote>
<p>If all is working, you will get a NoMethodError exception being thrown.&nbsp; To remedy this problem edit the SforceAuthServant.rb file and on line 15, change the line from <em>raise NotImplementedError.new </em>to <em>{:authenticated =&gt; true}.&nbsp; </em>Restarting the standalone server and rerunning the client will result in success.
<p>Now, I just needed to implement the code to call the LDAP server.&nbsp; First step was obtaining and installing the Gem for the Ruby&nbsp;<a href="http://raa.ruby-lang.org/project/net-ldap/">net-ldap</a> project.&nbsp; Validating the username and password was as simple as putting this code into authenticate method for the SforceAuthServant class:<br />
<blockquote>
<p>def authenticate(parameters)</p>
<p>ldap = Net::LDAP.new<br />ldap.host = &#8220;ldap.hmsonline.com&#8221;<br />ldap.auth parameters.username[0], parameters.password[0]<br />if ldap.bind_as(<br />&nbsp;&nbsp;&nbsp; :base =&gt; &#8220;dc=com&#8221;,<br />&nbsp;&nbsp;&nbsp; :filter =&gt; &#8220;(sAMAccountName=&#8221;+parameters.username[0]+&#8221;)&#8221;,<br />&nbsp;&nbsp;&nbsp; :password =&gt; &#8220;&#8221;<br />)<br />&nbsp; return {:authenticated=&gt;true}<br />else<br />&nbsp; return {:authenticated=&gt;false}<br />end</p>
<p>end&nbsp;</p>
</blockquote>
<p>Again, restarting the standalone server and using the client (with some tweaks to send the right parameters over) validated that the service was working successfully.</p>
<h2>Configuring Apache to use the CGI</h2>
<p>Obviously, I want SalesForce to use HTTPS when sending usernames and passwords.&nbsp; We use <br />Apache as our web server for SSL.&nbsp; To get the CGI set up, I made sure that the directory with the files was accessible from the Apache configuration and then added a .htaccess file</p>
<blockquote><p>Options +ExecCGI<br />AddHandler cgi-script .cgi</p>
</blockquote>
<p>Restarted Apache and I was done.&nbsp; The whole exercise took about an hour, and that was with me figuring out what was going on.&nbsp; The soap4r team has done a great job making setting up and and deploying a SOAP service&nbsp;quick, powerful, and easy to manage.</p>
<img src="http://www.innovationontherun.com/?ak_action=api_record_view&id=24&type=feed" alt="" /><!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a title="Click me to see the sites." href="#" onclick="$$('div.d24').each( function(e) { e.visualEffect('slide_down',{duration:2.5}) }); return false;"><strong><em>Bookmark to:</em></strong></a>
<br />
<div class="d24" style="overflow:hidden">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.dzone.com/links/add.html?description=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com&amp;url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;DZone"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/dzone.png" title="Add to&nbsp;DZone" alt="Add to&nbsp;DZone" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://slashdot.org/bookmark.pl?url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;Slashdot"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/slashdot.png" title="Add to&nbsp;Slashdot" alt="Add to&nbsp;Slashdot" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.squidoo.com/lensmaster/bookmark?http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F" rel="nofollow" title="Add to&nbsp;Squidoo"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/squidoo.png" title="Add to&nbsp;Squidoo" alt="Add to&nbsp;Squidoo" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.spurl.net/spurl.php?url=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F&amp;title=Using+Ruby%2C+SOAP%2C+and+Apache+to+implement+SSO+for+SalesForce.com" rel="nofollow" title="Add to&nbsp;Spurl"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/spurl.png" title="Add to&nbsp;Spurl" alt="Add to&nbsp;Spurl" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fwww.innovationontherun.com%2Fusing-ruby-soap-and-apache-to-implement-sso-for-salesforcecom%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://www.innovationontherun.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<br />
<a style="font-size:90%;text-align: right; " title="Click me to hide the sites." href="#" onclick="$$('div.d24').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); return false;">Hide Sites</a>
</div>
</div>
<!-- Social Bookmarks END -->
<script type="text/javascript">$$('div.d24').each( function(e) { e.visualEffect('slide_up',{duration:0.5}) }); </script>]]></content:encoded>
			<wfw:commentRss>http://www.innovationontherun.com/using-ruby-soap-and-apache-to-implement-sso-for-salesforcecom/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
