29 January, 2008

with_probability

In fuzzing my database for testing (see Fuzzing your Database and Faker), I've found the following to be very useful:

Object.class_eval do
  def with_probability(prob, &block)
    if rand <= prob
      block.call 
      return ProbabilisticDoer::Done.new
    else
      return ProbabilisticDoer::NotDone.new
    end
  end
end

module ProbabilisticDoer
  class NotDone
    def else_with_probability(prob, &block)
      with_probability(prob, &block)
    end
    def else(&block)
      with_probability(1, &block)
    end
  end
  
  class Done
    def else_with_probability(prob, &block)
      return self
    end
    def else(&block)
      return self
    end
  end
end

With that, you can do things like

u = User.create(...)
with_probability(9/10.0) do
  u.stuff_that_most_users_should_do
end

with_probability(0.01) do
  u.stuff_that_very_few_users_should_do
end.else_with_probability(0.2) do
  u.stuff_that_some_but_none_of_the_above_users_should_do
end.else do
  u.stuff_the_rest_of_the_users_should_do
end

1 comment:

Anonymous said...

nice but...

case rand
when 0.0..0.01
blah
when 0.01..0.2
blah2
else
blah3
end

would have been simpler, but maybe not as much fun for you :P