
Welcome to a tutorial on creating a basic text parser like those found in older interactive fiction games.
Now, I write “basic” here because, while this tutorial will walk you through the steps of creating a text parser example, it will not cover the more advanced functionality of navigating a world or an inventory system. This will, however, get you going with how to approach the problem.
To start, let’s look at the way a variable is created in Ruby:
someVar = "value"
That’s it. Unlike many other scripting languages, Ruby has no type, word, or punctuation requirements to creating a variable. It is simply some collection of numbers, letters, and the underscore. No dollar-sign needed!
With variable creation underway, let’s look at input and output.

In Ruby, the default input is the system default input. In nearly all cases, this is the command-line. It’s the same with the output, too. It defaults to the command-line as well. Getting input or putting output is a matter of working with the command-line.
In Ruby, we use the following to output text:
puts "Some string"
For input, we use the following:
gets
Like in Python and other scripting languages, you may have noticed that I have not used any semicolons in any of these statements. That’s because, while you can use semicolons, the common style is to exclude them. You can simply end the statement, press Enter to make a new line, and type more code.
Also like in Python, function calls can be made using only the keyword, a space, and the argument. While Ruby allows for parenthetical usage, the common style is to leave them off most method calls and only use them in the definition of a method. (As I’ll cover later.)
In practice, then, if I wanted to ask the user a question and then get their input, I would use the following code:
puts "Hey, input your name!"
name = gets
In use, that would look like this:
Running from the command-line, it asked for a name and I typed mine. During runtime, the value “Dan” would have been in the variable name.
To output the value of a variable, however, we need a process called interpolation. In Ruby, we need to encapsulate the name of the variable in two brackets and start with the pound sign. This allows us, if we want, to run functions on those variables, too.
Adding to our existing code, it would look like the following:
puts "Hey, input your name!"
name = gets
puts "Your name is #{name}"
Run, it would look like the following:
It asked for my name, I typed it, and it wrote what I typed.
Okay, so that’s variables and some input and output done, right? What if we wanted to test that input against something?
For that, we will use the case statement. In Ruby, this is the stand-in for the switch in many other languages. In fact, it works the same way.
case variable
when value1
#do something
when value2
#do another thing
end
For case, it starts with the variable or value to compare as the first argument after the word “case” and then, on the next line, a when and then, on the line after that, something to do. (Note: Ruby automatically ‘breaks’ for each when. There is no need write the word break in Ruby. It does it for you!)
Each command block in Ruby also ends with an end. For using if, or in this case, case statements, it needs to end with an end.
Going back to our example code, we can expand it to test our input.
Running, it would look like the following:
Using case, then, we can test our input against a number of different options and then do something in response.
With that in place, let’s add in a method to do something.
In Ruby, functions are called methods. (The same with in Java, too.)
To create a method, we use def and then an end. (Like in command blocks, methods end in an end. Nearly everything does in Ruby, actually.)
Adding to our existing code, we write the following:
The method in the above example does one thing: puts some text.
Something important to remember about methods in Ruby is that they do not need a return statement. Like many other styling options in Ruby, the return statement has been dropped in favor of the built-in “return the result of the last statement in a method.”
Along with seemingly missing semicolons and a lack of return statements, too, Ruby can actually look really foreign to those coming from learning code through the C and C++ family of languages like Java and other ECMAScript groups like ActionScript and JavaScript. But, in truth, it takes after Python and other languages like PHP in many ways, blending many of the positive aspects of those languages into its own way of doing things.
Coming back to our code, we should write another method for the other option.
Notice, this time, I’ve renamed the first method. With two methods “responding,” it would not be useful for them to have the same name. Now, we have a good_response and a bad_response. Both are called from within a case statement.
I’ve also been using another method I haven’t discussed yet. When using gets, it is often useful to “cut off” (chomp) the newline and return characters. Instead of reading the full input from the command-line, it can be useful to treat the string as something without the new and return characters. chomp lets us do that. It also is part of how Ruby calls methods part of an object’s class and parent object.
Like in other object-oriented languages, Ruby is based on the idea of everything being an Object. Numbers and String, as they are represented internally by Ruby, are they themselves objects. They have built-in methods and attributes.
One of the built-in methods for strings is the chomp method. As I wrote above, it “cuts out” the return and newline character from the input, making it easier for us to deal with what we get from a user typing on the command-line.
Running the code, it looks like the following:
Looking at the screenshots, it seems as if the input and output isn’t changing much from one to another. The reasoning for that is pretty simple: it isn’t.
In moving from a case statement to then one calling methods, we aren’t changing the interface for the user. Instead, I am demonstrating different ways to approach the problem. While Ruby can be treated like a scripting language, in that it runs and does one thing in that file, it can also be used in more complex ways, too. In fact, I’ve been moving from a straight-forward way of addressing the problem toward a functional programming model and will now show how to approach the same problem from an object-oriented way of thinking as well.
Creating objects in Ruby is pretty similar to how we’ve been using methods and command-blocks. However, instead of using def, we start an object with a new word, class.
In Ruby, a class is an object definition. It defines how an object should act and what its attributes are. However, unlike in other languages, Ruby has a special method for initializing the parameters and attributes: initialize. When a new instance of a class is created, its initialize method is called first.
Since we are moving toward an object-oriented approach, we need to move our code into our new object. Since we’ve already created the two methods of good_response and bad_response, we can copy that code over into our new class.
However, we’ve now got a problem. Where should we put the case statement? How about we put it within its own method? That way, we can call it as needed.
Good. Now, we’ve got code to parse some content and call the responses needed. However, it’s still only the definition. We need an instance of the object to actually do something.
To do that, we follow the syntax demonstrated with gets.chomp. We call the built-in method of new with the object of Parser.
As I wrote before, Ruby was created with an object-oriented approach in mind. So, not only is everything an object in Ruby, but the language also understand the concepts of public and private, too. In object-oriented design, this is a way of separating methods between those that are called from within classes with an inherence chain: either the parent or child of some class. (Ruby also allows mixins, but that’s a more advanced topic.)
In Ruby, to make some methods public, we use that word, public. To make others private, we use that word, too, private. In each case, it is on a single line and takes effect on all methods below it until the use of the other word or the class definition ends.
For example, going back to our code, we would have the following:
We can safely call parse from our instance of the Parser object because it is a public method.
If we run this as is, we get:
However, if we tried to access some private methods, we would get the following error (when trying to call good_response, for example):
Ruby will, as you see above, enforce the rules of public and private within an object. If a method is private, it cannot be called from outside its family of inherited objects.
Okay, so, we moved through a functional approach to a fully object-oriented one. What is next? Well, we still need something to puts some output in the form of a question, let us input something, and then let us do it again and again.
For that, we turn to one of the unique command functionalities of Ruby: loop.

In many programming languages, there are ways to create looping structures. Using for and while are very common across languages. However, in Ruby, there is a very literal way to create a loop: use the loop keyword.
For example, if we wanted to create a basic loop, we might do something like the following:
Right before starting the loop, we set a variable to be a value we are going to check within it (to prevent infinite looping). Then, right inside it, we subtract one from the variable, output its value, and then check to see if we should break. (The use of break within loop is why it is not used in a case statement. It already existed in this usage.)
Moving back to our code, we could implement a loop to ask for input, parse it, and then ask again.
Now, as long as we don’t enter “quit” from the interface, we can keep entering anything we want. It will check against the two options, “Dan” or not, and then act accordingly.
Running, it looks like the following:
And, using another set of inputs, it looks like this:
This is all very silly, you might be thinking. Checking input against names isn’t particularly useful outside of examples and wouldn’t really be used in any real-world projects.
And, of course, you’d be right. The example isn’t very useful by itself. However, it is the basis of the parsing text input mechanics for many interactive fiction games. It uses the idea of some looping interface, a Parser object, and some feedback for the player to see.
In each case, the player enters text, presses Enter, and then revises her strategy accordingly.
So, if we were to change the example into something more like a text adventure, it might look like the following:
Now, instead of names, we input verbs for the parser to handle.
For example, running it with new input might look like the following:
It looks much more like interactive fiction now, taking verbs as input and outputting some responses in turn. In fact, we we wanted to build on this, we’d need to program some nouns into the system, pairing up what was valid input for a pattern of “verb + noun” and translating that into something that had an effect.
As a final note on our changed and much more complex “basic” text parser in Ruby, there was a new method call snuck into the last update: downcase!. In Ruby, the use of an exclamation mark at the end of a line means the value of the object that invoked it is changed as a result of the call. Instead of passing back or returning some value, the function acts on the calling object instead.
In this case, that means that downcase, the method to change some string into its lowercase letters, is called on the variable and is changed in the process. The reason for this change has to do with case-sensitive string comparison. To simplify comparing some string to another, we reduce the first, incoming string to lowercase. That way, the code only need make one comparison and not account for all the variations in capitalization that can occur within the input string.