陷入这种Ruby逻辑

时间:2019-02-18 21:58:26

标签: ruby

我要解决这个问题。从测试中我以为我必须初始化类,但是看着解决方案我在想错误的方式。现在,我几乎了解了解决方案中的所有代码,但是我不理解的是吸气剂背后的逻辑。首先,我会写attr_accessor:title,因为最后我们写了标题,但可能会错了。其次,我不了解的事实是,我相信每次在类上调用新方法时,都必须使用初始化和分配属性的方法来实例化它。我不明白的第三件事是这行代码def title =(new_title)。我们在这里到底在做什么?我们是否正在这样做,否则以下代码将无法正常工作?谢谢。

 @book.title = "inferno"

这是rake文件:

# # Book Titles
#
# # Topics
#
# * classes and objects
# * instance variables
# * setter methods
# * strings
#
# # Notes
#
# Book Titles in English obey some strange capitalization rules. For example, "and" is lowercase in "War and Peace". This test attempts to make sense of some of those rules.
#

require 'book'

describe Book do

  before do
    @book = Book.new
  end

  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

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

        specify 'a' do
          @book.title = "to kill a mockingbird"
          expect(@book.title).to eq("To Kill a Mockingbird")
        end

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

      specify 'conjunctions' do
        @book.title = "war and peace"
        expect(@book.title).to eq("War and Peace")
      end

      specify 'prepositions' do
        @book.title = "love in the time of cholera"
        expect(@book.title).to eq("Love in the Time of Cholera")
      end
    end

    describe 'should always capitalize...' do
      specify 'I' do
        @book.title = "what i wish i knew when i was 20"
        expect(@book.title).to eq("What I Wish I Knew When I Was 20")
      end

      specify 'the first word' do
        @book.title = "the man in the iron mask"
        expect(@book.title).to eq("The Man in the Iron Mask")
      end
    end
  end
end

及其提供的解决方案:

class Book
  attr_reader :title

  def title=(new_title)
    words = new_title.split(" ")
    words = [words[0].capitalize] +
      words[1..-1].map do |word|
        little_words = %w{a an and the in of}
        if little_words.include? word
          word
        else
          word.capitalize
        end
      end
    @title = words.join(" ")
  end

end

1 个答案:

答案 0 :(得分:3)

首先,您需要了解有关访问器的概念。许多语言可以直接访问实例变量。 Ruby没有;它认为类外部的所有内容都应单独通过方法。因此,为了从外部读取或写入@title,请使用访问器。

attr_accessor是一种便捷方法,它定义了两种方法:属性读取器和属性写入器。当您说attr_accessor :title时,它等同于

def title()
  @title
end

def title=(value)
  @title = value
end

其中titletitle=是方法名称,而valuetitle=方法的参数。完成后,您可以编写

book.title=("New title")
puts book.title()

调用设置程序,然后调用getter。 Ruby在这里为我们提供了一些便利,因为这些是等效的语法糖:

book.title = "New title"
puts book.title

我们希望所有方法都通过方法的原因是,我们可以自定义方法。如果我们需要确保我们被允许阅读,或者如果我们想要设置的副作用,我们可以切换出一个accessor方法。但是,如果这样做,则不需要自动生成的访问器-我们将编写自己的访问器。

  

首先,我会写attr_accessor:title,因为最后我们写了标题,但可能会错了。

阅读器与默认阅读器相同。但是该解决方案希望创建一个自定义编写器,因此我们将自己定义它。因此,只有阅读器需要自动生成:attr_reader :title

  

第二,我不完全了解的事实是,我相信每次我们在类上调用新方法时,都必须使用初始化和分配属性的方法来实例化它。

有一个隐式的空initialize,它继承了每个不覆盖它的类。它不带参数,什么也不做,几乎是这样的:

def initialize()
end

如果您没有编写自己的initialize方法,则该方法正在使用。由于规范中所述的Book不接受new的参数,并且所有与标题的交互都通过属性访问器进行,因此您只需要使用默认的空initialize

  

我不明白的第三件事是这行代码def title =(new_title)。我们在这里到底在做什么?我们是否正在这样做,否则以下代码将无法正常工作?

如上所述,def title=(new_title)def factorial(n)的语法完全相同,只是方法名称很奇怪。 Ruby让方法以许多非常规的方式结束:带有问号以表示布尔结果,例如equal?,带有感叹号以表示危险操作,例如sort!,或带有等号以允许替代调用如上所述伪装成赋值的语法。