Skip to content

Instantly share code, notes, and snippets.

@ashmoran
Created October 21, 2012 16:11
Show Gist options
  • Save ashmoran/3927379 to your computer and use it in GitHub Desktop.
Save ashmoran/3927379 to your computer and use it in GitHub Desktop.
Trailing Stop Loss kata extracts for the Celluloid mailing list
require 'celluloid'
require_relative 'timers/null_timer'
require_relative 'timers/too_late_timer'
class MarketAgent
include Celluloid
class ActionError < RuntimeError; end
def initialize(dependencies)
@market = dependencies.fetch(:market)
@delay = dependencies.fetch(:delay)
@timer = NullTimer.new
end
def sell
@timer.cancel
@timer = after(@delay) do
@market.sell
@timer = too_late_timer
end
end
def belay
@timer.cancel
end
private
def null_timer
NullTimer.new
end
def too_late_timer
TooLateTimer.new(
ActionError.new("Sell order has already been issued")
)
end
end
require 'spec_helper'
require 'market_agent'
describe MarketAgent, focus: true do
include CelluloidHelpers
let(:market) { MockMarket.new(sell_action: ->{ sleep 0.07 }) }
subject(:agent) { MarketAgent.new(market: market, delay: 0.05) }
# Most examples removed
context "after the time specified" do
it "sells" do
agent.sell
sleep 0.06
expect(market.actions).to be == [ :sell ]
end
context "when told to belay" do
it "raises an error", focus: true do
agent.sell
sleep 0.06
expect {
agent.belay
}.to raise_error(MarketAgent::ActionError, "Sell order has already been issued")
end
end
end
end
require 'celluloid'
class MockMarketAgent
include Celluloid
def initialize(options = { })
@actions = [ ]
@sell_action = options.fetch(:sell_action, -> { })
end
def sell
@sell_action.call
@actions << :sell
end
def belay
@actions << :belay
end
def actions
@actions.dup
end
end
# It just turned out they're the exact same thing
MockMarket = MockMarketAgent
class NullTimer
def cancel
# NOOP
end
end
class TooLateTimer
def initialize(error)
@error = error
end
def cancel
raise @error
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment