<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2748851392016004874</id><updated>2011-04-21T14:16:46.782-07:00</updated><category term='camping'/><category term='cdk'/><category term='jruby'/><category term='perl'/><title type='text'>goesLightly</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://goeslightly.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2748851392016004874/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://goeslightly.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>j2</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2748851392016004874.post-3676100959183992016</id><published>2008-04-07T07:21:00.001-07:00</published><updated>2008-09-17T08:59:05.559-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cdk'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><category scheme='http://www.blogger.com/atom/ns#' term='camping'/><title type='text'>CampDepict: JRuby, CDK, and Camping</title><content type='html'>JRuby has a bright future, especially in areas where the immediacy of Ruby and the established APIs of Java meet. Rich Apodaca recently created a smiles to 2D structure tool using ruby, Rails, the &lt;a href="http://cdk.sf.net/"&gt;CDK&lt;/a&gt; Java cheminformatics library, and a java-to-ruby bridge (&lt;a href="http://depth-first.com/articles/2006/11/21/build-a-rails-cheminformatics-application-in-thirty-minutes"&gt;part 1&lt;/a&gt; and &lt;a href="http://depth-first.com/articles/2006/11/27/anatomy-of-a-cheminformatics-web-application-beautifying-depict"&gt;part 2&lt;/a&gt;). Here is the same project, created using JRuby, one of Rich's Java libraries, and &lt;a href="http://code.whytheluckystiff.net/camping/"&gt;Camping&lt;/a&gt; , a lightweight web framework.&lt;br /&gt;&lt;br /&gt;1. Install the JDK&lt;br /&gt;&lt;br /&gt;2. &lt;a href="http://jruby.codehaus.org/Getting+Started"&gt;Install JRuby&lt;/a&gt; - I'm using 1.1 here. Did you remember to set JRUBY_HOME? Is jruby in your PATH?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ jruby -v&lt;br /&gt;ruby 1.8.6 (2008-03-28 rev 6360) [x86-jruby1.1]&lt;/pre&gt;&lt;br /&gt;3. Install Camping and dependencies into jruby.&lt;br /&gt;&lt;pre&gt;$ jruby $JRUBY_HOME/bin/gem install camping --source &lt;a href="http://code.whytheluckystiff.net/"&gt;http://code.whytheluckystiff.net/&lt;/a&gt;&lt;/pre&gt;&lt;br /&gt;Note: if you don't have c ruby installed, the following will work:&lt;br /&gt;&lt;pre&gt;$ gem installed camping --source http://code.whytheluckystiff.net/&lt;/pre&gt;&lt;br /&gt;4. Download &lt;a href="http://sourceforge.net/projects/structure"&gt;structure-cdk-0.1.2&lt;/a&gt; from sourceforge, and save the two jars (cdk-20060714.jar and structure-cdk-0.1.2.jar) from the lib directory to $JRUBY_HOME/lib.&lt;br /&gt;&lt;br /&gt;5. Create a depict directory, and a depict/static directory.&lt;br /&gt;&lt;br /&gt;6. Create two 200x200 pngs called invalid.png, and blank.png. Store them in the static directory.&lt;br /&gt;&lt;br /&gt;7. Save campdepict.rb to the depict directory (text at the end of this entry).&lt;br /&gt;&lt;br /&gt;8. And run! (You can stop the server with a Ctrl-C).&lt;br /&gt;&lt;pre&gt;$ jruby $JRUBY_HOME/bin/camping campdepict.rb&lt;/pre&gt;&lt;br /&gt;(sorry, had some image upload issues with Blogger ... no pretty picture).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;'Splainin'&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;Camping deployments usually start as one file containing model, view and controller, but can be separated as needed (check that wiki). After some smiles validation by Index, the view passes the smiles string back to the Image_for controller, which calls the helper where the cdk routines get called.&lt;br /&gt;&lt;br /&gt;The smiles-to-png code in the image_for helper metho is a hybrid of Rich's rcdk code and depict code. But instead of extracting the Java calls to CDK in a separate Java class, the calls are embedded directly into the jruby class. JRuby lets you store Java objects directly as ruby objects. Although the ruby smiles string is transparently translated to Java ( ...parseSmiles( smiles ) ), the translation of the Java ByteArrayOutputStream to a ruby String requires a thunk routine (String.from_java_bytes out.toByteArray).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Final Notes&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The begin/rescue/end block is dependent on the cdk-20060714.jar packaged with structure-cdk-0.1.2. More recent versions have changes to both this code and the structure-cdk-0.1.2 package.&lt;br /&gt;&lt;br /&gt;There are some bugs, which I haven't tracked down yet. The code will not render salts, metals, or accurately depict chiral centers with wedge bonds.&lt;br /&gt;&lt;br /&gt;As per the jruby wiki, invoking jruby with a few command line switches will help the performance quite a bit:&lt;br /&gt;&lt;pre&gt;jruby -J-server -J-Djruby.thread.pooling=true $JRUBY_HOME/bin/camping campdepict.rb&lt;/pre&gt;&lt;br /&gt;Finally, it works just as well under windows as Linux.&lt;br /&gt;&lt;br /&gt;campdepict.rb&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;include Java&lt;br /&gt;&lt;br /&gt;Camping.goes :Campdepict&lt;br /&gt;&lt;br /&gt;module Campdepict::Controllers&lt;br /&gt;&lt;br /&gt;class Index &lt; '/'&lt;br /&gt;  def get&lt;br /&gt;    if input.smiles then&lt;br /&gt;      @smiles = input.smiles&lt;br /&gt;    else&lt;br /&gt;      @smiles = ''&lt;br /&gt;    end&lt;br /&gt;    @escapedsmiles = CGI::escape(@smiles)&lt;br /&gt;    render :smiles_picture&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Image_for &lt; R '/image_for'&lt;br /&gt;  def get&lt;br /&gt;    render_smiles(input.smiles)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Campdepict::Views&lt;br /&gt;def layout&lt;br /&gt;  html do&lt;br /&gt;    head do&lt;br /&gt;      title { "SMILES Depictor" }&lt;br /&gt;    end&lt;br /&gt;    body { self &lt;&lt; yield }&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def smiles_picture&lt;br /&gt;  h1 "Depict a SMILES String"&lt;br /&gt;  img :src=&gt; '/image_for/?smiles=#{@escapedSmiles}"&lt;br /&gt;  br&lt;br /&gt;  form :action =&gt; R(Index), :method =&gt; 'get' do&lt;br /&gt;    label 'Smiles', :for =&gt; 'smiles'&lt;br /&gt;                    input :name =&gt; 'smiles',&lt;br /&gt;                          :value =&gt; @smiles,&lt;br /&gt;                          :size =&gt; '50',&lt;br /&gt;                          :type =&gt; 'text&lt;br /&gt;  end&lt;br /&gt;  br&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Campdepict::Helpers&lt;br /&gt;  EDGE_SIZE = 200 # image size&lt;br /&gt;  MIME_TYPES = {'.css' =&gt; 'text/css',   '.js' =&gt; 'text/javascript',&lt;br /&gt;                '.jpg' =&gt; 'image/jpeg', '.png' =&gt; 'image/png'}&lt;br /&gt;  PATH = Dir.pwd&lt;br /&gt;&lt;br /&gt;  def render_smiles(smiles)&lt;br /&gt;    if ! smiles  (smiles.eql? '') then&lt;br /&gt;      return static_get('blank.png')&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    # cdk-20060714 dependent code&lt;br /&gt;    begin&lt;br /&gt;      smiles_parser = org.openscience.cdk.smiles.SmilesParser.new&lt;br /&gt;      sdg = org.openscience.cdk.layout.StructureDiagramGenerator.new&lt;br /&gt;      sdg.setMolecule( smiles_parser.parseSmiles( smiles ) )&lt;br /&gt;      sdg.generateCoordinates&lt;br /&gt;      image = Java::net.sf.structure.cdk.util.ImageKit.createRenderedImage(sdg.getMolecule(), EDGE_SIZE, EDGE_SIZE )&lt;br /&gt;    rescue&lt;br /&gt;      return static_get('invalid.png')&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    out = java.io.ByteArrayOutputStream.new&lt;br /&gt;    javax.imageio.ImageIO.write image, "png", out&lt;br /&gt;&lt;br /&gt;    String.from_java_bytes out.toByteArray&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  # static_get is straight outa the Camping wiki&lt;br /&gt;  def static_get(path)&lt;br /&gt;    @headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] "text/plain"&lt;br /&gt;    unless path.include? ".." # prevent directory traversal attacks&lt;br /&gt;      @headers['X-Sendfile'] = "#{PATH}/static/#{path}"&lt;br /&gt;    else&lt;br /&gt;      @status = "403"&lt;br /&gt;      "403 - Invalid path"&lt;br /&gt;    end&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2748851392016004874-3676100959183992016?l=goeslightly.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://goeslightly.blogspot.com/feeds/3676100959183992016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2748851392016004874&amp;postID=3676100959183992016' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2748851392016004874/posts/default/3676100959183992016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2748851392016004874/posts/default/3676100959183992016'/><link rel='alternate' type='text/html' href='http://goeslightly.blogspot.com/2008/04/campdepict-jruby-cdk-and-camping.html' title='CampDepict: JRuby, CDK, and Camping'/><author><name>j2</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2748851392016004874.post-7594564170431702787</id><published>2008-03-21T05:52:00.000-07:00</published><updated>2008-04-19T23:13:15.860-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>YAML and Legacy Perl</title><content type='html'>&lt;p&gt;While rewriting some legacy Perl, I got the jonesin' for some &lt;a href="http://www.yaml.org/"&gt;YAML &lt;/a&gt;to drive the setup factory. Unfortunately, I'm working on an old system running older Perl. Fortunately &lt;a href="http://search.cpan.org/%7Eadamk/YAML-Tiny-1.25/"&gt;YAML::Tiny&lt;/a&gt; came to the rescue, and worked as advertised. YAML::Tiny isn't a complete YAML parser, but it works well enough to translate things like this:&lt;br /&gt;&lt;pre&gt;--- MLSMR report configuration file&lt;br /&gt;REPORT_TYPE: MLSMR&lt;br /&gt;MLSMR_ISM: ValuesFrequency&lt;br /&gt;MLSMR_STRUCTURE_ID: ValuesFrequency&lt;br /&gt;MLSMR_STRUCTURE_SYNONYMS: Exists&lt;br /&gt;MLSMR_SAMPLE_ID: ValuesFrequency&lt;br /&gt;PUBCHEM_SID: ValuesFrequency&lt;br /&gt;FIELD_ORDER:&lt;br /&gt;   1: MLSMR_ISM MLSMR_STRUCTURE_ID MLSMR_STRUCTURE_SYNONYMS&lt;br /&gt;   2: MLSMR_SAMPLE_ID PUBCHEM_SID&lt;br /&gt;&lt;/pre&gt;And now someone else can configure those reports with a text editor.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2748851392016004874-7594564170431702787?l=goeslightly.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://goeslightly.blogspot.com/feeds/7594564170431702787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2748851392016004874&amp;postID=7594564170431702787' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2748851392016004874/posts/default/7594564170431702787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2748851392016004874/posts/default/7594564170431702787'/><link rel='alternate' type='text/html' href='http://goeslightly.blogspot.com/2008/03/yaml-and-legacy-perl.html' title='YAML and Legacy Perl'/><author><name>j2</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
