<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Robby on Rails: PL/Ruby loves RubyGems and DRb</title>
    <link>http://www.robbyonrails.com/articles/2005/08/22/pl-ruby-loves-rubygems-and-drb</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>thoughts.sort_by{|t| t[:topic]}.collect </description>
    <item>
      <title>PL/Ruby loves RubyGems and DRb</title>
      <description>&lt;p&gt;I admit it. I have had a torrid love affair with procedural languages ever since I started playing with PostgreSQL. The ability to share logic amongst all the applications touching the same database server.. was…well… a breath of fresh air.&lt;/p&gt;


	&lt;p&gt;What is a procedural language in Postgresql?&lt;/p&gt;


	&lt;p&gt;PostgreSQL docs describe them as, ”&amp;#8230;allows user-defined functions to be written in other languages besides &lt;span class="caps"&gt;SQL&lt;/span&gt; and C. “&lt;/p&gt;


	&lt;p&gt;Well, PostgreSQL has PLs for Perl, Python, Java, C, &lt;span class="caps"&gt;PHP&lt;/span&gt;… and even &lt;span class="caps"&gt;RUBY&lt;/span&gt;!&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
CREATE FUNCTION ruby_max(int4, int4) RETURNS int4 AS '
    if args[0].to_i &amp;gt; args[1].to_i
        return args[0]
    else
        return args[1]
    end
' LANGUAGE 'plruby';
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;PL/PGSQL is nice and all, but it’s not as fun as playing with Ruby. PL/Perl… well is perl, and PL/Python… is python. Both PL/Perl and PL/Python have untrusted variants. You see, they don’t want your PostgreSQL server to do anything harmful to the machine by being able to do stuff like system(&amp;#8216;cat /dev/null &amp;gt; /etc/passwd). But for some people, (like me) they want the flexibility of their language anyways. :-)&lt;/p&gt;


	&lt;p&gt;Note: Never do this if your system user that runs PostgreSQL has privileges to do anything harmful on your system.&lt;/p&gt;


	&lt;p&gt;The PL/Ruby documentation is minimal at the moment, but covers enough to get you started. I don’t know if many people are using it out there… but hopefully that is about to change! I’ve played with it a bit, but always wanted to be able to do stuff like require &amp;#8216;rubygems&amp;#8217;, but this is a feature of an untrusted language. I even found myself digging around in C code to see if I could figure out how to hack the plruby language to skip over those checks… but I am not a C programmer and I got lost in some header files.&lt;/p&gt;


	&lt;p&gt;Then it hit me. “Why haven’t you emailed the author?”&lt;/p&gt;


	&lt;p&gt;So I emailed the author of PL/Ruby, Guy Decoux, who responded pretty quickly with the answer to my dreams! Okay, I do have bigger dreams than this… but you get the idea.&lt;/p&gt;


	&lt;p&gt;First of all, some of you might be thinking, ”Why on Earth would you want to do this?”&lt;/p&gt;


	&lt;p&gt;Well, here is a simple example of how it could be used with RedCloth Let’s say that I want to be able to perform the following query from within &lt;span class="caps"&gt;SQL&lt;/span&gt;.&lt;/p&gt;


&lt;typo:code lang=ruby"&gt;&lt;span class="caps"&gt;SELECT&lt;/span&gt; redcloth(&amp;#8216;&lt;strong&gt;strong text&lt;/strong&gt; and &lt;em&gt;emphasized text&lt;/em&gt;&amp;#8216;);&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Why not do this in the application? Well, I do actually have a case where I have an older &lt;span class="caps"&gt;PHP&lt;/span&gt; application that I will be porting to Ruby in the future, but would like to give the application some access to some of the features of Ruby that I will be using, such as RedCloth.&lt;/p&gt;


	&lt;p&gt;Okay, so show me an example of one of these scary PostgreSQL functions.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
CREATE FUNCTION redcloth(text) RETURNS text AS '

  require ''rubygems''
  require ''redcloth''

  content = args[0]

  rc = RedCloth.new(content)

  return rc.to_html

' LANGUAGE 'plruby';
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;”Wait! You said this would be scary!?”&lt;/p&gt;


	&lt;p&gt;Well, PL/Ruby allows you to write… plain ole Ruby within your functions. (do you see where I am getting here?)&lt;/p&gt;


	&lt;h2&gt;PL/Ruby meets RedCloth&lt;/h2&gt;


&lt;pre&gt;&lt;code&gt;
 rb=# SELECT redcloth('*strong text* and _emphasized text_');
                             redcloth
------------------------------------------------------------------
 &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;strong text&amp;lt;/strong&amp;gt; and &amp;lt;em&amp;gt;emphasized text&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
(1 row)
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;PL/Ruby meets ShortURL&lt;/h2&gt;


&lt;pre&gt;&lt;code&gt;
CREATE FUNCTION rubyurlize(text) RETURNS text AS '

  require ''rubygems''
  require ''shorturl''

  return ShortURL.shorten(args[0])

' LANGUAGE 'plruby';
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;...which allows for&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
 rb=# SELECT
rb-#   rubyurlize('http://www.robbyonrails.com/') as link1,
rb-#   rubyurlize('http://moulon.inra.fr/ruby/plruby.html') as link2;
          link1           |         link2
--------------------------+------------------------
 http://rubyurl.com/lyoKm | http://rubyurl.com/dTo
(1 row)
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;PostgreSQL meets DRb&lt;/h2&gt;


	&lt;p&gt;Okay, this is one of the reasons why I wanted to play with PL/Ruby a bit more. Distributed Ruby Objects… from PostreSQL?&lt;/p&gt;


	&lt;h3&gt;What is DRb?&lt;/h3&gt;


	&lt;p&gt;If you don’t know already… per the description in &lt;span class="caps"&gt;RDOC&lt;/span&gt;, “dRuby is a distributed object system for Ruby. It allows an object in one Ruby process to invoke methods on an object in another Ruby process on the same or a different machine.”&lt;/p&gt;


	&lt;p&gt;It basically allows you to share an object to other machines… at the same time!&lt;/p&gt;


	&lt;p&gt;mmm…distributed objects…&lt;/p&gt;


	&lt;h3&gt;DRb Object&lt;/h3&gt;


	&lt;p&gt;Here is a simple ruby script that you would run from the shell. It creates a DRb object which accepts connections at localhost:9000.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
#!/usr/bin/ruby

require 'drb'

class MyRemoteObject
  def say(str)
    return "You say #{str}. I say #{str.reverse.upcase}!" 
  end
end

server = MyRemoteObject.new

DRb.start_service('druby://localhost:9000', server)
DRb.thread.join
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Start me up!&lt;/p&gt;


&lt;code&gt;$ ruby mydrb.rb&lt;/code&gt;

	&lt;p&gt;Now that we have DRb running and listening for connections…we need a client to connect to it.&lt;/p&gt;


	&lt;p&gt;DRb function in PL/Ruby&lt;/p&gt;


	&lt;p&gt;Here is a very simple DRb client script and I just drop that into a PostgreSQL function.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
CREATE FUNCTION drb_test(text) RETURNS text AS '

  require ''drb''

  DRb.start_service

  ro = DRbObject.new(nil, ''druby://localhost:9000'')

  return ro.say(args[0])

' LANGUAGE 'plruby';
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The result?&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
rb=# SELECT drb_test('Potato');
           drb_test
-------------------------------
 You say Potato. I say OTATOP!
(1 row)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Are we having fun yet?&lt;/p&gt;


	&lt;p&gt;Okay, so how do I manage to get this to work? Well… for that, you will have to read my blog post, Installing untrusted PL/Ruby for PostgreSQL&lt;/p&gt;


	&lt;p&gt;Let’s all go get some coffee (or tea) and start playing with PL/Ruby today!&lt;/p&gt;
</description>
      <pubDate>Mon, 22 Aug 2005 16:09:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:0e1f7180-23f5-4f8a-abb6-07dd31b7a863</guid>
      <author>Robby Russell</author>
      <link>http://www.robbyonrails.com/articles/2005/08/22/pl-ruby-loves-rubygems-and-drb</link>
      <category>Ruby</category>
      <category>PostgreSQL</category>
      <category>ruby</category>
      <category>drb</category>
      <category>postgresql</category>
    </item>
  </channel>
</rss>
