gobstones 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +133 -0
  3. data/.rubocop_todo.yml +75 -0
  4. data/.simplecov +1 -3
  5. data/.tool-versions +1 -0
  6. data/.travis.yml +9 -2
  7. data/Gemfile +11 -5
  8. data/Gemfile.lock +65 -39
  9. data/README.md +8 -1
  10. data/Rakefile +1 -1
  11. data/bin/gobstones +1 -1
  12. data/gobstones.gemspec +12 -11
  13. data/lib/gobstones/cli/printer.rb +41 -28
  14. data/lib/gobstones/cli/runner.rb +50 -15
  15. data/lib/gobstones/extensions/all.rb +1 -1
  16. data/lib/gobstones/extensions/boolean.rb +1 -5
  17. data/lib/gobstones/extensions/{fixnum.rb → integer.rb} +2 -4
  18. data/lib/gobstones/extensions/string.rb +1 -3
  19. data/lib/gobstones/lang/all.rb +3 -3
  20. data/lib/gobstones/lang/commands/all.rb +11 -10
  21. data/lib/gobstones/lang/commands/boom.rb +26 -0
  22. data/lib/gobstones/lang/commands/command_block.rb +23 -23
  23. data/lib/gobstones/lang/commands/conditional.rb +26 -0
  24. data/lib/gobstones/lang/commands/if.rb +13 -0
  25. data/lib/gobstones/lang/commands/if_then_else.rb +26 -0
  26. data/lib/gobstones/lang/commands/ir_al_origen.rb +15 -0
  27. data/lib/gobstones/lang/commands/mover.rb +23 -0
  28. data/lib/gobstones/lang/commands/multiple_assignment.rb +34 -21
  29. data/lib/gobstones/lang/commands/poner.rb +31 -0
  30. data/lib/gobstones/lang/commands/procedure_call.rb +8 -8
  31. data/lib/gobstones/lang/commands/repeat_with.rb +69 -0
  32. data/lib/gobstones/lang/commands/sacar.rb +29 -0
  33. data/lib/gobstones/lang/commands/single_assignment.rb +15 -20
  34. data/lib/gobstones/lang/commands/skip.rb +15 -0
  35. data/lib/gobstones/lang/commands/vaciar_tablero.rb +15 -0
  36. data/lib/gobstones/lang/commands/while.rb +20 -0
  37. data/lib/gobstones/lang/definitions/definition.rb +16 -23
  38. data/lib/gobstones/lang/definitions/definition_call.rb +7 -15
  39. data/lib/gobstones/lang/definitions/function.rb +1 -7
  40. data/lib/gobstones/lang/definitions/main.rb +1 -8
  41. data/lib/gobstones/lang/definitions/no_return_statement.rb +2 -8
  42. data/lib/gobstones/lang/definitions/procedure.rb +1 -7
  43. data/lib/gobstones/lang/definitions/return_from_function.rb +6 -13
  44. data/lib/gobstones/lang/definitions/return_from_main.rb +15 -10
  45. data/lib/gobstones/lang/definitions/var_tuple.rb +10 -12
  46. data/lib/gobstones/lang/expressions/arithmetic_expressions.rb +17 -27
  47. data/lib/gobstones/lang/expressions/boolean_expressions.rb +4 -10
  48. data/lib/gobstones/lang/expressions/comparison_expressions.rb +0 -16
  49. data/lib/gobstones/lang/expressions/enclosed_by_parens_expression.rb +3 -5
  50. data/lib/gobstones/lang/expressions/expression.rb +18 -0
  51. data/lib/gobstones/lang/expressions/function_call.rb +9 -6
  52. data/lib/gobstones/lang/expressions/one_arg_expression.rb +8 -16
  53. data/lib/gobstones/lang/expressions/primitive_functions.rb +24 -16
  54. data/lib/gobstones/lang/expressions/two_arg_expression.rb +9 -16
  55. data/lib/gobstones/lang/expressions/type_bound_functions.rb +30 -25
  56. data/lib/gobstones/lang/expressions/var_name.rb +9 -13
  57. data/lib/gobstones/lang/literals/all.rb +3 -3
  58. data/lib/gobstones/lang/literals/{booleans.rb → boolean.rb} +24 -22
  59. data/lib/gobstones/lang/literals/{colors.rb → color.rb} +4 -14
  60. data/lib/gobstones/lang/literals/{directions.rb → direction.rb} +3 -13
  61. data/lib/gobstones/lang/literals/literal.rb +35 -27
  62. data/lib/gobstones/lang/literals/number.rb +6 -8
  63. data/lib/gobstones/lang/program.rb +9 -16
  64. data/lib/gobstones/modules/equality_definition.rb +23 -0
  65. data/lib/gobstones/parser/ast/ast.rb +48 -70
  66. data/lib/gobstones/parser/parse_error.rb +2 -7
  67. data/lib/gobstones/parser/treetop_parser.rb +9 -14
  68. data/lib/gobstones/runner/board.rb +12 -15
  69. data/lib/gobstones/runner/cell.rb +14 -20
  70. data/lib/gobstones/runner/errors/all.rb +1 -1
  71. data/lib/gobstones/runner/errors/boom_error.rb +0 -5
  72. data/lib/gobstones/runner/errors/definition_not_found_error.rb +7 -7
  73. data/lib/gobstones/runner/errors/empty_cell_error.rb +0 -5
  74. data/lib/gobstones/runner/errors/gobstones_runtime_error.rb +0 -5
  75. data/lib/gobstones/runner/errors/gobstones_type_error.rb +2 -7
  76. data/lib/gobstones/runner/errors/out_of_board_error.rb +0 -5
  77. data/lib/gobstones/runner/errors/undefined_variable_error.rb +6 -4
  78. data/lib/gobstones/runner/errors/wrong_arguments_error.rb +0 -5
  79. data/lib/gobstones/runner/execution_context.rb +16 -33
  80. data/lib/gobstones/runner/head.rb +17 -20
  81. data/lib/gobstones/runner/program_result.rb +12 -0
  82. data/lib/gobstones/type_check_result.rb +0 -4
  83. data/spec/lang/commands/boom_spec.rb +7 -0
  84. data/spec/lang/commands/command_block_spec.rb +15 -0
  85. data/spec/lang/commands/if_spec.rb +32 -0
  86. data/spec/lang/commands/if_then_else_spec.rb +19 -0
  87. data/spec/lang/commands/ir_al_origen_spec.rb +11 -0
  88. data/spec/lang/commands/mover_spec.rb +30 -0
  89. data/spec/lang/commands/multiple_assignment_spec.rb +39 -22
  90. data/spec/lang/commands/poner_spec.rb +27 -0
  91. data/spec/lang/commands/procedure_call_spec.rb +26 -28
  92. data/spec/lang/commands/procedure_spec.rb +32 -32
  93. data/spec/lang/commands/repeat_with_spec.rb +64 -0
  94. data/spec/lang/commands/sacar_spec.rb +32 -0
  95. data/spec/lang/commands/single_assignment_spec.rb +5 -6
  96. data/spec/lang/commands/skip_spec.rb +10 -0
  97. data/spec/lang/commands/vaciar_tablero_spec.rb +10 -0
  98. data/spec/lang/commands/while_spec.rb +39 -0
  99. data/spec/lang/definitions/main_spec.rb +34 -0
  100. data/spec/lang/definitions/no_return_statement_spec.rb +4 -5
  101. data/spec/lang/definitions/var_tuple_spec.rb +4 -7
  102. data/spec/lang/expressions/arithmetic_expressions_spec.rb +37 -64
  103. data/spec/lang/expressions/boolean_expressions_spec.rb +25 -34
  104. data/spec/lang/expressions/comparison_expressions_spec.rb +109 -155
  105. data/spec/lang/expressions/enclosed_by_parens_expression_spec.rb +3 -7
  106. data/spec/lang/expressions/function_call_spec.rb +24 -20
  107. data/spec/lang/expressions/primitive_functions_spec.rb +28 -39
  108. data/spec/lang/expressions/type_bound_functions_spec.rb +10 -18
  109. data/spec/lang/expressions/var_name_spec.rb +8 -12
  110. data/spec/lang/literals/{booleans_spec.rb → boolean_spec.rb} +3 -5
  111. data/spec/lang/literals/color_spec.rb +19 -0
  112. data/spec/lang/literals/direction_spec.rb +46 -0
  113. data/spec/lang/literals/{numbers_spec.rb → number_spec.rb} +3 -4
  114. data/spec/matchers/parse_matcher.rb +9 -11
  115. data/spec/parser/arithmetic_expressions_spec.rb +51 -61
  116. data/spec/parser/assignments_spec.rb +21 -31
  117. data/spec/parser/boolean_expressions_spec.rb +35 -43
  118. data/spec/parser/command_block_spec.rb +18 -20
  119. data/spec/parser/data_types_spec.rb +9 -19
  120. data/spec/parser/function_calls_spec.rb +19 -19
  121. data/spec/parser/function_definitions_spec.rb +17 -22
  122. data/spec/parser/gobstones_program_spec.rb +30 -30
  123. data/spec/parser/if_command_spec.rb +19 -28
  124. data/spec/parser/main_definition_spec.rb +13 -16
  125. data/spec/parser/nested_expressions_spec.rb +20 -24
  126. data/spec/parser/primitive_expressions_spec.rb +33 -38
  127. data/spec/parser/procedure_calls_spec.rb +17 -18
  128. data/spec/parser/procedure_definitions_spec.rb +12 -15
  129. data/spec/parser/repeat_with_command_spec.rb +10 -10
  130. data/spec/parser/simple_commands_spec.rb +23 -37
  131. data/spec/parser/treetop_parser_spec.rb +87 -83
  132. data/spec/parser/var_tuple_spec.rb +8 -12
  133. data/spec/parser/while_command_spec.rb +11 -14
  134. data/spec/runner/board_spec.rb +28 -33
  135. data/spec/runner/cell_spec.rb +21 -28
  136. data/spec/runner/execution_context_spec.rb +18 -35
  137. data/spec/runner/head_spec.rb +54 -60
  138. data/spec/spec_helper.rb +10 -1
  139. data/spec/support/board_assertions.rb +18 -0
  140. data/spec/{gobstones_lang_test_objects.rb → support/gobstones_lang_test_objects.rb} +6 -4
  141. data/spec/type_checker_spec.rb +19 -25
  142. metadata +80 -56
  143. data/.ruby-version +0 -1
  144. data/lib/gobstones/lang/commands/boom_cmd.rb +0 -31
  145. data/lib/gobstones/lang/commands/conditional_cmd.rb +0 -31
  146. data/lib/gobstones/lang/commands/if_cmd.rb +0 -38
  147. data/lib/gobstones/lang/commands/ir_al_origen_cmd.rb +0 -19
  148. data/lib/gobstones/lang/commands/mover_cmd.rb +0 -27
  149. data/lib/gobstones/lang/commands/poner_cmd.rb +0 -35
  150. data/lib/gobstones/lang/commands/repeat_with_cmd.rb +0 -77
  151. data/lib/gobstones/lang/commands/sacar_cmd.rb +0 -33
  152. data/lib/gobstones/lang/commands/skip_cmd.rb +0 -19
  153. data/lib/gobstones/lang/commands/vaciar_tablero_cmd.rb +0 -19
  154. data/lib/gobstones/lang/commands/while_cmd.rb +0 -25
  155. data/lib/gobstones/modules/equal_by_class.rb +0 -13
  156. data/spec/lang/commands/boom_cmd_spec.rb +0 -8
  157. data/spec/lang/commands/cmd_block_spec.rb +0 -21
  158. data/spec/lang/commands/if_cmd_spec.rb +0 -50
  159. data/spec/lang/commands/ir_al_origen_cmd_spec.rb +0 -16
  160. data/spec/lang/commands/mover_cmd_spec.rb +0 -36
  161. data/spec/lang/commands/poner_cmd_spec.rb +0 -28
  162. data/spec/lang/commands/repeat_with_cmd_spec.rb +0 -60
  163. data/spec/lang/commands/sacar_cmd_spec.rb +0 -35
  164. data/spec/lang/commands/skip_cmd_spec.rb +0 -12
  165. data/spec/lang/commands/vaciar_tablero_cmd_spec.rb +0 -14
  166. data/spec/lang/commands/while_cmd_spec.rb +0 -43
  167. data/spec/lang/literals/colors_spec.rb +0 -13
  168. data/spec/lang/literals/directions_spec.rb +0 -45
@@ -1,11 +1,9 @@
1
1
  require 'gobstones/runner/board'
2
+ require 'gobstones/runner/errors/out_of_board_error'
2
3
 
3
4
  module Gobstones
4
-
5
5
  module Runner
6
-
7
6
  class Head
8
-
9
7
  MAX_ROWS = 9
10
8
  MAX_COLS = 9
11
9
 
@@ -16,15 +14,16 @@ module Gobstones
16
14
  end
17
15
 
18
16
  def self.with_position_and_board(x_pos, y_pos, board)
19
- new.with_position_and_board x_pos, y_pos, board
17
+ new.with_position_and_board(x_pos, y_pos, board)
20
18
  end
21
19
 
22
20
  def initialize
23
- with_position_and_board 0, 0, Board.new(MAX_ROWS, MAX_COLS)
21
+ with_position_and_board(0, 0, Board.new(MAX_ROWS, MAX_COLS))
24
22
  end
25
23
 
26
24
  def at_random
27
- @x_pos, @y_pos = rand(MAX_ROWS), rand(MAX_COLS)
25
+ @x_pos = rand(MAX_ROWS)
26
+ @y_pos = rand(MAX_COLS)
28
27
  self
29
28
  end
30
29
 
@@ -37,27 +36,28 @@ module Gobstones
37
36
 
38
37
  def can_move?(dir)
39
38
  check dir
40
- dir.can_move? self
39
+ dir.can_move?(self)
41
40
  end
42
41
 
43
42
  def can_move_north?
44
- @y_pos < MAX_COLS-1
43
+ @y_pos < MAX_COLS - 1
45
44
  end
46
45
 
47
46
  def can_move_south?
48
- @y_pos > 0
47
+ @y_pos.positive?
49
48
  end
50
49
 
51
50
  def can_move_east?
52
- @x_pos < MAX_ROWS-1
51
+ @x_pos < MAX_ROWS - 1
53
52
  end
54
53
 
55
54
  def can_move_west?
56
- @x_pos > 0
55
+ @x_pos.positive?
57
56
  end
58
57
 
59
58
  def move(dir)
60
59
  raise OutOfBoardError unless can_move?(dir)
60
+
61
61
  dir.move self
62
62
  end
63
63
 
@@ -78,7 +78,8 @@ module Gobstones
78
78
  end
79
79
 
80
80
  def go_to_origin
81
- @x_pos, @y_pos = 0, 0
81
+ @x_pos = 0
82
+ @y_pos = 0
82
83
  end
83
84
 
84
85
  def put(color)
@@ -90,26 +91,22 @@ module Gobstones
90
91
  end
91
92
 
92
93
  def number_of_balls(color)
93
- @board.number_of_balls x_pos, y_pos, color
94
+ @board.number_of_balls(x_pos, y_pos, color)
94
95
  end
95
96
 
96
97
  def are_there_balls?(color)
97
- @board.are_there_balls? x_pos, y_pos, color
98
+ @board.are_there_balls?(x_pos, y_pos, color)
98
99
  end
99
100
 
100
101
  def clone
101
- self.class.with_position_and_board x_pos, y_pos, board.clone
102
+ self.class.with_position_and_board(x_pos, y_pos, board.clone)
102
103
  end
103
104
 
104
105
  private
105
106
 
106
107
  def check(dir)
107
- raise GobstonesTypeError, "#{dir} is not a direction" \
108
- unless [Norte, Sur, Este, Oeste].include? dir.class
108
+ raise GobstonesTypeError, "#{dir} is not a direction" unless [Norte, Sur, Este, Oeste].include?(dir.class)
109
109
  end
110
-
111
110
  end
112
-
113
111
  end
114
-
115
112
  end
@@ -0,0 +1,12 @@
1
+ module Gobstones
2
+ module Runner
3
+ class ProgramResult
4
+ attr_reader :head, :return_values
5
+
6
+ def initialize(head, return_values)
7
+ @head = head
8
+ @return_values = return_values
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,7 +1,5 @@
1
1
  module Gobstones
2
-
3
2
  class TypeCheckResult
4
-
5
3
  def initialize(expected, actual)
6
4
  @expected = expected
7
5
  @actual = actual
@@ -10,7 +8,5 @@ module Gobstones
10
8
  def ok?
11
9
  @expected == @actual
12
10
  end
13
-
14
11
  end
15
-
16
12
  end
@@ -0,0 +1,7 @@
1
+ RSpec.describe Boom do
2
+ it 'raises an error when evaluating, with the message specified' do
3
+ message = 'This is a program error'
4
+
5
+ expect { described_class.new(message).evaluate(clean_context) }.to raise_error(BoomError, message)
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ RSpec.describe CommandBlock do
2
+ let(:context) { clean_context }
3
+
4
+ it 'evaluates all inner commands' do
5
+ command_block = described_class.new([Poner.new(rojo), Poner.new(verde), Poner.new(negro), Poner.new(azul)])
6
+ command_block.evaluate context
7
+
8
+ expect_balls(azul, negro, rojo, verde)
9
+ end
10
+
11
+ it 'builds an empty command block' do
12
+ expect(described_class.new([])).to be_empty
13
+ expect(described_class.empty).to be_empty
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.describe If do
2
+ subject(:evaluate_if_command) { described_class.new(condition, then_block).evaluate(context) }
3
+
4
+ let(:context) { clean_context }
5
+ let(:then_block) { CommandBlock.with_just(Poner.new(verde)) }
6
+
7
+ context 'when condition is true' do
8
+ let(:condition) { true_value }
9
+
10
+ it "evaluates the 'then' block" do
11
+ evaluate_if_command and expect_balls(verde)
12
+ end
13
+ end
14
+
15
+ context 'when condition is false' do
16
+ let(:condition) { false_value }
17
+
18
+ it "does not evaluate the 'then' block" do
19
+ evaluate_if_command and expect_no_balls(verde)
20
+ end
21
+ end
22
+
23
+ [42.to_gbs_num, norte, verde].each do |value|
24
+ context "when condition has a wrong type (#{value.class})" do
25
+ let(:condition) { value }
26
+
27
+ it 'raises a type error' do
28
+ expect { evaluate_if_command }.to raise_error(GobstonesTypeError, /is not a boolean/)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ RSpec.describe IfThenElse do
2
+ let(:context) { clean_context }
3
+ let(:then_block) { CommandBlock.with_just(Poner.new(verde)) }
4
+ let(:else_block) { CommandBlock.with_just(Poner.new(rojo)) }
5
+
6
+ it "evaluates the 'then' block and it does not evaluate the 'else' block" do
7
+ described_class.new(true_value, then_block, else_block).evaluate context
8
+
9
+ expect_balls(verde)
10
+ expect_no_balls(rojo)
11
+ end
12
+
13
+ it "does not evaluate the 'then' block and it evaluates the 'else' block" do
14
+ described_class.new(false_value, then_block, else_block).evaluate context
15
+
16
+ expect_no_balls(verde)
17
+ expect_balls(rojo)
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.describe IrAlOrigen do
2
+ let(:context) { clean_context }
3
+
4
+ it 'puts the head in 0, 0 when evaluating' do
5
+ context.head.move_north
6
+ context.head.move_east
7
+ described_class.new.evaluate context
8
+
9
+ expect_positioned_at(0, 0)
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ RSpec.describe Mover do
2
+ let(:context) { clean_context }
3
+
4
+ it 'moves the head to the specified direction when evaluating' do
5
+ described_class.new(norte).evaluate(context)
6
+
7
+ expect_positioned_at(0, 1)
8
+ end
9
+
10
+ it 'undoes the given movement' do
11
+ cmd = described_class.new(norte)
12
+
13
+ cmd.evaluate context
14
+ cmd.undo context
15
+
16
+ expect_positioned_at(0, 0)
17
+ end
18
+
19
+ it 'returns the opposite command' do
20
+ expect(described_class.new(norte).opposite).to eq(described_class.new(sur))
21
+ end
22
+
23
+ it 'fails if the argument is not a direction' do
24
+ expect { described_class.new(verde).evaluate(context) }.to raise_error(GobstonesTypeError, /is not a direction/)
25
+ end
26
+
27
+ it 'fails when the resulting position is out of board' do
28
+ expect { described_class.new(sur).evaluate(context) }.to raise_error(OutOfBoardError)
29
+ end
30
+ end
@@ -1,37 +1,54 @@
1
- describe MultipleAssignment do
2
-
3
- let(:my_function_return) { ReturnFromFunction.new [42.to_gbs_num, verde, MinDir.new] }
4
- let(:my_function_def) { Function.new 'myFunction', no_arguments, empty_body, my_function_return }
5
- let(:program) { Program.new [my_function_def], no_return_statement }
6
- let(:context) { program_context_for program }
1
+ RSpec.describe MultipleAssignment do
2
+ let(:my_function_return) { ReturnFromFunction.new([42.to_gbs_num, verde, MinDir.new]) }
3
+ let(:my_function_def) { Function.new('myFunction', no_arguments, empty_body, my_function_return) }
4
+ let(:call_to_my_function) { FunctionCall.new('myFunction', []) }
5
+ let(:program) { Program.new([my_function_def], no_return_statement) }
6
+ let(:context) { program_context_for(program) }
7
7
  let(:a) { 'a'.to_var_name }
8
8
  let(:b) { 'b'.to_var_name }
9
9
  let(:c) { 'c'.to_var_name }
10
+ let(:d) { 'd'.to_var_name }
10
11
 
11
- context "success" do
12
+ def expect_assignment(variable, value)
13
+ expect(context.has_variable_named?(variable.name)).to be(true)
14
+ expect(context.get(variable)).to eq(value)
15
+ end
12
16
 
13
- it "evaluates and set all the variables with the return values of a function call" do
14
- var_tuple = VarTuple.new [a, b, c]
15
- function_call = FunctionCall.new 'myFunction', []
16
- assign = MultipleAssignment.new var_tuple, function_call
17
+ context 'when assignment can be made' do
18
+ it 'evaluates and set all the variables with the return values of a function call' do
19
+ var_tuple = VarTuple.new([a, b, c])
20
+ assign = described_class.new(var_tuple, call_to_my_function)
17
21
  assign.evaluate context
18
- expect(context.has_variable_named?('a')).to be true
19
- expect(context.get(a)).to eq(42.to_gbs_num)
20
- expect(context.has_variable_named?('b')).to be true
21
- expect(context.get(b)).to eq(verde)
22
- expect(context.has_variable_named?('c')).to be true
23
- expect(context.get(c)).to eq(norte)
24
- end
25
22
 
23
+ expect_assignment(a, 42.to_gbs_num)
24
+ expect_assignment(b, verde)
25
+ expect_assignment(c, norte)
26
+ end
26
27
  end
27
28
 
28
- context "failure" do
29
+ context 'when assignment cannot be made' do
30
+ it 'fails if there are more variables to be assigned on the left' do
31
+ var_tuple = VarTuple.new([a, b, c, d])
32
+ assign = described_class.new(var_tuple, call_to_my_function)
29
33
 
30
- it "fails if there are more variables to be assigned on the left"
34
+ error_message = 'Wrong number of arguments in assignment: expected 4, got 3'
35
+ expect { assign.evaluate context }.to raise_error(Gobstones::Runner::WrongArgumentsError, error_message)
36
+ end
37
+
38
+ it 'fails if there are more things to assign on the right' do
39
+ var_tuple = VarTuple.new([a, b])
40
+ assign = described_class.new(var_tuple, call_to_my_function)
31
41
 
32
- it "fails if there are more things to assign on the right"
42
+ error_message = 'Wrong number of arguments in assignment: expected 2, got 3'
43
+ expect { assign.evaluate context }.to raise_error(Gobstones::Runner::WrongArgumentsError, error_message)
44
+ end
33
45
 
34
- it "fails if the expression on the right is not a function call"
46
+ it 'fails if the expression on the right is not a function call' do
47
+ var_tuple = VarTuple.new([a, b])
48
+ assign = described_class.new(var_tuple, Add.new(12.to_gbs_num, 23.to_gbs_num))
35
49
 
50
+ error_message = 'expected a function call in multiple assignment'
51
+ expect { assign.evaluate context }.to raise_error(Gobstones::Runner::GobstonesTypeError, error_message)
52
+ end
36
53
  end
37
54
  end
@@ -0,0 +1,27 @@
1
+ RSpec.describe Poner do
2
+ subject(:poner_cmd) { described_class.new(verde) }
3
+
4
+ let(:context) { clean_context }
5
+
6
+ it 'puts a ball of the given color in the current cell when evaluating' do
7
+ poner_cmd.evaluate(context)
8
+
9
+ expect(context.head.number_of_balls(verde)).to eq(1)
10
+ end
11
+
12
+ it 'undoes the command' do
13
+ context.head.put verde
14
+
15
+ poner_cmd.undo(context)
16
+
17
+ expect(context.head.number_of_balls(verde)).to eq(0)
18
+ end
19
+
20
+ it 'returns the opposite command' do
21
+ expect(poner_cmd.opposite).to eq(Sacar.new(verde))
22
+ end
23
+
24
+ it 'fails if the argument is not a color' do
25
+ expect { described_class.new(norte).evaluate(context) }.to raise_error(GobstonesTypeError, /is not a color/)
26
+ end
27
+ end
@@ -1,39 +1,37 @@
1
- describe "procedure calls" do
2
-
3
- it "evaluates an existing procedure when calling it" do
4
- poner_cmd = Poner.new verde
5
- body = CommandBlock.new [poner_cmd]
6
- my_procedure = Procedure.new 'MyProcedure', no_arguments, body
7
- program = Program.new [my_procedure], no_return_statement
8
- context = program_context_for program
9
-
10
- proc_call = ProcedureCall.new 'MyProcedure', []
1
+ RSpec.describe ProcedureCall do
2
+ it 'evaluates an existing procedure when calling it' do
3
+ poner_cmd = Poner.new(verde)
4
+ body = CommandBlock.with_just(poner_cmd)
5
+ my_procedure = Procedure.new('MyProcedure', no_arguments, body)
6
+ program = Program.new([my_procedure], no_return_statement)
7
+ context = program_context_for(program)
8
+
9
+ proc_call = described_class.new('MyProcedure', [])
11
10
  proc_call.evaluate context
12
11
 
13
- expect(context.head.are_there_balls?(verde)).to be true
12
+ expect(context.head.are_there_balls?(verde)).to be(true)
14
13
  end
15
14
 
16
- it "allows to call a procedure from another procedure" do
17
- poner_cmd = Poner.new azul
18
- inner_procedure_body = CommandBlock.new [poner_cmd]
19
- inner_procedure = Procedure.new 'Inner', no_arguments, inner_procedure_body
20
- call_to_inner_procedure = ProcedureCall.new 'Inner', []
21
- outer_procedure_body = CommandBlock.new [call_to_inner_procedure]
22
- outer_procedure = Procedure.new 'Outer', no_arguments, outer_procedure_body
23
- program = Program.new [outer_procedure, inner_procedure], no_return_statement
24
- program_context = program_context_for program
25
-
26
- call_to_outer_procedure = ProcedureCall.new 'Outer', []
15
+ it 'allows to call a procedure from another procedure' do
16
+ poner_cmd = Poner.new(azul)
17
+ inner_procedure_body = CommandBlock.with_just(poner_cmd)
18
+ inner_procedure = Procedure.new('Inner', no_arguments, inner_procedure_body)
19
+ call_to_inner_procedure = described_class.new('Inner', [])
20
+ outer_procedure_body = CommandBlock.with_just(call_to_inner_procedure)
21
+ outer_procedure = Procedure.new('Outer', no_arguments, outer_procedure_body)
22
+ program = Program.new([outer_procedure, inner_procedure], no_return_statement)
23
+ program_context = program_context_for(program)
24
+
25
+ call_to_outer_procedure = described_class.new('Outer', [])
27
26
  call_to_outer_procedure.evaluate program_context
28
27
 
29
- expect(program_context.head.are_there_balls?(azul)).to be true
28
+ expect(program_context.head.are_there_balls?(azul)).to be(true)
30
29
  end
31
30
 
32
- it "fails to execute an undefined procedure" do
33
- proc_call = ProcedureCall.new 'UndefinedProcedure', []
31
+ it 'fails to execute an undefined procedure' do
32
+ proc_call = described_class.new('UndefinedProcedure', [])
34
33
 
35
- expect { proc_call.evaluate clean_context }
36
- .to raise_error(DefinitionNotFound, DefinitionNotFound.message_for('UndefinedProcedure'))
34
+ expect { proc_call.evaluate clean_context }.
35
+ to raise_error(DefinitionNotFound, DefinitionNotFound.message_for('UndefinedProcedure'))
37
36
  end
38
-
39
37
  end
@@ -1,63 +1,63 @@
1
- describe Procedure do
2
-
1
+ RSpec.describe Procedure do
3
2
  let(:context) { clean_context }
4
3
 
5
- it "executes its body and leaves state in the program context" do
6
- poner_cmd = Poner.new rojo
7
- body = CommandBlock.new [poner_cmd]
8
- procedure = Procedure.new 'MyProcedure', no_arguments, body
4
+ it 'executes its body and leaves state in the program context' do
5
+ poner_cmd = Poner.new(rojo)
6
+ body = CommandBlock.with_just(poner_cmd)
7
+ procedure = described_class.new('MyProcedure', no_arguments, body)
9
8
  procedure.evaluate context
10
- expect(context.head.are_there_balls?(rojo)).to be true
9
+
10
+ expect_balls(rojo)
11
11
  end
12
12
 
13
- it "fails getting a variable which is in the outer context" do
13
+ it 'fails getting a variable which is in the outer context' do
14
14
  var_name = 'var'.to_var_name
15
15
  context.set var_name, verde
16
16
 
17
- poner_cmd = Poner.new var_name
18
- body = CommandBlock.new [poner_cmd]
19
- procedure = Procedure.new 'MyProcedure', no_arguments, body
17
+ poner_cmd = Poner.new(var_name)
18
+ body = CommandBlock.with_just(poner_cmd)
19
+ procedure = described_class.new('MyProcedure', no_arguments, body)
20
+
20
21
  expect { procedure.evaluate context }.to raise_error(UndefinedVariableError)
21
22
  end
22
23
 
23
- it "sets arguments in the new context so they can be used" do
24
+ it 'sets arguments in the new context so they can be used' do
24
25
  a_color = 'a_color'.to_var_name
25
26
  a_direction = 'a_direction'.to_var_name
26
- args = VarTuple.new [a_color, a_direction]
27
- mover_cmd = Mover.new a_direction
28
- poner_cmd = Poner.new a_color
29
- body = CommandBlock.new [mover_cmd, poner_cmd]
30
- procedure = Procedure.new 'MyProc', args, body
27
+ args = VarTuple.new([a_color, a_direction])
28
+ mover_cmd = Mover.new(a_direction)
29
+ poner_cmd = Poner.new(a_color)
30
+ body = CommandBlock.new([mover_cmd, poner_cmd])
31
+ procedure = described_class.new('MyProc', args, body)
31
32
 
32
33
  procedure.evaluate context, [negro, norte]
33
34
 
34
- expect(context.head.are_there_balls?(negro)).to be true
35
+ expect_balls(negro)
35
36
  expect(context.head.y_pos).to eq(1)
36
37
  end
37
38
 
38
- it "does not set arguments as var names in outer context" do
39
+ it 'does not set arguments as var names in outer context' do
39
40
  a_direction = 'a_direction'.to_var_name
40
- args = VarTuple.new [a_direction]
41
- procedure = Procedure.new 'MyProc', args, empty_body
41
+ args = VarTuple.new([a_direction])
42
+ procedure = described_class.new('MyProc', args, empty_body)
42
43
 
43
44
  procedure.evaluate context, [oeste]
44
45
 
45
- expect(context.has_variable_named?('a_direction')).to be false
46
+ expect(context.has_variable_named?('a_direction')).to be(false)
46
47
  end
47
48
 
48
- it "fails if it is executed with more arguments than expected" do
49
- procedure = Procedure.new 'MyProcedure', no_arguments, empty_body
49
+ it 'fails if it is executed with more arguments than expected' do
50
+ procedure = described_class.new('MyProcedure', no_arguments, empty_body)
51
+
50
52
  error_message = "Wrong number of arguments in procedure 'MyProcedure': expected 0, got 1"
51
- expect { procedure.evaluate context, [norte] }
52
- .to raise_error(WrongArgumentsError, error_message)
53
+ expect { procedure.evaluate context, [norte] }.to raise_error(WrongArgumentsError, error_message)
53
54
  end
54
55
 
55
- it "fails if it is executed with less arguments than expected" do
56
- args = VarTuple.new ['arg1'.to_var_name, 'arg2'.to_var_name]
57
- procedure = Procedure.new 'MyProcedure2', args, empty_body
56
+ it 'fails if it is executed with less arguments than expected' do
57
+ args = VarTuple.with_names(%w[arg1 arg2])
58
+ procedure = described_class.new('MyProcedure2', args, empty_body)
59
+
58
60
  error_message = "Wrong number of arguments in procedure 'MyProcedure2': expected 2, got 1"
59
- expect { procedure.evaluate context, [verde] }
60
- .to raise_error(WrongArgumentsError, error_message)
61
+ expect { procedure.evaluate context, [verde] }.to raise_error(WrongArgumentsError, error_message)
61
62
  end
62
-
63
63
  end