hfesoio
hfesoio

Reputation: 29

Why is my code capitalizing words when I have specified not to?

class Book
    # write your code here
        attr_accessor :title

        def title= (title)

          @title = title.split()
          @title = @title.map {
              |x|
              index = @title.index(x)
               if x == 'and' or x == 'in' or x == 'of' or x == 'the' or x == 'a' or x == 'an' and index != 0

                x = x       
              else
                x.capitalize
              end
          }
          @title = @title.join(" ")
          return @title
        end              
    end

This is an exercise from the Project Ruby on the Odin Project. It's about capitalizing the titles of a book bound to some certain conditions life if the word is a preposition or an article or a conjunction then dont capitalize it unless it occurs in the beginning of the title then capitalize it. I have written the code for it but it isn't working as you can see :

index = @title.index(x)
if x == 'and' or x == 'in' or x == 'of' or x == 'the' or x == 'a' or x == 'an' and index != 0
  x = x
else 
  x.capitalize
end

But again it doesn't work

expected: "The Man in the Iron Mask"
got: "The Man in The Iron Mask"

The second The gets capitalized too when I have said in the if statement that if it isn't equal to the first word then don't capitalize it but it still capitalizes it.

Upvotes: 0

Views: 66

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110675

The problem with your code has been identified. One way to obtain the desired result is to use String#gsub with a simple regular expression.

LITTLE_WORDS = %w| a an and in of the |
  #=> ["a", "an", "and", "in", "of", "the"] 
LWR = /\b#{LITTLE_WORDS.join('|')}\b/i
  #=> /\ba|an|and|in|of|the\b/i

def normalize(str)
  str.gsub(/\S+/) do |word|
    if Regexp.last_match.begin(0).zero?
      word.capitalize
    else
      word.match?(LWR) ? word.downcase : word.capitalize
    end
  end
end

normalize("tHe cat and    A hAt")
  #=> "The Cat and    a Hat"

See Regexp::last_match (same as the value of the global variable $~) and MatchData#begin. Notice that this preserves spacing in the string.

In the publishing industry such articles, prepositions and conjunctions are often referred to as "little words", and written "a", "an", "and", "in", "of", "the".

Upvotes: 0

spickermann
spickermann

Reputation: 106882

Because index(x) always returns the first match.

I would rewrite it like this:

class Book    
  attr_accessor :title

  DO_NOT_CAPITALIZE = %w[and in of the a an]

  def title=(title)
    words = title.split.map do |word|
      # capitalize all word that are not excluded
      DO_NOT_CAPITALIZE.include?(word) ? word : word.capitalize
    end

    # always capitalize the first word
    @title = words.join(' ').capitalize
  end              
end

Upvotes: 4

Related Questions