A gem providing a mechanism to dispense instances of a class, somewhere between a true singleton and new instance each time.
Originally developed for Simulmedia.
Installation
Add this line to your application's Gemfile:
# update with the version of your choice
gem 'gumball'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install gumball
Usage
Let's say we have some expensive operation we need to utilize the value of. We need to refresh it occasionally, but if we sometimes get a slightly-stale copy, that's ok.
class ExpensiveThing
def self.value
sleep 5
rand(1..100)
end
end
We set up a new dispenser for that operation. These dispensers are best saved as class variables, so the dispenser itself is a singleton.
require 'gumball'
dispenser = Gumball::Dispenser.new(300) { ExpensiveThing.value }
# => #<Gumball::Dispenser:0x007f87eff446c8 @ttl=300, @last_refreshed=nil, @refresh_block=#<Proc:0x007f87eff44678@(irb):9>, @on_change_block=nil>
dispenser.item # this will take a while
# => 90
dispenser.item # if run in quick succession, returned result is immediate, and value is the same
# => 90
sleep 305
dispenser.item # ttl has expired... prepare to wait
# => 41
dispenser.item # we've saved our refreshed version, and our response is immediate!
# => 41
If we want to be able to set up our dispenser so that we can perform some other operation in the event the value actually changes:
# note the optional logger paseed in below...
dispenser = Gumball::Dispenser.new(300, logger: Logger.new($stdout)) { ExpensiveThing.value }
dispenser.on_change { |o, n| puts "OUR VALUE CHANGED: #{o} -> #{n}" }
The on_change
method counts on equality being properly implemented between the values, and ONLY fires when inequality between
old and new items is detected. If the refresh pulls in the same value, the on_change
block is not triggered.
Problems?
Please submit an issue. We'll figure out how to get you up and running with Gumball as smoothly as possible.