我正在使用test-first-ruby-master(您可以在https://github.com/appacademy/test-first-ruby找到它。)
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
这是我得到的&#34;缩进&#34;部分:
<hello>
<goodbye>
<come_back>
+ <ok_fine be="that_way"/>
</come_back>
</goodbye>
</hello>
与正确的答案相反,第4行(&#39; ok_fine是=&#34; that_way&#34; /&#39;)似乎是靠近左边的两个缩进比它应该是的。与其余的线相反,第4行不是块,而是被调用方法的参数&come; back&#39;。 我看不出我的错误在哪里。即使在代码中编写异常(其中(###)在我的代码中)也似乎对第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行提供正确数量的缩进,那么也会增加其后行的缩进次数,因此方法&#39; indent2&#39;需要修改。
答案 0 :(得分: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")
)没有嵌套的块,而是一个参数。在我的代码中,我建立了一个条件(if block),当有一个块存在且在第一个条件内时,第二个条件(if @indentation == true
)为@indentation为真时:
if block
if @indentation == false
"<#{method}>#{yield}</#{method}>"
elsif @indentation == true
...
在第二个条件下,我创建了变量'string',我在其中挖掘了不同的部分:
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,因此跳过第4行。
我已经重新编写了代码,所以它现在通过了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}\"/>" }
如果有一个块我“屈服”它,如果有和参数是一个哈希我把它铲成'字符串'。
此外,当我缩进或者铲除方法时,存在此异常unless !block
,否则它会引入不需要的缩进和'\ n',如果有一个方法没有块(作为行)第4次)。
最后,我必须在最后添加
if indent2 == ""
string << "\n"
end
因为解决方案最后需要'\ n'。
我希望这个答案可以帮助其他人
注意:我在我的问题中写了一个'NOTE',我认为我必须修改'indent2'。那显然我不必这样做,因为我得到的输出没有被认为是第4行(因为它没有块),所以'indent2'的较大缩进(“”)是正确的。