Toy Robot is a Ruby CLI app that let users simulate the movement of a Toy Robot on a 5X5 tabletop.
The problem specification can be found at PROBLEM.md
This app has been developed and tested with ruby version 2.5.3.
Installation Instructions:
On NixOs (my primary OS)
You can run nix-shell on the root of the project and it will install the correct version of ruby (with other required dependencies).
Install any of the available ruby version managers e.g. rbenv or rvm
Then run rbenv install 2.5.3 or rvm install 2.5.3 to install the correct version of ruby.
Some of the ruby gem dependencies have native extensions, so make sure the system has build tools installed so they can be compiled (search google for command line developer tools on macOS (or OSX)).
Use your operating systems manual or search on google on how to install a specific version of ruby on your specific OS.
https://www.ruby-lang.org/en/downloads/ can be a good starting point.
Install ruby following the installation instructions above. Then run bin/setup from the root of the project to set up the project (installing required gems).
Once the dependencies have been installed, run bin/run to start the REPL and then follow the instructions.
The program also supports interpreting commands from a file for convenience. Create a file with one command per line then run it like INPUT_FILE=/path/to/commands/file bin/run. It will interpret the file line by line if it exists and will fall back to the REPL if it does not.
The project includes example command files at spec/fixtures and can be used like INPUT_FILE=./spec/fixtures/commands_file_with_all_valid_commands.txt bin/run from the root of the project.
Enjoy!
Run bundle exec rspec to run the tests. It will generate code coverage into the coverage directory. You can also run bin/console and it will instantiate few useful objects and drop you on a pry console. Convenient for experimenting.
- Assumed it's OK to convert the text entered by the user into uppercase
- Assumed there's no restriction on usage of any specific paradigm or set of gems. Chose to use
few gems from
dry-rbwhich I wouldn't usually do without discussing with the team. Assumed this is either a solo project or my team members have moderate level of understanding of how theResulttype works (and usage ofbindfromdry-monadgem).
- Uses domain entities and value objects to represent the core entities it works with and use
dry-typesto enforce correctness of the data. - Use dependency injection where applicable.
- Use builders to construct a
CommandDescriptorso theSimulatorcan perform it's operation without worrying about invalid commands. As long as it receives an instance of theCommandDescriptorit can be sure that it has a valid command. - Tries to follow
SRP(Single Responsibility Principle) but couldn't spend enough time looking back at them after finishing it. Sometimes looking at a complete solution gives opportunities to find out modelling/design problems. - Tries to use
Resulttype to represent errors rather than usingexception for control flowor passing around nils when a recoverable error occurs. - Tries to use
CLIas a delivery mechanism while striving to make the core of theappreusable with other delivery mechanisms easily (e.g. web).
- Implemented proper validation with
dry-schemasto provide better error messages. - Spent a bit more time with the data types to see if there's any low hanging refactoring that can be performed.
- Would have researched ways to write integration spec for testing
bin/run. - Would have spent a bit more time thinking about edge cases and had written more specs if the app was not handling any of those cases
- Though about if I should move
Entities::RobotintoValueObjectsnamespace. Though it feels like it's an entity, it's being used as an immutable value object. - Would have introduced a
Sumtype for the return value of theCommandInterpreter, something along the line ofCommandInterpreterResult = Entities::Robot | Types::Strict::Stringso it could either return an updated robot or some output to return to the user (forREPORTcommand) and simulator could do the right thing based on that(and it won't have to pry into thecommand_identifieritself, which I think is not it's responsibility).
The code is available as open source under the terms of the MIT License. A copy of which is included in LICENSE.txt