Tag: ruby

Difference between do-end and {} blocks

Posted by on February 7, 2010

There is a important difference between the two block syntaxes in Ruby: Their precedence.
Consider following code:

def method1(*args)
  puts "method1 got a block" if block_given?
end
 
def method2(*args)
  puts "method2 got a block" if block_given?
end
 
method1 method2 do
end
 
method1 method2 {
}

You would expect both method calls to produce the same result, wouldn’t you?
Output:

method1 got a block
method2 got a block

Obviously the do-end block is passed to the first method in the expression while the {} block is passed to the method called directly before it.
Another example shows that the assignment does not count as a method call here:

#[...]
class Foo
  def bar=(o)
    puts "Foo#bar= got a block" if block_given?
  end
end
foo = Foo.new
 
foo.bar = method1 method2 do
end 
#method1 got a block
 
foo.bar = method1 method2 {
} 
#method2 got a block

dm-optlock v 0.1.4

Posted by on January 10, 2009

Update: dm-optlock now on github

I released a new version of dm-optlock. It is NOT compatible with v 0.1.2’s code, because replaced the set_locking_column method by a method called add_locking_column. Your DB should be compatible.

class Model
  include DataMapper::Resource
  ...
  add_locking_column :my_version_col
end

It takes a options hash just like DataMapper’s property method does. I added it to enforce some options on the locking column.

Optimistic Locking for Datamapper

Posted by on October 1, 2008

Update(2009-3-3): dm-optlock now on github

Update(2009-1-10): New version

I should be learning for my test on next tuesday, but coding helps keeping me in a good mood.
Here is a little gem I will need in a future project for which I’ve choosen merb + datamapper. Datamapper doesn’t support any row level locking.
My code checks if the record you want to save was changed since you loaded it. If it was changed it raises an exception (DataMapper::StaleObjectError). It works quite like ActiveRecord’s optimistic locking.
You need to define this column in your model you want to be locked:

property :lock_version, Integer, :default => 0

Anywhere in your code where you update your objects you should be prepared to handle the exception:

begin
  if @obj.update_attributes({:dummy => 123})
    #successful
  else
    #validation errors?
  end
rescue DataMapper::StaleObjectError
  #tell the user that he was too slow
  #or even better: show him the conflicts and let him merge the changes
end

The gem can be downloaded here:
dm-optlock-0.1.0.gem
Please let me know what you think of it. I’ll try and put it on RubyForge, too.

(00:27) Little update:
I added a ’set_locking_column’ method.
dm-optlock-0.1.2.gem

Update:
dm-optlock is on Rubyforge.
Now you can get it like this:

gem install dm-optlock

Mergesort in Ruby

Posted by on September 18, 2008

While playing around with stable sorting I implemented Mergesort.

class Array
  def mergesort(&cmp)
    if cmp == nil
      cmp = lambda { |a, b| a <=> b }
    end
    if size <= 1
      self.dup
    else
       halves = split.map{ |half|
        half.mergesort(&cmp)
      }
      merge(*halves, &cmp)
    end
  end
 
 
  protected
  def split
    n = (length / 2).floor - 1
    [self[0..n], self[n+1..-1]]
  end
 
  def merge(first, second, &predicate)
    result = []
    until first.empty? || second.empty?
     if predicate.call(first.first, second.first) <= 0
        result << first.shift
      else
        result << second.shift
      end 
    end
    result.concat(first).concat(second)
  end
end

It is not suitable for productive use as it’s quite slow. It’s about ten times slower than the stable_sort method from my earlier post.
A little benchmark sorting an array of 2,000,000 random integers:

                user     system      total        real
Original Sort 0.630000   0.010000   0.640000 (  0.639860)
Stable Sort 12.780000   0.700000  13.480000 ( 13.477982)
Mergesort 109.170000  13.420000 122.590000 (122.617323)

Stable Array Sorting in Ruby

Posted by on September 18, 2008

Ruby uses some kind of Quicksort to sort its arrays. Unfortunately Quicksort is not stable.
When you get sorted data from your database, which almost certainly sorts faster than anything in Ruby, you sometimes may want the data to be resorted in a stable way.

I found following snippet:

class Array
  def stable_sort
    n = 0
    sort_by {|x| n+= 1; [x, n]}
  end
end

I extended it to accept a block like the original sort method does:

class Array
  def stable_sort
    n = 0
    c = lambda { |x| n+= 1; [x, n]}
    if block_given?
      sort { |a, b|
        yield(c.call(a), c.call(b))        
      }
    else
      sort_by &c
    end
  end
end