• Applying Ruby’s Blocks Sep 9, 2008

    Posted by Mike Naberezny in Ruby

    Not long ago, we took a look at the basics of Ruby Block Scope. When you’re first getting started with Ruby’s blocks (closures), little things like that can be frustrating. Blocks can seem so foreign that you might be tempted to think that they’ll make your code more difficult to read or understand. Once you get past the learning curve, blocks can be leveraged to improve the readability and maintainability of code in some situations.

    Here’s a few examples of applying Ruby’s blocks to everyday problems.

    Handling Timeouts

    Ruby’s Timeout library is used to ensure that a block of code doesn’t execute longer than a certain amount of time. This is a handy feature since the block can wrap many operations which might not otherwise support a configurable timeout.

    require 'timeout'
    
    Timeout::timeout(20) do
      # Potentially long-running code
    end
    

    The Timeout::timeout method takes a timeout value in seconds. If the block takes longer to execute than the timeout value, it will be interrupted.

    Working with Files

    In PHP, file_get_contents and file_put_contents provide convenient ways to quickly read and write files. Often, we need to do a bit more. It’s common to open a file, perform some operations on it, and then close the file.

    $f = fopen('/path/to/foo', 'w') ;
    fwrite($f, 'foo') ;
    fclose($f);
    

    Ruby’s File.open can be used like above but it can also be passed a block.

    File.open('/path/to/foobar', 'w') do |f|
      f.write 'chars'
    end
    

    When the block exits, the file will automatically be closed. This is a best practice for working with files in Rails applications.

    The block version is nice from a maintenance perspective. It’s easy to accidentally remove the call to fclose and doing so won’t produce an obvious error. However, removing the block’s end will cause a parse error. In PHP, this is not so much of an issue because PHP will close any file handles left open at the end of each request.

    Performing Benchmarks

    Within the context of the Rails framework, you can call the benchmark method within a controller action. Given this action:

    def show
      @user = User.find(params[:id], :include => [:preferences])
      # ...
    end
    

    Just put a block around a piece of code to measure it:

    def show
      benchmark do
        @user = User.find(params[:id], :include => [:preferences])
      end
      # ...
    end
    

    The result of the benchmark will be output to the log, such as log/development.rb. There is also a benchmark helper method available in all views that does the same. The Ruby standard library also has a Benchmark library you can use outside of Rails.

    Changing the Directory

    If you’ve ever written a command line script that had to temporarily change the working directory to perform some operations, it might have looked something like this:

    $here = getcwd();
    chdir('/path/to/somewhere/else');
    // perform some operations
    chdir($here);
    

    You can do the above almost verbatim in Ruby also. However, a better way to temporarily change the directory is to pass a block to Dir.chdir.

    Dir.chdir('/path/to/somewhere/else') do
      # perform some operations
    end
    

    The working directory will be changed before entering the block, and automatically changed back when the block closes. Not only is it cleaner, it makes your scripts easier to maintain since you can’t accidentally remove the returning Dir.chdir.

  • Horde/Routes 0.3 Released Jun 15, 2008

    Posted by Mike Naberezny in PHP,Python,Ruby

    Horde/Routes is a URL mapping system for PHP 5. It is a direct port of the Routes, a Python library that is part of the Pylons project. Horde/Routes is a standalone library designed to be integrated into any MVC framework.

    This release brings in some changes from Routes 1.8. The most noticeable change is that custom actions on RESTful routes are now delimited with the forward slash (/) instead of the semicolon (;). This was done for parity with Ruby on Rails.

    I have also fixed some bugs, notably that the resource route generator failed to generate routes that recognized PUT and DELETE requests on “formatted” resources (/messages/1.xml). This fix will be merged upstream to the Python version.

    I am also using the Python version and I met with Ben Bangert, the author of the Python version, at PyCon 2008. Each release of Horde/Routes has resulted in patches to the Python version. It’s nice how this small ecosystem has developed around the routes concept between these projects (Ruby on Rails, Pylons, and our work in Horde).

    Since Horde/Routes 0.3, the default RESTful routes generated by Horde/Routes are fully compatible with the latest version of ActiveResource. We have a new project at work that is using Horde/Routes and ActiveResource together and it works well.

  • Deploying on Phusion Passenger May 13, 2008

    Posted by Mike Naberezny in PHP,Ruby

    A very large number of PHP developers, perhaps even the majority, are building smaller web applications. These applications receive only a moderate amount of traffic and usually have a single database server, often on the same machine.

    Deployment, or moving your application to production for use by real customers, is largely an afterthought for these small PHP applications. In many cases, decent PHP code can just be installed on the server and it runs without much trouble.

    One of the points we stress towards the back of our book is that deploying Rails applications can be more difficult than deploying their PHP counterparts. There are more moving parts and things to you’ll need to learn. Until you get the hang of it, deploying even small Rails applications can be frustrating.

    A recent development has greatly improved this situation.

    Introducing Phusion Passenger

    PHP can be deployed using a variety of server configurations. Some of these can be just as frustrating as traditional Rails deployments. However, the majority of PHP applications are still deployed on Apache using mod_php. PHP’s tight integration with Apache is simple, proven, and just works for many needs.

    Phusion is a small company in the Netherlands that recently released an open source product called Passenger (mod_rails). Passenger aims to take the complexity out of deploying Rails applications by also integrating with Apache.

    Installing Passenger on the average Linux or Mac server is usually simple. It is installed as a gem and contains an automated installer program that compiles and installs the necessary components. Once installed, many Rails applications can be deployed under Apache simply by configuring a VirtualHost for each application. The installer even outputs an example for you to copy and paste.

    Passenger gives a deployment experience closer to what we’ve come to appreciate with PHP. In the background, there’s still more moving parts, but Passenger automatically manages them. It spawns Rails application server processes, proxies to them, and largely eliminates the configuration and glue that other Rails deployment options leave up to you. Passenger has nice documentation for when some configuration is necessary.

    At work, we develop applications in both PHP and Ruby. We’ve been testing Passenger for a few weeks on a dedicated server and recently deployed an application on it. We have been very impressed with its reliability, performance, and easy-of-use compared to previous Rails deployment options. You should give Passenger strong consideration, especially if you’re just starting out.

    Finally, Rails on Shared Hosting

    Traditionally, deploying Rails applications on shared hosts (usually with FastCGI) has been difficult and unreliable. Due to this, many Rails applications are deployed on small VPS plans from providers like Rimuhosting and Slicehost. These run well, typically using small Mongrel cluster behind a frontend proxy balancer. However, VPS plans are usually more expensive and more work to set up and maintain than shared hosting.

    Passenger makes running Rails applications on shared hosting much better. Dreamhost, a major shared hosting provider, recently announced full support for Passenger. We tested a small Rails application on Dreamhost using it and we were impressed. It seemed to run without issues and with reasonable performance.

    Deploying some Rails applications on shared hosting may soon become commonplace.

    Thinking Ahead

    Will better Rails deployment options or Rails on shared hosting mean it’s time to switch from PHP? No. It’s unlikely this blog will switch from WordPress anytime soon and Phusion’s own blog even runs on WordPress. There are many great PHP applications out there. More importantly, sometimes PHP will simply be a more appropriate solution.

    PHP, Ruby, and Rails are all great tools you can choose from. You’ll still need to learn these tools, their relative strengths, and when it’s appropriate to apply each.

    Passenger just means Rails deployment is getting simpler and more mature. It also means deploying PHP and Rails applications together on the same Apache instance is now much easier. These are more reasons to consider adding Rails to your toolbox. It’s certainly a great time to be building web applications.

  • Parsing Quoted Strings in Ruby Apr 28, 2008

    Posted by Mike Naberezny in Python,Ruby

    Python has a nice module in the standard library called shlex that parses strings as a Unix shell would. Here’s a Python interpreter session demonstrating its usage:

    >>> import shlex
    >>> shlex.split('foo "bar baz" qux')
    ['foo', 'bar baz', 'qux']
    

    It’s useful for creating your own mini-languages or external DSLs that need to parse quoted strings like the one shown above.

    We recently built an inventory tracking application in Ruby that has a user interface for selecting search filters. To expose the same search capabilities as a web service, we created a simple query language. I was looking for an shlex equivalent in Ruby.

    It turns out that the Ruby Standard Library has a module called Shellwords:

    >> require 'shellwords'
    => true
    >> Shellwords::shellwords('foo "bar baz" qux')
    => ["foo", "bar baz", "qux"]
    

    Shellwords is a little less capable than shlex but handles the most common use case just fine. It’s a convenient solution for a problem that comes up too often.

    Update: Ruby 1.8.7 has added the shortcut methods Shellwords.split and String#shellsplit. Very nice.

  • Fail Early Mar 25, 2008

    Posted by Mike Naberezny in Ruby

    I’m pleased to have been able to contribute a recipe to Mike Clark’s new book, Advanced Rails Recipes. The concept presented in my recipe, “Fail Early”, is that you can use initializers to prevent your application from starting up under certain conditions.

    Rails applications typically run under persistent application server processes, like mongrel or thin. When a Rails application starts, it goes through a startup procedure that is performed only once. The startup includes reading the environment configuration files and running any initializers that have been set up. This can also be used as an opportunity to detect potentially dangerous situations and bail out.

    “Fail Early” uses the case of pending migrations to demonstrate. If the application is started while there are pending migrations for the production database, the results can wreck production data. Instead, an initializer detects this condition and exits by calling Ruby’s Kernel.abort.

    Here’s another case where this idea is useful. It’s well-known that the Ruby-based MySQL driver included with Rails isn’t suitable for use in production. In fact, Rails will produce this warning in the log if it is in use:

    WARNING: You’re using the Ruby-based MySQL library that ships with Rails. This library is not suited for production. Please install the C-based MySQL library instead (gem install mysql).

    This can go unnoticed in the log. Instead, we can write a short initializer that detects this condition and aborts the application start if the production server is misconfigured.

    config/initializers/check_mysql_driver.rb:

    if RAILS_ENV == 'production'
      config = ActiveRecord::Base.configurations['production']
      if config['adapter'] == 'mysql'
        ActiveRecord::Base.require_mysql
        if Mysql::VERSION.to_s.include?('-ruby')
          abort "Ruby-based MySQL driver is not suitable for production"
        end
      end
    end
    

    When the initializer above is run in a production environment that has the Ruby-based MySQL driver instead of the C-based one, startup will be aborted.

    $ mongrel_rails start -e production
    ** Starting Mongrel listening at 0.0.0.0:3000
    ** Starting Rails with production environment...
    Ruby-based MySQL driver is not suitable for production
    $
    

    You can run many other safety checks like this at startup. Since they will be run only once and not per-request, your application incurs no performance penalty by doing so.

  • Ruby Block Scope Feb 18, 2008

    Posted by Mike Naberezny in Ruby

    Ruby’s blocks, or closures, are a feature that does not have a direct equivalent in PHP. We devote a fair number of pages to this topic in the book. Even so, it will take a bit of time and practice before you feel completely comfortable with them. Let’s take a look at an easy way that Ruby’s block scoping might trip you up.

    In this example, we have an array of fruit. We want to iterate through the array and print the name of each fruit. At the end, we want to print the name of the last fruit again.

    $fruit = array('apple', 'banana', 'orange');
    foreach ($fruit as $f) { print "$f, "; }
    
    print $f;
    

    Note: the purpose of this and the following examples is to demonstrate variable scoping. They are not intended to be the shortest or most efficient ways to perform the tasks.

    As you probably expected, here’s the output of the above program:

    apple, banana, orange, orange
    

    This works because PHP has simple scoping rules. Within a function, any variables that get defined are available any time later in the function. Variables defined before constructs like foreach() and while() are available inside those constructs. Variables defined inside those constructs are defined in the same scope and are available outside of those constructs, like $f above.

    When you first start writing programs in Ruby, you’ll probably start out by converting bits of your PHP programs over before you get into the swing.

    With that in mind, let’s now try directly converting our PHP program to Ruby:

    fruit = %w[apple banana orange]
    fruit.each { |f| print "#{f}, " }
    
    print f
    

    If you’re wondering about the %w, that’s a word array (see Useful Perlisms in Ruby for this and other tricks). Otherwise, this looks very similar to the PHP version.

    However, you might find the results to be unexpected:

    apple, banana, orange,
    NameError: undefined local variable or method 'f'
    

    In Ruby, scoping is lexical. There can be many levels of scope and scope can even be manipulated. When a block is called in Ruby, it is bound to the scope of its caller. This means that within the same method, variables defined above the block are available inside the block. However, variables defined within the block are not normally available outside the block. In the example above, Ruby raised a NameError because f was only defined within the block, not above it.

    If you really needed to do the example in Ruby, you could define a variable above the block to store the last value through the iteration.

    fruit = %w[apple banana orange]
    last_fruit = nil
    
    fruit.each do |f|
      print "#{f}, "
      last_fruit = f
    end
    
    print last_fruit
    

    Since the last_fruit variable is defined above the block, it is available both inside and below the block. The program now works as you might expect.

    While that helps us begin to understand Ruby’s scoping and gets the job done, a much simpler and more idiomatic Ruby solution for this particular problem would be this:

    fruit = %w[apple banana orange]
    fruit.each { |f| print "#{f}, " }
    
    print fruit.last
    

    The Array#last method is the equivalent of PHP’s end(). By just using it instead, our code is both more concise and readable.

  • Useful Perlisms in Ruby Jan 3, 2008

    Posted by Mike Naberezny in Ruby

    PHP syntax shows obvious similarities to Perl. For example, we have the prefixing of variables ($), the arrow for object access (->), and semicolons terminating our statements. While it’s perhaps less obvious to PHP developers at first, Ruby’s syntax has also been influenced by Perl in various ways.

    Ruby has quite a few interesting syntax features, some inspired by Perl and some not, that are sometimes lumped together as the “Perlisms” in Ruby. Let’s explore a few of the more useful ones you’ll likely encounter in Rails applications.

    Word Arrays

    Ruby has a very convenient syntax for arrays:

    days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
    

    However, if your array elements are words (no spaces), you can do one better.

    days = %w[Mon Tue Wed Thu Fri]
    

    The %w array modifier allows you to write more readable arrays of words by omitting the noise of the quotes and commas.

    Regular Expression Matches

    In PHP, regular expressions are written inside strings. These strings are passed to functions like preg_match() that perform the matching:

    $text = 'You have 12 new messages';
    
    if (preg_match('/(\d+) new/', $text, $matches)) {
      print "Found {$matches[1]} messages";
    }
    

    Ruby’s regular expressions aren’t written inside strings because they have a native syntax supported by the language. We can write the above example as:

    text = 'You have 12 new messages'
    
    if matches = /(\d+) new/.match(text)
      puts "Found #{matches[1]} messages"
    end
    

    Since /(\d+) new/ is itself an object, we can call the match method on it. The snippet otherwise looks similar to the PHP version.

    However, there’s another way:

    text = 'You have 12 new messages'
    
    puts "Found #{$1} messages" if text =~ /(\d+) new/
    

    You can use the =~ operator to test if a regexp matches and !~ to test if it doesn’t. Also, Ruby automatically assigns the regexp matches to special variables. $1 is the first match, $2 is the second match, and so on.

    Finally, we reversed the conditional to shorten the snippet a bit.

    Grouping Thousands

    Have you ever needed a fairly large numeric literal?

    bytes = 1048576
    

    You might appreciate that Ruby allows you to use underscores in numbers.

    bytes = 1_048_576   # Ruby's Grouping
    
    bytes = 1.megabyte  # Rails' ActiveSupport
    

    You can use the underscore to group thousands or whatever you like, and Ruby will just filter it out. For common numbers like byte multiples, Rails takes it to another level of readability with special methods like megabyte shown above.

    Parting Thoughts

    There’s quite a few other so-called Perlisms in Ruby. Some are great, and some aren’t so great. For example, you can access Ruby’s load path with the readable $LOAD_PATH variable or the cryptic $: variable. This post from Nick Seiger has some really obscure features of Ruby.

    Ruby’s language design makes programming very convenient, but it’s power is that its allows us to write intuitive programs that often read like natural language. When you abuse the syntax features, you only make code harder to read.

    Experienced PHP developers learn that there are some aspects of the PHP language, deprecated or not, that you might want to avoid for cleaner code. This is sometimes true of Ruby also, as with most programming languages.

    While the features demonstrated above are useful and popular, some features of Ruby aren’t popular in the Rails community at all. Most of the pre-defined variables that aren’t words fall into this category. In general, Rails developers always strive to write programs that are easier to understand and maintain.

    Becoming an effective Rails developer is not only learning the features of the Ruby language, but developing a sense of good taste for how to use those features.

  • Rails Hackfest Winner Dec 5, 2007

    Posted by Mike Naberezny in Ruby

    I was pleased to learn today that I am a winner in the Rails Hackfest.

    The Hackfest is a contest where your ranking is primarily determined by how many of your patches get accepted into Rails core during the contest month.

  • Keep the Flash and Test it, too. Sep 8, 2007

    Posted by Mike Naberezny in Ruby,Testing

    The flash in Ruby on Rails is a special hash that is stored in the session. Its contents are available to the next request and cleared out immediately after.

    This makes is very useful one-time events, such as an item being added to a shopping cart:

    flash[:success] = "#{cart.items.size} items added to your cart."
    

    The flash[:success] will be available for the next request only.

    However, Ajax requests will also clear the flash. This can lead to the sometimes mysterious problem of the flash contents disappearing before their intended request because an intermediate Ajax request caused them to be cleared.

    The solution is to explicitly preserve the flash contents in actions that could unintentionally clear it. This is done using flash.keep:

    flash.keep
    

    The current contents of the flash will then be preserved for the next request. You can also pass a specific key such as flash.keep(:foo).

    On one application I work on, we make Ajax requests periodically on a timer. Putting flash.keep in these Ajax actions was a simple way to make sure they didn’t unexpectedly gobble the flash contents.

    Of course, once adding flash.keep, we also want to add a functional test for it. You might try doing this:

    def test_something_keeps_flash
      @request.flash[:foo] = 'bar'
      xhr :get, :something
      assert_response :success
      assert_equal 'bar', @response.flash[:foo]
    end
    

    You’d be close but wrong. That would seem like a natural way to do it but unfortunately, the flash can’t be populated that way due to how TestRequest was built. It doesn’t have a flash attribute and the session doesn’t have a FlashHash. However, that won’t stop us from writing our test.

    We could try monkeypatching but I try to avoid clever things like that. This problem is easily remedied with a helper in test_helper.rb:

    def make_flash_hash(with_contents = {})
      returning ActionController::Flash::FlashHash.new do |flash_hash|
        flash_hash.update with_contents
      end
    end
    

    Our test case now can now use the simple make_flash_hash helper to populate the request’s session with flash:

    def test_something_keeps_flash
      @request.session['flash'] = make_flash_hash(:foo => 'bar')
      xhr :get, :something
      assert_response :success
      assert_equal 'bar', @response.flash[:foo]
    end
    

    In addition to using @request.session as shown above, you could also populate the session in the xhr method directly. I like the former for readability.

    Whichever way you choose to do it, writing the functional test will ensure that you’ll continue to preserve the flash when the application changes later.

  • Faster TDD with Stakeout.rb Sep 4, 2007

    Posted by Mike Naberezny in PHP,Ruby,Testing

    I’m a big fan of Autotest and it runs almost constantly on my machine. Autotest automatically reruns your tests whenever your files change. Instead of constantly flipping to another shell to rerun your tests, just let Autotest cheerfully do it for you in the background. It’s highly addictive.

    The only problem with Autotest is that it is specific to Ruby. I do a mix of different kinds of programming including Ruby, PHP, Python, and C. I’d like my TDD to be accelerated for all of these languages.

    Thanks to Geoffrey Grossenbach, last week I came across stakeout.rb from Mike Clark. This is a tiny, dead simple Ruby script that runs an arbitrary command when certain files change. This is a stripped-down Autotest for everybody else. I’m sure it has all kinds of other uses as well.

    To get started testing with stakeout.rb, you’ll need Ruby installed. Any recent version is fine and you might already have it installed. Next, grab the stakeout.rb script and add the shebang line to the top (Unix-like OS assumed):

    #!/usr/bin/env ruby -w
    
    if ARGV.size < 2
      puts "Usage: stakeout.rb  [files to watch]+"
    ...
    

    Make the file executable and put it somewhere in your PATH. You can test it out by typing stakeout.rb from an arbitrary directory and you should see the help message.

    Next, change over to a project directory where you have some test files. Most of the projects that I am involved with tend to use some directory structure similar to this:

    /project_name
      /lib
      /test
      ...
    

    To test such a project, run stakeout.rb from the /project_name directory. Most PHP projects using PHPUnit tend to have an AllTests.php file or equivalent to run all the tests, so we’ll assume this for the example:

    project_name$ stakeout.rb "php test/AllTests.php" **/*
    

    The first argument is what command to run when the tests change. The second argument, and any subsequent arguments, are the files to watch for changes. These can use a Ruby globbing pattern. The pattern **/* will watch all files under project_name recursively, which includes lib/ and test/.

    Once stakeout.rb is run, it will show no output but will sit and wait for changes. As soon as you change a watched file, stakeout.rb will automatically rerun you tests and will continue to do so until you exit with Control-C.