I am trying to create a Book class, with 1 attribute: title, which must be capitalize if entering in lowercase. My code works in repl.it but rspec still show NoMethodError (undefined method 'title' for #(Book.... #title="Inferno")
My code:
class Book
def initialize(title=nil)
#title = title
end
def title=(new_title)
title = new_title.capitalize!
end
end
Rspec:
require 'book'
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
Thank you.
try this out.
class Book
attr_reader :title
def initialize(title=nil)
#title = title && title.capitalize!
end
def title=(new_title)
#title = new_title && new_title.capitalize!
end
end
class Book
def initialize(title=nil)
#title = title
end
def title=(new_title)
title = new_title.capitalize!
puts title
puts #title
end
def title
#title
end
end
b = Book.new('hello')
b.title = 'hello'
--output:--
Hello
hello
#title and title are two different variables.
Related
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
Suppose I have:
Book = Struct.new(:title, :content)
book = Book.new('harry potter', 'a bunch of content here')
p book.title #=> harry potter
What I want the last line to produce is "Harry Potter". I know I can do something like:
Book = Struct.new(:title, :content) do
def capitalized_title
self.title.gsub(/\S+/, &:capitalize)
end
end
and then call capitalized_title, but what I want is to not have to create a separate method, instead, have some way of when you assign "title" to a new Book object, the title is immediately capitalized. Some kind of hook method, I would guess.
class Book < Struct.new(:title, :content)
def title
super.gsub(/\S+/, &:capitalize)
end
end
book = Book.new('harry potter', 'a bunch of content here')
book.title # => "Harry Potter"
Book = Struct.new(:title, :content) do
alias orig_title title
def title
orig_title.gsub(/\S+/, &:capitalize)
end
end
To prevent title is called every time, override title=:
Book = Struct.new(:title, :content) do
alias orig_title= title=
def initialize(*args)
super
self.title = title
end
def title= value
self.orig_title = value.gsub(/\S+/, &:capitalize)
end
end
You could create an initialize method for the class Book (borrowing #falsetru's nice way of capitalizing the the words in title). First note that Book does not have its own initialize method;;
Book = Struct.new(:title, :content)
#=> Book
Book.private_instance_methods(false)
#=> []
Rather, it inherits from Struct:
Book.private_instance_methods.include?(:initialize)
#=> true
Book.instance_method(:initialize).owner
#=> Struct
Struct.private_instance_methods(false)
#=> [:initialize, :initialize_copy]
We add an initialize method in the usual way:
Book = Struct.new(:title, :content) do
def initialize(title,content)
self.title = title.gsub(/\S+/, &:capitalize)
self.content = content
end
end
confirm:
Book.private_instance_methods(false)
#=> [:initialize]
and test:
book = Book.new('harry potter', 'a bunch of content here')
book.title
#=> "Harry Potter"
book.content
#=> "a bunch of content here"
If there were more than just two instance variables, we might do this:
Book = Struct.new(:title, :content) do
def initialize(title,content)
super
self.title = title.gsub(/\S+/, &:capitalize)
end
end
I am trying to figure out why my code below is not working. As you can see, the code is very brief and simple.
Could someone please help me understand why I am receiving this error message:
"NoMethodError: undefined method `<<' for nil:NilClass"
when I enter this command into terminal (after loading script):
mex_cuisine.add_recipe("charro beans")
The script:
class Cookbook
attr_accessor :title, :recipes, :recipe
def initialize(title)
#title = title
#recipes = []
end
def add_recipe(recipe)
#recipe = recipe
#recipes << #recipe
end
end
class Recipe
attr_accessor :name, :ingredients, :steps
def initialize(name, ingredients, steps)
#name = name
#ingredients = ingredients
#steps = steps
end
end
Your assistance is much appreciated.
Thank you.
**Edit:
Substituting this code:
def add_recipe(recipe)
#recipes.push(recipe)
puts "Added a recipe to the collection: #{recipe.title}"
end
causes the same error... Here is the long version:
NoMethodError: undefined method push' for nil:NilClass
from cookbook.rb:10:inadd_recipe'
from (irb):173
from /Users/patrickmeaney/.rvm/rubies/ruby-2.1.1/bin/irb:11:in `'
**Edit:
Here is the given test code:
mex_cuisine = Cookbook.new("Mexican Cooking")
burrito = Recipe.new("Bean Burrito", ["tortilla", "bean"], ["heat beans", "place beans in tortilla", "roll up"])
mex_cuisine.recipes # []
mex_cuisine.add_recipe(burrito)
Put the following code in a file called my_prog.rb:
class Cookbook
attr_accessor :title, :recipes, :recipe
def initialize(title)
#title = title
#recipes = []
end
def add_recipe(recipe)
#recipe = recipe
#recipes << #recipe
end
end
class Recipe
attr_accessor :name, :ingredients, :steps
def initialize(name, ingredients, steps)
#name = name
#ingredients = ingredients
#steps = steps
end
end
class Cookbook
attr_accessor :title, :recipes, :recipe
def initialize(title)
#title = title
#recipes = []
end
def add_recipe(recipe)
#recipe = recipe
#recipes << #recipe
end
end
class Recipe
attr_accessor :name, :ingredients, :steps
def initialize(name, ingredients, steps)
#name = name
#ingredients = ingredients
#steps = steps
end
end
mex_cuisine = Cookbook.new("Mexican Cooking")
burrito = Recipe.new("Bean Burrito", ["tortilla", "bean"], ["heat beans", "place beans in tortilla", "roll up"])
mex_cuisine.recipes # []
mex_cuisine.add_recipe(burrito)
Open a terminal window and cd to the same directory as my_prog.rb. Then run your program:
ruby my_prog.rb
There will be no errors.
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