Skip to content

Instantly share code, notes, and snippets.

@pinkopaque22
Created December 17, 2015 23:48
Show Gist options
  • Save pinkopaque22/52a965f5c5cdd88f06f6 to your computer and use it in GitHub Desktop.
Save pinkopaque22/52a965f5c5cdd88f06f6 to your computer and use it in GitHub Desktop.
__Details__
As you know from completing the previous exercise, it is tedious to write numerous getter and setter methods. Getter and setter methods are so common that Ruby provides a shortcut to create them. The attr_accessor method creates a getter and setter method based on an argument. You pass attr_accessor a Symbol:
class Square
attr_accessor :size
end
s = Square.new
s.size = 10 # This is the setter
s.size #=> 10 # This is the getter
We now have getter and setter methods for size, because we called:
attr_accessor :size
The size=() and size methods are dynamically generated when we add attr_accessor :size to Square.
Behold the magic of Ruby! It's actually not magic but "dynamic programming", which we'll cover later.
To complete this exercise, create a Playlist class. It should have attributes for name, author, and song_list. These attributes should be readable and writable.
__Specs__
describe "Playlist" do
describe "instance variables" do
it "should be able to create a country playlist" do
playlist = Playlist.new
# Setters
playlist.name = "Country"
playlist.author = "Blake Shelton"
playlist.song_list = ["Sure Be Cool If You Did", "God Gave Me You"]
# Getters
expect( playlist.name ).to eq("Country")
expect( playlist.author ).to eq("Blake Shelton")
expect( playlist.song_list ).to eq(["Sure Be Cool If You Did", "God Gave Me You"])
end
it "should be able to create a Rock playlist" do
playlist = Playlist.new
# Setters
playlist.name = "Rock"
playlist.author = "R&R"
playlist.song_list = ["Radioactive", "Clouds"]
# Getters
expect( playlist.name ).to eq("Rock")
expect( playlist.author ).to eq("R&R")
expect( playlist.song_list ).to eq(["Radioactive", "Clouds"])
end
end
end
__Code__
class Playlist
attr_accessor :name
n = Playlist.new
n.name
attr_accessor :author
a = Playlist.new
a.author
attr_accessor :song_list
s = Playlist.new
s.song_list
end
__Details__
Create a Book class with three instance methods:
set_title(title) should take an argument and use it to set the @title instance variable.
set_author(author) should take an argument and use it to set the @author instance variable.
Finally, description should accept no arguments and return a string formatted as: "Title was written by author" using the @title and @author instance variables.
__Specs__
describe "Book" do
describe "setters" do
it "should respond to #set_title" do
expect(Book.new).to respond_to(:set_title)
end
it "should set @title" do
book = Book.new
book.set_title("Z for Zachariah")
expect(book.instance_variable_get(:@title)).to eq("Z for Zachariah")
end
it "should respond to #set_author" do
expect(Book.new).to respond_to(:set_author)
end
it "should set @author" do
book = Book.new
book.set_author("Robert C. O'Brien")
expect(book.instance_variable_get(:@author)).to eq("Robert C. O'Brien")
end
end
describe "#description" do
it "should return the correct title and author" do
book = Book.new
book.set_title("Railsea")
book.set_author("China Miéville")
expect(book.description).to eq("Railsea was written by China Miéville")
end
it "should return the correct title and author" do
book = Book.new
book.set_title("The Tombs of Atuan")
book.set_author("Ursula Le Guin")
expect(book.description).to eq("The Tombs of Atuan was written by Ursula Le Guin")
end
end
end
__Code__
class Book
def set_title(title)
@title = title
end
def set_author(author)
@author = author
end
def description
"#{@title} was written by #{@author}"
end
end
__Details__
As we learned in the checkpoint, getter and setter methods can access attributes of a class instance.
Let's explore another example as a refresher. Below we define two methods in the Car class. The color=(c) method sets the @color instance variable, and the color method gets the @color instance variable. The last two lines of code below demonstrate how the getter and setter methods are used on the ferrari instance of the Car class:
class Car
def color=(c)
@color = c
end
def color
@color
end
end
ferrari = Car.new
ferrari.color = "Red" # setter
ferrari.color # getter
#=> "Red"
The = in color=(c) makes the setter method more idiomatic. The Ruby interpreter lets you put a space between the equal sign and the method. The following two lines are equivalent.
ferrari.color=("Red")
ferrari.color = "Red"
Most Rubyists prefer the latter syntax with the extra spaces.
To complete this exercise, rewrite your Book class from the previous exercise. The new Book class should have attributes to describe its title, number of pages, and author.
These instance variables should be settable and gettable.
__Specs__
describe "Book" do
describe "should be able get/set attributes for Wool" do
it "should be able to get/set title" do
b = Book.new
b.title = "A Slight Trick of the Mind"
expect(b.title).to eq("A Slight Trick of the Mind")
end
it "should be able to get/set pages" do
b = Book.new
b.pages = 528
expect(b.pages).to eq(528)
end
it "should be able to get/set author" do
b = Book.new
b.author = "Hugh Howey"
expect(b.author).to eq("Hugh Howey")
end
end
describe "should be able get/set attributes for Station Eleven" do
it "should be able to get/set title" do
b = Book.new
b.title = "Station Eleven"
expect(b.title).to eq("Station Eleven")
end
it "should be able to get/set pages" do
b = Book.new
b.pages = 352
expect(b.pages).to eq(352)
end
it "should be able to get/set author" do
b = Book.new
b.author = "Emily St. John Mandel"
expect(b.author).to eq("Emily St. John Mandel")
end
end
end
__Code__
class Book
def title=(t)
@title = t
end
def title
@title
end
def pages=(pg)
@pages = pg
end
def pages
@pages
end
def author=(a)
@author = a
end
def author
@author
end
end
book = Book.new
book.title = "@title"
__Details__
The RSpec which tests your code can fail or pass, but it can also raise errors. If the RSpec errors, nothing in the console will run.
To test this, try some basic functionality in the console:
p "The console is not erroring."
If you hit run, you may be dismayed that the console is erroring, and your code doesn't print. This is because the specs testing this code expect certain things in the code that aren't there. If your code doesn't behave as expected, the specs will fail. On the other hand, if your code doesn't have certain expected components, the specs won't even arrive at failure, and they'll bring the console down with them.
Let's review the error message. The important part is:
uninitialized constant MadeUpClass
This error is telling us the spec is looking for a "constant" (think "class") named MadeUpClass, and because the spec isn't finding this constant, the spec is throwing an error. We can solve this error by defining the MadeUpClass class in our console:
class MadeUpClass
end
If you run the code again, you'll get a NoMethodError saying undefined method 'return_string' for #<MadeUpClass:0x007f0c32dbb600> (or some other number). This is a similar failure, but now it's a failure, not an interpreter error. You can see this by trying to print something again. Although the tests are failing, your output should be printed below them.
This test failure tells us the spec expects the return_string method to be defined on instances of MadeUpClass. To fix this, let's add that method:
class MadeUpClass
def return_string
end
end
Press run again. We get RSpec::Expectations::ExpectationNotMetError, with a message telling us that the test expected a specific string to be returned from the method, while the method returned nothing (nil).
To make the tests pass, return that string from the method.
This exercise should familiarize you with some errors you might encounter in this console, and how to deal with them.
Look out for these errors if you try to run example code in the in-browser Ruby console (which runs specs which can have class expectations). They might prohibit your code from running, so if you want to test out basic Ruby, we suggest using irb.
Error messages in Ruby are generally quite helpful. Always read them and consider their meaning.
__Specs__
describe MadeUpClass do
describe "#return_string" do
it "returns the right string" do
expect( MadeUpClass.new.return_string ).to eq("String to return")
end
end
end
__Code__
class MadeUpClass
def return_string
p "String to return"
end
end
__Results__
"String to return"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment