Paul Barry

Customizing Generators in Rails 3

January 13, 2010

As you probably already know, Rails 3 is just around the corner. There are some pretty nice features being added and one of them is the ability to customize the way the generators work. I personally prefer Haml over ERB, RSpec over Test::Unit and Factory Girl over Fixtures. So let’s see how we can configure a Rails 3 app to do that.

First, follow Yehuda’s instructions on how to create a Rails 3 app. Next, you have to tell Rails that you want to use Haml, RSpec and Factory Girl. First, add this somewhere in the Gemfile:

gem "haml"

only :test do
  gem "rspec"
  gem "rspec-rails"
  gem "factory_girl"
end

Then, re-run the bundler and initialize the Haml plugin:

$ gem bundle
$ bin/haml --rails .

Finally, you have to install the custom generators for the frameworks that you want to use. I found a repo on github that already had RSpec, so I forked it and added Haml and Factory Girl. Clone the repo into the lib/generators directory of your app:

$ git clone git://github.com/pjb3/rails3-generators.git lib/generators

Now, in the config/application.rb file in your app, near the bottom there is a section related to config.generators. Put this in that section:

config.generators do |g|
  g.template_engine :haml
  g.test_framework :rspec, :fixture => true, :views => false
  g.fixture_replacement :factory_girl, :dir => "spec/factories"
end

Here is where we reap the benefits of the modularity in Rails 3. What this says is that we want to use Haml as the template enging, we want to use RSpec as the test framework and we want to generate fixtures with our generated specs, but we don’t want to generate view specs and that instead of fixtures, we actually want to use factory girl and we want the factories to be put into spec/factories. Whew! So does this all work?

$ script/generate rspec:install
$ script/generate scaffold person name:string dob:date age:integer male:boolean bio:text

At this point you should see that Rails has generated what we want, which is scaffolding that uses Haml for the views, RSpec for the tests and Factory Girl for the fixtures. Run the migrations, start the server and open the browser http://localhost:3000/people to see your scaffolding in action.

Now if you try to actually run rake spec, you’ll get an error, at least I do. I’m not sure that RSpec 1.X is going to ever work with Rails 3. I think the intent is for RSpec 2 to be compatible with Rails 3, so keep an eye out for that.

Guarding Logger Statements In Ruby

December 9, 2009

Whether you are a Java or a Ruby programmer, I’m sure you are familiar with this idiom:

require 'logger'

log = Logger.new(STDOUT)
log.level = Logger::INFO

log.debug("hello")
log.info("Done")

That’s a simple logger where the log level is set to info, so the debug statement isn’t logged, but the info statement is. One gotcha to look out for is something like this:

require 'logger'

log = Logger.new(STDOUT)
log.level = Logger::INFO

def fib(n)
  if n < 1
    0
  elsif n < 2
    1
  else
    fib(n-1) + fib(n-2)
  end
end

log.debug("fib(30) => #{fib(30)}")
log.info("Done")

This also just logs “Done”, but it take more than a few seconds to do so. The reason why is that even though you aren’t logging the string that gets passed to debug, the ruby interpreter still has to incur the cost of generating the string and passing it to debug, where it gets ignored.

If you are an old Java programmer like me, you’ll probably know you can fix it like this:

require 'logger'

log = Logger.new(STDOUT)
log.level = Logger::INFO

def fib(n)
  if n < 1
    0
  elsif n < 2
    1
  else
    fib(n-1) + fib(n-2)
  end
end

if log.debug?
  log.debug("fib(30) => #{fib(30)}")
end
log.info("Done")

That works, but it’s not the Ruby way of doing it. It’s the idiomatic way of doing it in Java, but that is due to the fact that Java doesn’t have anonymous functions nor a concise syntax for creating them. The Ruby way of doing it is:

require 'logger'

log = Logger.new(STDOUT)
log.level = Logger::INFO

def fib(n)
  if n < 1
    0
  elsif n < 2
    1
  else
    fib(n-1) + fib(n-2)
  end
end

log.debug { "fib(30) => #{fib(30)}" }
log.info("Done")

The difference between this version and the original is that instead of passing a string to debug, we pass a block that returns a string when it is called. We don’t have to wrap it in an if statement because the block can be conditionally evaluated based on the current log level.

The difference between the if statement and the block is admittedly minor. That being said, prefer the block syntax. :)

The important thing to remember is that if you have a debug statement that does any kind of calculating, pass it a block instead of just a string to avoid the overhead associated with unnecessarily building the string.

Posted in Technology | Topics RubyOnRails, Ruby, Java | 2 Comments

Performance Testing with Httperf

November 10, 2009

If you need to do some performance testing of your web app, one tool that is pretty easy to use is httperf. I recommend watching the Peepcode screencast on httperf to get some good tips on how to doing performance testing. There is also some reading material on httperf created by Ted Bullock available. These are great resources, but here’s the quick and dirty on how to get httperf going.

First, to install httperf, if you are using Macports, you can simply do sudo port install httperf, which is what I did. Alternatively, you can get httperf from the httperf download page.

Once you’ve got it installed, make sure the site you are testing on is running with all the production settings turned on. The Peepcode screencast goes into detail about how to do that for a Rails app. Then, if you are trying to test the /profile page on myfancysocialnetwork.com, you would run a command like this:

httperf --server myfancysocialnetwork.com --port 80 --uri /profile --num-conns 100

This will hit the profile page 100 times and report back with statistics like the minimum response time, maximum response time and the average response time, including standard deviation. You will certainly want to adjust the --num-conns option based on the page you are testing. If it’s a pretty slow page with response times over a second or two, then 100 is probably ok. If it’s a more well behaved page that renders in a few hundred milliseconds, then a large number like 10000 might be better. The goal is to make sure that it runs long enough to generate enough samples to make the results statistically relevant. You’ll also want to read the documentation/watch the screencast to get info on other options like rate to create different kinds of test scenarios.

Posted in Technology | Topics Httperf | 2 Comments

How To Write A Spelling Corrector In Ruby

November 5, 2009

If you haven’t seen it before, Peter Norvig has a spelling corrector that is written in just 21 lines of Python code (not counting blank lines and the import). He also lists a few other implementations in other languages, include one in Ruby. The Ruby one was listed as 34 lines. I was surprised that it was that many lines more in Ruby, so I wanted to give it a try. I didn’t look at the Ruby solution first and here’s what I came up with:

require 'set'

def words(text)
  text.downcase.scan /[a-z]+/ 
end

def train(features)
  features.inject(Hash.new(1)){|model, f| model[f] += 1; model }
end

NWORDS = train(words(File.open('big.txt').read))

ALPHABET = 'abcdefghijklmnopqrstuvwxyz'.split //

def edits1(word)
  s = (0..word.size).map{|i| [word[0,i], word[i,word.size]]}
  deletes    = s.map{|a,b| !b.empty? ? a + b[1..-1] : nil}.compact
  transposes = s.map{|a,b| b.size > 1 ? a + b[1].chr + b[0].chr + b[2..-1] : nil}.compact
  replaces   = s.map{|a,b| !b.empty? ? ALPHABET.map{|c| a + c + b[1..-1]} : nil}.flatten.compact
  inserts    = s.map{|a,b| ALPHABET.map{|c| a + c + b}}.flatten
  Set.new(deletes + transposes + replaces + inserts)
end

def known_edits2(word)
  s = edits1(word).map do |e1| 
    edits1(e1).map{|e2| NWORDS.include?(e2) ? e2 : nil}.compact
  end.flatten
  s.empty? ? nil : Set.new(s)
end

def known(words)
  s = Set.new(words.find{|w| NWORDS.include?(w)})
  s.empty? ? nil : s
end

def correct(word)
  candidates = known([word]) || known(edits1(word)) || known_edits2(word) || [word]
  candidates.max{|a,b| NWORDS[a] <=> NWORDS[b] }
end

To run this, download the data file, put the code in a file called spelling.rb, then start up IRB:

$ wget http://norvig.com/big.txt
$ irb -r spelling -f --simple-prompt
>> correct "speling"
=> "spelling"
>> correct "korrecter"
=> "corrected"

This one weighs in at 30 lines. I tried to do this as close to the Python implementation as possible. I also tried to use idiomatic Ruby. You could shave the number of lines down below 21, but it wouldn’t meet any reasonable Ruby style guidelines. I’m still probably cheating a little as a few of those lines are approaching 100 characters, but it’s at least reasonable, in my opinion. Here are some things I noticed that caused the Ruby version to be longer or less clear:

  1. end vs. significant indentation

    6 of the lines are just an end statement. Python uses indentation to end methods, so the end statements aren’t needed in Python. This adds more lines, but has trade offs. I actually really like the idea of significant indentation, it’s one of the reasons that I’m such a big fan of Haml. But it falls down in certain places. For example, Ruby has Embedded Ruby, which looks similar to JSP or PHP, but it’s actually trivial to implement the basic cases. It truly is embedded Ruby, because the code between the <% %> and <%= %> tags is just ruby code. You commonly see things like this:

    <% if logged_in? %>
      Welcome, <%= current_user.login %>
    <% else %>
      Howdy Stranger!
    <% end >
    

    You can’t do this in Python because of the lack of the end statement. This is why I’m surprised Haml was invented in Ruby and not Python. In Python, it fits with the language and is actually necessary, whereas in Ruby, significant indentation isn’t part of the language and ERB is actually pretty good. There is a Python port of HAML, but I’m not sure how well that works or how widely it is used in the Python community.

  2. List Comprehensions vs. Blocks

    Python and Ruby, compared to C, Java, etc., have very powerful, concise syntax for iterating through and transforming collections, but they are very different. Python uses list comprehensions and Ruby uses blocks. As you can see above, there are certain cases where list comprehensions are very compact. List comprehensions can have a guard, which is a little cleaner than the Ruby equivalent where you have to return nil if the guard doesn’t match and then compact that result. Also, when you want to iterate over two lists, you can do so with mutliple for statements, whereas in Ruby you do nested blocks and then flatten the result.

  3. Collection Slicing

    Python has a little cleaner, more consistent syntax for breaking up collections into sub collections. It also treats strings as a collection of characters more consistently.

  4. Truthiness

    In Python, many things are considered false. I’m not sure what the entire list is, but it seems to include empty collections (and therefore empty strings) as empty. Since Ruby only treats nil and false as false, we have to return nil instead of an empty set from the known and known_edits2 methods, so that the series of statements in the first line of the correct method will work correctly.

In summary, in this case, the Python code is shorter and clearer, but it’s pretty close. I’m sure there are other code examples where the Ruby code would be a little shorter, but I do think in general, Ruby and Python are going to be pretty close in terms of code clarity and number of lines of code.

Posted in Technology | Topics Python, Ruby

Ain't Nothing But A G Thang

October 9, 2009

You’ve probably seen more than a few articles on the web showing how to build a Rack app. If not, here’s a good one to start with. You’ll quickly see that building a Rack app is really simple, which is why Rack is awesome, because it’s simple. But what about writing a Rack-compliant server? Well it turns out that is pretty easy as well.

I just pushed a little Rack-compliant HTTP Server that I wrote using GServer to github. The whole thing is less than 200 lines of code. The core of it is short enough that I can explain how it works here.

First, GServer. GServer, which is short for “Generic Server” makes it pretty simple to create a multithreaded TCP Server. Taking out some error handling code, here’s what the GServer looks like for our Rack HTTP Server:

module GThang
  class HttpServer < GServer

    attr_reader :port, :rack_app

    def initialize(options={})
      @port = options[:Port] || 8080
      @rack_app = options[:rack_app]
      super(@port)
    end

    def serve(socket)
      RackHandler.new(socket, rack_app, port).handle_request
    end

  end
end

So all there is to a GServer is basically a serve method. This will be called each time a client connects to the server. The argument to the method is the client socket connection. You read and write data from the socket as you see fit for your application. As you can see here, we just pass the socket, along with the rack app and the port to the RackHandler initializer and then call handle_request on that. We’ll look at how you setup the rack app in a minute, but first let’s take a look at the meat of what the RackHandler does. The handle_request method looks like this:

def handle_request
  return unless add_rack_variables_to_env
  return unless add_connection_info_to_env
  return unless add_request_line_info_to_env
  return unless add_headers_to_env
  send_response(app.call(env))
end

So what happens is the various add_ methods build up the rack environment. Once the environment is ready, we call the rack app. The rack app responds with the standard 3 element array, which we pass off to the send_response method, which writes the actual http response to the client. Take a look at the full code for this on github for the details.

Now the fun part is that we now have a fully functional HTTP server that is capable of acting as a file server or serving a Rails app. All we have to do is give the HttpServer the correct Rails app. If you look in the examples, you see this for the file server:

GThang::HttpServer.run(
  Rack::CommonLogger.new(
    Rack::Lint.new(
      Rack::Directory.new(root, Rack::File.new(root)))),
  :Port => 8080)

Now I choose to write it this way to make it clear what is actually happening. You will normally see the builder DSL used to configure a rack app, which would look like this:

use Rack::CommonLogger.new
use Rack::Lint.new
use Rack::Directory.new(root)
run Rack::File.new(root)

This is obviously a lot cleaner, but to understand how Rack works, you have to realize that all this is doing is what we see in the first example. A Rack app with Rack middleware is simple a chain of apps that call the next app in the chain, possibly modifying the environment or response before or after the rest of the chain is called.

So there you have it, beauty in simplicity.

Posted in Technology | Topics Rack, Ruby, Rails | 8 Comments