A simulator of a toy robot that moves on a tabletop.
Upgrade some Ruby Gem versions
Remove spuriously duplicated spec for Table
Add a couple more maintenance highlights to the README


browse  log 



You can also use your local clone with git send-email.


toy-robot is a simulator of a toy robot that moves on a tabletop.

Demonstration of interactive toy-robot use


toy-robot reads instructions from STDIN, executing them one at a time until EOF is reached. (On a Linux or OSX system, type C-d to generate an EOF character).

#valid commands


Put the toy robot on the table in position X,Y and facing NORTH, SOUTH, EAST or WEST. If the robot is already placed, issuing another valid PLACE command will place the robot in the newly specified location.


Moves the toy robot one unit forward in the direction it is currently facing.


Rotates the robot 90 degrees to the left (i.e. counter-clockwise) without changing the position of the robot.

Rotates the robot 90 degrees to the right (i.e. clockwise) without changing the position of the robot.


Announces the X,Y and F of the robot.


Ensure you have Git and Ruby 3.2.0 installed. Optionally, install rbenv to manage Ruby versions, and editorconfig for automatic editor configuration.

Then, in a console execute:

git clone https://git.sr.ht/~duncan-bayne/toy-robot
cd toy-robot
gem install bundler
bundle config set --local without ':development'
bundle install

#supported operating systems

toy-robot should install on pretty much any recent Unix or Unix-like operating system, and Microsoft Windows. I've tested it on the following operating systems (both on amd64):

  • FreeBSD 13.1
  • Linux Mint 21 'Vanessa'



$ ./toy_robot.rb

From a file instructions.txt containing instructions:

$ cat instructions.txt | ./toy_robot.rb

With invalid commands:

$ ./toy_robot.rb
Ignoring PLACE with invalid arguments.
Ignoring MOVE until robot is PLACEd.



I developed toy-robot test first; you can see the commit log for how I proceeded, and how I subsequently kept the code on current library and Ruby versions.

I made the following assumptions:

  • lines that are either empty or contain only whitespace can be completely ignored
  • multiple valid PLACE statements are valid
  • case-sensitivity was by design (e.g. PLACE but not place)
  • abbreviations are not allowed (e.g. NORTH but not N)
  • comma separators are required (e.g. 0,0,NORTH but not 0 0 NORTH)
  • this is a Unix program (so it observes the Rule of Silence and only reports on errors or when instructed)

Depending upon the time available and the background of the intended users, some of those assumptions could easily be challenged. E.g. Windows users are not used to case sensitivity or silent success.

If I were to add any more commands, or increase the complexity of the commands, I would consider refactoring the Simulator class to use the Command Pattern. That would allow easy unit testing of the individual commands.


I first created toy-robot ten years ago, and have been maintaining it since. It's grown from a simple take-home exercise into a rolling demo of my approach to software maintenance - both technically, and from the perspective of developer experience. Over the years I've:

  • upgraded from Ruby 1.x, through Ruby 2.x, to Ruby 3.x.
  • upgraded to Bundler 2.4.4
  • switched to "modern" RSpec structure
  • added automated test-running
  • switched to RubyCritic from older, now unmaintained, analysis tools
  • added support for RBS type signatures
  • added asciinema screencast recordings for better docs
  • added LSP support for better editor integration


Feature requests, bug reports, and questions can be raised on the Tracker page.

If you'd like to contribute code, you can use Sourcehut's patchset feature.



To install all the development Gems required, run:

bundle config unset --local without
bundle install

If you want to update the screencast, you'll also need to install the following additional tools:

  1. asciinema for recording screencasts.
  2. agg for converting screencast recordings into GIFs.
#type signatures

As of this commit, the toy-robot codebase supports RBS type signatures. It also enforces them when specs are run, either manually, through Rake, or through Guard.

The type signatures are not complete; see all tickets labelled type-signature for a list of remaining work.

#Language Server Protocol (LSP) support

As of this commit, the toy-robot codebase supports LSP for integration with any LSP-supporting editor.

To start the LSP server:

 $ bundle exec solargraph socket
Solargraph is listening PORT=7658 PID=87172

... then enable LSP in your editor of choice. I've tested this with https://melpa.org/#/eglot in GNU Emacs 28.2, and it works well.

#running automated tasks

Specs, documentation and quality checks are automated through rake. E.g. to display a list of all tasks:

$ bundle exec rake -T
rake build_screencast   # Generates screencast animation from asciinema file
rake default            # Runs all specs and quality tests, then generates documentation and the screencast animation
rake documentation      # Generates HTML documentation from Markdown files
rake record_screencast  # Starts recording for the screencast
rake ruby_critic        # Run RubyCritic
rake specs              # Run RSpec code examples

To run everything:

/usr/home/duncan/.rbenv/versions/3.2.0/bin/ruby -I/usr/home/duncan/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rspec-core-3.12.1/lib:/usr/home/duncan/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rspec-support-3.12.0/lib /usr/home/duncan/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/rspec-core-3.12.1/exe/rspec --pattern spec/\*\*/\*_spec.rb --backtrace
I, [2023-02-15T10:35:57.794502 #55703]  INFO -- : Setting up hooks for ::ToyRobot::Table
I, [2023-02-15T10:35:57.794640 #55703]  INFO -- rbs: Installing runtime type checker in ToyRobot::Table...
I, [2023-02-15T10:35:57.814380 #55703]  INFO -- rbs: Setting up method hook in #place...
I, [2023-02-15T10:35:57.821965 #55703]  INFO -- : Setting up hooks for ::ToyRobot
I, [2023-02-15T10:35:57.822010 #55703]  INFO -- rbs: Installing runtime type checker in ToyRobot...
I, [2023-02-15T10:35:57.823270 #55703]  INFO -- : Setting up hooks for ::ToyRobot
I, [2023-02-15T10:35:57.823320 #55703]  INFO -- rbs: Installing runtime type checker in ToyRobot...
I, [2023-02-15T10:35:57.823919 #55703]  INFO -- : Setting up hooks for ::ToyRobot
I, [2023-02-15T10:35:57.823969 #55703]  INFO -- rbs: Installing runtime type checker in ToyRobot...

Finished in 0.04144 seconds (files took 0.65782 seconds to load)
55 examples, 0 failures

Coverage report generated for RSpec to /usr/home/duncan/code/toy-robot/coverage. 242 / 244 LOC (99.18%) covered.
running flay smells
running flog smells
running reek smells
running complexity
running attributes
running churn
running simple_cov
New critique at file:////usr/home/duncan/code/toy-robot/tmp/rubycritic/overview.html
Score: 90.94
58 / 58 [==================================================================================================================================================================] 100.00 % 258.89/s


toy-robot is licensed under the GNU Lesser General Public License.

#why the LGPL?

The GPL is specifically designed to reduce the usefulness of GPL-licensed code to closed-source, proprietary software. The BSD license (and similar) do not mandate code-sharing if the BSD-licensed code is modified by licensees. The LGPL achieves the best of both worlds: an LGPL-licensed library can be incorporated within closed-source proprietary code, and yet those using an LGPL-licensed library are required to release source code to that library if they change it.