Dondo Land

Bryan Donovan's Weblog

All | General | Music | Rails

20080202 Saturday February 02, 2008

 Ruby: benchmarking ways to pass options to a method

I've wondered before what the fastest way is to pass a hash of options to a method in Ruby.. so today I benchmarked a few methods I've used in the past.

I've seen three main ways of passing an options hash to a method and extracting the options or use default values if they weren't passed in:

  • Merge the options with a hash of defaults, then assign values to local variables (or just use the options hash directly within the method)
  • Use something like var = options[:var] || 'default'
  • Use the delete method on the hash, e.g., var = options.delete(:var) || 'default'

From what I can tell, using delete is the fastest:

require 'benchmark'

def ops_delete(ops={})
  a = ops.delete(:a) || 11
  b = ops.delete(:b) || 22
  c = ops.delete(:c) || 33
  d = ops.delete(:d) || 44
end

def ops_merge(ops={})
  ops = {:a => 11, :b => 22, :c => 33, :d => 44}.merge(ops)
  a = ops[:a]
  b = ops[:b]
  c = ops[:c]
  d = ops[:d]
end

def ops_or(ops={})
  a = ops[:a] || 11
  b = ops[:b] || 22
  c = ops[:c] || 33
  d = ops[:d] || 44
end


n = 100000
puts "With no option values passed"
Benchmark.bmbm(7) do |x|
  x.report("delete:") { n.times do ops_delete; end }
  x.report("merge:")  { n.times do ops_merge;  end }
  x.report("or_nil:") { n.times do ops_or;     end }
end

puts
puts "With some option values passed"
Benchmark.bmbm(7) do |x|
  x.report("delete:") { n.times do ops_delete(:a => 5, :c => 2); end }
  x.report("merge:")  { n.times do ops_merge(:a => 5, :c => 2);  end }
  x.report("or_nil:") { n.times do ops_or(:a => 5, :c => 2);     end }
end

puts
puts "With all option values passed"
Benchmark.bmbm(7) do |x|
  x.report("delete:") { n.times do ops_delete(:a => 5, :b => 1, :c => 2, :d => 4); end }
  x.report("merge:")  { n.times do ops_merge(:a => 5, :b => 1, :c => 2, :d => 4);  end }
  x.report("or_nil:") { n.times do ops_or(:a => 5, :b => 1, :c => 2, :d => 4);     end }
end

Results (rehearsals omitted):

With no option values passed
              user     system      total        real
delete:   0.210000   0.000000   0.210000 (  0.209877)
merge:    0.720000   0.000000   0.720000 (  0.750394)
or_nil:   0.260000   0.000000   0.260000 (  0.258416)

With some option values passed
              user     system      total        real
delete:   0.250000   0.000000   0.250000 (  0.255536)
merge:    0.830000   0.000000   0.830000 (  0.831358)
or_nil:   0.310000   0.000000   0.310000 (  0.314737)

With all option values passed
              user     system      total        real
delete:   0.310000   0.000000   0.310000 (  0.306889)
merge:    0.900000   0.000000   0.900000 (  0.905261)
or_nil:   0.340000   0.000000   0.340000 (  0.348061)

This was done in Ruby 1.8.4 on a 2GHz MacBook Intel Core Duo with 1GB 667 MHz DDR2 SDRAM.



(2008-02-02 14:34:51.0/2008-02-02 14:34:51.0) Permalink Comments [4]
Trackback: http://blogs.sun.com/bdonovan/entry/ruby_benchmarking_ways_to_pass

20071215 Saturday December 15, 2007

 Handling authenticated users with RSpec

Nothing new here, but thought I would share something that set me back a bit when first learning RSpec and testing controllers. If you're using a user authentication system like acts_as_authenticated, you have a method available in your controllers called "current_user" which of course returns the currently logged in user. To simulate this in a controller spec using RSpec, you can tell the controller to return a mock User object when current_user is called:

before do
  controller.stub!(:current_user).and_return(mock_model(User, :to_param => "1"))
end

Of course you may have to change the :to_param value to something else, depending on what you're testing (e.g., maybe different users have different roles/permissions).

Thanks to Igal Koshevoy for the last tip I needed to get this working. Igal wrote the awesome AutomateIt open source tool for automating the setup and maintenance of servers, applications and their dependencies.



(2008-02-02 14:36:56.0/2007-12-15 13:36:57.0) Permalink Comments [2]
Trackback: http://blogs.sun.com/bdonovan/entry/handling_authenticated_users_with_rspec

20071024 Wednesday October 24, 2007

 Adding an Open Flash Chart to a Ruby/Rails application

If you want to add a simple line graph to a Rails application but for one reason or another don't want to/can't use RMagick et al, a relatively simple way to do it is with the Open Flash Chart plugin. It includes a Ruby plugin in the zip archive called "ruby-ofc-library-pullmonkey". You just need to copy that to your Rails app's vendor/plugin directory and rename it to "open_flash_chart". Then you'll be able to make a graph like this in no time:

Open Flash Chart converted to JPG
Here's the code:
require 'open_flash_chart'
class AuditsController < ApplicationController

  def drilldown
    @audits = Audit.find_for_drilldown(params)  # or find(:all), etc.
    #merge the drilldown_graph action and this controller with other params (such as date range)
    url = url_for(params.merge({'controller' => 'audits', 'action' => 'drilldown_graph'}))
    @graph = OpenFlashChart.swf_object(250,150,url)
  end

  def drilldown_graph
    @audits = Audit.find_for_drilldown(params)
    ofc = OpenFlashChart.new
    ofc.title("My Title", "{font-size: 16px;}")
    ofc.set_data(@audits.map{|a| a.percent.to_f})
    ofc.line_hollow(2,3,'#C06600', 'Audit Score', 12)
    ofc.set_x_labels(@audits.map{|a| a.audit_date.strftime('%m/%d')})
    ofc.set_x_label_style(9, '0x000000', 0, 3)
    ofc.x_axis_color('0x999999','0xe3e3e3')
    ofc.set_y_max(100)
    ofc.set_y_min(50)
    ofc.set_bg_color('#ffffff')
    ofc.set_y_label_steps(5)
    ofc.set_y_label_style(1, "#000000")
    ofc.y_axis_color('0x999999','0xe3e3e3')
    render :text => ofc.render
  end
end

# View (drilldown.rhtml)

<%= @graph %>



(2008-02-02 14:37:42.0/2007-10-24 09:38:42.0) Permalink Comments [4]
Trackback: http://blogs.sun.com/bdonovan/entry/adding_an_openflash_chart_to


« November 2009
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
       
Today


XML







Today's Page Hits: 7