Skip to content

Instantly share code, notes, and snippets.

@yaroslav
Last active February 4, 2018 16:25
Show Gist options
  • Save yaroslav/ae8c258031a83c33c7f1bb448a8b1582 to your computer and use it in GitHub Desktop.
Save yaroslav/ae8c258031a83c33c7f1bb448a8b1582 to your computer and use it in GitHub Desktop.
class Board
class BoardOccupiedError < StandardError
end
attr_reader :board
attr_reader :last_step_successful
def initialize
@board = []
@last_step_successful = true
end
def occupied?(location)
!@board[location]
end
def put_at(stone, location)
if occupied?(location)
@last_step_successful = false
else
@board[location] = stone
@last_step_successful = true
end
@board
end
def put_at!(stone, location)
put_at(stone, location)
raise BoardOccupiedError, "Board at #{location} is occupied!" unless @last_step_successful
end
def clear_at(location)
@board[location] = nil
@board
end
end
## Use cases
# 1. Silent moves. Also chaining!
board.put_at(stone, location).put_at(stone2, location2)
# 2. Silent moves, control flow
# ("as a user, if the move is impossible, I get a message")
board = board.put_at(stone, location)
if board.last_step_successful
redirect_to :next_move
else
flash[:error] = "Board is occupied!"
end
# 3. Moves with exception handling
board.put_at!(stone, location)
# 3.1 we don't expect any errors and only see them in logs/error catching services
# ...
# 3.2 we use exceptions for flow control, yay!
# ...
board.put_at!(stone, location)
rescue BoardOccupiedError
flash[:error] = "Board is occupied!"
# ...
## Alternative approach
# `put_at` returns `true` or `false`, `board` is accessble via `#board`
#
# Cons: non-chainable
#
# Pros: easier code
#
# Pros 2: you probably don't really need chaining anyway since you need to
# check on errors after every move
class Board
class BoardOccupiedError < StandardError
end
attr_reader :board
def initialize
@board = []
end
def occupied?(location)
!@board[location]
end
def put_at(stone, location)
success = false
unless occupied?(location)
@board[location] = stone
success = true
end
success
end
def put_at!(stone, location)
put_at(stone, location) ||
raise BoardOccupiedError, "Board at #{location} is occupied!"
end
end
## Use cases
if board.put_at(stone.location)
flash[:message] = "Done!"
else
flash[:error] = "Yikes!"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment