jherdman.ca

a programming blog

Open Ended Ruby Date Ranges

Have you ever needed an open-ended Date range in Ruby? Well, check this out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'date'

some_date = Date.today
tomorrow = some_date + 1
yesterday = some_date - 1

open_ended_range = (some_date..1/0.0)
# => ((2456206j,0s,0n),+0s,2299161j)>..Infinity

open_ended_range.include?(tomorrow)
# => true

open_ended_range.include?(yesterday)
# => false

Pretty rad stuff.

A Common Rails Controller Testing Antipattern

Here’s a run of the mill test for a Rails controller action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
describe PostsController do
  describe 'GET #show' do
    let(:post) { mock_model(Post) }

    before do
      Post.stub(:find => post)
    end

    it 'loads the requested resource' do
      get :show, :id => post.id
      expect(assigns(:post)).to eq(post)
    end
  end
end

This isn’t a horrible test, but there’s a common antipattern where we are requesting the resource: we’re explicitly using the record’s database ID, line 10. All ActiveRecord objects have a URI friendly name via the ActiveModel::Naming#to_param method. Let’s rewrite our test to use this method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
describe PostsController do
  describe 'GET #show' do
    let(:post) { mock_model(Post) }

    before do
      Post.stub(:find => post)
    end

    it 'loads the requested resource' do
      get :show, :id => post.to_param
      expect(assigns(:post)).to eq(post)
    end
  end
end

This insulates us from changes to how a resource might be represented in the URI, and more accruately represents how Rails internally handles your resource with URI helpers. For more of the gory details, check out ActionDispatch::Routing::PolymorphicRoutes.

Edit

  • Updated both examples to remove another common silly antipattern in my examples. A tip of the hat to @camwest.

Programming Goals for 2012

Ah, January. It’s a new year, and a time wherein we set new goals for the year. An important part of goal setting is visibility – not only being reminded of your goals, but being able to track and measure your progress towards attaining them.

Learn a Functional Language

I mostly do object oriented programming using Ruby on a day-to-day basis. It’s high time I learn a functional language. The paradigm shift will not only help me think in new ways, but it will open up new avenues of solving problems.

Here are some candidate languages:

  • Haskell
  • Clojure
  • Scheme
  • Erlang

I’ve been reading Learn You a Haskell, and I’m quite enjoying it, but Clojure has a certain appeal to me I can’t quite put my finger on yet.

Have a Better Understanding of the Foundations

I primarily work on HTTP APIs, but I don’t feel that I understand enough about HTTP, TCP/IP, and networking in general. I need to rectify this.

Publish More Blog Articles

I want to ensure my learnings have been captured and thought out, so I intend on blogging about them much more frequently than I have in the past. This article, in fact, is the first step towards this goal.

A Quick Cucumber Tip

DRY code makes me a happy camper, so when I see patterns in my regular expressions in my Cucumber stories, I get a little agitated. These patterns come up quick frequently if you are using the explicit record retrieval pattern in your stories. Here are some examples of the steps we want to refine:

1
2
3
4
5
6
7
8
9
10
Given /^I am a logged in user with the email address "([^"]+)"$/ do |email_address|
  user = User.find_by_email_address!(email_address)
  # etc
end

When /^I view the (\d+)(?:st|nd|rd|th) item$/ do |pos|
  within "#items .item:nth-child(#{pos})" do
    # etc
  end
end

Note the "(["]+)" and (?:st|nd|rd|th) patterns. Let’s extract those patterns so that we never have to type them out again.

The key to this is to recognize that Cucumber automatically loads all Ruby files in the “support” and “step_definitions” directories. Let’s create a file called “constants.rb” in “support”. Here’s mine:

We can now rewrite our step definitions above to use these constants:

1
2
3
4
5
6
7
8
9
10
Given /^I am a logged in user with the email address #{PHRASE}$/ do |email_address|
  user = User.find_by_email_address!(email_address)
  # etc
end

When /^I view the (\d+)#{POSITION} item$/ do |pos|
  within "#items .item:nth-child(#{pos})" do
    # etc
  end
end

Now we have cleaner steps, with less repetition, and they should take us a little less time to write out in the future. Use, abuse and fork my module above.

A Quick Vim Tips – Using Markdown

Vim is my text editor of choice. It doesn’t have all of the niceties of TextMate, so you often have to assemble them yourself through user scripts and configuration. One of those areas that Vim needed a little assistance in was its support of Markdown. The following are some quick tips for improving Vim’s handling of Markdown.

Get Better Syntax Support

Ben Williams has written a fairly good syntax definition for Markdown. It’s unfortunately not on Vim’s script index, so you’ll just have to grab it from his blog.

Preview Support

Chances are your package management system has Discount available. Install it. Once you do so, you’ll have a command line tool called “markdown” at your disposal. Once you do so, open up your vimrc and add the following to it:

1
2
3
" Markdown preview
imap <leader>p <ESC>:w!<CR>:!markdown % < %.html && open %.html<CR><CR>a
map  <leader>p <ESC>:w!<CR>:!markdown % < %.html && open %.html<CR><CR>a

This will generate a preview of your Markdown file that you are currently viewing. If you’re really clever, you’ll also add “*.mkd.html” to your gitignore file so that you don’t have to worry about the generated preview.

Soft Wrap Your Document

Head on over to Vim Casts to learn about how to use soft word wrapping in your documents. I find soft wrapped text much more natural looking when writing documents.

Public Asset Bundling in Rails

IMPORTANT NOTE

The below is kept merely for historical purposes. You should not use the techniques described below as Rails’ Asset Pipeline is a much better option


Sometimes, in larger Rails projects, we want to group together JavaScript or CSS files. Let’s use the the Uploadify project to illustrate how we can use a seldom discussed Rails feature to simplify inclusion of CSS and JavaScript files that are used in conjunction with each other: ActionView::Helpers::AssetTagHelper.

Materials

Considering the Norm

Rails defines a set of default JavaScript files to include in our view when we use #javascript_include_tag(:default). From the Rails documentation we can see an example of the output:

1
2
3
4
5
javascript_include_tag :defaults # =>
    "<script type='text/javascript' src='/javascripts/prototype.js'></script>
    <script type='text/javascript' src='/javascripts/effects.js'></script>
    ...
    <script type='text/javascript' src='/javascripts/application.js'></script>"

This is called an expansion. We have expansions for JavaScript and Stylesheets. We can use with both #javascript_include_tag and #stylesheet_link_tag. We can also register our own. It’s through expansions that we can bundle together JavaScript and and CSS files.

Registering Expansions

Registering expansions is done through two different methods: ActionView::Helpers::AssetTagHelper.register_javascript_expansion, and ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion. Each of these methods takes a Hash as an argument which points to a list of asset names (e.g. “jquery.js”).

Let’s look at how we would define the default :default for our JavaScript bundle:

1
2
3
4
5
6
ActionView::Helpers::AssetTagHelper.register_javascript_expansion :default => [
  'prototype',
  'effects',
  ...
  'application'
]

That’s a little verbose for setting the default, so Rails provides us ActionView::Helpers::AssetTagHelper.register_javascript_include_default. Let’s try this again:

1
2
3
4
5
6
ActionView::Helpers::AssetTagHelper.register_javascript_include_default(
  'prototype',
  'effects',
  ...
  'application'
)

Let’s set a default using jQuery:

1
2
3
4
ActionView::Helpers::AssetTagHelper.register_javascript_include_default(
  'jquery',
  'application'
)

Easy as pie! Let’s setup expansions for Uploadify:

1
2
3
4
5
6
7
8
ActionView::Helpers::AssetTagHelper.register_javascript_expansion :uploadify => [
  'swfobject',
  'uploadify',
]

ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :uploadify => [
  'uploadify'
]

Now we can easily maintain asset bundles. Cool, eh?

Another Way to Define Node.js Objects

In my last post I discussed different ways to define objects using the CommonJS module system as implemented in Node.js. There’s one particular example I wanted to revisit:

1
2
3
4
5
6
7
8
9
10
11
12
13
var Circle = function (radius) {
  this.radius = radius
}

Circle.PI = 3.14

Circle.prototype = {
  area: function () {
      return Circle.PI * this.radius * this.radius
  }
}

exports.Circle = Circle

I had decried this form as awkward as illustrated by this scenario:

1
2
3
4
5
6
node> var circle = require('circle_object')
{ Circle: { [Function] PI: 3.14 } }
node> var c = new circle.Circle(2)
{ radius: 2 }
node> c.area()
12.56

I was reading some of the source code for the new 0.1.90 release of Node, and I saw an example that made me realize we’re using this object wrong. Here’s a better way to use the above definition:

1
2
3
4
5
6
node> var Circle = require('circle_object').Circle
{ Circle: { [Function] PI: 3.14 } }
node> var c = new Circle(2)
{ radius: 2 }
node> c.area()
12.56

Look at that! We’ve got traditional style objects without polluting the global object.

Understanding Node.js’ “Require”

I’ve been playing with Node.js lately. Node is an asynchronous, JavaScript library for building server-side applications that uses CommonJS conventions. One of these conventions, modules, has confused me for quite a while now. Let’s take a closer look at them.

We’re going to be using Node version 0.1.33 in this article. Let’s get to it.

The Basics

Let’s build some functions to deal with circles. Here’s some code you can find in the Node documentation:

1
2
3
4
5
6
7
8
9
var PI = 3.14

exports.area = function (r) {
  return PI * r * r
}

exports.circumference = function (r) {
  return 2 * PI * r
}

Okay. Now let’s use this in Node. If you’re like me, your first session in Node will look something like this:

1
2
3
4
5
6
7
8
9
node> require.paths.unshift('.')
3
node> require('circle')
{ area: [Function], circumference: [Function] }
node> area
ReferenceError: area is not defined
    at EventEmitter.anonymous (eval at readline (/usr/local/lib/node/libraries/repl.js:48:9))
    at EventEmitter.readline (/usr/local/lib/node/libraries/repl.js:48:19)
    at node.js:845:9

What Just Happened?

Coming from a Ruby background, I would have expected methods I required to be available to me. That’s not the case with CommonJS modules. Let’s take a look at how you should have used this module:

1
2
3
4
5
6
node> require.paths.unshift('.')
3
node> var circle = require('circle')
{ area: [Function], circumference: [Function] }
node> circle.area(5)
78.5

Success! We can now do what math that every grade four student can do. Let’s try something else:

1
2
node> circle.PI
node>

Nada! Node doesn’t spell it out, but we’ve just called a property of circle that doesn’t exist. Let’s verify:

1
2
3
node> typeof circle.PI == 'undefined'
true
node>

Making Sense of Things

Is the above a little confusing for you? It sure was for me at first. If you read the Node documentation, you’ll see a nugget that might provide a clue. Check this out:

To export an object, add to the special exports object. (Alternatively, one can use this instead of exports.)

So, we can rewrite our circle like this:

1
2
3
4
5
6
7
8
9
var PI = 3.14

this.area = function (r) {
  return PI * r * r
}

this.circumference = function (r) {
  return 2 * PI * r
}

And what is this? Well, it’s your object! So, we can think of this module as this:

1
2
3
4
5
6
7
8
9
10
11
function circle () {
  var PI = 3.14

  this.area = function (r) {
      return PI * r * r
  }

  this.circumference = function (r) {
      return 2 * PI * r
  }
}

You’re seen this before. It’s a JavaScrip object. So modules are really nothing more than objects. As a short form, we’re just defining the body of the object. Now we have a mental model of how CommonJS modules work. In fact, we’d use this object just like we used our circle functions with Node:

1
2
3
node> var c = new circle();
node> c.area(5)
78.5

Where You’re Probably Making Your Mistake (and I Did Too)

You, probably like me, come from an Object-Oriented background. Let’s look at how we’d write our circle in my favourite language, Ruby.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Circle
  PI = 3.14
  
  attr_accessor :radius
  
  def intialize(radius)
      self.radius = radius
  end
  
  def area
      PI * radius ** 2
  end
end

And to use it…

1
2
3
4
> require 'circle'
> c = Circle.new(2)
> c.area
=> 12.56

If you’re anything like me, you’d be tempted to do something like this when you first try out Node:

1
2
3
4
5
6
7
8
9
10
11
12
13
var Circle = function (radius) {
  this.radius = radius
}

Circle.PI = 3.14

Circle.prototype = {
  area: function () {
      return Circle.PI * this.radius * this.radius
  }
}

exports.Circle = Circle

What happens when we try to use this module?

1
2
3
4
5
6
node> var circle = require('circle_object')
{ Circle: { [Function] PI: 3.14 } }
node> var c = new circle.Circle(2)
{ radius: 2 }
node> c.area()
12.56

Hmm. Awkward. We can get around this simple by removing the var, and dropping exports as follows:

1
2
3
4
5
6
7
8
9
10
11
Circle = function (radius) {
  this.radius = radius
}

Circle.PI = 3.14

Circle.prototype = {
  area: function () {
      return Circle.PI * this.radius * this.radius
  }
}

And we can use it like we did with our Ruby object:

1
2
3
4
5
6
7
8
node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
28.259999999999998

Our Circle object was defined on the global object. So, surprise, surprise, it’s globally available to us too.

However, we’ve seen that we don’t really need to do this most of the time. We can simply write the body of our function and export the API we wish to make public.

In Summary

Let’s look at what we’ve learned:

  • In a CommonJS module, if you want something to be available to your user, you must export it.
  • Things that aren’t exported are still available to the exported functions and values. This is why area can access the value of PI, but we couldn’t. In this way, PI is private.
  • The file defining our functions acts as a namespace. Methods and values we provide users of our module must bed exported.
  • If you want to write a traditional class, define it on the global object (please see edit)

Try writing a module in Node. Practice what we’ve learned.

A Note on the Final Example (edit, April 8, 2010)

In reading comments on Reddit, I wanted to make note of masklinn’s comment:

The piece of code at the end is downright dangerous (because it mucks up
global objects, potentially overwriting properties in other modules), and
there’s nothing object oriented about ruby’s behavior, if anything it’s
abject-oriented. Ruby’s require is akin’s to PHP’s include or C’s very own
#include, it just dumps the required file in the local namespace and executes
it.

Node.js’s original behavior, where require actually creates and returns a
full-fledged object is infinitely cleaner and far more object-oriented.

Masklinn is absolutely correct! In case it was entirely clear above, I feel it important to reiterate that this is not a good way to make objects when using Node. It’s dangerous, and unnecessary. Try to think of the file as the contents of your class’ body, and the exported methods as the public interface.

Hello, World!

This is my blog. This was going to be a mission statement. Instead I’ve decided to just ramble incoherently for a bit and suggest that I may eventually have content.