我正在尝试使用“method_missing”格式化标签,我想要的结果如下所示。
<foo>\n
<bar>\n
<ab/>\n
</bar>\n
</foo>\n
我认为需要运行索引,但我不清楚最佳位置,或者这是否是最好的方法。我该如何添加缩进?
def method_missing(meth, *args, &block)
if args.length > 0
my_other_method(args)
else
my_method(meth.to_s, &block)
end
end
def my_other_method(args)
"<#{args}/>"
end
def my_method(meth)
s = "<#{meth}>\n"
s << "#{_indentation}"
s << yield.to_s << "\n"
s << "#{_indentation}"
s << "</#{meth}>\n"
end
def _indentation
("--" * _level.to_i) # dashes added to more easily infer spacing
end
def _level
caller.rindex {|val| val.scan('my_method')} / 3
end
p foo{bar{baz(:a => "b"){}}}
我得到了错误的输出(不确定是什么导致额外的\ n)
<foo>\n
--<bar>\n
----<ab>\n
----</bar>\n
\n
--</foo>\n
答案 0 :(得分:1)
您可以使用调用堆栈来获取缩进级别。请参阅我的代码中的caller
。
我还建议在某些类中隔离您的代码,以便您可以使用更多标记,因为main
中可能会定义很多方法
所以,我稍微修改了你的代码:
class TagFormatter
def method_missing(method_name, *args, &block)
_tagify method_name, args, &block
end
def _tagify(tag_name, args)
if block_given?
s = "#{_indentation}<#{tag_name}#{_attrs args}>\n"
s << (yield || "")
s << "#{_indentation}</#{tag_name}>\n"
else
"#{_indentation}<#{tag_name}#{_attrs args}/>\n"
end
end
def _indentation
" " * _level
end
def _level
caller.index { |val| val =~ /instance_eval/ } / 3 - 1
end
def _attrs(args)
args.map { |arg| _to_attr arg }.join if args
end
def _to_attr(arg)
if arg.kind_of? Hash
arg.map { |k, v| %Q{ #{k}="#{v}"}}
else
%Q{ #{arg.to_s}}
end
end
end
示例:
> tf = TagFormatter.new
> puts tf.instance_eval 'foo{bar{baz(:a => "b"){}}}'
<foo>
<bar>
<baz a="b">
</baz>
</bar>
</foo>
> puts tf.instance_eval 'foo{bar{baz(:a => "b")}}' # no block given in baz
<foo>
<bar>
<baz a="b"/>
</bar>
</foo>
> puts tf.instance_eval 'foo{bar{baz("disabled", :readonly, :a=>"b")}}'
<foo>
<bar>
<baz disabled readonly a="b"/>
</bar>
</foo>