gates_of_moria 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,5 +20,6 @@ Gem::Specification.new do |gem|
20
20
  gem.add_development_dependency('rspec', '~> 2.11.0')
21
21
  gem.add_development_dependency('turnip')
22
22
  gem.add_development_dependency('pry')
23
+ gem.add_development_dependency('greenletters')
23
24
 
24
25
  end
@@ -0,0 +1,13 @@
1
+ class Door
2
+ def self.read
3
+ "fcrnx sevraq naq ragre"
4
+ end
5
+
6
+ def self.tell text
7
+ if text == 'sevraq'
8
+ "The door opens!"
9
+ else
10
+ "The door remains firmly shut."
11
+ end
12
+ end
13
+ end
@@ -33,3 +33,7 @@
33
33
  ;____: `._ `' _,' ;____:
34
34
  {______} \___________________/ {______}
35
35
  SSt |______|_______________________________|______|
36
+
37
+ Welcome to the Gates of Moria! After many adventures, you and your companions have come upon a door to the Dwarven kingdom of Moria. But you cannot open the door by brute strength, so you will have to use your wits.
38
+
39
+ You can leave the game at any time by typing 'exit'
@@ -0,0 +1,81 @@
1
+ {
2
+ "questions": [
3
+ {
4
+ "help_texts": [ "Are you ready to begin your adventure? Answer in Ruby.",
5
+ "In Ruby, we say things are correct, or 'truthy', when they are true.",
6
+ "We often use true to say yes, as well",
7
+ "Try telling Ruby that it is 'true' that you want to begin your adventure.",
8
+ "Try reading http://www.ruby-lang.org/en/documentation/quickstart/ to get started!"
9
+ ],
10
+ "expected_response": "result == true"
11
+ },
12
+ {
13
+ "title": "\nPart 1: Strings\n===============\n",
14
+ "help_texts": [ "Now give me the name Gandalf as a String.",
15
+ "Strings are typically wrapped in either single quotes or double quotes.",
16
+ "Try putting Gandalf's name in quotes."
17
+ ],
18
+ "expected_response": "result == 'Gandalf'"
19
+ },
20
+ {
21
+ "title": "\nPart 2: Variables\n=================\n",
22
+ "help_texts": [ "Let me know your name by assigning it to a variable called @name",
23
+ "Variables hold information. We use the equal sign to assign an object to a variable.",
24
+ "Here's how I would tell Ruby my name:\n @name = \"Matt\"",
25
+ "In this case, we want to assign the value of your name, as a String, to the variable @name.",
26
+ "I think you might like reading about variables:\n http://mislav.uniqpath.com/poignant-guide/book/chapter-3.html#section2"
27
+ ],
28
+ "expected_response": "@name.class == String && @name.length > 0"
29
+ },
30
+ {
31
+ "title": "\nPart 3: Methods\n===============\n",
32
+ "help_texts": [ "Now send the String 'sevraq' to the translate method.",
33
+ "We say that we are sending a message to an object when we invoke a method.",
34
+ "In this case, the object we are sending the translate message to is the global object. But don't worry too much about that yet!",
35
+ "You can send a message to Ruby like this:\n method(parameters)",
36
+ "I think you would like this part of the book Programming Ruby:\n http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_methods.html"
37
+ ],
38
+ "expected_response": "result == 'friend'",
39
+ "setup_code": "def translate(s); s.tr!('A-Za-z', 'N-ZA-Mn-za-m'); end",
40
+ "_comments": [ "So now we know that the strange word 'sevraq' is really the word 'friend' when we run it through the translator!"]
41
+ },
42
+ {
43
+ "title": "\nPart 4: Objects\n===============\n",
44
+ "help_texts": [ "The great big door is before you.\n\nSend the message 'read' to the Door object to read what it says.",
45
+ "When we send a message to an object, we're invoking a method with that name on the object.",
46
+ "The Door class has a method called 'read'.",
47
+ "If I wanted to blow the Horn of Gondor, I might write in Ruby:\n HornOfGondor.blow!",
48
+ "If you've got time, you might want to watch this video to get a deep dive into what these object things are:\n\nhttp://confreaks.com/videos/1133-scrc2012-thinking-in-objects\n\n(it is roughly 26 minutes long)"
49
+ ],
50
+ "expected_response": "result == 'fcrnx sevraq naq ragre'",
51
+ "setup_code": "load 'lib/gates_of_moria/data/door.rb'"
52
+ },
53
+ {
54
+ "title": "\nPart 5: Putting it all together\n===============================\n",
55
+ "help_texts": [ "So now we've got this weird text from the Door, and it appears to be the same strange language that we translated before.\n\nLet's use our translate method again on the String returned by reading the Door.",
56
+ "Remember how we sent the String 'sevraq' as a parameter to translate() before?\n\nWe can do the same thing with Door.read, because Door.read will return the strange text as a String and send it as a parameter to translate().",
57
+ "If I wanted to translate some text from the first page of a book, I might do this:\n\n translate(OldBook.first_page)"
58
+ ],
59
+ "expected_response": "result = 'speak friend and enter'"
60
+ },
61
+ {
62
+ "title": "\nPart 6: Solving the Riddle\n==========================\n",
63
+ "help_texts": [ "Huh, the secret message on the door is the text 'speak friend and enter'\n\nNow that we know that the text on the door is a riddle, and we know how to speak in it's secret language, try sending the Door the message 'tell' with the parameter of the answer to the riddle.",
64
+ "Remember that we need to speak in the Door's language.\n\n You can use the translate() method to turn the word 'friend' back into its strange language.",
65
+ "The tell() method on the Door class tries to answer the riddle. Give it another try!",
66
+ "The Door expects the tell method to receive the string 'sevraq', which is its secret word for 'friend'!"
67
+ ],
68
+ "expected_response": "result == 'The door opens!'",
69
+ "setup_code": ""
70
+ }
71
+ ],
72
+
73
+ "question_template":
74
+ {
75
+ "title": "\nPart N: Foo\n===============\n",
76
+ "help_texts": [ ""
77
+ ],
78
+ "expected_response": "",
79
+ "setup_code": ""
80
+ }
81
+ }
@@ -5,15 +5,22 @@ module GatesOfMoria
5
5
  def initialize(output_buffer, input_buffer, motd = nil)
6
6
  @output_buffer = output_buffer
7
7
  @input_buffer = input_buffer
8
- @motd = motd || File.read(File.expand_path("../motd.txt", __FILE__))
9
- @questions = File.read(File.expand_path("../questions.json", __FILE__))
8
+ @motd = motd || File.read(File.expand_path("../data/motd.txt", __FILE__))
9
+ @questions = File.read(File.expand_path("../data/questions.json", __FILE__))
10
10
  end
11
11
 
12
12
  def start
13
13
  @output_buffer.puts @motd
14
+
14
15
  @repl = GatesOfMoria::REPL.new(@output_buffer, @input_buffer, @questions)
15
16
 
16
- @repl.start
17
+ player_won = @repl.start
18
+
19
+ if player_won
20
+ @output_buffer.puts "Congratulations! You've opened the door to the mines.\n\nGood luck on your future adventures.\n\nMight I suggest trying RubyWarrior next?\n"
21
+ else
22
+ @output_buffer.puts "\n\nYour adventures with Ruby are not over yet!\n\nMay I suggest trying the game again, or going to read up on how Ruby works at:\n\n http://www.ruby-lang.org/en/documentation/quickstart/\n"
23
+ end
17
24
  end
18
25
 
19
26
  end
@@ -5,28 +5,37 @@ module GatesOfMoria
5
5
  @input_buffer = input_buffer
6
6
 
7
7
  @questions = JSON.parse(questions)['questions']
8
+ @last_question = @questions.pop
8
9
  end
9
10
 
10
11
  def start
11
12
  ask_the_questions
13
+ ask_last_question
12
14
  end
13
15
 
14
16
  def answer_question(expected_answer, user_input)
15
17
  begin
16
18
  result = eval(user_input)
19
+ rescue SystemExit
20
+ display_leaving_game
21
+ exit 0
17
22
  rescue SyntaxError, Exception
18
23
  politely_say_their_ruby_is_invalid
19
24
  return false
20
25
  end
21
- @output_buffer.puts "\n=> #{result}\n"
26
+ @output_buffer.puts "\n=> #{result}\n\n"
22
27
  eval(expected_answer)
23
28
  end
24
29
 
25
30
  private
31
+
32
+ def ask_last_question
33
+ return prompt_with_help_texts @last_question
34
+ end
35
+
26
36
  def ask_the_questions
27
37
  @questions.each do |question|
28
38
  if prompt_with_help_texts question
29
- display_you_are_correct
30
39
  next
31
40
  end
32
41
  end
@@ -35,6 +44,7 @@ module GatesOfMoria
35
44
 
36
45
  def prompt_with_help_texts question
37
46
  eval(question['setup_code']) if question.has_key?('setup_code')
47
+ @output_buffer.puts(question['title']) if question.has_key?('title')
38
48
  question['help_texts'].each do |ht|
39
49
  prompt_question ht
40
50
 
@@ -61,8 +71,8 @@ module GatesOfMoria
61
71
  @output_buffer.puts("Sorry, that's not it.")
62
72
  end
63
73
 
64
- def display_you_are_correct
65
- @output_buffer.puts("Correct! Next up...")
74
+ def display_leaving_game
75
+ @output_buffer.puts("\nYou are leaving the game. Play again soon!\n")
66
76
  end
67
77
  end
68
78
  end
@@ -1,3 +1,3 @@
1
1
  module GatesOfMoria
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,8 @@
1
+ Feature: Answering Last Question Wrong
2
+
3
+ Scenario: User answers last question wrong
4
+ Given I am not playing
5
+ When I start a new quiz
6
+ And I answer all questions up to the last one
7
+ And I answer the last question incorrectly
8
+ Then I should see encouraging text to keep trying
@@ -1,20 +1,10 @@
1
- Feature: Player Starts the Quiz
2
- As a player
3
- I want to start the quiz
4
- So that I can proceed to Ruby Warrior
5
-
6
- Scenario: start quiz
7
- Given I am not playing
8
- When I start a new quiz
9
- Then I should see the Gates of Moria
10
- And I should be prompted for the answer to the first question
1
+ Feature: Answering questions
11
2
 
12
3
  Scenario: user answers first question correctly
13
4
  Given I am not playing
14
5
  When I start a new quiz
15
6
  When I answer the first question correctly
16
7
  Then I should not see the first help text
17
- And I should see that I was correct
18
8
  And I should be prompted for the answer to the second question
19
9
 
20
10
  Scenario: user answers first question incorrectly
@@ -0,0 +1,13 @@
1
+ Feature: Starting and Quitting
2
+ As a player
3
+ I want to start the quiz
4
+ So that I can proceed to Ruby Warrior
5
+
6
+ Scenario: starting and quitting the game
7
+ Given I am not playing
8
+ When I start a new quiz
9
+ Then I should see the Gates of Moria
10
+ And I should be prompted for the answer to the first question
11
+
12
+ When I quit
13
+ Then the game should end
@@ -1,46 +1,109 @@
1
- step 'I am not playing' do
1
+ step 'I am not playing' do
2
2
  end
3
3
 
4
- step 'I start a new quiz' do
5
- # simulate a game playing input/output session:
6
- @output = StringIO.new
7
- @input = StringIO.new
8
- @motd = 'gates'
4
+ step 'I start a new quiz' do
5
+ @game = Greenletters::Process.new('bin/gates_of_moria')
6
+ @game.start!
7
+ end
8
+
9
+ step 'I quit' do
10
+ @game << prepare_input("exit")
11
+ end
9
12
 
10
- @quiz = GatesOfMoria::Quiz.new(@output, @input, @motd)
11
- @quiz.start
13
+ step 'the game should end' do
14
+ @game.kill!
12
15
  end
13
16
 
14
17
  step 'I should see the Gates of Moria' do
15
- @output.string.should include(@motd)
18
+ expected_pattern = massage_pattern("DOORS OF DURIN")
19
+ @game.wait_for(:output, expected_pattern)
16
20
  end
17
21
 
18
22
  step 'I should be prompted for the answer to the first question' do
19
- @output.string.should include("Let me know your name by assigning it to a variable called '@name'!")
23
+ expected_pattern = massage_pattern "Are you ready to begin your adventure"
24
+ @game.wait_for(:output, expected_pattern)
20
25
  end
21
26
 
22
27
  step 'I should be prompted for the answer to the second question' do
23
- @output.string.should include("Now send the string 'sevraq' to the translate method.")
28
+ expected_pattern = massage_pattern "Now give me the name Gandalf as a String"
29
+ @game.wait_for(:output, expected_pattern)
24
30
  end
25
31
 
26
32
  step 'I answer the first question correctly' do
27
33
  step 'I should be prompted for the answer to the first question'
28
- @input.gets "name = 'Matt'"
34
+ @game << prepare_input("true")
29
35
  end
30
36
 
31
37
  step 'I answer the first question incorrectly' do
32
38
  step 'I should be prompted for the answer to the first question'
33
- @input.gets "moo = 'baz'"
39
+ @game << prepare_input("moo")
34
40
  end
35
41
 
36
42
  step "I should see the first help text" do
37
- @output.string.should include("Variables hold information. We use the equal sign to assign information into a variable:\n@name = \"Matt\"")
43
+ expected_pattern = massage_pattern('In Ruby, we say things are')
44
+ @game.wait_for(:output, expected_pattern)
38
45
  end
39
46
 
40
47
  step "I should not see the first help text" do
41
- @output.string.should_not include("Variables hold information. We use the equal sign to assign information into a variable:\n@name = \"Matt\"")
48
+ pattern = massage_pattern('In Ruby, we say things are')
49
+ @game.check_until(pattern).should be_nil
50
+ end
51
+
52
+ step "I answer all the questions correctly" do
53
+ step "I answer all questions up to the last one"
54
+
55
+ # Part 6:
56
+ @game << prepare_input("Door.tell('sevraq')")
57
+ @game.wait_for(:output, massage_pattern('The door opens'))
58
+ end
59
+
60
+ step "I should see that I've won the game" do
61
+ @game.wait_for(:output, massage_pattern('Congratulations'))
62
+ end
63
+
64
+ step "I answer all questions up to the last one" do
65
+ step "I answer the first question correctly"
66
+ # Part 1:
67
+ @game << prepare_input('"Gandalf"')
68
+ @game.wait_for(:output, massage_pattern('Part 2'))
69
+
70
+ # Part 2:
71
+ @game << prepare_input("@name = 'Matt'")
72
+ @game.wait_for(:output, massage_pattern('Part 3'))
73
+
74
+ # Part 3:
75
+ @game << prepare_input("translate('sevraq')")
76
+ @game.wait_for(:output, massage_pattern('Part 4'))
77
+
78
+ # Part 4:
79
+ @game << prepare_input("Door.read")
80
+ @game.wait_for(:output, massage_pattern('Part 5'))
81
+
82
+ # Part 5:
83
+ @game << prepare_input("translate(Door.read)")
84
+ @game.wait_for(:output, massage_pattern('speak friend and enter'))
85
+ @game.wait_for(:output, massage_pattern('Part 6'))
86
+ end
87
+
88
+ step "I answer the last question incorrectly" do
89
+ # Part 6:
90
+ @game.wait_for(:output, massage_pattern('try sending the Door the message'))
91
+ @game << prepare_input("Door.tell('moo')")
92
+ @game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
93
+
94
+ #answer second help text wrong:
95
+ @game << prepare_input("Door.tell('moo')")
96
+ @game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
97
+
98
+ #answer third help text wrong:
99
+ @game << prepare_input("Door.tell('moo')")
100
+ @game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
101
+
102
+ #answer fourth help text wrong:
103
+ @game << prepare_input("Door.tell('moo')")
104
+ @game.wait_for(:output, massage_pattern("=> The door remains firmly shut."))
42
105
  end
43
106
 
44
- step "I should see that I was correct" do
45
- @output.string.should include("Correct!")
107
+ step "I should see encouraging text to keep trying" do
108
+ @game.wait_for(:output, massage_pattern('Your adventures with Ruby are not over yet'))
46
109
  end
@@ -0,0 +1,10 @@
1
+ Feature: Winning the game
2
+ In order to continue on to Ruby Warrior
3
+ As a player
4
+ I want to be told that I've won the game
5
+
6
+ Scenario: winning the game
7
+ Given I am not playing
8
+ When I start a new quiz
9
+ And I answer all the questions correctly
10
+ Then I should see that I've won the game
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'gates_of_moria'
3
+ require 'greenletters'
4
+ require 'shellwords'
3
5
 
4
6
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
5
7
  Dir.glob("spec/acceptance/steps/**/*steps.rb") { |f| load f, true }
@@ -0,0 +1,7 @@
1
+ RSpec.configure do |config|
2
+ config.after(:each) do
3
+ if @game && @game.alive?
4
+ @game.kill!
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ def prepare_input(text)
2
+ text.chomp + "\n"
3
+ end
4
+
5
+ def massage_pattern(text)
6
+ Regexp.new(Regexp.escape(text.strip.tr_s(" \r\n\t", " ")).gsub('\ ', '\s+'))
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gates_of_moria
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-01-25 00:00:00.000000000 Z
13
+ date: 2013-01-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -60,6 +60,22 @@ dependencies:
60
60
  - - ! '>='
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: greenletters
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
63
79
  description: A simple quiz to test Ruby knowledge
64
80
  email:
65
81
  - matt@bendyworks.com
@@ -78,17 +94,23 @@ files:
78
94
  - bin/gates_of_moria
79
95
  - gates_of_moria.gemspec
80
96
  - lib/gates_of_moria.rb
81
- - lib/gates_of_moria/motd.txt
82
- - lib/gates_of_moria/questions.json
97
+ - lib/gates_of_moria/data/door.rb
98
+ - lib/gates_of_moria/data/motd.txt
99
+ - lib/gates_of_moria/data/questions.json
83
100
  - lib/gates_of_moria/quiz.rb
84
101
  - lib/gates_of_moria/repl.rb
85
102
  - lib/gates_of_moria/version.rb
86
- - spec/acceptance/player_starts_the_quiz.feature
103
+ - spec/acceptance/answering_last_question_wrong.feature
104
+ - spec/acceptance/answering_questions.feature
105
+ - spec/acceptance/starting_and_quitting.feature
87
106
  - spec/acceptance/steps/player_steps.rb
107
+ - spec/acceptance/winning_the_game.feature
88
108
  - spec/fixtures/one_question.json
89
109
  - spec/gates_of_moria/quiz_spec.rb
90
110
  - spec/gates_of_moria/repl_spec.rb
91
111
  - spec/spec_helper.rb
112
+ - spec/support/ending_processes.rb
113
+ - spec/support/greenletters.rb
92
114
  homepage: https://github.com/mathias/gates_of_moria
93
115
  licenses: []
94
116
  post_install_message:
@@ -114,9 +136,14 @@ signing_key:
114
136
  specification_version: 3
115
137
  summary: A simple quiz to test Ruby knowledge
116
138
  test_files:
117
- - spec/acceptance/player_starts_the_quiz.feature
139
+ - spec/acceptance/answering_last_question_wrong.feature
140
+ - spec/acceptance/answering_questions.feature
141
+ - spec/acceptance/starting_and_quitting.feature
118
142
  - spec/acceptance/steps/player_steps.rb
143
+ - spec/acceptance/winning_the_game.feature
119
144
  - spec/fixtures/one_question.json
120
145
  - spec/gates_of_moria/quiz_spec.rb
121
146
  - spec/gates_of_moria/repl_spec.rb
122
147
  - spec/spec_helper.rb
148
+ - spec/support/ending_processes.rb
149
+ - spec/support/greenletters.rb
@@ -1,13 +0,0 @@
1
- {
2
- "questions": [
3
- {
4
- "initial_prompt": "Let me know your name by assigning it to a variable called '@name'!",
5
- "expected_response": "@name.class == String && @name.length > 0",
6
- "help_texts": [ "Let me know your name by assigning it to a variable called '@name'!", "Variables hold information. We use the equal sign to assign information into a variable:\n@name = \"Matt\"", "bar", "baz" ]
7
- }, {
8
- "expected_response": "result == 'friend'",
9
- "help_texts": ["Now send the string 'sevraq' to the translate method."],
10
- "setup_code": "def translate(s); s.tr!('A-Za-z', 'N-ZA-Mn-za-m'); end"
11
- }
12
- ]
13
- }