I'm trying to pass this rspec
describe "title" do
it "should capitalize the first letter" do
#book.title = "inferno"
expect(#book.title).to eq("Inferno")
end
it "should capitalize every word" do
#book.title = "stuart little"
expect(#book.title).to eq("Stuart Little")
end
With this code
class Book
attr_accessor :title
def initialize(title="")
#title = capital(title)
end
def capital(title)
articles = %w(the a an and of in the)
new_title = []
title.split.each do |w|
articles.include?(w)? new_title << w : new_title << w.capitalize
end
new_title[0] = new_title[0].capitalize
new_title.join(" ")
end
end
book = Book.new("stuart little")
puts book.title
And I get "Stuart Little" when I run the code, but I keep getting errors when I run it through rspec. (eg, it just returns as "stuart little").
I'm thoroughly confused why this is happening, so I'm hoping someone can shed some light for me.
You only run your capital method, when you assign a title to the new method, but not when you assign it to the title= setter method.
I would replace the attr_accessor with a attr_reader and add a custom title= setter method:
class Book
attr_reader :title
def initialize(title = '')
self.title = title # calls the setter below
end
def title=(title)
#title = capital(title)
end
private
def capital(string)
articles = %w( a an and in of the )
words = title.split.map do |word|
articles.include?(word) ? word : w.capitalize
end
words.join(' ').capitalize
end
end
The code below checks to see if in the file '08_book_titles' I have reversed the string that is in the class Book and method title contained in the code below. That string being "inferno".
require '08_book_titles'
describe Book do
before do
#book = Book.new
end
describe 'title' do
it 'should capitalize the first letter' do
#book.title = "inferno"
#book.title.should == "Inferno"
end
I tried the following to no avail. Any help is much appreciated.
class Book
def title
return yield.capitalize
end
end
If you want to store the capitalized form, then
class Book
attr_accessor :title
def title=( title )
#title = title.capitalize
end
end
If you want to preserve the original form
class Book
attr_accessor :title
def title
#title.capitalize
end
end
I'm currently working through a set of TestFirst problems. The spec for the problem I'm working on can be found here: http://testfirst.org/live/learn_ruby/book_titles
I've tested the title method outside of the class so I know that it works, but once I place it in the class I get the following error:
1) Book title should capitalize the first letter
Failure/Error: #book.title.should == "Inferno"
ArgumentError:
wrong number of arguments (0 for 1)
Here's what I have so far:
class Book
attr_accessor :title
def initialize(title=nil)
#title = title
end
def title(title)
first_check = 0
articles = %w{a the an in and of}
words = title.split(" ")
words.each do |word|
if first_check == 0
word.capitalize!
first_check += 1
elsif !articles.include?(word)
word.capitalize!
end
end
#title = words.join(" ")
end
end
If someone could explain how the class should be formatted, it'd be greatly appreciated!
Your problem is right here:
def title(title)
Your Book#title method expects an argument but you're not giving it one in your spec:
#book.title.should == "Inferno"
# ----^^^^^ this method call needs an argument
I think you actually want a Book#title= method:
def title=(title)
# The same method body as you already have
end
Then you'll use the title accessor method that attr_accessor :title supplies and assigning a new title will use your title= method. And since you're supplying your own mutator method, you could use attr_reader instead:
class Book
attr_reader :title
def initialize(title=nil)
#title = title
end
def title=(title)
#...
end
end
Currently struggling through an rspec tutorial and would really appreciate some clarification.
Code is:
class Book
attr_reader :title
def initialize(title=nil)
#title = title = title && title.capitalize!
end
def title=(new_title = nil)
#title = new_title && new_title.each do |word|
word.capitalize!
end
end
Two questions:
Why are there two sets of #title (that is: why is it defined in both initialize and title as being set = to different things)?
Why does the title method have an = after it? The code breaks if I do not use the =.
edit: for the purposes of my rspec tutorial this is the code i finally tried that worked
class Book
attr_accessor :title
def initialize(title = nil)
#title = title
end
def title=(book_title = nil)
#title = book_title.capitalize
end
end
My initial problem was with the title= method. Finally I came upon a thread that explain what method= function was. It is necessary if you want to assign a value to something within a class method (at least that is my understanding at this point. Feel free to correct me).
I would appreciate any tips in this new code as well.
Let's analize that:
attr_reader :title
Here we are basically defining the method:
def title; #title; end
which returns the instance variable #title.
def initialize(title=nil)
#title = title = title && title.capitalize!
end
Here we are defining a 0-1 arguments constructor which can be reduced to:
def initialize(title=nil)
title && #title = title.capitalize
end
The fact is that title within the constructor is the argument variable and not the title or title= method, therefore the title= method defined later is never called here. Notice that && is used for short-circuit evaluation here.
def title=(new_title = nil)
#title = new_title && new_title.each do |word|
word.capitalize!
end
Here we actually have two syntax errors: the first one is that for Strings (which I assume is the type of a title as it appears to call String#capitalize! later) does not have the each method. Whoever wrote this probably meant String#each_char or to String#split it first instead.
The second error is that the block after the each is not closed with an end.
Now assuming this version instead:
def title=(new_title = nil)
#title = new_title && new_title.split(' ').each { |word| word.capitalize! }.join(' ')
end
the title= would just assign title to the #title variable for the same reason (short-circuit evaluation) as before and could be reduced to:
def title=(new_title = nil)
new_title && #title = new_title
end
The initialize method is called when an instance of the class is constructed. The #title = ... there sets the initial value of #title.
The title= method is called when someone subsequently sets the value of title on an instance of the class. It then adjusts the value of #title accordingly. See Ruby Accessors for a detailed explanation.
As an example:
book = Book.new # calls initialize
book.title = 'foo' # calls title=
My problem is probably quite easy, but I couldn't find an answer anywhere.
When create a class, for example:
class Book
#author = "blabla"
#title = "blabla"
#number_of_pages"
I want to create a method to print out my variables. And here I'm getting a problem when I try:
def Print
puts #author, #title, #number_of_pages
end
I am getting nothing.
When I try:
def Print
puts "#author, #title, #number_of_pages"
end
I get straight: "#author, #title, #number_of_pages"
How can I make the Print method print out the variables' values?
You should move your variable initializations to initialize:
class Book
def initialize
#author = "blabla"
#title = "blabla"
#number_of_pages = 42 # You had a typo here...
end
end
The way you have it in your question, the variables are class instance variables (which you can Google if you're curious about, but it's not really relevant here).
Initialized as (normal) instance variables, your first version of Print() works if you're just looking to dump the state -- it prints each parameter on its own line.
To make your second version of Print() work, you need to wrap your variables in #{} to get them interpolated:
def print # It's better not to capitalize your method names
puts "#{#author}, #{#title}, #{#number_of_pages}"
end
In addition to the allready exellent answer of Darshan, here is the way you would do it optimally
class Book
attr_accessor :author, :title, :number_of_pages
#so that you can easily read and change the values afterward
def initialize author, title, number_of_pages = nil
#so that you don't really need to provide the number of pages
#author = author
#title = title
#number_of_pages = number_of_pages
end
def print
puts "#{#author}, #{#title}, #{#number_of_pages}"
end
end
my_book = Book.new("blabla", "blabla", 42)
my_book.title = "this is a better title"
my_book.print
#=>blabla, this is a better title, 42
I think Darshan Computing has already solved your problem very well. But here I would like to give you alternative ways of achieving that.
I assume that you'd like to print out all the instance variables you have in the class. The method instance_variables could return an array of all your instance_variables in symbols. And then you can iterate them do whatever you want. Please be careful: instance_variable_get is pretty convenient but not the best practice.
class Book
attr_reader :author, :title, :number_of_pages
def initialize(author, title, number_of_pages)
#author = author
#title = title
#number_of_pages = number_of_pages
end
def print_iv(&block)
self.instance_variables.each do |iv|
name = iv
value = send(iv.to_s.gsub(/^#/, ''))
# value = instance_variable_get(iv) # Not recommended, because instance_variable_get is really powerful, which doesn't actually need attr_reader
block.call(name, value) if block_given?
end
end
end
rb = Book.new("Dave Thomas", "Programming Ruby - The Pragmatic Programmers' Guide", 864)
# rb.instance_variables #=> [:#author, :#title, :#number_of_pages]
rb.print_iv do |name, value|
puts "#{name} = #{value}"
end
#=> #author = Dave Thomas
#=> #title = Programming Ruby - The Pragmatic Programmers' Guide
#=> #number_of_pages = 864
# You can also try instance_eval to run block in object context (current class set to that object)
# rb.instance_eval do
# puts author
# puts title
# puts number_of_pages
# end