Thursday, 16 April 2009

Problem When Upgrading From Rails 2.2.2 to 2.3.2

I've just installed the latest Active* gems to move my Rails install to 2.3.2. When I ran a console I got the following error

Loading development environment (Rails 2.3.2)
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.2/lib/active_support/dependencies.rb:443:in `load_missing_constant':NameError: uninitialized constant ApplicationController 

I googled this and found a couple of posts on the issue but nothing obvious that I was doing. After generating a 2.3.3 app and comparing files the solution was obvious and easy. I 2.2.2 the ApplicationController class is in a file called Application.rb, in 2.3.2 this has changed to application_controller.rb. Changing the file name has fixed my problem.

Posted by kevin at 6:37 PM in Ruby

Thursday, 2 April 2009

DevWeek 2009 Demos

Are now available on the Rock Solid Knowledge site. I've upload the 'So you think you now JavaScript', 'Design for Testing' and Day of 'Ruby and Rails' talks. Andy's already put up the 'Day of Patterns' and 'Patterns Dartboard' talks

Posted by kevin at 2:19 PM in General

Wednesday, 1 April 2009

Ruby idioms in ASP.Net MVC

In Rails there is a mechanism by which you can mimic variadic methods (Ruby also supports true variadic methods) by treating the last parameter as a hash. I can write a function definition like this

def pass_a_hash(s, h) 
  puts s
  h.each { |key, value| puts "#{key} => #{value}"} if h.class == Hash  
end

and call it either like

pass_a_hash "kevin", {:a => "b", :c => "d"}
or
pass_a_hash "kevin", :a => "b", :c => "d"
either way this prints
kevin
a => b
c => d

The second style is much neater, it hides the use of the hash and instead makes it seem like we are using named parameters. This is used all over Rails, especially on web pages where you need to specify things such as controllers and actions. You will often see code like:

<%= link_to "Add", :action => :add, :controller => :students %>

Here we are calling the 'link_to' method passing a string and a hash of options, just like above

Microsoft (bless 'em) have tried to mimic this in ASP.Net MVC by letting you can write code similar to the 'link_to' Rails method. On an ASP.Net view you can do something like:

<%= Html.RouteLink("Add", new {action = "add", controller = "students"}) %>

And this adds a link to the page with the text "Add" and a url something like http://server.com/students/add. This is similar to ActionLink and they both eventually call into a method called GenerateRouteLink. In the ASP.Net case the second parameter is not a hash (oh for first class hashes in C#) but an instance of an anonymous class. Using Reflector we can see what this method does.

Internally RouteLink creates a RoutedDictionary passing the anonymous instance as a parameter to its constructor

    return htmlHelper.RouteLink(linkText, new RouteValueDictionary(routeValues));

The RouteValueDictionary constructor looks like this

public RouteValueDictionary(object values)
{
    this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
    this.AddValues(values);
}

and AddValues does this:

private void AddValues(object values)
{
    if (values != null)
    {
        foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
        {
            object obj2 = descriptor.GetValue(values);
            this.Add(descriptor.Name, obj2);
        }
    }
}

public void Add(string key, object value)
{
    this._dictionary.Add(key, value);
}

So AddValues uses reflection to build a dictionary of name/value pairs

Just like in Rails, when the element is rendered this dictionary is interrogated and the values used to build the URL.

Neat, but still more ceremony than in Ruby!

Posted by kevin at 5:45 PM in Ruby

Ruby Essence vs Ceremony

Last week at DevWeek Tim Ewald and I tried to show some of the elegance of Ruby and I'd like to try and repeat that example here.

We started with a Lion class in honour of the news story that week about "Christian the Lion" (hey, look it up yourselves!). The class is very simple

class Lion

  attr_accessor :message, :name

  def speak
    @message
  end

  def to_s
    "#{self.name} says #{self.message}"
  end

  @@lions = {}

  def self.create message, name
    if @@lions[name] == nil
      @@lions[name] = Lion.new(message, name)
    end
    return @@Lions[name]
  end

  def initialize(message, name)
    @message = message
    @name = name
  end

end

The bit we care about is the self.create method. The idea here is that we provide a function to only allow the creation of one lion with any given name (this was a demo so it didn't need to make sense). To do this there is a class level dictionary (a static) in which to store new lions. We only add lions to this dictionary if they are unique, otherwise we return an existing lion. The code as it is written is not very Ruby-ish, it reads more like C++, C# or Java code than Ruby and that's what I'd like to change.

The first step is to remove the 'return' keyword. In Ruby the last statement in a method is the return value so we can change the code to look like this:

def self.create message, name
  if @@lions[name] == nil
    @@lions[name] = Lion.new(message, name)
  end
  @@Lions[name]
end

The 'if' statement isn't very idiomatic either and in Ruby this can be reduced to

def self.create message, name
  @@lions[name] = Lion.new(message, name) if @@lions[name] == nil 
  @@lions[name]
end

We're still not quite there though. Ruby (like C#) has a 'null co-alescing' operator, which lets me say "if 'x' is not null, use it, else do 'y'", and I can rewrite the above 'if' using this operator (|| in Ruby). It also means I can do away with the final return statement

def self.create message, name
  @@lions[name] || @@lions[name] = Lion.new(message, name)
end

Which says, if @@lions[name] is not null return the value, else assign Lion.new to @@lions[name] and return that value

One line to do what it would take four lines to do in other languages and no keywords. As my friend Stu Halloway would put it, essence over ceremony!

Posted by kevin at 5:34 PM in Ruby

« April »
SunMonTueWedThuFriSat
   1234
567891011
12131415161718
19202122232425
2627282930