Archive for the 'Ruby' Category


Rails iCalendar improvement

Saturday, September 30th, 2006

I came across this thread that simplifies the ical controller from my previous example. It correctly sets the content type header and removes the need for a template. The new version is:

class IcalController < ApplicationController

caches_page :competitions

def competitions headers[’Content-Type’] = “text/calendar”

cal = Icalendar::Calendar.new

Competition.find_all.each do |comp|
  event = Icalendar::Event.new
  event.start = comp.date
  event.end = comp.date
  event.summary = comp.name

  cal.add event
end

render_without_layout :text => cal.to_ical

end

I hadn’t used the render_without_layout command before, but it’s very handy for situations like this.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Rails iCalendar improvement digg.com digg it!  |  reddit reddit!

Getters and Setters

Friday, September 29th, 2006

I was chatting to Simon the other day and the question of, should you have getters and setters in your Ruby classes, or should you just let other classes access the attributes directly, came up. We were talking about ActiveRecord, which dynamically creates them for any columns in the table the class is representing.

The short answer is, if you want other classes to access that data, yes, you need getters and/or setters, but for different reasons that you might think if you come from a Java world. Getters and setters are one of my pet peeves in Java. I hate it when I see them thrown in by default for every field in the class, reducing it to nothing more than a C struct.

The good reason for not allowing direct access to a field in Java is data encapsulation. By making it private you can decide if it’s read-only or read/write (or neither). But I think this is a poor reason, in so much that other objects shouldn’t be pulling data out, but asking it to do things. Rather than starting from a view point of what data does this class provide, you should think of what are its responsibilities.

But that is tangential to what I want to talk about, why are getters and setters so prevalent in Java? I think the first reason is the early OR mapping frameworks. They typically required you to inherit from a class, or broke OO (no inheritance in EJBs?!?), so you treated the domain object as struct, just to ferry data from Java to the database. Then you’d put logic in other objects and you’re just doing procedural programming. I think the situation is better now that you can work with POJOs (e.g. Hibernate) but you still see tutorials following the old pattern.

The second reason is the madness that is field access in Java. Getters and setters can protect you from this. Java binds field access at compile time, i.e. to a variable’s static type, e.g.:

public class A {
    int num = 0;
}

public class B extends A {
    int num = 2;
}

public class Test {
    public static void main(String[] args) throws Exception {
        A a = new B();
        System.out.println(a.num);

        B b = new B();
        System.out.println(b.num);
    }
}

Would output:

0
2

when you’d hope it would do something sensible like:

2
2

i.e. you shadow fields rather than override them, so you can get weird bugs if the static type is different from the runtime type. The variables can even be different types! Methods are determined by your runtime type so we can make sure we’re always accessing the right variable, e.g.:

public class A {
    int num = 0;

    public int getNum() { return this.num; }
}

public class B extends A {
    int num = 2;

    public int getNum() { return this.num; }
}

public class Test {
    public static void main(String[] args) throws Exception {
        A a = new B();
        System.out.println(a.getNum());

        B b = new B();
        System.out.println(b.getNum());
    }
}

Does output:

2
2

so unless the field is defined in your class, you really shouldn’t access it directly. This means to be safe, all fields should be private and we need protected scope getters and setters if we want that field available for subclasses, what a pain, but helps explain why they are so prevalent.

Back to Ruby, how does it deal with this? If you look back at the top I said if you want to access the data you need getters and setters. This is because attributes (Ruby’s name for fields) are private to an object, and everything you ask from an object has to be a method, basically you couldn’t get to that attribute directly if you wanted to! Ruby also doesn’t have the problem of field shadowing because you don’t declare variables, so when you reference it, you’re referencing the only variable with that name.

So what do the getters and setters look like?

class Test 
    def someField
        @someField
    end

    def someField=(newValue)
        @someField = newValue
    end
end

aObject  = Test.new
test.someField = "blah"
test.someField >> "blah"

i.e. our getters and setters look like we’re accessing a field directly but they are actually method calls. Without these, if we tried to access a field, Ruby would complain that no such method exists.

Since this is such a common pattern Ruby has some shortcuts:

read-only:

class Test
    attr_reader :someField
end

write only:

class Test
    attr_writer :someField
end

read/write:

class Test
    attr_accessor :someField
end

All these methods can take multiple arguments if you’re defining multiple fields.

A good summary of all this can be found here:

http://www.rubycentral.com/book/tut_classes.html#S2

But Ruby’s not perfect. A subclass can access attributes from its parent. which means you’re dependant on its implementation, but a code review can stop that.

The bigger problem is clashes with mixins. If a mixin uses an instance variable you can get collisions. A mixin has no state, that instance variable it refers to belongs to the object that included the mixin, so if it uses a variable with the same name you can get some weird behaviour. Because there is no static typing, the object’s methods and the mixin’s method can change what is held in that attribute and you won’t see that error until runtime where you’ll probably see a missing method error. Typical workarounds are prefixing variables with some sort of namespace to avoid collisions, or using a module level hash to store the mixin’s state outside of the object.

All in all I prefer the Ruby way of getters and setters. On the surface it looks the same but by preventing direct access to attributes and using virtual attributes (not covered here), you classes are less likely to become structs and more like genuine objects.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Getters and Setters digg.com digg it!  |  reddit reddit!

Upgrading a Rails app

Wednesday, September 20th, 2006

Now that I have some free time I can work on my golf league Rails app. There’s a bunch of stuff I want to do:

  • Upgrade to Rails 1.1
  • Upgrade to the stable release of Typo (4.0.x)
  • Start using Capistrano for deployment
  • Add in some tests

Typo

Last time round I started using Typo to manage news and photos (via Flickr). The problem was that I was using a trunk version (r933), which had some stability issues to say the least, but did the job. The biggest problem was a memory leak that caused DreamHost to kill it off whenever it got some significant load. A lot of these issues have been fixed in the current stable release (4.0.x), and it also uses Rails 1.1, so that’s a good excuse to upgrade (although unnessary for the other bit because it’s a separate app).

One thing I always wanted to do was integrate the admin screens of the league manager as tabs in Typo’s admin pages. I think this is being talked about for 4.1 but isn’t available now. So that doesn’t leave much space for tighter integration, and I don’t like having to maintain two code trees. Typo is also overkill for the odd monthly announcement.

Another thing I’ve considered is using a simpler CMS, e.g. Radiant. I haven’t looked at it much, but it supports something called behaviours, which allows you to do something different on a particular page. That could replace the standalone app that handles leaderboards, forms, etc. Another alternative is to just write a simple news posting system, then I wouldn’t have to worry about merging code bases, user models and all the authentication headaches.

If anyone else has experience in running two Rails apps as part of one web app, I’d love to hear about it.

Rails 1.1

I only just upgraded to 1.0 the last time round. It would be nice to see what the current state of the art is. The main problem here is that my copy of Agile Web Development with Rails only covers Rails 1.0, all my info on Rails 1.1 is a bunch of blog clippings.

What I’d prefer to focus on is the performance and memory enhancements I’ve been reading about on RailsExpress.blog. Rails on DreamHost is slow, and if you consume too much memory, your app gets killed. It’d be nice to sort this stuff out, especially since my users aren’t all technical.

Capistrano

Another pain with Rails is that almost certainly, deploying the thing that works on my laptop onto DreamHost won’t work. I don’t know much about Capistrano, but I’ve heard it takes away deployment pain, so I want to give it a go.

Testing

Being a hobby app there are no tests. Most of the logic is just editing records so I don’t need tests, but there are some tricky scoring and ranking things that should be verified with test cases. After that there’s ZenTest. It’s an automated tester that makes sure everything is still working with each change. It’s a different style of development that I’d like to try, it sounds a lot more helpful than occassionaly doing an ‘ant test’ that takes several minutes to run. ;)

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Upgrading a Rails app digg.com digg it!  |  reddit reddit!

Why do we still have Arrays?

Saturday, July 29th, 2006

Continuing my look into language features, today I’m asking why are we still using arrays? Or more specifically why does Java have C-style arrays? An array is essentially a list, an ordered collection of things. Lists are a vital data structure in programming but why is there this first-class array primitive in Java?

Let’s first look at C. Arrays in C are nothing more than syntactical sugar for pointer arithmetic. Consider the following example.

int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
a[1]; /* equals 2 */
int *a = malloc(10 * sizeof(int));
for (int i = 0; i < 10; i++) {
    *(a + i) = i;
}
*(a + 1); /* equals 2 */

These two bits of code are, for all intends and purposes, the same. Since they are the same there are some limitations placed on arrays in C, i.e. they are fixed length, and things need to be next to each other in memory because of the way pointer arithmetic works.

We don’t really want these restrictions on lists, I may want to change the number of elements, and where they’re located in memory should be an implementation detail. For the second point in particular, Java does make it an implementation detail when you decide to use ArrayList or LinkedList.

So what is an array in Java? It’s not an instance of the Array class, but it is an object. It has a field named ‘length’ (public final), and it implements the Cloneable interface. int[].class.getName() is [I. That doesn’t tell us much, but IMHO it’s a hack in the language to implement C-style arrays. It is fast, according to Peter Norvig’s IAQ on Java, accessing an array is 15-30 times faster than accessing an element of a Vector. But that could just be synchronization overhead, and Vector is probably implemented with arrays anyway. There should be some low level language feature that allows us to access that speed.

So what’s my gripe? Arrays in Java should be so much more than copies of the things in C. The Java Collections API which is one of the best Java APIs, and the List type should have the array syntax. Take a look at Arrays in Ruby, which are essentially a good list implementation with array syntax.

a = [1 ,2, 3, 4, 5]
a[1] » 2

b = [6, 7, 8, 9, 10]
a + b » [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

N.B. this produces a new array, but you can use the ‘concat’ method to append them to the same array

c = [2, 4, 6, 8, 10]
(a + b) - c » [1, 3, 5, 7, 9]

Ruby’s Array class also does a lot more.

The concept of C-style arrays need to be dropped. We don’t handle pointers any more, we shouldn’t be bound by the limitations. The concept we’re using is the list data structure, we should make that, along with all of its potential features, our first class type.

Update: I simplified the way to get the int[] class name (Thanks Shai).

Update 2: Corrected a typo in the C example (Thanks JDB).

Disclaimer: In the C example the first declaration will assign memory from the stack and the latter from the heap, so they’re not the same, but I just want to demonstrate elements in the array are next to each other in memory and hence [] notation can be changed to pointers.

Disclaimer 2: I know Vector’s methods are synchronized, and ArrayList is essentially the same thing without the synchronization overhead, hence faster. The performance numbers I pulled up are old and it used Vectors, thanks Shai for providing up to date numbers.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Why do we still have Arrays? digg.com digg it!  |  reddit reddit!

Open Classes

Tuesday, July 18th, 2006

One nice feature of Ruby that I wish I had with Java is the able to change the standard classes. For example, Ruby’s Array class has a map function, but no reduce function. So we simply add methods to the class:

class Array
  def reduce(n)
    each do |value|
      n = yield(n, value)
    end

    n
  end

  def sum(initial = 0)
    reduce(initial) { |n, value| n + value }
  end

  def product(initial = 1)
    reduce(initial) { |n, value| n * value }
  end
end

[ 1, 2, 3, 4, 5 ].sum   »  15 
[ 1, 2, 3, 4, 5 ].product   »  120

(Example from Programming Ruby, where the method is called ‘inject’ and is defined in a separate Mixin so it can be included in other classes, e.g. Range)

In the above example we add the reduce method to the Array class and two additional methods, sum and product, which make use of reduce. The reduce method takes an initial value for the reduction and a code block to act on each element of the array.

We can’t replicate this elegance in Java because the classes are closed. Extending the class only gets us halfway there because only instances of the sub class have the method, i.e. others methods that return the original class won’t have it. Therefore we tend to end up abandoning OO and sticking the function somewhere else, e.g.:

public interface Functor {
  Object function(Object acc, Object value);
}

public class ArrayUtils {
  public static Object reduce(Object[] array, Object initial, Functor f) {
    Object result = initial;
    for (Object o : array) {
      result = f.function(result, o);
    }

    return result;
  }

  public static Integer sum(Integer[] integers) {
    return reduce(integers, 0, new Functor() { 
      public Object function(Object acc, Object value) { return ((Integer) acc) + ((Integer) value); }
    });
  }

  public static Integer product(Integer[] integers) {
    return reduce(integers, 1, new Functor() { 
      public Object function(Object acc, Object value) { return ((Integer) acc) * ((Integer) value) }
    });
  }
}

ArrayUtils.sum(new Integer[] {1, 2, 3, 4, 5});   »  15 
ArrayUtils.product(new Integer[]{1, 2, 3, 4, 5});   »  120

The Java version does the same thing, but just looks wrong to me. Sure autoboxing cleans it up a bit and generics would do more (at the expensive of having to instantiate ArrayUtils), but you can’t get around defining the methods outside of the class, and having code blocks passed around as anonymous classes.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Open Classes digg.com digg it!  |  reddit reddit!

icalendar and Rails

Monday, June 26th, 2006

I’ve recently used icalendar to output an ical from a Rails app I’m running. It’s incredibly simple, here’s what I did:

  1. Create an ical_controller:
    script/generate controller ical
  2. Add a method to generates the events:
    require 'icalendar'
    
    class IcalController < ApplicationController
    
      caches_page :competitions
    
      def competitions
        @cal = Icalendar::Calendar.new
    
        Competition.find_all.each do |comp|
          event = Icalendar::Event.new
          event.start = comp.date
          event.end = comp.date
          event.summary = comp.name
    
          @cal.add event
        end
      end
    
    end
  3. Create a view (app/views/ical/competitions.rhtml):
    < %= @cal.to_ical %>
  4. Install icalendar into your vendor directory:
    cd vendor
    gem unpack icalendar
  5. Add the necessary dependency to config/environment.rb
    require 'icalendar-0.96.4/lib/icalendar'

And that’s it. Once deployed you can access your ical and import it anywhere. I’ve tried mine out with Google Calendar and it imported without a hitch. One deficiency in icalendar is the inability to give a name or description to the calendar itself, so you’ll have to rename it in your calendar application. The only caveat in the above code is the caching directive in the controller. I’ve cached the entire page because the events don’t change frequently. To expire the cache you’ll have to add the following line to the appropriate controller methods where your events changes:

expire_page :controller => "ical", :action => "competitions"
Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit icalendar and Rails digg.com digg it!  |  reddit reddit!

More Rails on DreamHost Pain

Sunday, May 14th, 2006

I thought I sorted out my problems with my sites needing Rails 1.0 by configuring them to use specific versions of the required gems. But this was short lived, the other day my sites just stopped working. I reported the problem to DreamHost and after a couple days they told me I was trying to use a version of a gem that wasn’t available. The various gems and the versions needed are:

rails 1.0.0 1.1.0
activerecord 1.13.2 1.14.0
actionpack 1.11.2 1.12.0
actionmailer 1.1.5 1.2.0
activesupport 1.2.5 1.3.0
actionwebservice 1.0.0 1.1.0

I had setup my environment.rb file to lock the gems to the versions needed for Rails 1.0.0, this got around the problems with the Rails 1.1 upgrade. So what went wrong? DreamHost uninstalled activerecord 1.13.2, 1.14.0 doesn’t work with Rails 1.0. “Aha!” I hear a lot of you say, “you should have run rake freezegems“, which is in fact what I did to get everything working again, but I do have an issue with it. By running freezegems you’re copying the libraries into your application, so for each app you need a complete copy of Rails. That’s a pretty old school way of doing things, we’ve had shared libraries for a long time now.

But space is not my major concern, my first one is minor bug fixes. If there’s a bug, or more likely a security issue, there should be a compatible version of the library released with the fix. This minor upgrade should continue working with my application without me doing anything, if you copy the library into your app you don’t get this benefit. The other issue is that by copying Rails into your application it doesn’t matter if your host has Rails installed since you’re using your own copy. All those gems that DreamHost installs? Absolutely useless. I install them on my laptop, do a rake freezegems and copy the whole lot over. On a related note by uninstalling activerecord 1.13.2 I couldn’t have done freezegems on the host, I had to do it locally.

This is such an unsustainable (I could say ‘doesn’t scale’ but I know how bothered people get with that phrase ;) ) way of managing libraries. Sure it’s fine for my two applications, but what happens if you have ten, or a hundred? Each time a new version of a gem is released you need to go to each one of them and do a ‘rake freeze_gems’. If your host doesn’t install the complete set of versions you need, then you need to do it somewhere else and copy everything over, madness!

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit More Rails on DreamHost Pain digg.com digg it!  |  reddit reddit!

Rails 1.1 Follow Up

Wednesday, March 29th, 2006

In the end DreamHost has uninstalled Rails 1.1 and all other dependencies. An odd move if you ask me since it was more work involved than fixing the upgrade. I think the main issue of contention was that Typo (a Ruby blogging program) doesn’t work with 1.1.

Before that I did manage to get all my sites working properly. There are three main ways to do this:

  1. rake gem_freeze
  2. Copy Rails 1.0 to your vendor directory:
    svn export http://dev.rubyonrails.org/svn/rails/tags/rel_1-0-0 rails
    
    Or do it manually as laid out here.
  3. Or insert the appropriate lines from the wiki to specify certain versions of Rails and its components. This requires your host to have older versions of the gems. A few caveats:
    • Make sure you have require ‘rubygems’
    • Make sure the dependencies come before any lines that need them, e.g.:
      ActiveRecord::Base.configurations = File.open("#{RAILS_ROOT}/config/database.yml") { |f| YAML::load(f) }
      
    • Comment out the default require lines for Rails
Also make sure you kill any old ruby processes so the changes can have an affect. To be honest I used a combination of 2 and 3, I’m fairly certain only one made a difference, and I know which one, but since the site is live and is now working, I’m very reluctant to change anything. As for future Rails hosts, my shortlist is:
  1. OCS Solutions
  2. Planet Aragon
  3. and a distant third, TextDrive

I think I’ll go with OCS Solutions, because they seem very serious about Rails, they support lighttp, I couldn’t find any bad press about them and they’re cheap. DreamHost is good for testing Rails apps, but I definitely wouldn’t recommend them for client hosting.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Rails 1.1 Follow Up digg.com digg it!  |  reddit reddit!

Rails 1.1 Pain

Wednesday, March 29th, 2006

DreamHost upgraded to Rails 1.1 last night, which broke my sites. Of course this was just a few hours after I announced them, making me look like a complete tit. Strictly speaking I should have locked my version of Rails to prevent this sort of thing happening, but a warning would have been nice. I doubt they would have upgraded to an incompatible version of PHP without mentioning it. Actually the problem is not so much the upgrade, but it was a partial upgrade. They forgot to upgrade activerecord, so no Rails sites work. So far it’s been over 10 hours without a word from their support team. All they need to do is roll out one gem across their servers.

I managed to get one site back up but the other is still down. DreamHost have always been a bit slow when it comes to Rails performance so I’m on the look out for a new host for my Rails sites. A quick search shows users on TextDrive (the official RoR host) went through a similar unannounced upgrade. If you know any solid Rails hosting company, let me know.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Rails 1.1 Pain digg.com digg it!  |  reddit reddit!

Typo Sidebar - CalendarHelper

Wednesday, March 8th, 2006

One of the sidebar plugins I wrote needed a calendar. I decided to use Jeremy Voorhis’s calendar-helper. There are examples on his page on how to use it so I won’t go into those details here. The reason for this post is about how to get it working with Typo.

It proved fiddly because after putting the file in the ‘components’ directory made it visible in my controller class (with require 'calendar-helper' and include CalendarHelper) but not in ‘content.rhtml’. After a lot of Googling I found that the component needed to be installed as a global view helper. Those instructions aren’t the clearest, so here’s what you need to do:

  1. Install calendar_helper.rb to /typo/vendor/plugins/calendar_helper/lib
  2. In calendar_helper.rb change module CalendarHelper to module ActionView::Helpers::CalendarHelper
  3. At the bottom of calendar_helper.rb (after the last end) add
    ActionView::Base.send(:include, ActionView::Helpers::CalendarHelper)
  4. Create a file: ‘/typo/vendor/plugins/calendar_helper/init.rb‘ and put in it:
    require 'calendar_helper'
    

And after those four easy steps the ‘calendar’ function is now available in ‘content.rhtml’.

Spread the word: Technorati related  |  del.icio.us bookmark it!  |  submit Typo Sidebar - CalendarHelper digg.com digg it!  |  reddit reddit!