naufragio
naufragio

Reputation: 73

How Ruby classes work

This is an exercise from the odin project where they give you a file with the test specifications and you have to write the program in order to pass them.

The program is working, but I've just started Ruby classes and I do not understand why doesn't work if I do a modification that I'll show:

Rspec

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

    it 'should capitalize every word' do
      @book.title = "stuart little"
      @book.title.should == "Stuart Little"
    end

    describe 'should capitalize every word except...' do
      describe 'articles' do
        specify 'the' do
          @book.title = "alexander the great"
          @book.title.should == "Alexander the Great"
        end

        specify 'an' do
          @book.title = "to eat an apple a day"
          @book.title.should == "To Eat an Apple a Day"
        end
      end

      specify 'conjunctions' do
        @book.title = "war and peace"
        @book.title.should == "War and Peace"
      end

      specify 'the first word' do
        @book.title = "the man in the iron mask"
        @book.title.should == "The Man in the Iron Mask"
      end
    end
  end
end

Code

class Book
  def title
    @title
  end

  def title=(title)
    @title = titlieze(title)
  end

  private
  def titlieze(title)
    stop_words = %w(and in the of a an)
    title.capitalize.split.map{|w| stop_words.include?(w) ? w : w.capitalize}.join(' ')
  end

end

Why if I write my code like this

class Book

  def title=(title)
    @title = titlieze(title)
    @title
  end

  private
  def titlieze(title)
    stop_words = %w(and in the of a an)
    title.capitalize.split.map{|w| stop_words.include?(w) ? w : w.capitalize}.join(' ')
  end

end

then I get this error:

Failure/Error: expect(@book.title).to eq("Inferno")

     NoMethodError:
       undefined method `title' for #<Book:0x000000017bd0a8 @title="Inferno">
       Did you mean?  title=

But the method "title" is defined no? why it says it is not?

Upvotes: 0

Views: 58

Answers (1)

spickermann
spickermann

Reputation: 106802

Because def title=(title) defines setter method named title= to assign a value to the @title variable. And it is important to note that the = is part of the method name.

Whereas the specifications complain about a missing getter method named title (without a =).

Your second version is missing that title getter method for the @title variable. You may just use the attr_reader macro to add such a getter method:

class Book
  attr_reader :title

  # ...
end

attr_reader :title is just a shortcut that generates a method like in your first version:

def title
  @title
end

Upvotes: 2

Related Questions