maux_robot 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +9 -3
- data/bin/maux_robot +1 -0
- data/lib/maux_robot.rb +14 -5
- data/lib/maux_robot/cli.rb +10 -32
- data/lib/maux_robot/formatter.rb +14 -0
- data/lib/maux_robot/formatter/csv.rb +11 -0
- data/lib/maux_robot/formatter/json.rb +17 -0
- data/lib/maux_robot/parser.rb +39 -0
- data/lib/maux_robot/position.rb +32 -16
- data/lib/maux_robot/robot.rb +64 -14
- data/lib/maux_robot/table.rb +3 -3
- data/lib/maux_robot/version.rb +3 -3
- data/spec/maux_robot/cli_spec.rb +12 -59
- data/spec/maux_robot/formatter/csv_spec.rb +13 -0
- data/spec/maux_robot/formatter/json_spec.rb +13 -0
- data/spec/maux_robot/formatter_spec.rb +23 -0
- data/spec/maux_robot/parser_spec.rb +73 -0
- data/spec/maux_robot/position_spec.rb +56 -53
- data/spec/maux_robot/robot_spec.rb +41 -40
- data/spec/maux_robot/table_spec.rb +3 -5
- data/spec/spec_helper.rb +5 -0
- metadata +17 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9c718637133d2a7b8dfb7d42fdcd754ce4eff6ec1fba93f7fe5ddaaa612d1cc1
|
4
|
+
data.tar.gz: 064f6ebc5ceefaa8dc44a2ff1f577178675cf362ffb77c3726c6e2ae6f62f1f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cd5c5b6adfccdda316a95ac5f88cefbef598239ed2e981c47f10a70b63a0133af84b70b1effafa04dc0643efafa22bb183d8779d43630310e6068a6a854c370
|
7
|
+
data.tar.gz: 51e46cca8fc6e0239ae9c286611fc11e4589959d5338fac2317107fd2703e3112c201ca63e50bdda96aade74e1c2d71a78c02ff7d93f83b40009d9c41c4bed29
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
[](https://travis-ci.org/mauriciovieira/maux_robot)
|
2
|
+
[](https://codeclimate.com/github/mauriciovieira/maux_robot/maintainability)
|
3
|
+
[](https://codeclimate.com/github/mauriciovieira/maux_robot/test_coverage)
|
4
|
+
|
1
5
|
# maux_robot
|
2
6
|
|
3
7
|
Maux version of a Toy Robot Simulator in Ruby
|
@@ -22,7 +26,8 @@ PLACE X,Y,F
|
|
22
26
|
MOVE
|
23
27
|
LEFT
|
24
28
|
RIGHT
|
25
|
-
REPORT
|
29
|
+
REPORT [csv|json]
|
30
|
+
VERBOSE
|
26
31
|
```
|
27
32
|
|
28
33
|
* `PLACE` will put the toy robot on the table in position X,Y
|
@@ -38,7 +43,8 @@ in the direction it is currently facing.
|
|
38
43
|
* `LEFT` and `RIGHT` will rotate the robot 90 degrees
|
39
44
|
in the specified direction
|
40
45
|
without changing the position of the robot.
|
41
|
-
* `REPORT` will announce the X,Y and F of the robot.
|
46
|
+
* `REPORT` will announce the X,Y and F of the robot. If `csv` or `json` is passed, it formats the whereabouts accordingly. The default format is `csv`.
|
47
|
+
* `VERBOSE` will turn the error messages (talkative mode) on or off. The robot starts with talkative mode set to off.
|
42
48
|
|
43
49
|
* A robot that is not on the table ignores the `MOVE`, `LEFT`, `RIGHT` and `REPORT` commands.
|
44
50
|
|
@@ -101,4 +107,4 @@ The Toy Robot Challenge was originally formulated by [Jon Eaves](https://twitter
|
|
101
107
|
**Mauricio Vieira (mauriciovieira)**
|
102
108
|
+ <http://mauriciovieira.net>
|
103
109
|
+ <https://twitter.com/mauriciovieira>
|
104
|
-
+ <https://github.com/mauriciovieira>
|
110
|
+
+ <https://github.com/mauriciovieira>
|
data/bin/maux_robot
CHANGED
data/lib/maux_robot.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "maux_robot/version"
|
4
|
+
require "maux_robot/cli"
|
5
|
+
require "maux_robot/formatter"
|
6
|
+
require "maux_robot/formatter/csv"
|
7
|
+
require "maux_robot/formatter/json"
|
8
|
+
require "maux_robot/parser"
|
9
|
+
require "maux_robot/position"
|
10
|
+
require "maux_robot/table"
|
11
|
+
require "maux_robot/robot"
|
12
|
+
|
13
|
+
module MauxRobot
|
14
|
+
end
|
data/lib/maux_robot/cli.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MauxRobot
|
4
|
-
|
5
4
|
# The CLI is a class responsible of handling command line interface
|
6
5
|
class CLI
|
7
|
-
ALLOWED_ORDERS = %i[left right move place report].freeze
|
8
|
-
|
9
6
|
attr_reader :robot
|
10
7
|
def initialize
|
11
8
|
@robot = Robot.new
|
@@ -19,43 +16,24 @@ module MauxRobot
|
|
19
16
|
def run_script(all_input)
|
20
17
|
all_input.split("\n").each do |line_input|
|
21
18
|
command = parse(line_input)
|
22
|
-
|
19
|
+
begin
|
20
|
+
execute(command) if command
|
21
|
+
rescue MauxRobot::RobotError => e
|
22
|
+
puts e if @robot.talkative
|
23
|
+
end
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
27
|
def parse(line_input)
|
27
|
-
|
28
|
-
order = sanitize_order(clean_input.shift)
|
29
|
-
return unless order
|
30
|
-
|
31
|
-
command = { order: order }
|
32
|
-
|
33
|
-
if clean_input.any?
|
34
|
-
arguments = sanitize_arguments(clean_input.join(''))
|
35
|
-
command[:arguments] = arguments
|
36
|
-
end
|
37
|
-
|
38
|
-
command
|
28
|
+
Parser.new.parse(line_input)
|
39
29
|
end
|
40
30
|
|
41
31
|
def execute(command)
|
42
|
-
if command
|
43
|
-
@robot.send(command[:order])
|
44
|
-
else
|
32
|
+
if command.key?(:arguments)
|
45
33
|
@robot.send(command[:order], command[:arguments])
|
34
|
+
else
|
35
|
+
@robot.send(command[:order])
|
46
36
|
end
|
47
37
|
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def sanitize_order(input_string)
|
52
|
-
order = input_string.downcase.to_sym
|
53
|
-
order if ALLOWED_ORDERS.include?(order)
|
54
|
-
end
|
55
|
-
|
56
|
-
def sanitize_arguments(arguments)
|
57
|
-
arguments = arguments.delete(' ').split(',')
|
58
|
-
{ x: arguments[0], y: arguments[1], face: arguments[2] }
|
59
|
-
end
|
60
38
|
end
|
61
|
-
end
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module MauxRobot
|
6
|
+
module Formatter
|
7
|
+
class Json
|
8
|
+
def generate(position)
|
9
|
+
JSON.generate(
|
10
|
+
x: position.x,
|
11
|
+
y: position.y,
|
12
|
+
face: position.face.upcase.to_s
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MauxRobot
|
4
|
+
class Parser
|
5
|
+
ALLOWED_ORDERS = %i[left right move place report verbose].freeze
|
6
|
+
|
7
|
+
def parse(line_input)
|
8
|
+
clean_input = line_input.strip.squeeze(" ").split(" ")
|
9
|
+
order = sanitize_order(clean_input.shift)
|
10
|
+
return unless order
|
11
|
+
|
12
|
+
command = {order: order}
|
13
|
+
|
14
|
+
if clean_input.any?
|
15
|
+
arguments = sanitize_arguments(order, clean_input.join(""))
|
16
|
+
command[:arguments] = arguments
|
17
|
+
end
|
18
|
+
|
19
|
+
command
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def sanitize_order(input_string)
|
25
|
+
order = input_string.downcase.to_sym
|
26
|
+
order if ALLOWED_ORDERS.include?(order)
|
27
|
+
end
|
28
|
+
|
29
|
+
def sanitize_arguments(order, arguments)
|
30
|
+
case order
|
31
|
+
when :place
|
32
|
+
arguments = arguments.delete(" ").split(",")
|
33
|
+
{x: arguments[0], y: arguments[1], face: arguments[2]}
|
34
|
+
when :report
|
35
|
+
{format_type: arguments.downcase.to_sym}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/maux_robot/position.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "maux_robot"
|
4
4
|
|
5
5
|
module MauxRobot
|
6
|
-
|
7
6
|
# This class represents the Robot position on the table
|
8
7
|
class Position
|
9
8
|
attr_reader :x, :y, :face
|
10
9
|
|
11
|
-
POSSIBLE_DIRECTIONS = [
|
10
|
+
POSSIBLE_DIRECTIONS = %i[north west south east].freeze
|
12
11
|
POSSIBLE_MOVEMENTS = {
|
13
|
-
north: {
|
14
|
-
west:
|
15
|
-
south: {
|
16
|
-
east:
|
17
|
-
}
|
12
|
+
north: {x: 0, y: 1},
|
13
|
+
west: {x: -1, y: 0},
|
14
|
+
south: {x: 0, y: -1},
|
15
|
+
east: {x: 1, y: 0}
|
16
|
+
}.freeze
|
18
17
|
|
19
|
-
def initialize(x, y, face)
|
18
|
+
def initialize(x, y, face) # rubocop:disable Naming/UncommunicativeMethodParamName
|
20
19
|
@x = x.to_i
|
21
20
|
@y = y.to_i
|
22
21
|
@face = face&.downcase&.to_sym || :invalid
|
@@ -26,24 +25,41 @@ module MauxRobot
|
|
26
25
|
POSSIBLE_DIRECTIONS.include?(@face)
|
27
26
|
end
|
28
27
|
|
29
|
-
def
|
30
|
-
|
28
|
+
def left
|
29
|
+
return self unless valid_direction?
|
30
|
+
|
31
|
+
next_direction_index = (POSSIBLE_DIRECTIONS.index(@face) + 1) % 4
|
31
32
|
@face = POSSIBLE_DIRECTIONS[next_direction_index]
|
32
33
|
end
|
33
34
|
|
34
|
-
def
|
35
|
-
|
35
|
+
def right
|
36
|
+
return self unless valid_direction?
|
37
|
+
|
38
|
+
next_direction_index = (POSSIBLE_DIRECTIONS.index(@face) - 1)
|
36
39
|
@face = POSSIBLE_DIRECTIONS[next_direction_index]
|
37
40
|
end
|
38
41
|
|
39
42
|
def forward_position
|
43
|
+
return self unless valid_direction?
|
44
|
+
|
40
45
|
x = @x + POSSIBLE_MOVEMENTS[@face][:x]
|
41
46
|
y = @y + POSSIBLE_MOVEMENTS[@face][:y]
|
42
47
|
Position.new(x, y, @face)
|
43
48
|
end
|
44
49
|
|
45
|
-
def
|
46
|
-
|
50
|
+
def report(format_type = :csv)
|
51
|
+
formatter = MauxRobot::Formatter.from(format_type)
|
52
|
+
puts formatter.generate(self)
|
53
|
+
end
|
54
|
+
|
55
|
+
def ==(other)
|
56
|
+
other.x == x && other.y == y && other.face == face
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class NullPosition < Position
|
61
|
+
def initialize
|
62
|
+
super(nil, nil, nil)
|
47
63
|
end
|
48
64
|
end
|
49
|
-
end
|
65
|
+
end
|
data/lib/maux_robot/robot.rb
CHANGED
@@ -1,41 +1,91 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "forwardable"
|
4
|
+
|
3
5
|
module MauxRobot
|
6
|
+
class RobotError < StandardError; end
|
7
|
+
|
8
|
+
# Error to notify that the robot was not placed yet
|
9
|
+
class RobotNotPlacedYet < RobotError
|
10
|
+
def initialize
|
11
|
+
super("The robot was not placed yet!")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Error to notify that the position is/would be outside the table
|
16
|
+
class NotOkToGo < RobotError
|
17
|
+
def initialize(position)
|
18
|
+
super("It's not ok to go to #{position.x},#{position.y}")
|
19
|
+
end
|
20
|
+
end
|
4
21
|
|
5
22
|
# The main class. It executes the actions using its table and position
|
6
23
|
class Robot
|
7
|
-
attr_reader :position
|
24
|
+
attr_reader :position, :talkative
|
8
25
|
|
9
|
-
def initialize(table=MauxRobot::Table.new)
|
26
|
+
def initialize(table = MauxRobot::Table.new)
|
10
27
|
@table = table
|
28
|
+
@position = MauxRobot::NullPosition.new
|
29
|
+
@talkative = false
|
11
30
|
end
|
12
31
|
|
13
|
-
def place(x:, y:, face:)
|
32
|
+
def place(x:, y:, face:) # rubocop:disable Naming/UncommunicativeMethodParamName
|
14
33
|
position = MauxRobot::Position.new(x, y, face)
|
15
34
|
|
16
|
-
|
35
|
+
ok_to_go?(position) do
|
17
36
|
@position = position
|
18
37
|
end
|
38
|
+
@position
|
39
|
+
end
|
40
|
+
|
41
|
+
def move
|
42
|
+
robot_placed? do
|
43
|
+
next_position = @position.forward_position
|
44
|
+
|
45
|
+
ok_to_go?(next_position) do
|
46
|
+
@position = next_position
|
47
|
+
end
|
48
|
+
|
49
|
+
@position
|
50
|
+
end
|
19
51
|
end
|
20
52
|
|
21
53
|
def left
|
22
|
-
|
54
|
+
robot_placed? do
|
55
|
+
@position.left
|
56
|
+
end
|
23
57
|
end
|
24
58
|
|
25
59
|
def right
|
26
|
-
|
60
|
+
robot_placed? do
|
61
|
+
@position.right
|
62
|
+
end
|
27
63
|
end
|
28
64
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
if @table.contains?(next_position)
|
33
|
-
@position = next_position
|
65
|
+
def report(format_type: :csv)
|
66
|
+
robot_placed? do
|
67
|
+
@position.report(format_type)
|
34
68
|
end
|
35
69
|
end
|
36
70
|
|
37
|
-
def
|
38
|
-
|
71
|
+
def verbose
|
72
|
+
@talkative = !@talkative
|
73
|
+
is_not = @talkative ? "is" : "is not"
|
74
|
+
puts "Robot #{is_not} talkative now."
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def ok_to_go?(position)
|
80
|
+
raise NotOkToGo, position unless @table.contains?(position)
|
81
|
+
|
82
|
+
yield
|
83
|
+
end
|
84
|
+
|
85
|
+
def robot_placed?
|
86
|
+
raise RobotNotPlacedYet if @position.class == MauxRobot::NullPosition
|
87
|
+
|
88
|
+
yield
|
39
89
|
end
|
40
90
|
end
|
41
|
-
end
|
91
|
+
end
|
data/lib/maux_robot/table.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MauxRobot
|
4
|
-
|
5
4
|
# This class represents a table according to simulation rules
|
6
5
|
class Table
|
7
|
-
def initialize(x: [0, 4], y: [0, 4])
|
6
|
+
def initialize(x: [0, 4], y: [0, 4]) # rubocop:disable Naming/UncommunicativeMethodParamName
|
8
7
|
@x = x
|
9
8
|
@y = y
|
10
9
|
end
|
11
10
|
|
12
11
|
def contains?(position)
|
13
|
-
position.
|
12
|
+
position.valid_direction? &&
|
13
|
+
position.x.between?(@x[0], @x[1]) &&
|
14
14
|
position.y.between?(@y[0], @y[1])
|
15
15
|
end
|
16
16
|
end
|
data/lib/maux_robot/version.rb
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
module MauxRobot
|
4
4
|
# This module holds the MauxRobot version information.
|
5
5
|
module Version
|
6
|
-
STRING =
|
6
|
+
STRING = "0.2.0"
|
7
7
|
|
8
|
-
MSG =
|
8
|
+
MSG = "%s (using Parser %s, running on %s %s %s)"
|
9
9
|
|
10
10
|
def self.version(debug = false)
|
11
11
|
if debug
|
12
12
|
format(MSG, STRING, Parser::VERSION,
|
13
|
-
|
13
|
+
RUBY_ENGINE, RUBY_VERSION, RUBY_PLATFORM)
|
14
14
|
else
|
15
15
|
STRING
|
16
16
|
end
|
data/spec/maux_robot/cli_spec.rb
CHANGED
@@ -1,71 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "maux_robot"
|
4
4
|
|
5
5
|
describe MauxRobot::CLI do
|
6
|
-
|
7
|
-
context 'valid orders' do
|
8
|
-
it '#report' do
|
9
|
-
expect(subject.parse('REPORT')).to eq(order: :report)
|
10
|
-
end
|
11
|
-
|
12
|
-
it '#move' do
|
13
|
-
expect(subject.parse('MOVE')).to eq(order: :move)
|
14
|
-
end
|
15
|
-
|
16
|
-
it '#left' do
|
17
|
-
expect(subject.parse('LEFT')).to eq(order: :left)
|
18
|
-
end
|
19
|
-
|
20
|
-
it '#right' do
|
21
|
-
expect(subject.parse('RIGHT')).to eq(order: :right)
|
22
|
-
end
|
23
|
-
|
24
|
-
it '#place' do
|
25
|
-
expect(subject.parse('PLACE 0,3,WEST')).to eq(order: :place, arguments: { x: '0', y: '3', face: 'WEST' })
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context 'orders with spaces and downcase' do
|
30
|
-
it '#report' do
|
31
|
-
expect(subject.parse(' repoRT')).to eq(order: :report)
|
32
|
-
end
|
6
|
+
subject(:cli) { described_class.new }
|
33
7
|
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
it '#left' do
|
39
|
-
expect(subject.parse(' LefT ')).to eq(order: :left)
|
40
|
-
end
|
41
|
-
|
42
|
-
it '#right' do
|
43
|
-
expect(subject.parse(' rigHt')).to eq(order: :right)
|
44
|
-
end
|
45
|
-
|
46
|
-
it '#place' do
|
47
|
-
expect(subject.parse('PLACE 2 , 1 , NOrth')).to eq(order: :place, arguments: { x: '2', y: '1', face: 'NOrth' })
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'ignores anything else' do
|
52
|
-
expect(subject.parse('blablabla balbla')).to eq(order: nil)
|
53
|
-
end
|
54
|
-
end
|
8
|
+
describe "#execute" do
|
9
|
+
let(:position) { MauxRobot::Position.new(0, 2, :east) }
|
55
10
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
expect(
|
60
|
-
subject.execute(order: :move)
|
11
|
+
context "when input is parsed without arguments" do
|
12
|
+
it "sends proper message to robot" do
|
13
|
+
allow(cli.robot).to receive(:move).and_return(position)
|
14
|
+
expect(cli.execute(order: :move)).to eq(position)
|
61
15
|
end
|
62
16
|
end
|
63
17
|
|
64
|
-
context
|
65
|
-
it
|
66
|
-
expect(
|
67
|
-
subject.execute(order: :place, arguments: { x: '0', y: '2', face: 'EAST' })
|
18
|
+
context "when place is parsed command with arguments" do
|
19
|
+
it "sends proper message to robot" do
|
20
|
+
expect(cli.execute(order: :place, arguments: {x: "0", y: "2", face: "EAST"})).to eq(position)
|
68
21
|
end
|
69
22
|
end
|
70
23
|
end
|
71
|
-
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe MauxRobot::Formatter::Csv do
|
4
|
+
let(:position) { MauxRobot::Position.new(1, 2, :west) }
|
5
|
+
|
6
|
+
describe "#generate" do
|
7
|
+
subject(:csv_formatter) { described_class.new }
|
8
|
+
|
9
|
+
it "Formats a position as CSV" do
|
10
|
+
expect(csv_formatter.generate(position)).to eq("1,2,WEST")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe MauxRobot::Formatter::Json do
|
4
|
+
let(:position) { MauxRobot::Position.new(1, 2, :west) }
|
5
|
+
|
6
|
+
describe "#generate" do
|
7
|
+
subject(:json_formatter) { described_class.new }
|
8
|
+
|
9
|
+
it "Formats a position as JSON" do
|
10
|
+
expect(json_formatter.generate(position)).to eq('{"x":1,"y":2,"face":"WEST"}')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe MauxRobot::Formatter do
|
4
|
+
subject(:formatter) { described_class }
|
5
|
+
|
6
|
+
describe "#from" do
|
7
|
+
describe "valid format_types" do
|
8
|
+
it "returns csv formatter" do
|
9
|
+
expect(formatter.from(:csv).class).to eq(MauxRobot::Formatter::Csv)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns json formatter" do
|
13
|
+
expect(formatter.from(:json).class).to eq(MauxRobot::Formatter::Json)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "invalid format_types" do
|
18
|
+
it "defaults to csv formatter" do
|
19
|
+
expect(formatter.from(:anything).class).to eq(MauxRobot::Formatter::Csv)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/BlockLength
|
4
|
+
describe MauxRobot::Parser do
|
5
|
+
subject(:parser) { described_class.new }
|
6
|
+
|
7
|
+
describe "#parse" do
|
8
|
+
context "with valid orders" do
|
9
|
+
it "#report" do
|
10
|
+
expect(parser.parse("REPORT")).to eq(order: :report)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#report csv" do
|
14
|
+
expect(parser.parse("REPORT CSV")).to eq(order: :report, arguments: {format_type: :csv})
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#report json" do
|
18
|
+
expect(parser.parse("REPORT JSON")).to eq(order: :report, arguments: {format_type: :json})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#move" do
|
22
|
+
expect(parser.parse("MOVE")).to eq(order: :move)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "#left" do
|
26
|
+
expect(parser.parse("LEFT")).to eq(order: :left)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#right" do
|
30
|
+
expect(parser.parse("RIGHT")).to eq(order: :right)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "#verbose" do
|
34
|
+
expect(parser.parse("VERBOSE")).to eq(order: :verbose)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#place" do
|
38
|
+
expect(parser.parse("PLACE 0,3,WEST")).to eq(order: :place, arguments: {x: "0", y: "3", face: "WEST"})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with orders with spaces and downcase" do
|
43
|
+
it "#report" do
|
44
|
+
expect(parser.parse(" repoRT")).to eq(order: :report)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "#move" do
|
48
|
+
expect(parser.parse("move ")).to eq(order: :move)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "#left" do
|
52
|
+
expect(parser.parse(" LefT ")).to eq(order: :left)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "#right" do
|
56
|
+
expect(parser.parse(" rigHt")).to eq(order: :right)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "#place" do
|
60
|
+
expect(parser.parse("PLACE 2 , 1 , NOrth")).to eq(
|
61
|
+
order: :place, arguments: {x: "2", y: "1", face: "NOrth"}
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "with invalid orders" do
|
67
|
+
it "ignores anything else" do
|
68
|
+
expect(parser.parse("blablabla balbla")).to be_nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# rubocop:enable Metrics/BlockLength
|
@@ -1,12 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
# rubocop:disable Metrics/BlockLength:
|
5
4
|
describe MauxRobot::Position do
|
6
|
-
describe
|
7
|
-
context
|
8
|
-
it
|
9
|
-
position =
|
5
|
+
describe "#initialize" do
|
6
|
+
context "when text input is given" do
|
7
|
+
it "normalizes arguments" do
|
8
|
+
position = described_class.new("0", "1", "SOUTH")
|
10
9
|
|
11
10
|
expect(position.x).to eq(0)
|
12
11
|
expect(position.y).to eq(1)
|
@@ -15,65 +14,65 @@ describe MauxRobot::Position do
|
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
describe
|
19
|
-
context
|
20
|
-
it
|
21
|
-
position =
|
17
|
+
describe "#valid_direction?" do
|
18
|
+
context "when a possible diretion is given" do
|
19
|
+
it "is valid" do
|
20
|
+
position = described_class.new(5, 0, :south)
|
22
21
|
|
23
22
|
expect(position.valid_direction?).to eq(true)
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
27
|
-
context
|
28
|
-
it
|
29
|
-
position =
|
26
|
+
context "when a not possible direction is given" do
|
27
|
+
it "is not valid " do
|
28
|
+
position = described_class.new(1, 1, :south_west)
|
30
29
|
|
31
30
|
expect(position.valid_direction?).to eq(false)
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
36
|
-
describe
|
37
|
-
let(:position) {
|
35
|
+
describe "rotation" do
|
36
|
+
let(:position) { described_class.new(2, 2, :north) }
|
38
37
|
|
39
|
-
|
40
|
-
it
|
41
|
-
position.
|
38
|
+
describe "#left" do
|
39
|
+
it "rotates counter-clockwise" do
|
40
|
+
position.left
|
42
41
|
expect(position.face).to eq(:west)
|
43
42
|
|
44
|
-
position.
|
43
|
+
position.left
|
45
44
|
expect(position.face).to eq(:south)
|
46
45
|
|
47
|
-
position.
|
46
|
+
position.left
|
48
47
|
expect(position.face).to eq(:east)
|
49
48
|
|
50
|
-
position.
|
49
|
+
position.left
|
51
50
|
expect(position.face).to eq(:north)
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
|
-
|
56
|
-
it
|
57
|
-
position.
|
54
|
+
describe "#right" do
|
55
|
+
it "rotates clockwise" do
|
56
|
+
position.right
|
58
57
|
expect(position.face).to eq(:east)
|
59
58
|
|
60
|
-
position.
|
59
|
+
position.right
|
61
60
|
expect(position.face).to eq(:south)
|
62
61
|
|
63
|
-
position.
|
62
|
+
position.right
|
64
63
|
expect(position.face).to eq(:west)
|
65
64
|
|
66
|
-
position.
|
65
|
+
position.right
|
67
66
|
expect(position.face).to eq(:north)
|
68
67
|
end
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
72
|
-
describe
|
73
|
-
context
|
74
|
-
let(:position) {
|
71
|
+
describe "#forward_position" do # rubocop:disable Metrics/BlockLength
|
72
|
+
context "when facing north" do
|
73
|
+
let(:position) { described_class.new(5, 0, :north) }
|
75
74
|
|
76
|
-
it
|
75
|
+
it "returns a new position 1 step upwards" do
|
77
76
|
new_position = position.forward_position
|
78
77
|
expect(position.x).to eq(5)
|
79
78
|
expect(position.y).to eq(0)
|
@@ -82,10 +81,10 @@ describe MauxRobot::Position do
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
85
|
-
context
|
86
|
-
let(:position) {
|
84
|
+
context "when facing west" do
|
85
|
+
let(:position) { described_class.new(2, 1, :west) }
|
87
86
|
|
88
|
-
it
|
87
|
+
it "returns a new position 1 step leftwards" do
|
89
88
|
new_position = position.forward_position
|
90
89
|
expect(position.x).to eq(2)
|
91
90
|
expect(position.y).to eq(1)
|
@@ -94,10 +93,10 @@ describe MauxRobot::Position do
|
|
94
93
|
end
|
95
94
|
end
|
96
95
|
|
97
|
-
context
|
98
|
-
let(:position) {
|
96
|
+
context "when facing south" do
|
97
|
+
let(:position) { described_class.new(1, 3, :south) }
|
99
98
|
|
100
|
-
it
|
99
|
+
it "returns a new position 1 step downwards" do
|
101
100
|
new_position = position.forward_position
|
102
101
|
expect(position.x).to eq(1)
|
103
102
|
expect(position.y).to eq(3)
|
@@ -106,10 +105,10 @@ describe MauxRobot::Position do
|
|
106
105
|
end
|
107
106
|
end
|
108
107
|
|
109
|
-
context
|
110
|
-
let(:position) {
|
108
|
+
context "when facing east" do
|
109
|
+
let(:position) { described_class.new(2, 0, :east) }
|
111
110
|
|
112
|
-
it
|
111
|
+
it "returns a new position 1 step rightwards" do
|
113
112
|
new_position = position.forward_position
|
114
113
|
expect(position.x).to eq(2)
|
115
114
|
expect(position.y).to eq(0)
|
@@ -119,26 +118,30 @@ describe MauxRobot::Position do
|
|
119
118
|
end
|
120
119
|
end
|
121
120
|
|
122
|
-
describe
|
123
|
-
context
|
124
|
-
let(:position) {
|
125
|
-
|
126
|
-
|
121
|
+
describe "#report" do
|
122
|
+
context "when x, y and face are defined" do
|
123
|
+
let(:position) { described_class.new(5, 0, :north) }
|
124
|
+
|
125
|
+
it "prints X,Y,FACE" do
|
126
|
+
expect { position.report }.to output("5,0,NORTH\n").to_stdout
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
130
|
-
context
|
131
|
-
let(:position) {
|
132
|
-
|
133
|
-
|
130
|
+
context "when only face is defined" do
|
131
|
+
let(:position) { described_class.new(nil, nil, "SOUTH") }
|
132
|
+
|
133
|
+
it "prints 0,0,FACE" do
|
134
|
+
expect { position.report }.to output("0,0,SOUTH\n").to_stdout
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
137
|
-
context
|
138
|
-
let(:position) {
|
139
|
-
|
140
|
-
|
138
|
+
context "when face is not defined" do
|
139
|
+
let(:position) { described_class.new(5, 0, nil) }
|
140
|
+
|
141
|
+
it "prints X,Y,INVALID" do
|
142
|
+
expect { position.report }.to output("5,0,INVALID\n").to_stdout
|
141
143
|
end
|
142
144
|
end
|
143
145
|
end
|
144
146
|
end
|
147
|
+
# rubocop:enable Metrics/BlockLength:
|
@@ -1,48 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
describe MauxRobot::Robot do
|
3
|
+
describe MauxRobot::Robot do # rubocop:disable Metrics/BlockLength
|
6
4
|
subject(:robot) { described_class.new }
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
let(:null_position) { MauxRobot::NullPosition.new }
|
7
|
+
|
8
|
+
describe "#place" do
|
9
|
+
context "when given a valid place" do
|
10
|
+
it "has a position" do
|
11
11
|
robot.place(x: 0, y: 0, face: :north)
|
12
12
|
|
13
|
-
expect(robot.position).not_to
|
13
|
+
expect(robot.position).not_to eq null_position
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
context
|
18
|
-
it
|
19
|
-
robot.place(x: 5, y: 0, face: :south)
|
20
|
-
|
21
|
-
expect(robot.position).to be_nil
|
17
|
+
context "when given an invalid place" do
|
18
|
+
it "raises NotOkToGo error" do
|
19
|
+
expect { robot.place(x: 5, y: 0, face: :south) }.to raise_error MauxRobot::NotOkToGo
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
|
-
context
|
26
|
-
it
|
27
|
-
robot.place(x: 0, y: 2, face: :south_east)
|
28
|
-
|
29
|
-
expect(robot.position).to be_nil
|
23
|
+
context "when given an invalid direction" do
|
24
|
+
it "raises NotOkToGo error" do
|
25
|
+
expect { robot.place(x: 0, y: 2, face: :south_east) }.to raise_error MauxRobot::NotOkToGo
|
30
26
|
end
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
34
|
-
describe
|
35
|
-
context
|
36
|
-
it
|
37
|
-
robot.
|
38
|
-
robot.
|
39
|
-
|
40
|
-
expect(robot.position).to be_nil
|
30
|
+
describe "#left" do
|
31
|
+
context "when robot is not placed" do
|
32
|
+
it "raises RobotNotPlacedYet error" do
|
33
|
+
expect { robot.left }.to raise_error MauxRobot::RobotNotPlacedYet
|
34
|
+
expect(robot.position).to eq null_position
|
41
35
|
end
|
42
36
|
end
|
43
37
|
|
44
|
-
context
|
45
|
-
it
|
38
|
+
context "when robot is placed" do
|
39
|
+
it "rotates accordingly" do
|
46
40
|
robot.place(x: 1, y: 2, face: :south)
|
47
41
|
robot.left
|
48
42
|
|
@@ -51,18 +45,17 @@ describe MauxRobot::Robot do
|
|
51
45
|
end
|
52
46
|
end
|
53
47
|
|
54
|
-
describe
|
55
|
-
context
|
56
|
-
it
|
57
|
-
robot.
|
58
|
-
robot.right
|
48
|
+
describe "#right" do
|
49
|
+
context "when robot is not placed" do
|
50
|
+
it "raises RobotNotPlacedYet error" do
|
51
|
+
expect { robot.right }.to raise_error MauxRobot::RobotNotPlacedYet
|
59
52
|
|
60
|
-
expect(robot.position).to
|
53
|
+
expect(robot.position).to eq null_position
|
61
54
|
end
|
62
55
|
end
|
63
56
|
|
64
|
-
context
|
65
|
-
it
|
57
|
+
context "with robot placed" do
|
58
|
+
it "rotates accordingly" do
|
66
59
|
robot.place(x: 3, y: 2, face: :north)
|
67
60
|
robot.right
|
68
61
|
|
@@ -71,9 +64,16 @@ describe MauxRobot::Robot do
|
|
71
64
|
end
|
72
65
|
end
|
73
66
|
|
74
|
-
describe
|
75
|
-
context
|
76
|
-
it
|
67
|
+
describe "#move" do
|
68
|
+
context "with robot not placed" do
|
69
|
+
it "raises RobotNotPlacedYet error" do
|
70
|
+
expect { robot.right }.to raise_error MauxRobot::RobotNotPlacedYet
|
71
|
+
expect(robot.position).to eq null_position
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when placing on the table" do
|
76
|
+
it "updates its position" do
|
77
77
|
robot.place(x: 3, y: 2, face: :north)
|
78
78
|
robot.move
|
79
79
|
|
@@ -83,10 +83,11 @@ describe MauxRobot::Robot do
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
context
|
87
|
-
it
|
86
|
+
context "when outside the table" do
|
87
|
+
it "stays where it is" do
|
88
88
|
robot.place(x: 0, y: 0, face: :south)
|
89
|
-
|
89
|
+
|
90
|
+
expect { robot.move }.to raise_error MauxRobot::NotOkToGo
|
90
91
|
|
91
92
|
expect(robot.position.x).to eq(0)
|
92
93
|
expect(robot.position.y).to eq(0)
|
@@ -1,17 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'maux_robot'
|
4
|
-
|
5
3
|
describe MauxRobot::Table do
|
6
4
|
subject(:table) { described_class.new(x: [-1, 2], y: [3, 6]) }
|
7
5
|
|
8
|
-
|
9
|
-
it
|
6
|
+
describe "#contains?" do
|
7
|
+
it "contains a position inside boundaries" do
|
10
8
|
position = MauxRobot::Position.new(0, 4, :north)
|
11
9
|
expect(table.contains?(position)).to be true
|
12
10
|
end
|
13
11
|
|
14
|
-
it
|
12
|
+
it "does not contain a position outside boundaries" do
|
15
13
|
position = MauxRobot::Position.new(3, 2, :east)
|
16
14
|
expect(table.contains?(position)).to be false
|
17
15
|
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: maux_robot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauricio Vieira
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: standard
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 3.6.0
|
19
|
+
version: 0.4.7
|
23
20
|
type: :development
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 3.6.0
|
26
|
+
version: 0.4.7
|
33
27
|
description: " Maux version of a Toy Robot Simulator.\n"
|
34
28
|
email: maux_robot@mauriciovieira.net
|
35
29
|
executables:
|
@@ -44,19 +38,28 @@ files:
|
|
44
38
|
- bin/maux_robot
|
45
39
|
- lib/maux_robot.rb
|
46
40
|
- lib/maux_robot/cli.rb
|
41
|
+
- lib/maux_robot/formatter.rb
|
42
|
+
- lib/maux_robot/formatter/csv.rb
|
43
|
+
- lib/maux_robot/formatter/json.rb
|
44
|
+
- lib/maux_robot/parser.rb
|
47
45
|
- lib/maux_robot/position.rb
|
48
46
|
- lib/maux_robot/robot.rb
|
49
47
|
- lib/maux_robot/table.rb
|
50
48
|
- lib/maux_robot/version.rb
|
51
49
|
- spec/maux_robot/cli_spec.rb
|
50
|
+
- spec/maux_robot/formatter/csv_spec.rb
|
51
|
+
- spec/maux_robot/formatter/json_spec.rb
|
52
|
+
- spec/maux_robot/formatter_spec.rb
|
53
|
+
- spec/maux_robot/parser_spec.rb
|
52
54
|
- spec/maux_robot/position_spec.rb
|
53
55
|
- spec/maux_robot/robot_spec.rb
|
54
56
|
- spec/maux_robot/table_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
55
58
|
homepage: https://github.com/mauriciovieira/maux_robot
|
56
59
|
licenses:
|
57
60
|
- GPL-3.0
|
58
61
|
metadata:
|
59
|
-
homepage_uri: https://
|
62
|
+
homepage_uri: https://github.com/mauriciovieira/maux_robot/blob/master/README.md
|
60
63
|
changelog_uri: https://github.com/mauriciovieira/maux_robot/blob/master/CHANGELOG.md
|
61
64
|
source_code_uri: https://github.com/mauriciovieira/maux_robot/
|
62
65
|
documentation_uri: https://github.com/mauriciovieira/maux_robot/
|
@@ -69,15 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
72
|
requirements:
|
70
73
|
- - ">="
|
71
74
|
- !ruby/object:Gem::Version
|
72
|
-
version: 2.
|
75
|
+
version: 2.6.0
|
73
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
77
|
requirements:
|
75
78
|
- - ">="
|
76
79
|
- !ruby/object:Gem::Version
|
77
80
|
version: '0'
|
78
81
|
requirements: []
|
79
|
-
|
80
|
-
rubygems_version: 2.6.12
|
82
|
+
rubygems_version: 3.0.3
|
81
83
|
signing_key:
|
82
84
|
specification_version: 4
|
83
85
|
summary: Maux version of a Toy Robot Simulator.
|