gobstones 0.0.2 → 0.0.3

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.
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