Rails and Merb Merge: ORM Agnosticism (Part 5 of 6)

By Yehuda Katz | February 23rd, 2010 at 10:02AM

It’s been a little while since I’ve last posted in this series. During that time, we released Rails 3.0 beta, and announced the launch of RailsPlugins.org. Plugin authors have registered almost 150 plugins, with 40 already boasting compatibility with Rails 3. Over the next few weeks, we’re going to roll out some more features to help users find projects to help get updated, so keep an eye out.

Today I’m going to talk about the features we added to Rails 3 to provide ORM agnosticism. When we first started, the idea of such agnosticism was pretty fuzzy. As we approached the beta, we became convinced that we would shoot for the moon and give DataMapper, Sequel and other ORMs first-class access to all of the same parts of the framework that ActiveRecord had. Again, this sounds pretty fuzzy, so let me lay it out for you.

ActiveRecord is a Framework Extension

You read that right. While Rails itself ships with ActiveRecord as a default, the Railties gem, responsible for bootstrapping Rails, knows nothing about ActiveRecord. In order to achieve this, we had to make that bootstrapping process much more pluggable. While this is amazing for extensions, like DataMapper, that want to replace a built-in framework, it also exposes more functionality to any Rails extension distributed as a gem.

Rails::Railtie

In short, Railties now coordinates the initialization process, which involves the activation of a number of individual Railtie subclasses. Cute, no? Every Rails framework has its own Railtie subclass, which provides a number of useful pieces of functionality:

  • The ability to add a key (like config.active_record) to an Application’s configuration, and assign it defaults that will exist before Application configuration. For instance, a plugin could use this functionality to set a configuration key as an Array, so the Application could simply do config.action_view.view_paths << "my_path". While this isn’t exactly earth-shattering, it levels the playing field between Rails components, like ActiveRecord, and third-party extensions, like DataMapper or Haml
  • The ability to create additional generators that hook into Rails’ default generators. For instance, Rails’ scaffold generator invokes sub-generators for stylesheets, template engine, test framework, helpers, and ORM. For instance, when a user installs Haml as a gem, it can register itself as the handler for template engine generators, and provide replacements for each case where Rails provides a default implementation. In this case, Haml would replace the template engine generators provide by ActionController’s Railtie
  • The ability to supply Rake tasks to load when the user invokes the Rake command. If DataMapper supplies the same named Rake tasks as those supplied by the ActiveRecord Railtie, the user can completely remove ActiveRecord and replace it with DataMapper, retaining all of the named Rake tasks. This would allow other tasks, such as those used in testing, to automatically prepare the database and other tasks it performs by invoking tasks with certain names (like db:create)
  • Supply a log subscriber to integrate seamlessly with the uniform request logging. This allows extensions like DataMapper to add their timings into the log output. In this case, DataMapper simply replaces the “Model” timing that ActiveRecord provides, allowing a level of very tight integration with the rest of the framework
  • Specify initializers that should run at specific points in the initialization process. This allows extensions to set things up very early in the boot process, but then defer some setup until after the user has configured their application, or after specific parts of the initialization process have occurred. Each initializer also receives an instance of the Application object, giving it full access to the user’s configuration

In fact, if you take a look at ActiveRecord’s deep integration with the rest of the framework (which is roughly equivalent to its highly coupled implementation in Rails 2.3), you’ll find that it looks extremely similar to DataMapper’s equally deep integration. In fact, a major goal of the work we put into improving modularity in Rails 3 was to maintain the same level of stack integration we’ve historically had, while exposing the same toolchain for those who wanted to replace only certain elements of the stack.

The ActiveModel API

Giving DataMapper access to the same level of integration with Railties as ActiveRecord is one of two major pillars in making Rails truly ORM agnostic. The second part is decoupling Rails’ historic connection between ActiveRecord, its ORM, and ActionPack, its controller and view layer. In this area, Rails takes a holistic, very conventional approach to linking the model and the view using REST principles.

In particular, domain objects, persisted via the ORM, can have canonical URLs that are used pervasively throughout the controller and view layer. The specific URLs can be configured via the router, and Rails 3’s router is particularly powerful, but once configured, objects do have canonical URLs.

@post = Post.first
 
redirect_to @post           #=> Location: /posts/orm-agnosticism
redirect_to Post            #=> Location: /posts
 
form_for @post              #=> <form action="/posts/orm-agnosticism" method="PUT">
form_for Post.new           #=>
 
error_messages_for @post    #=> a representation of the validation errors that exist on the object
 
link_to @post.title, @post  #=> <a href="/posts/orm-agnosticism">
                            #     Rails and Merb Merge: ORM Agnosticism (Part 5 of 6)
                            #   </a>
 
posts_path                  #=> "/posts"
post_path(@post)            #=> "/posts/orm-agnosticism"
 
@posts = Post.where(:author => "wycats")
 
render @post                #=> renders "_post.html.erb", passing in @post as a local
render @posts               #=> renders a collection of "_post.html.erb", passing in each
                            #   Post instance as a local in turn
 
respond_with @post          #=> performs content negotiation between the formats
                            #   the client is willing to Accept (xml, json, html),
                            #   and the formats the @post object is willing to
                            #   provide. The available providable formats are
                            #   transparently determined by introspecting the @post
                            #   object. Additionally, if the object has not been persisted,
                            #   redirect it back to the editing page for further modification.
                            #   If it has been persisted, redirect it back to the index (or
                            #   some other appropriate path).</form>

In short, Rails 2.3 provided a fair bit of integrated functionality between ActiveRecord and ActionPack. For instance, to determine what an object’s canonical URL was, Rails called an internal .class.naming method on it, which provided the information needed to form the canonical URLs. And while other ORMs could attempt to emulate these internals, there was no guarantee that they’d be used in the same way from release to release (and, in fact, they evolved quite a bit, making them a moving target at best).

In Rails 3, we opened them up, exposing an explicit public API via ActiveModel. The ActiveModel API requires that objects respond to to_model, returning an Object that complies with the larger ActiveModel API. This allows objects that already implement methods with the same names as those required by the API to create a facade that presents itself to ActionPack as a fully compliant model.

The API itself is fairly small, with a few methods around validation, the ability to determine whether an object has persisted or not (which can be safely stubbed by objects without persistence), and a number of methods that tell ActionPack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly, and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API.

The DataMapper ORM has already released a Rails extension (called dm-rails) that implements both the Railtie functionality and ActiveModel, making it a full drop-in replacement for ActiveRecord. The Sequel ORM is also hard at work on their Railtie and ActiveModel adapter.

The really great thing about all of this is that we didn’t need to sacrifice one bit of the (some have said overly) tight integration between various parts of Rails, to provide the ability to swap in entirely different components with the same apparent “coupling” that the Rails frameworks have with each other.

As always, questions and comments are welcome!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 10% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

Rake and Ant Together: A Pick It n’ Stick It Approach

By Thomas Enebo | February 19th, 2010 at 11:02AM

Recently, I landed a new library for JRuby that will be part of JRuby 1.5. Before I start I want to conjure the image you see below this text: that’s Right!  Mr. Potato Head: a role model for us all. Something that delights us for hours (or at least, probably did, at one point in our lives), is flexible, and is not only a toy, but also a starchy food product.

Mister Potato Head (Courtesy of Flickr user MyMollyPop)

Bear with me for a second, and excuse what must have just sounded like a wee bit of lunacy. The the truth is, we live in a world where, as programmers, we construct Mr. Potato Heads every day. We’re confronted with making software where not only are we required to stick various elements together, but also to arrange them in the most pleasing way possible.  Software design is really just like decorating a potato. The potato of this blog entry will be build software.

Build Tools

In the Java world, Ant is the 800 pound potato of build tools.  It’s in virtually every Java build environment on the planet.  To date, I have only really known one person who really really liked Ant.

For the most part, I think people respect Ant as a tool which is a bit syntactically gross, but which gets the job done reliably.  It is also lamented for having little support for imperative programming constructs. This seems to have been by design, but it doesn’t seem to make very many programmers happy.

In the Ruby world we have Rake. Rake, by contrast, has a much nicer syntax than Ant. It also allows any construct that the Ruby language allows, since Rake is just a DSL-like API for building software running in a Ruby interpreter. On the other hand, if you have the need to perform common tasks in the Java world, then it lacks a bunch of standardized cross-platform tasks that Ant contains. You find yourself breaking out into lots of icky shell commands (javac -classpath #{my_files}) and this works great until you try and build something on, gasp, Windows.

A pragmatic (but not so great) reality is that most Java shops may warm to switching to a different build technology, but are unlikely to switch over projects en masse. Even if they were enough in love with Rake to switch, they’d need to hobble together replacements for tasks that they take for granted in Ant. That is… until now.

Use Cases

JRuby’s Rake and Ant integration handles the following use cases:

  • Call any ant task or type from within Rake
  • Allow Rake to be invoked from within Ant
  • Allow Rake tasks to be imported as callable Ant targets
  • Allow Ant to be invoked from Rake
  • Allow Ant targets to be called as Rake tasks from within Rake

Let’s break these down one at a time…

Call Any Ant Task or Type From Within Rake

The truth is, Ant is really just a built-in library in JRuby. You could just write a script and not use it in Rake:

require 'ant'

ant do build_dir = "java_build" # Regular Ruby variables interact fine

# But defining and consuming Ant properties is fine property :name => "src.dir", :value => "java_src"

path(:id => "project.class.path") do pathelement :location => "classes" end

mkdir :dir => build_dir

javac(:destdir => build_dir) do classpath :refid => "project.class.path" src { pathelement :location => "${src.dir}" } end

jar :destfile => "simple_compile.jar", :basedir => build_dir end This example constructs an instance of an Ant project, then makes a directory, compiles some Java source, and finally, generates a jar file of the results. All of these are just Ant tasks. They’ll work on any platform. Sweet, I say! This does, however, lack dependency management.  So let’s use Rake to do it instead:

require 'ant'

build_dir = "java_build" file build_dir

task :setup => build_dir do ant.property :name => "src.dir", :value => "java_src" ant.path(:id => "project.class.path") do pathelement :location => "classes" end end

task :compile => :setup do ant.javac(:destdir => build_dir) do classpath :refid => "project.class.path" src { pathelement :location => "${src.dir}" } end end

task :jar => :compile do ant.jar :destfile => "simple_compile.jar", :basedir => build_dir end

task :default => :jar [Quick note: since we can combine the best of both worlds, you don't need to ever set an Ant property if you don't want to. Just use a Ruby variable or constant. Different folks for different strokes...]

This snippet shows how easy it is to consume Ant tasks in a Rakefile. Really, JRuby’s Ant library is just a straight-forward set of APIs that map clearly to Ant’s original syntax. Looking up how to do something is a very straight-forward task.

The other benefit mentioned above is that Rake can use imperative programming in it. Let’s consider a snippet like this in Ant:

      <java classname="${mainclass}">
        <arg value="--command"/>
        <arg value="maybe_install_gems"/>
        <arg value="--no-ri"/>
        <arg value="--no-rdoc"/>
        %lt;arg value="--env-shebang"/>
      </java>
It can use imperative conveniences:
command = "--command may_install_gems --no-ri --no-rdoc --env-shebang"
ant.java :classname => "${mainclass}" do
  command.split(/\s+/).each { |value| arg :value => value }
end
So if you’re a Rake user already and you need to do Java things, then using this support should be a pretty simple decision. Heck, there are many other optional Ant tasks that may be useful even if you’re not doing Java things.

Allow Rake to be Invoked From Within Ant

If you have the ability to write the equivalent of an Ant project using Rake, then you may want to make part of your project driven by Rake. However, if you do this, you may still need to call it from within Ant. We can do this with the new ‘Rake’ task.

If we pretend the previous Rakefile existed parallel to a build.xml file we have then in that Ant’s build.xml file we could have:

<?xml version="1.0" encoding="UTF-8"?>
<project name="foobar" default="default" basedir=".">
  <description>Builds, tests, and runs the project foobar.</description>

<target name="load-rake-task"> <taskdef name="rake" classname="org.jruby.ant.Rake"/> </target>

<target name="default" depends="load-rake-task"> <rake task="jar"/> </target>

... </project> This Ant script’s ‘default’ target will load our Rake task and then call Rake (file defaults to ‘Rakefile’), and more specifically, call the task ‘jar’ (task defaults to ‘default’). There are a couple of cool scenarios to consider here:

1. Try Rake by only dipping your toes in the water

This strategy is great if you like Rake but are worried you don’t have enough influence to get your development team to switch their entire build suite. You can just stick a Rakefile off to the side for some new functionality and let your teammates evaluate how much they like it. If they do, then switch the rest later… or don’t. The idea that most Java shops will big-bang change their build software is extremely unlikely. An incremental strategy is your best bet.

2. Easier integration with Java tools

Even if you’re totally sold on Rake, you still need to know that software like NetBeans expects to see a build.xml file, so it can interact with your project. Having a small shim like the one above makes you play nice with any tools that expect Ant.

This is the simplest way to call Rake from Ant, but the next option may suit your needs better…

Allow Rake Tasks to be Imported as Callable Ant Targets

The big missing feature of the Rake task in the script above is that it’s only one-way. You can call Rake, but then the Rakefile you call has no meaningful interaction with the Ant side of things. Sure it can call Ant tasks, but it can’t see properties or Ant targets that are defined in the calling build.xml file.

To have better interoperability we have another Ant task: RakeImport. RakeImport will require the specified Rakefile and then register all of its tasks with Ant dependency management system. Let’s look at a simple example:

<?xml version="1.0" encoding="UTF-8"?>

<project name="foobar" default="top-level" basedir="."> <description>Builds, tests, and runs the project foobar.</description>

&lt;taskdef name="rakeimport" classname="org.jruby.ant.RakeImport"/&gt;
&lt;rakeimport/&gt;

&lt;target name="top-level" depends="its_in_rake" /&gt;

&lt;target name="its_in_ant"&gt;
  &lt;echo message="ant: its_in_ant"/&gt;
&lt;/target&gt;

</project> In Ant, we specify that we want to use RakeImport and then immediately call it. This loads the following Rakefile and registers all of its tasks with Ant:

task :its_in_rake => [:setup, :its_in_ant]  do
  puts "it's in Rake"
end

task :setup do puts "setup in Rake" end Now let’s run ‘ant top-level’; we now see the following output:

Buildfile: build.xml
[rakeimport] (in /Users/enebo/work/akakamiari/samples/rake_import_example2)

setup: setup in Rake

its_in_ant: [echo] ant: its_in_ant

its_in_rake: it's in Rake

top-level:

BUILD SUCCESSFUL Total time: 7 seconds This output shows that it’s executing both Ant targets and Rake tasks in the desired order. its_in_ant executes as a dependency of its_in_rake which in turn executes because it is a dependency of the Ant target ‘top-level’.

The scenarios for this level of integration:

1. Choosing the best tool

Since Rake gives a full imperative programming environment there are some things that are trivial to do in Rake which are cumbersome (or impossible without writing a custom Ant task) in Ant. You can move that stuff into Rake, but still continue using Ant for everything else.

2. Toe wet… time to go waist deep

In the previous section we used the Rake task to demonstrate to your development group that Rake is useful. This allows you to start depending on the capabilities of Rake more by being able to inject Rake tasks into the Ant dependency graph. Your group is still using Ant as the main build tool, but you’re delegating more of the build to Rake.

Allow Ant to be Invoked From Rake

Let’s look at things from the other side of the coin. If you’re already a Rake user, but you need to interact with existing Ant build files, we’ve also got solutions for you. The first method allows you to just call Ant from within Rake:

task :call_ant do
  ant '-f my_build.xml my_target1'
end
Alternatively, you can also supply arguments as a list:
args = ['-f', 'my_build.xml', 'my_target1']
task :call_ant do
  ant args
end
Believe it or not, this doesn’t just execute ant; it loads it into your JRuby environment. This is nice because it doesn’t spawn a second JVM to run Ant.

As I mentioned at the beginning of this section, you may want to just call into Ant, but not have any more interaction than that. That’s ok, but if you want more….

Allow Ant Targets to be Called as Rake Tasks From Within Rake

‘ant_import’ beats ‘ant’ in flexibility because it ends up registering all of Ant’s top-level targets with Rake’s dependency management system. Once you import an Ant file into Rake, you can call the Ant tasks as if they were ordinary Rake tasks. A simple example:

task :ant_import do
  ant_import
end

task :compile => [:ant_import, :its_in_ant_setup] do # Do some compilation end This example will load ant_import when the compile task is executed which will in turn load the build.xml file in the current directory and load all of its Ant targets. I did not ant_import at the top-level of the Rakefile to show that you may only want to load the Ant targets if you are actually planning on using them.

Details Details

This code has just landed in JRuby trunk. All of the examples listed here should work, but this code is brand new. It’s a work in progress that will firm up by the time JRuby 1.5 is out. So this means two things for the reader:

1. You can help find problems and help improve the library

In other words, if this interests you, then you can get involved early and help address problems or enhance the library. Odds are you can make the difference between this integration being great or merely good.

Getting started note: the current practice for running the examples above is to copy jruby-complete.jar into $ANT_HOME/lib. You can manually set your classpath to include jruby-complete.jar as well, but I found it less error prone to just copy the jar.

2. If you don’t like unfinished software then wait for 1.5

Some people don’t like the hassles or have the time to play with unfinished software. If you’re in this position, then don’t worry. We’ll get things working nicely for 1.5. We don’t want an early test run to ruin anyone’s expectations.

Conclusion

Going back to our original Mr. Potato Head theme, I was hoping to show that sometimes combining things together really is the best strategy. In theory, it’s nice to start over and make something pure and wonderfully homogenous. In practice, there are always pesky real-life details that get in the way. Why rewrite everything when you can just attach the new technology on the side? If you do have the long term goal of replacing an older technology, why not do it incrementally? Every big-bang rewrite project I have ever been in has basically failed in a significant way. Change things one piece at a time and your chances of success are much higher.

Our new Rake/Ant integration is meant to allow incremental change, or at least to allow the best features of each tool to be used together. It embodies the reality that both tools may be necessary and that replacing one for the other probably won’t be a 100% solution.

As always, questions and comments are welcome!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 8% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

Congratulations Are in Order!

By Leah Silber | February 17th, 2010 at 11:02AM
Carl LercheNew Rails Core
Team member Carl Lerche

Some of you may not have noticed, but over Presidents Day weekend two new faces slipped on to the official Rails Core Team roster; we’d like to congratulate Carl Lerche and José Valim on all their hard work this last year!

2009 was a tremendous year for Rails, and we’re finally nearing the finish line with Rails 3. Both Carl and José spent a tremendous amount of time working on Rails 3, and were key factors in getting the codebase as far as it’s come. Without a doubt, Rails wouldn’t be where it is without their efforts.

We’re proud and pleased to have both Carl and José on the Engine Yard open source team, as well as the rest of the dedicated engineers working on Engine Yard-supported open source Ruby projects: Yehuda Katz and Mikel Lindsaar on Rails, Evan Phoenix and Brian Ford on Rubinius, Charles Nutter, Tom Enebo and Nick Sieger on JRuby, and Kirk Haines on Ruby 1.8.6.

The future of Ruby, Rails and all things open source is looking bright; see you there!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 8% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

A Hint of Hubris

By Larry Diehl | February 16th, 2010 at 10:02AM

Ruby is a highly dynamic language with impressive capabilities for runtime redefinition of classes, objects, methods, and variables. Haskell, on the other hand, is a purely functional language that confines mutation within a sophisticated static type system. Given their many differences one or the other may be more suited for whatever problem you might be working on (see polyglot programming), but sometimes, a mix of both would be even better. Thanks to Hubris, you now have that option!

Hubris is a gem that allows you to call out to natively compiled Haskell shared objects. In this post, I’ll talk a bit more about why you might want to do that, how you’d go about doing that, and share some real world examples.

So Why Would I Want To Use Haskell?

It’s easy for any decent programmer to spot the many striking differences between Ruby and Haskell, but why a Rubyist might be interested in  Haskell is a question worth asking. There are two primary scenarios:

1. Native Extensions

When CPU-intensive algorithms are needed for a task in Ruby, you usually drop down to the C or C++ level to take advantage of the highly optimized code yielded by a C/C++ compiler. Unfortunately, for someone without significant experience in the language, it can be easy to run into memory management woes, not to mention the frustration of dealing with a more hands-on (with respect to memory and explicit typing) language like C.

Haskell is a managed memory language with one of the most powerful type inference capabilities around. What this means is that you can avoid being bothered with explicitly denoting types at function call-sites, and choose whether or not to add types to definitions for the particular function you’re working on. Additionally, GHC (Haskell’s most prominent compiler for production applications) produces compiled native code that has performance in the same league as C/C++.

2. Concurrency

Many popular languages (especially Object Oriented ones) allow unconstrained mutation of data (e.g. mutator! methods in Ruby). This has always had implications for the difficulty of reasoning in the resulting code. But lately, this has become a bigger problem because it makes reasoning about concurrent program execution a nightmare.

What differentiates Haskell from many other functional languages is that Haskell isolates side effects statically in types rather than dynamically in language constructs. In effect, this means you can statically determine a list of functions/places to look (and eliminate many of the places you don’t have to look) when problems related to side effects do come up.

3. And More

Haskell  as a whole has many other useful properties, such as implicit laziness, implicit argument currying, a typeclass system for generic programming, various concurrency constructs including an STM and a wonderful concurrency debugger… just to name a few. Rubyists who enjoyed Why’s Poignant Guide to Ruby may enjoy parsing through Learn You a Haskell for Great Good.

Okay, I Buy It: Now How Can I Do It?

Now that we’ve seen why you might want to use Haskell, we’ll take a look at how to use Hubris from Ruby. There are two main modes of operation: a way to embed a Ruby string containing Haskell code inline, and a way to load code from a plain Haskell .hs file. Like so:

class Example
  hubris :inline => "foo :: Integer -> Integer; foo x= 1330 + x"
end

Example.new.foo # => 1337

class Example
  hubris :source => "MyHaskell.hs"
end

Example.new.my_awesome_function "go ye forth into a world unknown" Note that due to support for the :inline option, you can even experiment with adding new functions dynamically in an irb session (compile errors like type conflicts get spit out for you to read)! In the background, Hubris will compile code to /var/hubris/cache and then link it in to your running Ruby program.

The first time you run the code, it will be a bit slower as it compiles the Haskell, but subsequent runs will load the cached .so files directly. Another nice property is that the already compiled code is compared against a saved hash in order to only recompile when changes have been made.

As the Hubris README demonstrates, a third option is load modules already installed on the system:

hubris :module => "Data.ByteString", :packages => ["bytestring"]
Hubris comes with an example Rack app that exposes a Haskell implementation of the Fibonacci function. I’ll show it to you here as a compact Sinatra app. A likely use case for Rubyists will be to leverage Ruby’s mature web development library ecosystem by exposing an API for a compact and optimized Haskell algorithm/program .
require 'sinatra'
require 'hubris'

helpers do hubris :inline => <<-HASKELL fibonacci :: Int -> Int fibonacci n = fibs !! n where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) HASKELL end

get '/:number' do fibonacci(params[:number].to_i).inspect end As you can see, sensible conversions between data types in both languages are done automatically. Below is a table of the mappings between Ruby and Haskell types (see the Hubris specs for example uses). Try  searching Hoogle (no, that’s not a typo) to find Haskell functions supporting types you’re interested in.

Ruby Haskell
TrueClass/FalseClass Boolean
Fixnum/Bignum Integer
Float Double
String Data.ByteString
Array List
Hash Map.Map
value or nil Maybe
Not yet Multiple arguments
Not yet Tuple
Not yet Algebraic types

Hubris currently lacks support for calling functions with multiple arguments (or tuples or custom algebraic types)—which is a serious drawback. However, this is not by design and you can track the Github issues for those missing features via the links in the table above.

In the future, fine-grained interaction between both languages will be possible. For example, unit testing Haskell functions with RSpec, including those with multiple arguments. For the time being, you can take a more coarse-grained approach by passing a hash of many values to a single interface function in Haskell.

A Real-World Example

I’ll end my overview by linking to a more complicated example that exposes a Ruby webservice to a coarsely-grained Haskell function. Here, a Sinatra web service is passed a JSON string, which is parsed into a Ruby Hash (actually using C via the JSON gem), then passed to a Haskell function, which is converted on the Haskell side to a Map and then returns an [[Int]] List that gets converted into a nested Ruby Array of integers to finally return the web response as a String. (That made for a long and hard to read sentence, but go through it slowly: it makes sense.)

Rather than calling out to a simple Fibonacci function, you call a basic implementation of a Multi-layer Perceptron Neural Network. HUnit is used for unit testing in Haskell. These tests correspond to values in a handwritten derivation of the first epoch of learning the XOR problem. A Ruby integration test drives the whole stack via rack-test on the XOR problem. A rake task runs both sets of tests to conveniently validate expected behavior. Explaining the algorithm would be enough content for at least a separate post, but hopefully Neurosis can serve as a useful Hubris reference implementation to fiddle around with in the meantime.

Conclusion

There are some serious limitations that prevent fine-grained interaction between Ruby and Haskell. Nevertheless, Hubris has strong potential as a useful library and can be used today via coarse-grained interfaces. Note that Hubris has been tested to work on MRI 1.8 and 1.9, but should work with any Ruby that conforms to MRI’s C API.

Installation of the Haskell-side of the library is a bit of a pain right now, but this wiki page is recording the team’s progress as they work on fixing it.

So here we are: it’s time to go out and write your own Haskell code, to be called from Ruby (or find a favorite Haskell library to reuse)… that is, if you can make it past installation ;)

As always, leave any questions and comments!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 10% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

Announcement: New Engine Yard Private Cloud Infrastructure

By Tom Mornini | February 11th, 2010 at 8:02AM

Today is an exciting day at Engine Yard, and I wanted you hear about it from me first. We’ve selected Terremark, a major hosting and infrastructure provider, to provide the infrastructure for our next generation private cloud services.

For Engine Yard Cloud (Amazon Web Services) customers, this move will have no impact on you whatsoever.

When we opened for business more than three years ago, racking and stacking our own hardware wasn’t really a choice: being self-funded well before the concept of cloud computing existed, doing it ourselves was the only way we could introduce our customers to our vision for application deployment and management.

How times have changed! Infrastructure vendors now agree with most of the concepts that we pioneered back then, eliminating the need for us to do it ourselves. We’ve always felt that specializing in Ruby on Rails and the surrounding stack would allow us to make deploying and scaling Rails applications as easy and efficient as it is to create those applications.

Today’s announcement will allow us to further focus on enabling our customers to leverage today’s and tomorrow’s rapidly evolving infrastructure and providing the best Rails Platform-as-a-Service technologies and support.

While there are many advantages to the Terremark infrastructure, we’re most excited about their  sophisticated fibre-channel storage area network. The Terremark SAN affords greater reliability and substantially higher throughput than our current storage system; we know that our customers will see great benefit and peace of mind from this.

Terremark has an excellent track record supporting the needs of large enterprise and federal government agencies. Their datacenters have SAS 70 level II, PCI and HIPAA certifications, and we’re confident that our private cloud customers will find this new infrastructure meets the most demanding application requirements.

Over the next six months, we will migrate all current Slice, Fractional Cluster and Dedicated Cluster environments that currently reside on the Engine Yard private cloud to Terremark.

At a high level, not much will change for our private cloud customers. In particular, I want to emphasize that there are no changes in your support team or support processes.

Based on our extensive planning with Terremark, we expect migrations to require minimal effort for our private cloud customers.

If you’re a private cloud customer, you will hear from your Engine Yard account manager in the next few weeks to discuss a migration plan that makes sense for you.

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 10% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...