Last active
February 4, 2018 16:25
-
-
Save yaroslav/ae8c258031a83c33c7f1bb448a8b1582 to your computer and use it in GitHub Desktop.
Board put_at (https://twitter.com/TotherAlistair/status/960018354168913925)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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