Archive for the 'Ruby (on Rails)' Category

Test-Driven JavaScript with ScrewUnit and BlueRidge

Jonah and I are taking our presentation about Javascript Testing on the road next Tuesday at 6:30 in Palo Alto, at the SDForum

The teaser for it… Recent evolutions in JavaScript testing frameworks now allow creating test suites, test-driving development, and running tests on a continuous integration server. This allows us to support more complex JavaScript, have confidence in the implementation, and push more of the logic from the server into the browser, reducing the load on the server…

Hope to see you there.

Erector views – undefined method `default_url_options’

I’m posting this because it took me too long to figure this out. Hope it saves someone else some trouble. If you want to use named route helpers to generate urls in your erector widgets you need to include ActionController::UrlWriter in your class, like so:


class Views::Layouts::BasicPage < Erector::Widgets::Page
include ActionController::UrlWriter
...
end

Automatically deploying to Engine Yard Cloud

I’m working on a application which is deployed to Engine Yard’s Cloud infrastructure and I wanted to automatically redeploy the application whenever our tests passed on our continuous integration server.

Engine Yard will eventually allow us to push a branch to our cloud environment from git (ie “git push engineyard master”) but until that is available the best option seems to be to trigger a github post receive hook directly.

To that end I rewrote an existing script to trigger post receive hooks as a rake task; http://gist.github.com/271433
Continue reading ‘Automatically deploying to Engine Yard Cloud’

assert_changes and assert_no_changes in Ruby

Update: This code and documentation is now available on github: http://github.com/ndp/assert_changes/tree/master

The Problem

On our work on gobalto.com, we spend time to have good fixture data for our tests– data that can represent all the important application states that our tests require. As a result, our tests are very dependent on the data. It’s important that someone doesn’t inadvertantly change it in subtle ways. This has led us to write not only asserts at the end of tests, but pre-conditions as well. For example,

    ...
    inotech = companies(:inotech)
    assert inotech.services.public.include?(categories(:a))
    assert inotech.services.public.include?(categories(:b))
    assert inotech.services.public.include?(categories(:c))
 
    post :edit_services_dialog, :id=&gt;inotech.id,
                                          :service_category_id=&gt;categories(:a).id
    inotech.reload
 
    assert inotech.services.public.include?(categories(:a))
    assert !inotech.services.public.include?(categories(:b))
    assert !inotech.services.public.include?(categories(:c))

Although the pre-conditions were introduced to guard against accidentally changing fixture data (or just to figure out what’s going on), we don’t necessarily delete them. They provide stronger tests. And in some ways, leaving in pre-conditions make the code more readable by providing documentation of your assumptions to the readers. The code above would be hard to follow without the clarifying pre-conditions. What do we expect to change and what stays the same?

Unfortunately all these asserts make the tests twice as long. And there’s a subtle readability problem: there’s no relationship between the corresponding pre- and post-conditions. In the example above, you have to scan carefully to see that the three assertions are repeated, but negated (b and c only). The reader must mentally put pieces together. And it’s not DRY. Using local variables doesn’t help much.

The Solution

I was inspired by a nice little test helper called assert_difference. It takes a string to evaluate and a block to execute. It’s useful for checking on state changes– especially database changes– during a test:

assert_difference('Company.count', -1) do
    Company.delete_one
end

(Without this method, we rely on a count of all database records, or merely look for specific ones. The former approach leads to brittle tests, and the latter to incomplete assertions.)

A limitation of assert_difference is that it only deals with integers. What if it were generalized? Here goes:

    i = true
    assert_changes 'i' =&gt; false do   # read as: i changes to false
      i = false
    end

Continue reading ‘assert_changes and assert_no_changes in Ruby’

Convenient CSS and Javascript in Ruby on Rails

I get tired of hunting through a hierarchy of folders and files, from the views to the public folder, to locate a certain CSS or Javascript file. It’d be convenient to have them right with the markup, but embedding these definitions within your HTML markup is a bad idea for several reasons. For our current project, I proposed we put everything in the view directory so they are easy to find:

app/
  views/
    home/
      index.html.rb
      index.css
      index.js

The convention is clear: to add page-specific CSS code, just create a new file with the same name as the view, in the same folder. Easy to add, edit and remove. The alternative (using the public folder), usually leads to a parallel hierarchy and the inconvenience of that.

I also thought, that this being Rails and all, the files should be included automatically. It turned out to be pretty easy. Continue reading ‘Convenient CSS and Javascript in Ruby on Rails’

Using paginating_find with has_finder

I’ve been enjoying using has_finder by Nick at Pivotal Labs and recently added pagination to the application I am providing volunteer time to for the San Francisco Bike Kitchen.

I like the semantics of paginating_find over will_paginate but am not married to that choice if anyone wants to try to convince me otherwise.

In any case, I wanted to paginate the finders created by has_finder. I wrote a simple ActiveRecord mixin that provides a class method ‘acts_as_paginated and is used in your model like:

class Visit < ActiveRecord::Base
  belongs_to :person
 
  acts_as_paginated :size=> 10
 
  has_finder :for_person, lambda { |person| {
    :conditions => { :person_id => person},
    :order => 'datetime DESC'
  } }
 
  has_finder :in_date_range, lambda { |from,to| {
    :conditions => [ "visits.datetime >= ? and visits.datetime <= ?", from, to ]
  } }
end

Client code looks like:

from, to = Date.new(2008,2,1), Date.new(2008,2,3)
visits = Visit.for_person(@person).in_date_range(from, to).paginate(:page => 3)

The mixin looks like:

# Provides Model.paginate(options={}) to allow
# the paginating_find plugin to be used with the has_finder plugin.
#
# Usage:
#   acts_as_paginated
#   acts_as_paginated :page => 2, size => 10
#
# Install:
#   Save this file as lib/acts_as_paginated.rb and require 'acts_as_paginated'
#   in environment.rb.
#
module HasFinder
module PaginatingFind #:nodoc:
 
def self.included(mod)
  mod.extend(ClassMethods)
end
 
module ClassMethods
  def acts_as_paginated(options={ :page => 1, :size => 20})
    cattr_accessor :paginate_defaults
    self.paginate_defaults = options
 
    self.class_eval do
      extend HasFinder::PaginatingFind::SingletonMethods
    end
  end
end
 
module SingletonMethods
  def paginate(args={})
  options = self.paginate_defaults.clone
    options[:page] = args[:page].to_i if args[:page]
      options[:size] = args[:size].to_i if args[:size]
        find(:all, :page => { :size => options[:size], :current => options[:page], :first => 1 })
      end
    end
  end
end
 
ActiveRecord::Base.send(:include, HasFinder::PaginatingFind)

It also works to paginate associations:

@person.visits.paginate(:size => 4)

markaby_scaffold Rails Plugin

We’ve been enjoying using Markaby on our recent rails projects. When bootstrapping with scaffolding there’s a common recipe of turning ERB views into Markaby and then refactoring views with Markaby helper functions.

One project wrote a rake task that converts ERB views to Markaby. Then Ingar created a plugin that re-implements the base Rails scaffolding to create Markaby views that output the same HTML as the base Rails scaffolding. I took his work one standard refactor further to introduce a MarkabyHelper with helper functions for the layout of form inputs and model views.

Usage

./script/plugin install http://svn.carbonfive.com/public/carbonfive/rails/plugins/markaby_scaffold/trunk/

Use it as you would regular Rails scaffolding:

./script/generate markaby_scaffold Post title:string body:text published:boolean

Prerequisites

markaby_scaffold requires that you install Markaby as a Rails plugin.

Gravy

Unfortunately, Markaby does not appear to be getting the love that it deserves. There is an issue using Markaby with Rails 2.0.2 for which Randy has submitted a patch. This plugin includes a monkey patch for Markaby and Rails 2.0.2 that provides this fix so you don’t have to apply it yourself.

Additionally, the generated MarkabyHelper includes support for using Markaby in your helpers, provides a quick start for refactoring the scaffolding layouts and includes test cases to get you started testing your Markaby helpers.

Google Talking with JRuby and Smack

We’ve kicked off a new project that extends well beyond standard webapp frameworks and tools including significant instant messaging integration. Portions of the project will use Ruby on Rails for web functionality. I know that the open source Jabber software from Jive Software is excellent quality and feature rich. Would JRuby be a good tool for leveraging these Java libraries in a Ruby environment?

Here’s a toy chat client and parrot bot I wrote for the Google Talk service using JRuby and the Java Smack API from Jive’s open source portal ignite realtime.

Continue reading ‘Google Talking with JRuby and Smack’

JRubyGems Release

I’m releasing a first version of JRubyGems. This post is documentation until I come up with something better.

JRubyGems allows you to package RubyGems on your Java application classpath. It removes the file system dependencies on locally installed gems that get awkward when using JRuby and dependent gems in a Java environment.

Usage

Use JRubyGems as a replacement for RubyGems. Instead of

require 'rubygems'
gem 'activerecord'

use

require 'jrubygems'
gem 'activerecord'

Behind the scenes JRubyGems requires RubyGems and injects behavior specific to finding gems on the Java classpath if they are not already installed.

You make JRubyGems available to your application by putting the jar on your application classpath.

Get It

Source is available from Subversion at https://svn.carbonfive.com/public/carbonfive/jruby/jrubygems/trunk/. The tests in ruby/test/test_jrubygems.rb illustrate JRubyGems’ behavior.

The jar at http://mvn.carbonfive.com/public/com/carbonfive/jruby/jrubygems/0.3/jrubygems-0.3.jar is all you need to try it out in your own scripts. With JRuby you can require jar files that are in your load path to get them on your classpath and make Ruby files in the jar available on your load path. So if I have a folder lib/ in my load path with the file lib/jrubygems-0.3.jar, I can use JRubyGems directly from a JRuby script with:

require 'jrubygems-0.3.jar'
require 'jrubygems'

Most Java applications using embedded Ruby will have their own classpath management strategy. Just make sure the JRubyGems jar gets on the classpath of your application. If you are using Maven, you can use JRubyGems from the Carbon Five repository:

<repositories>
  <repository>
    <id>c5-public-repository</id>
    <name>Carbon Five Public Repository</name>
    <url>http://mvn.carbonfive.com/public</url>
  </repository>
</repositories>
 
<dependencies>
  <dependency>
    <groupId>com.carbonfive.jruby</groupId>
    <artifactId>jrubygems</artifactId>
    <version>0.3</version>
  </dependency>
</dependencies>

If you are using Maven you can also require your JRuby dependency with:

<dependency>
  <groupId>org.jruby</groupId>
  <artifactId>jruby-complete</artifactId>
  <version>1.1RC1</version>
</dependency>

Packaging Gem Dependencies

JRubyGems expects a gem to be available on your application classpath as a .gem file (the distribution package for a gem) under the classpath location /gems. This means you can have a gems/ folder on your classpath with a bunch of .gem files in it, a jar with all your .gem files under /gems or a jar per .gem file with each file under /gems in each jar. (A limitation in the JDK’s ClassLoader.getResources method which only returns file system locations for a passed-in empty String prevented me from allowing .gem files in jar roots.)

For our migration application, I built a jar for each gem dependency and deployed it to our central Maven repository. My Maven build references these dependencies in my project POM just as I would a jar dependency.

<dependency>
  <groupId>com.carbonfive.jruby.gems</groupId>
  <artifactId>activerecord</artifactId>
  <version>1.15.6</version>
</dependency>

I just grabbed the .gem files from my local JRuby installation’s gem cache dir at jruby-1.1b1/lib/ruby/gems/1.8/cache/ to build these jars for now.

I like that Raven takes exactly the opposite approach – managing jar dependencies as gems.

Background

Christian and I have a side project at Carbon Five to create a standard mechanism for managing database migrations for our Java projects. The first implementation defines a migration as a SQL script to be run against the target database. I thought it would be cool to support ActiveRecord migrations too, especially for providing an easy way to do the data migrations that accompany a schema change.

My prototype of this idea went well (more on that some other time) but I quickly ran into an issue with the gem dependency for ‘activerecord-jdbc-adapter’ and its dependencies ‘activesupport’ and ‘activerecord’. The issue is that my Java project was nicely portable but the gems create a dependency on the runtime system having specific gems installed. If I install the gems locally, I also have to install them on other runtime systems like our continuous integration server.

I found another example of a JRuby user running into this problem when reading about this example of using the RedCloth Ruby library to format text in a Spring/Java application. Note the “ugly underbelly” footnote.

In the Ruby world, this is the way things work. Large Ruby applications (especially Rails applications) often rely on system services like cron to do their work. These applications have their own mechanisms for setting up new runtime systems. In the Java world, we expect to package our application with all of its dependencies and deploy it to little more than a JVM and webapp container.

Java has the classpath abstraction to address minimizing file system dependencies while Ruby uses the file system directly and extensively. I’ve seen a couple approaches for addressing this mismatch between Java and Ruby. All of them involve taking some set of resources packaged in a Java archive (jar, war), extracting it to a file system location at runtime and configuring Ruby to use the resources at that location. The “jruby-complete” JRuby distribution unpacks the core Ruby libraries into ~/.jruby/. GoldSpike, the Rails plugin for packaging Rails applications as war files, bundles gems in WEB-INF and configures GEM_HOME at runtime to use the gems from the unpacked war.

I decided to take a similar approach with JRubyGems – bundle gem dependencies in the application classpath and install them on the local file system on demand if they are not already available. As I expect happens with many JRuby projects, it took a little Java and a little Ruby and works quite well.

How It Works

The main flow for RubyGems to load a gem that has not yet been loaded for an application is:

  1. Kernel::gem
  2. Kernel::activate_gem_with_options
  3. Gem.activate
  4. Gem.source_index.find_name
  5. Gem.activate each dependency of this gem first
  6. Finish activating this gem

JRubyGems replaces the Gem.activate implementation to insert a couple steps that:

  1. Check if the gem is locally installed
  2. Search the Java classpath for the gem source if not installed
  3. Install the gem locally
  4. Continue with the base Gem.activate implementation

This ensures that gems and their transitive dependencies are installed and loaded.

The classpath searching is implemented in Java.

Release History

0.3 2008-01-28

  • Upgrade to use JRuby 1.1RC1 and RubyGems 1.0.1 (bundled with 1.1RC1)
  • Added test for gem that bundles a jar in lib/ (hpricot)

0.2 2008-01-07

  • Resolved issues with transitive dependency installation
  • Force install of classpath gems to avoid dependency errors
  • Additional logging of install locations

0.1 2008-01-04

Initial release.

Thoughts on JRuby

At Carbon Five we have built our professional consulting practice on the solid foundation of enterprise Java development. In 2007 we added Ruby and Ruby on Rails as development tool and framework that complement our existing values and process in many fantastic ways.

Looking forward, I want to be sure that we take maximum advantage of our existing knowledge and new learning in both Java and Ruby. I have high hopes for JRuby as a valuable bridge that spans both languages and gives developers the flexibility to use the strengths of the two. Sun appears to feel the same way as they have hired the two core JRuby developers, Charles Nutter and Thomas Enebo, to work on JRuby full time.

In preparation for more specific posts, here are some light musings on JRuby.

JRuby 1.0

Released mid-2007 JRuby 1.0 was focused on Ruby compatibility. The idea is that any Ruby script or application you can run with the native C Ruby interpreter, you can run with JRuby. The success of this effort can be observed with Ruby on Rails applications now running on JRuby. Of course, there are some limitations.

In addition to running pure Ruby, JRuby can access the Java environment in which it is running. You get the Ruby niceties that you would expect like optional conversion of CamelCase method names to underscore_separated.

list = java.util.ArrayList.new
list.add("one")
list.add_all [2, "three"]

Any Java classes in the Java classpath are available to your JRuby script. Additionally, you can ‘require foo.jar’ to make it available on your classpath at runtime.

You can also extend Java classes in JRuby.

class MyList < java.util.ArrayList
  def say_hi
    "hi"
  end
end

Internally, many core Ruby classes have been rewritten to delegate to core Java classes.

JRuby 1.1

JRuby 1.1 is presently in beta. The top priorities for JRuby 1.1 are performance and Java integration. Ruby is not fast. JRuby 1.0 was worse. Performance was not a priority for 1.0 and the consensus is that there are a lot of easy performance wins that it is now time to take advantage of. In his blog, Charles Nutter states:

Straight-line execution is now typically 2-4x better than Ruby 1.8.6. Rails whole-app performance ranges from just slightly slower to slightly better, though there have been reports of specific apps running many times faster.

Java Integration

Java integration refers to features for the using Ruby from Java rather than Java from Ruby as I discuss above. When I first started looking at JRuby Christian and I were working on a Java library to manage database migrations ala RoR and some other neat tricks we’ve seen along the way. (More on that later.) I thought it would be cool if you could write migrations using ActiveRecord’s migration features and invoke them from Java. I found myself looking for the easy means to invoke Ruby from Java. Some of this is in place with more slated for future JRuby versions.

The Spring Framework provides JRuby integration through which you can expose Ruby classes as Spring-managed beans. This example of using the RedCloth Ruby library to format text in a Java application is a pretty slick example of how this works.

This post does point out one issue that I ran into with using Ruby from Java – RubyGems. Gems are Ruby libraries available from central repositories and installed on the system running Ruby. For Java applications, this dependency on system-installed resources is lame. To address this issue, I’ve spent some time working on a solution for packaging Ruby gem dependencies in Java applications. More on JRubyGems coming soon.