| |
Dondo Land
Bryan Donovan's Weblog
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
Trackback: http://blogs.sun.com/bdonovan/entry/ruby_benchmarking_ways_to_pass
|
|
|
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
Trackback: http://blogs.sun.com/bdonovan/entry/handling_authenticated_users_with_rspec
|
|
|
Tuesday November 27, 2007 |
|
How to build a nice photo site in a couple of hours
My friend Elizabeth needed to get a website up for her photography, so I said I'd see what I could do. After trying to customize Gallery (PHP), which is a really good way to go in general, I figured I should look into a quick, customized solution. I'm already familiar with the CakePHP framework (and since my host has crappy support for Ruby/Rails, I didn't want to use a Rails solution), I searched around a bit and found a good tutorial on how to set up a photo gallery with CakePHP using the Flickr API.
After about an hour I had a fully-functioning site up. The next few hours were spent tweaking the layout/design (and figuring out Internet Explorer bugs). I added some more JavaScript to the final solution that updates a caption in addition to the main photo. The results can be found at esoule.com. She's also got an online store at Etsy as well if you want to buy anything.
(2007-11-27 08:17:41.0/2007-11-27 08:17:41.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/how_to_build_a_nice
|
|
|
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:
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
Trackback: http://blogs.sun.com/bdonovan/entry/adding_an_openflash_chart_to
|
|
|
Wednesday May 23, 2007 |
|
Wasting Space on Web Pages
One thing that annoys me a lot on the web is the extremely inefficient use of space on many (if not most) web pages. Why does the header always take up a third of the page? Or take a look at this:
That's a screen shot of my fantasy baseball league's live scoring page on a 21" monitor (1280x1040 resolution) where I've set the browser window size to 1024x768. The three things I really want to see on that page are: (1) The score of this week's match-up (5-4), (2) How each player is doing today (the section below the score) and (3) how this week's stats break down by category (which isn't even close to being on the page.. it's way below).
So the problem with this page is that we have about 9.5 inches of screen height to work with, and the score takes up almost 2 inches (it could easily take up 1/2 an inch), and the rest of the junk above the score takes up about 5 inches. The ad banner at the top is huge, but hey, it's supposed to generate money for the site, so I can accept that (and by accept I mean I block it with adblock of course, but it still takes up the space). The biggest problem is that the section between the top banner ad and the scoreboard takes up about 3.5 inches, which is more than a third of the page, yet conveys almost nothing. I'm quite aware that I'm on the Big Sky Baseball 2007 (listed twice for some reason) page, so maybe they could make that text a little smaller? There's also at least an inch of wasted white space in the "GameCenter" section. The links below "GameCenter" could be next to it instead of below for one thing.
Of course, this is only one of many web sites with similar problems, although this is about as bad as it gets.
I'm by no means web design expert, but I'm pretty sure I'm right about this. I even get annoyed by the space taken up by the header on my own website, UrbanDrinks.com, and it's only about an inch or so.
(2007-05-23 14:23:35.0/2007-05-23 14:23:35.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/wasting_space_on_web_pages
|
|
|
Friday May 18, 2007 |
|
Statistics for manufacturing using Ruby
In my job at Sun as a quality engineer I have made several web-based applications to help analyze and report our manufacturing quality data. One common situation is where we have a number of units that tested during a time period and a number of them failed, and we want to know if the fail rate was worse than a threshold fail rate.
For example, we might have a threshold fail rate of 10% (in reality the thresholds we use are much, much lower, but this is easier for demonstration purposes) and tested 100 units, 12 of which failed. If we treat these 100 units as a sample out of a theoretical infinite population, are we at least 95% confident that population's fail rate is greater than or equal to 10%? To find out, we can use the binomial distribution class from the rubystats Ruby library (I ported this from the PHPMath project. It's available at RubyForge or you can install it with "gem install rubystats" on a system that already has RubyGems installed).
Once you have the rubystats gem installed, you can test our scenario rather easily. Below is a code sample that tests 10 scenarios against the 10% threshold (called bad_fail_rate in the code). This consists of finding the cumulative probability of observing f or more failures if the theoretical infinite population's true fail rate is 0.10. We use the cdf method (cumulative density function) to calculate the probability of observing (f-1) or fewer failures, then subtract that value from 1. If it's less than 0.05 (the alpha value for 95% confidence, i.e. 1 - 0.95 = 0.05), then the fail rate is significant.
require 'rubygems'
require 'rubystats'
require 'binomial_distribution'
tested = [100, 68, 67, 96, 46, 2, 13, 33, 88, 71]
failed = [12, 9, 12, 7, 7, 0, 6, 4, 5, 5]
bad_fail_rate = 0.10
alpha = 0.05
for i in 0..9
t = tested[i]
f = failed[i]
bin = BinomialDistribution.new(t,bad_fail_rate)
cdf = bin.cdf(f-1)
pval = 1 - cdf
pval = sprintf("%.3f",pval).to_f
status = pval <= alpha ? "RED ALERT" : "OK"
puts "Tested: #{t}\tFailed: #{f}\tpval: #{pval}\tStatus:#{status}"
end
Which outputs:
Tested: 100 Failed: 12 pval: 0.297 Status:OK
Tested: 68 Failed: 9 pval: 0.237 Status:OK
Tested: 67 Failed: 12 pval: 0.033 Status:RED ALERT
Tested: 96 Failed: 7 pval: 0.856 Status:OK
Tested: 46 Failed: 7 pval: 0.172 Status:OK
Tested: 2 Failed: 0 pval: 1.0 Status:OK
Tested: 13 Failed: 6 pval: 0.001 Status:RED ALERT
Tested: 33 Failed: 4 pval: 0.423 Status:OK
Tested: 88 Failed: 5 pval: 0.947 Status:OK
Tested: 71 Failed: 5 pval: 0.85 Status:OK
As you can see, the first scenario where 12 out of 100 failed is not statistically significant at 95% confidence.
(2008-02-02 14:38:55.0/2007-05-18 16:05:41.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/statistics_for_manufacturing_using_ruby
|
|
|
Wednesday January 24, 2007 |
|
Portland is the Happiest Town
We've recently added quite a few places to the UrbanDrinks.com (a Portland happy hour website and side project of mine) database, thanks in part to the excellent Portland Happy Hour Guidebook, and now have over 180 different places in Portland with happy hours! That's a lot considering it doesn't count any of the surrounding metropolitan area. Downtown Portland alone has 52 happy hours today. Wow. When I started this project I had no idea how many happy hours in Portland there really were.
So despite the gray, drizzly days, Portland has got to be the happiest place in the country!
(2007-06-19 13:41:44.0/2007-01-24 10:34:47.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/portland_is_the_happiest_town
|
|
|
Monday December 04, 2006 |
|
Confessions of a Sun Rails Developer
I'm really glad to see that Sun is supporting the JRuby project now, and seems to be supporting scripting languages in general. I feel like now I don't have to give excuses at work. I've been developing web applications used Sun-wide internally for over a year and a half now. I work as a quality engineer in Operations, so I'm not really surrounded by Java developers, but I've still received the occasional question asking why I didn't develop in Java (or Perl, another favorite here). The truth is that I just don't know much Java, and some attempts to learn J2EE a couple of years ago frustrated me a bit. Also, I already knew some PHP, so I developed in PHP at Sun for a couple of years until I got good at it. Then I found Rails and tried it out. I immediately got it installed on my server and started developing in Rails from then on.
I like Rails because it provides that perfect mix of coding ease and structure. The Ruby language is extremely flexible, easy to understand, and truly object-oriented. PHP provides much of this, but the language is much more verbose. PHP seems to be a gateway language for many new developers (myself included, aside from some C/C++ in college), and not surprisingly, there are a lot of bad PHP applications out there (I am the guilty author of some). Ruby, on the other hand, is being learned for the most part by new Rails developers. The Rails framework definitely helps new developers create well-organized applications from the beginning. Basically, if PHP would have become popular because of a framework, we wouldn't have as much bad PHP code out there. I really like PHP still, but I like the Ruby/Rails stack better. When I do write PHP code, I try to structure it as well as possible, usually with a variety of PEAR libraries and using CakePHP as a framework (CakePHP follows a lot of Rails-like conventions, and is a very good framework). I wish the PHP books I read when I first started out used a good framework to teach with. However, if they had, we might not have needed this "Rails Revolution".
With JRuby, I hope to see Ruby get faster, and maybe I'll learn Java so I can write fast, compiled portions of my future Rails apps. Long live Java and Ruby!
(2006-12-04 09:04:08.0/2006-12-04 09:04:08.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/confessions_of_a_sun_rails
|
|
|
Friday October 27, 2006 |
|
This is one of those events in life that makes you say "wow, what are the odds of that happening?".
Shortly after I graduated high school, I moved to Phoenix, Arizona to start college at DeVry in July 1997. I was the first of four roommates to arrive, and since the apartment was in my name, I was the one going through the paperwork process. One of my new roommates, whom I hadn't met yet, was Clint Carlson from Alaska, who was also going to be attending DeVry and was scheduled to arrive that same day. I was in the apartment management office waiting for my turn to sign some papers when I overheard the guy in front of me say he was Clint Carlson. So I of course introduced myself and asked him if he was from Alaska (to make sure it wasn't some other random Clint Carlson), and he replied "yes".
"So I guess we're going to be roommates," I responded.
"Um, no, my roommate is so-and-so."
"Uh.. you're Clint Carlson from Alaska, right? Are you going to DeVry?"
"Yeah, start in a few days."
"Um.. I think you're my roommate then. I'm rooming with Clint Carlson from Alaska who's going to start DeVry next week."
"Well, my roommate is so-and-so, so maybe you got the wrong guy.."
Yeah right. So I asked the apartment manager if there was more than one Clint Carlson moving today.
"Yep, I guess there are."
"Two Clint Carlsons from Alaska, moving into the same apartment complex in Phoenix, Arizona on the same day and both attending DeVry? AND I happen to be in the apartment management office when the wrong one is here signing papers?"
"Yep, two Clints from Alaska moving in today."
"Wow, what are the odds of that?"
So there you have it. That's probably the strangest coincidence that's happened to me. I'd like to hear some other stories.
p.s. I don't believe in any voodoo or fate stuff, so my statistics-oriented mind chalks this up to random chance alone.
(2006-10-27 08:43:44.0/2006-10-27 08:41:06.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/crazy_coincidences
|
|
|
Friday October 06, 2006 |
|
UrbanDrinks.com Screenshot
Thought I should add a pretty picture to go with my previous post. The red bars are little graphs to show the time ranges when the happy hours occur, created using RMagick.
(2006-10-05 21:48:33.0/2006-10-06 05:00:00.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/urbandrinks_com_screenshot
|
|
|
Saturday September 30, 2006 |
|
UrbanDrinks.com Site Launch
I'm excited to say that we've finally launched the beta version of UrbanDrinks.com, a happy-hour website focused on Portland, Oregon.
This has been a side-project I've been working on since early July using Ruby on Rails (in fact, it's what my RubyQuiz post was all about). I've learned a lot so far about the Google Maps API and designing a database to handle all of the time ranges and associated happy hours, as well as just polishing (er... maybe "sanding" is a better term) my Ruby skills. I've also had the pleasure of pulling my hair out dealing with Internet Explorer CSS bugs.
I have to thank Guilhem Vellut for his wonderful Google Maps Rails Plugin. This plugin made the Google Maps portion of the project a thousand times easier. Of course, I should also thank the people who responded to the DayRange RubyQuiz and the Rails and Ruby developers in general. They really do make web development fun.
The site is still under development, so there could be some bugs. Definitely let us know if you find any or if you have any comments or suggestions. We also have an UrbanDrinks blog where we'll keep you posted on site updates and our opinions on various things related to happy hours. Enjoy!
(2006-10-05 21:49:59.0/2006-09-30 11:37:05.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/urbandrinks_com_site_launch
|
|
|
Sunday August 27, 2006 |
|
Rubyquiz has accepted my submission, asking readers to write a class that returns a range of days in a human-readable format. The quiz can be found here.
Here's an excerpt explaining the idea..
If you've ever created a web application that deals with scheduling recurring events, you may have found yourself creating a method to convert a list of days into a more human-readable string.
For example, suppose a musician plays at a certain venue on Monday, Tuesday, Wednesday, and Saturday. You could pass a list of associated day numbers to your object or method, which might return "Mon-Wed, Sat".
The purpose of this quiz is to find the best "Ruby way" to generate this sentence-like string.
[...]
Here are some example lists of days and their expected returned strings:
1,2,3,4,5,6,7: Mon-Sun
1,2,3,6,7: Mon-Wed, Sat, Sun
1,3,4,5,6: Mon, Wed-Sat
2,3,4,6,7: Tue-Thu, Sat, Sun
1,3,4,6,7: Mon, Wed, Thu, Sat, Sun
7: Sun
1,7: Mon, Sun
1,8: ArgumentError
To my surprise, there have already been several submissions with varying ways of solving the problem. This is a good way to learn some Ruby for sure..
(2006-08-27 12:10:46.0/2006-08-27 10:15:06.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/day_range_rubyquiz
|
|
|
Saturday August 05, 2006 |
|
We should have played board games in business school
This game is brilliant and fun. Here's a quick description of Modern Art:
Five different artists have produced a bunch of paintings, and it's the player's task to be both the buyer and the seller, hopefully making a profit in both roles. He does this by putting a painting from his hand up for auction each turn. He gets the money if some other player buys it, but must pay the bank if he buys it for himself. After each round, paintings are valued by the number of paintings of that type that were sold. The broker with the most cash after four rounds is the winner.
If you don't want to get the board game, you can get a free Windows version here.
(2006-08-05 09:22:07.0/2006-08-05 09:22:07.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/we_should_have_played_board
|
|
|
Wednesday August 02, 2006 |
|
Everyone should get a Sun Ray
If you run a company with a separate computer for each employee, you should really stop doing that and switch over to running a company with a Sun Ray for every employee. Yeah, this is a "plug" for Sun, but I'm serious about this. Sun recently set me up with a Sun Ray at home (a Sun Ray 170 to be exact), and I'm very impressed. We've been using Sun Rays at work for a few years now, but seeing them work so well from home is whole other level of technological coolness. Here's a short list of benefits:
- I don't have to maintain anything. All of the applications sit on centralized servers, which are much easier and cheaper to maintain than individual (especially Windows-based) systems.
- I can leave my session at work with various applications open, even if I'm in the middle of typing an email, and when I get home, I simply insert my badge/smart card and I can pick up where I left off.
- It's fast. Right now I'm typing this from 13 miles away from the servers and I can see no delay as I type. Sometimes the screen jitters a bit when I switch windows, but it's not bad at all.
- It's secure. I don't have to worry about setting up my laptop to be hacker-proof and don't have to worry about it being stolen.
- It's completely quiet and power efficient. The first time I used a Sun Ray at home, I found it almost too quiet in my condo. No fans, no heat, no hard drive noise.
- This 17" LCD is way nicer than my laptop display!
Heck, if I had a family, I'd set up a small Sun Ray network at home. Of course, I'd also make my kids use Solaris or Linux too...
(2006-08-02 22:33:19.0/2006-08-02 22:10:00.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/everyone_should_get_a_sun
|
|
|
Tuesday January 10, 2006 |
|
Baseball Annual for Geeks
Here's a shameless plug for a great baseball book.. The Hardball Times 2006 Baseball Annual. It's got the best statistics around for you stats heads and great articles on everything from pitch counts to game-by-game breakdowns of the world series.
This is a plug since I helped generate some of the stats for the book and developed the stats section of their website.
(2006-01-10 08:30:11.0/2006-01-10 08:30:00.0)
Permalink
Trackback: http://blogs.sun.com/bdonovan/entry/baseball_annual_for_geeks
|
|
|
|
| « February 2010 | | Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|
| | 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 | | | | | | | | | | | | | | | | Today |
Today's Page Hits: 70
|