2017-04-10 85 views
0

我正在開發test-first-ruby-master(你可以在https://github.com/appacademy/test-first-ruby找到它)。測試優先 - 紅寶石13_xml_document

13_xml_document_spec.rb是我的代碼必須通過的Rspec測試。這個測試有幾個任務,但它是我的代碼沒有完成的最後一個(稱爲「縮進」)。

這裏是Rspec的測試:

require "13_xml_document" 


describe XmlDocument do 
    before do 
    @xml = XmlDocument.new 
    end 

    it "renders an empty tag" do 
    expect(@xml.hello).to eq("<hello/>") 
    end 

    it "renders a tag with attributes" do 
    expect(@xml.hello(:name => "dolly")).to eq('<hello name="dolly"/>') 
    end 

    it "renders a randomly named tag" do 
    tag_name = (1..8).map{|i| ("a".."z").to_a[rand(26)]}.join 
    expect(@xml.send(tag_name)).to eq("<#{tag_name}/>") 
    end 

    it "renders block with text inside" do 
    expect(@xml.hello { "dolly" }).to eq("<hello>dolly</hello>") 
    end 

    it "nests one level" do 
    expect(@xml.hello { @xml.goodbye }).to eq("<hello><goodbye/></hello>") 
    end 

    it "nests several levels" do 
    xml = XmlDocument.new 

    xml_string = xml.hello do 
     xml.goodbye do 
     xml.come_back do 
      xml.ok_fine(:be => "that_way") 
     end 
     end 
    end 

    expect(xml_string).to eq('<hello><goodbye><come_back><ok_fine 
be="that_way"/></come_back></goodbye></hello>') 
    end 

    it "indents" do 
    @xml = XmlDocument.new(true) 

    xml_string = @xml.hello do 
     @xml.goodbye do 
     @xml.come_back do 
      @xml.ok_fine(:be => "that_way") 
     end 
     end 
    end 

    expect(xml_string).to eq(
     "<hello>\n" + 
     " <goodbye>\n" + 
     " <come_back>\n" + 
     "  <ok_fine be=\"that_way\"/>\n" + 
     " </come_back>\n" + 
     " </goodbye>\n" + 
     "</hello>\n" 
    ) 
    end 

end 

這裏是我的代碼:

class XmlDocument 

def initialize(indentation = false) 
    @indentation = indentation 
    @counter = 0 
end 

def method_missing(method, *args, &block) 

    hash = {} 

    if block 
     if @indentation == false 
      "<#{method}>#{yield}</#{method}>" 
     elsif @indentation == true 

      string = "" 

      string << indent1 
      string << "<#{method}>\n" 
       (###) 
      add_indent 

      string << indent1 
      string << yield + "\n" 

      sub_indent 

      string << indent2 
      string << "</#{method}\>" 

      string 
     end 

    elsif args[0].is_a?(Hash) 

     args[0].map { |key,value| "<#{method.to_s} #{key.to_s}=\"#{value.to_s}\"/>" }.join(" ") 

    elsif hash.empty? 

     "<#{method.to_s}/>" 
    end   
end 


def indent1 
    " " * @counter 
end 


def indent2 
    " " * @counter 
end 


def add_indent  
    @counter += 1 
end 


def sub_indent 
    @counter -= 1 
end 
end 

這是輸出我得到了 「縮進」 部分:

<hello> 
     <goodbye> 
     <come_back> 
    + <ok_fine be="that_way"/> 
     </come_back> 
     </goodbye> 
    </hello> 

與正確的答案相反,第四行('ok_fine be =「that_way」/')似乎是靠近左側的兩個縮進比它應該是b即與其餘行不同,第4行不是塊,而是被調用方法'come_back'的一個參數。 我看不到我的錯誤在哪裏。即使在代碼中寫入異常(其中(###)位於我的代碼中)也不會對第4行產生任何影響。

這裏是例外(###):

if args[0].is_a?(Hash) 
    add_indent 
    string << indent 
    arg[0].map{|key, value| string << "<#{method.to_s} #{key.to_s}=\"#{value.to_s}\"/>"} 
end 

注意:我認爲,如果我設法給第4行縮進的正確的數字,這也將增加的縮進的數量後面的行,所以方法'indent2'將需要修改。

回答

0

我想出了問題所在。正如我在質詢時說,在Rspec的測試,他們有以下輸入:

xml_string = xml.hello do 
    xml.goodbye do 
    xml.come_back do 
     xml.ok_fine(:be => "that_way") 
    end 
    end 
end 

,其中4號線(xml.ok_fine(:be => "that_way"))沒有一個塊嵌套,而是一個說法。在我的代碼建立了條件(如果塊),用於當有一個塊存在,並且這個第一條件的內部,用於當@indentation是真的第二條件(if @indentation == true):

if block 
    if @indentation == false 
     "<#{method}>#{yield}</#{method}>" 
    elsif @indentation == true 
      ... 

正是這個第二條件內我創建變量「字符串」,我在不同的部分鏟:

elsif @indentation == true 

     string = "" 

     string << indent1 
     string << "<#{method}>\n" 
      (###) 
     add_indent 

     string << indent1 
     string << yield + "\n" 

     sub_indent 

     string << indent2 
     string << "</#{method}\>" 

     string 
    end 

但由於4號線不攜帶塊,第一個條件(如塊)它沒有返回true和因此這第四行被跳過。

我重新寫我的代碼,所以現在它通過Rspec的測試:

class XmlDocument 

def initialize(indentation = false) 
    @indentation = indentation 
    @counter = 0 
end 

def method_missing(method, args = nil, &block) 
    string = "" 
    arguments = args 

    if @indentation == false 
     if (arguments == nil) && (block == nil) 
      "<#{method.to_s}/>" 

     elsif arguments.is_a?(Hash) 
      arguments.map { |key,value| "<#{method.to_s} #{key.to_s}=\"#{value.to_s}\"/>" }.join(" ") 

     elsif block 
      "<#{method}>#{yield}</#{method}>" 
     end 

    elsif @indentation == true 

     if (block) || (arguments.is_a?(Hash)) 

      string << indent1 
      string << "<#{method}>\n" unless !block 
      add_indent 
      string << indent1 unless !block 

      if block 
       string << yield + "\n" 
      elsif arguments.is_a?(Hash) 
       arguments.map { |key,value| string << "<#{method.to_s} #{key.to_s}=\"#{value.to_s}\"/>" } 
      end 
      sub_indent 
      string << indent2 unless !block 
      string << "</#{method}\>" unless !block 

      if indent2 == "" 
       string << "\n" 
      end 
     end 
     string 
    end 
end 

def indent1 
    " " * @counter 
end 

def indent2 
    " " * @counter 
end 

def add_indent 
    @counter += 1 
end 

def sub_indent 
    @counter -= 1 
end 

相反我在我的問題寫的代碼,在這其中,兩個主條件是@indentation == false@indentation == true,並且在這兩個條件中,我爲不同情況(塊或無塊,參數或無參數...)建立了不同的例外情況。特別是對於elsif @indentation == true,我創建了一個接受第4行的條件:if (block) || (arguments.is_a?(Hash)),或者換句話說,它接受具有塊或參數(特別是哈希)的方法。現在

,我鏟在「串」不同部分,當我到達塊,以產生有一個分岔:

if block 
     string << yield + "\n" 
    elsif arguments.is_a?(Hash) 
     arguments.map { |key,value| string << "<#{method.to_s} #{key.to_s}=\"#{value.to_s}\"/>" } 

如果有一個塊I「產量」它,如果有和論據是一個哈希我把它鏟成'字符串'。

另外,當我縮進或剷除一個方法時,會出現這個異常unless !block,否則如果有方法沒有塊(如第4行),則會引入不需要的縮進和'\ n'。

最後,我不得不在最後

if indent2 == "" 
    string << "\n" 
end 

因爲該解決方案需要一個「\ n」末增加。

我希望這個答案可以幫助其他

注:我在我的問題,我認爲我將不得不修改「indent2」寫了「注意」。很明顯,我不必這樣做,因爲我得到的輸出沒有考慮第四行(因爲它沒有塊),所以'indent2'的更大縮進(「」)是可以的。